Avoid matching directories when searching PATH

When searching for an executable, performs an additional check to
determine if the path is a file.
This commit is contained in:
Alexandre Gomes Gaigalas 2023-01-10 07:39:13 -03:00
parent f5520209f5
commit f1bafb12a8
2 changed files with 59 additions and 20 deletions

View file

@ -16,16 +16,18 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/intrin/bits.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/intrin/strace.internal.h" #include "libc/calls/struct/stat.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/ok.h" #include "libc/sysv/consts/ok.h"
#include "libc/sysv/consts/s.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static bool IsExePath(const char *s, size_t n) { static bool IsExePath(const char *s, size_t n) {
@ -48,6 +50,9 @@ static bool AccessCommand(const char *name, char *path, size_t pathsz,
size_t pathlen) { size_t pathlen) {
size_t suffixlen; size_t suffixlen;
suffixlen = strlen(suffix); suffixlen = strlen(suffix);
if (IsWindows() && suffixlen == 0 && !IsExePath(name, namelen) &&
!IsComPath(name, namelen))
return false;
if (pathlen + 1 + namelen + suffixlen + 1 > pathsz) return false; if (pathlen + 1 + namelen + suffixlen + 1 > pathsz) return false;
if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) { if (pathlen && (path[pathlen - 1] != '/' && path[pathlen - 1] != '\\')) {
path[pathlen] = !IsWindows() ? '/' path[pathlen] = !IsWindows() ? '/'
@ -57,7 +62,16 @@ static bool AccessCommand(const char *name, char *path, size_t pathsz,
} }
memcpy(path + pathlen, name, namelen); memcpy(path + pathlen, name, namelen);
memcpy(path + pathlen + namelen, suffix, suffixlen + 1); memcpy(path + pathlen + namelen, suffix, suffixlen + 1);
if (!access(path, X_OK)) return true; if (!access(path, X_OK)) {
struct stat st;
if (!stat(path, &st)) {
if (S_ISREG(st.st_mode)) {
return true;
} else {
errno = EACCES;
}
}
}
if (errno == EACCES || *err != EACCES) *err = errno; if (errno == EACCES || *err != EACCES) *err = errno;
return false; return false;
} }

View file

@ -16,15 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/intrin/safemacros.internal.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/dirent.h" #include "libc/calls/struct/dirent.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/log/check.h" #include "libc/log/check.h"
#include "libc/mem/mem.h"
#include "libc/mem/gc.internal.h" #include "libc/mem/gc.internal.h"
#include "libc/mem/mem.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
@ -58,7 +59,12 @@ void TearDown(void) {
TEST(commandv, testPathSearch) { TEST(commandv, testPathSearch) {
EXPECT_NE(-1, touch("bin/sh", 0755)); EXPECT_NE(-1, touch("bin/sh", 0755));
EXPECT_STREQ("bin/sh", commandv("sh", pathbuf, sizeof(pathbuf))); if (IsWindows()) {
EXPECT_EQ(NULL, commandv("sh", pathbuf, sizeof(pathbuf)));
EXPECT_EQ(errno, ENOENT);
} else {
EXPECT_STREQ("bin/sh", commandv("sh", pathbuf, sizeof(pathbuf)));
}
} }
TEST(commandv, testPathSearch_appendsComExtension) { TEST(commandv, testPathSearch_appendsComExtension) {
@ -67,44 +73,63 @@ TEST(commandv, testPathSearch_appendsComExtension) {
} }
TEST(commandv, testSlashes_wontSearchPath_butChecksAccess) { TEST(commandv, testSlashes_wontSearchPath_butChecksAccess) {
EXPECT_NE(-1, touch("home/sh", 0755)); EXPECT_NE(-1, touch("home/sh.com", 0755));
i = __syscount; i = __syscount;
EXPECT_STREQ("home/sh", commandv("home/sh", pathbuf, sizeof(pathbuf))); EXPECT_STREQ("home/sh.com",
if (!IsWindows()) EXPECT_EQ(i + 1, __syscount); commandv("home/sh.com", pathbuf, sizeof(pathbuf)));
if (!IsWindows()) EXPECT_EQ(i + 2, __syscount);
} }
TEST(commandv, testSlashes_wontSearchPath_butStillAppendsComExtension) { TEST(commandv, testSlashes_wontSearchPath_butStillAppendsComExtension) {
EXPECT_NE(-1, touch("home/sh.com", 0755)); EXPECT_NE(-1, touch("home/sh.com", 0755));
i = __syscount; i = __syscount;
EXPECT_STREQ("home/sh.com", commandv("home/sh", pathbuf, sizeof(pathbuf))); EXPECT_STREQ("home/sh.com", commandv("home/sh", pathbuf, sizeof(pathbuf)));
if (!IsWindows()) EXPECT_EQ(i + 2, __syscount); if (!IsWindows()) EXPECT_EQ(i + 3, __syscount);
} }
TEST(commandv, testSameDir_doesntHappenByDefaultUnlessItsWindows) { TEST(commandv, testSameDir_doesntHappenByDefaultUnlessItsWindows) {
EXPECT_NE(-1, touch("bog", 0755)); EXPECT_NE(-1, touch("bog.com", 0755));
if (IsWindows()) { if (IsWindows()) {
EXPECT_STREQ("./bog", commandv("bog", pathbuf, sizeof(pathbuf))); EXPECT_STREQ("./bog.com", commandv("bog.com", pathbuf, sizeof(pathbuf)));
} else { } else {
EXPECT_EQ(NULL, commandv("bog", pathbuf, sizeof(pathbuf))); EXPECT_EQ(NULL, commandv("bog.com", pathbuf, sizeof(pathbuf)));
EXPECT_EQ(errno, ENOENT);
} }
} }
TEST(commandv, testSameDir_willHappenWithColonBlank) { TEST(commandv, testSameDir_willHappenWithColonBlank) {
CHECK_NE(-1, setenv("PATH", "bin:", true)); CHECK_NE(-1, setenv("PATH", "bin:", true));
EXPECT_NE(-1, touch("bog", 0755)); EXPECT_NE(-1, touch("bog.com", 0755));
if (IsWindows()) { if (IsWindows()) {
EXPECT_STREQ("./bog", commandv("bog", pathbuf, sizeof(pathbuf))); EXPECT_STREQ("./bog.com", commandv("bog.com", pathbuf, sizeof(pathbuf)));
} else { } else {
EXPECT_STREQ("bog", commandv("bog", pathbuf, sizeof(pathbuf))); EXPECT_STREQ("bog.com", commandv("bog.com", pathbuf, sizeof(pathbuf)));
} }
} }
TEST(commandv, testSameDir_willHappenWithColonBlank2) { TEST(commandv, testSameDir_willHappenWithColonBlank2) {
CHECK_NE(-1, setenv("PATH", ":bin", true)); CHECK_NE(-1, setenv("PATH", ":bin", true));
EXPECT_NE(-1, touch("bog", 0755)); EXPECT_NE(-1, touch("bog.com", 0755));
if (IsWindows()) { if (IsWindows()) {
EXPECT_STREQ("./bog", commandv("bog", pathbuf, sizeof(pathbuf))); EXPECT_STREQ("./bog.com", commandv("bog.com", pathbuf, sizeof(pathbuf)));
} else { } else {
EXPECT_STREQ("bog", commandv("bog", pathbuf, sizeof(pathbuf))); EXPECT_STREQ("bog.com", commandv("bog.com", pathbuf, sizeof(pathbuf)));
}
}
TEST(commandv, test_DirPaths_wontConsiderDirectoriesExecutable) {
EXPECT_NE(-1, mkdir("Cursors", 0755));
EXPECT_EQ(NULL, commandv("Cursors", pathbuf, sizeof(pathbuf)));
EXPECT_EQ(errno, ENOENT);
}
TEST(commandv, test_DirPaths_wontConsiderDirectoriesExecutable2) {
EXPECT_NE(-1, mkdir("this_is_a_directory.com", 0755));
EXPECT_EQ(NULL,
commandv("this_is_a_directory.com", pathbuf, sizeof(pathbuf)));
if (IsWindows()) {
EXPECT_EQ(errno, EACCES);
} else {
EXPECT_EQ(errno, ENOENT);
} }
} }