Avoid matching directories when searching PATH (#717)

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-03-06 13:15:32 -03:00 committed by GitHub
parent e2f429b742
commit 775f456d4c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
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);
} }
} }