aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2024-10-07 05:46:31 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2024-10-07 05:46:31 +0200
commit860b3d066f6aaa12dfa0cd2351559e05288cf9b5 (patch)
tree2cfc5bb917507ae6ff3086a66acb8b6e89d1f67c
parent748b1681549067f2e27ab2b9102ef9352cfa8a4c (diff)
downloadbusybox-w32-860b3d066f6aaa12dfa0cd2351559e05288cf9b5.tar.gz
busybox-w32-860b3d066f6aaa12dfa0cd2351559e05288cf9b5.tar.bz2
busybox-w32-860b3d066f6aaa12dfa0cd2351559e05288cf9b5.zip
ash: command -v CMD must skip (go to next path) when CMD exists, but is not executable
Upstream commit: Date: Fri, 5 Apr 2024 17:55:46 +0800 exec: Check executable bit when searching path Andrej Shadura <andrew.shadura@collabora.co.uk> wrote: ... > https://bugs.debian.org/874264 > -------- Forwarded Message -------- > Subject: dash: 'command -v' mistakenly returns a shell script whose > executable is not set > Date: Mon, 04 Sep 2017 10:45:48 -0400 > From: Norman Ramsey <nr@cs.tufts.edu> > To: Debian Bug Tracking System <submit@bugs.debian.org> ... > I tracked a build bug in s-nail to a problem with dash. Symptom: > building s-nail tries to run /home/nr/bin/clang, a script whose > executable bit is not set. We tracked the problem to the result of > running `command -v clang` with /bin/sh: ... This is inherited from NetBSD. There is even a commented-out block of code that tried to fix this. Anyway, we now have faccessat so we can simply use it. function old new delta test_exec - 125 +125 find_command 911 918 +7 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/0 up/down: 132/0) Total: 132 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/ash.c54
1 files changed, 51 insertions, 3 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 8e029765d..984a71f07 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -491,6 +491,11 @@ struct globals_misc {
491 char **trap_ptr; /* used only by "trap hack" */ 491 char **trap_ptr; /* used only by "trap hack" */
492 492
493 /* Rarely referenced stuff */ 493 /* Rarely referenced stuff */
494
495 /* Cached supplementary group array (for testing executable'ity of files) */
496 int ngroups;
497 gid_t *group_array;
498
494#if ENABLE_ASH_RANDOM_SUPPORT 499#if ENABLE_ASH_RANDOM_SUPPORT
495 random_t random_gen; 500 random_t random_gen;
496#endif 501#endif
@@ -523,6 +528,8 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc;
523#define may_have_traps (G_misc.may_have_traps ) 528#define may_have_traps (G_misc.may_have_traps )
524#define trap (G_misc.trap ) 529#define trap (G_misc.trap )
525#define trap_ptr (G_misc.trap_ptr ) 530#define trap_ptr (G_misc.trap_ptr )
531#define ngroups (G_misc.ngroups )
532#define group_array (G_misc.group_array)
526#define random_gen (G_misc.random_gen ) 533#define random_gen (G_misc.random_gen )
527#define backgndpid (G_misc.backgndpid ) 534#define backgndpid (G_misc.backgndpid )
528#define INIT_G_misc() do { \ 535#define INIT_G_misc() do { \
@@ -10171,6 +10178,7 @@ static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc,
10171#endif 10178#endif
10172#if ENABLE_ASH_TEST || BASH_TEST2 10179#if ENABLE_ASH_TEST || BASH_TEST2
10173static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); } 10180static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); }
10181// TODO: pass &ngroups and &group_array addresses to test_main to use cached supplementary groups
10174#endif 10182#endif
10175#if ENABLE_ASH_SLEEP 10183#if ENABLE_ASH_SLEEP
10176static int FAST_FUNC sleepcmd(int argc, char **argv) { return sleep_main(argc, argv); } 10184static int FAST_FUNC sleepcmd(int argc, char **argv) { return sleep_main(argc, argv); }
@@ -13782,6 +13790,43 @@ readcmdfile(char *name)
13782 13790
13783/* ============ find_command inplementation */ 13791/* ============ find_command inplementation */
13784 13792
13793static int test_exec(/*const char *fullname,*/ struct stat *statb)
13794{
13795 /*
13796 * TODO: use faccessat(AT_FDCWD, fullname, X_OK, AT_EACCESS)
13797 * instead: executability may depend on ACLs, capabilities
13798 * and who knows what else, not just mode bits.
13799 * (faccessat2 syscall was added to Linux in May 14 2020)
13800 */
13801 mode_t stmode;
13802 uid_t euid;
13803 enum { ANY_IX = S_IXUSR | S_IXGRP | S_IXOTH };
13804
13805 /* Do we already know with no extra syscalls? */
13806 if (!S_ISREG(statb->st_mode))
13807 return 0; /* not a regular file */
13808 if ((statb->st_mode & ANY_IX) == 0)
13809 return 0; /* no one can execute */
13810 if ((statb->st_mode & ANY_IX) == ANY_IX)
13811 return 1; /* anyone can execute */
13812
13813 /* Executability depends on our euid/egid/supplementary groups */
13814 stmode = S_IXOTH;
13815 euid = geteuid();
13816//TODO: cache euid?
13817 if (euid == 0)
13818 /* for root user, any X bit is good enough */
13819 stmode = ANY_IX;
13820 else if (statb->st_uid == euid)
13821 stmode = S_IXUSR;
13822 else if (statb->st_gid == getegid())
13823 stmode = S_IXGRP;
13824 else if (is_in_supplementary_groups(&ngroups, &group_array, statb->st_gid))
13825 stmode = S_IXGRP;
13826
13827 return statb->st_mode & stmode;
13828}
13829
13785/* 13830/*
13786 * Resolve a command name. If you change this routine, you may have to 13831 * Resolve a command name. If you change this routine, you may have to
13787 * change the shellexec routine as well. 13832 * change the shellexec routine as well.
@@ -13808,9 +13853,12 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13808 if (errno == EINTR) 13853 if (errno == EINTR)
13809 continue; 13854 continue;
13810#endif 13855#endif
13856 absfail:
13811 entry->cmdtype = CMDUNKNOWN; 13857 entry->cmdtype = CMDUNKNOWN;
13812 return; 13858 return;
13813 } 13859 }
13860 if (!test_exec(/*name,*/ &statb))
13861 goto absfail;
13814 } 13862 }
13815 entry->cmdtype = CMDNORMAL; 13863 entry->cmdtype = CMDNORMAL;
13816 return; 13864 return;
@@ -13923,9 +13971,6 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13923 e = errno; 13971 e = errno;
13924 goto loop; 13972 goto loop;
13925 } 13973 }
13926 e = EACCES; /* if we fail, this will be the error */
13927 if (!S_ISREG(statb.st_mode))
13928 continue;
13929 if (lpathopt) { /* this is a %func directory */ 13974 if (lpathopt) { /* this is a %func directory */
13930 stalloc(len); 13975 stalloc(len);
13931 /* NB: stalloc will return space pointed by fullname 13976 /* NB: stalloc will return space pointed by fullname
@@ -13938,6 +13983,9 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path)
13938 stunalloc(fullname); 13983 stunalloc(fullname);
13939 goto success; 13984 goto success;
13940 } 13985 }
13986 e = EACCES; /* if we fail, this will be the error */
13987 if (!test_exec(/*fullname,*/ &statb))
13988 continue;
13941 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); 13989 TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
13942 if (!updatetbl) { 13990 if (!updatetbl) {
13943 entry->cmdtype = CMDNORMAL; 13991 entry->cmdtype = CMDNORMAL;