diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 56 |
1 files changed, 51 insertions, 5 deletions
diff --git a/shell/ash.c b/shell/ash.c index 679846574..b37446233 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -671,6 +671,10 @@ struct globals_misc { | |||
671 | char **trap_ptr; /* used only by "trap hack" */ | 671 | char **trap_ptr; /* used only by "trap hack" */ |
672 | 672 | ||
673 | /* Rarely referenced stuff */ | 673 | /* Rarely referenced stuff */ |
674 | |||
675 | /* Cached supplementary group array (for testing executable'ity of files) */ | ||
676 | struct cached_groupinfo groupinfo; | ||
677 | |||
674 | #if ENABLE_ASH_RANDOM_SUPPORT | 678 | #if ENABLE_ASH_RANDOM_SUPPORT |
675 | random_t random_gen; | 679 | random_t random_gen; |
676 | #endif | 680 | #endif |
@@ -714,6 +718,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
714 | #define may_have_traps (G_misc.may_have_traps ) | 718 | #define may_have_traps (G_misc.may_have_traps ) |
715 | #define trap (G_misc.trap ) | 719 | #define trap (G_misc.trap ) |
716 | #define trap_ptr (G_misc.trap_ptr ) | 720 | #define trap_ptr (G_misc.trap_ptr ) |
721 | #define groupinfo (G_misc.groupinfo ) | ||
717 | #define random_gen (G_misc.random_gen ) | 722 | #define random_gen (G_misc.random_gen ) |
718 | #define backgndpid (G_misc.backgndpid ) | 723 | #define backgndpid (G_misc.backgndpid ) |
719 | 724 | ||
@@ -729,6 +734,8 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; | |||
729 | curdir = nullstr; \ | 734 | curdir = nullstr; \ |
730 | physdir = nullstr; \ | 735 | physdir = nullstr; \ |
731 | trap_ptr = trap; \ | 736 | trap_ptr = trap; \ |
737 | groupinfo.euid = -1; \ | ||
738 | groupinfo.egid = -1; \ | ||
732 | } while (0) | 739 | } while (0) |
733 | 740 | ||
734 | 741 | ||
@@ -2579,7 +2586,7 @@ initvar(void) | |||
2579 | #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT | 2586 | #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT |
2580 | vps1.var_text = "PS1=\\w \\$ "; | 2587 | vps1.var_text = "PS1=\\w \\$ "; |
2581 | #else | 2588 | #else |
2582 | if (!geteuid()) | 2589 | if (!get_cached_euid(&groupinfo.euid)); |
2583 | vps1.var_text = "PS1=# "; | 2590 | vps1.var_text = "PS1=# "; |
2584 | #endif | 2591 | #endif |
2585 | vp = varinit; | 2592 | vp = varinit; |
@@ -11342,7 +11349,7 @@ static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, a | |||
11342 | static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); } | 11349 | static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); } |
11343 | #endif | 11350 | #endif |
11344 | #if ENABLE_ASH_TEST || BASH_TEST2 | 11351 | #if ENABLE_ASH_TEST || BASH_TEST2 |
11345 | static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); } | 11352 | static int FAST_FUNC testcmd(int argc, char **argv) { return test_main2(&groupinfo, argc, argv); } |
11346 | #endif | 11353 | #endif |
11347 | #if ENABLE_ASH_SLEEP | 11354 | #if ENABLE_ASH_SLEEP |
11348 | static int FAST_FUNC sleepcmd(int argc, char **argv) { return sleep_main(argc, argv); } | 11355 | static int FAST_FUNC sleepcmd(int argc, char **argv) { return sleep_main(argc, argv); } |
@@ -15101,6 +15108,42 @@ readcmdfile(char *name) | |||
15101 | 15108 | ||
15102 | /* ============ find_command inplementation */ | 15109 | /* ============ find_command inplementation */ |
15103 | 15110 | ||
15111 | static int test_exec(/*const char *fullname,*/ struct stat *statb) | ||
15112 | { | ||
15113 | /* | ||
15114 | * TODO: use faccessat(AT_FDCWD, fullname, X_OK, AT_EACCESS) | ||
15115 | * instead: executability may depend on ACLs, capabilities | ||
15116 | * and who knows what else, not just mode bits. | ||
15117 | * (faccessat2 syscall was added to Linux in May 14 2020) | ||
15118 | */ | ||
15119 | mode_t stmode; | ||
15120 | uid_t euid; | ||
15121 | enum { ANY_IX = S_IXUSR | S_IXGRP | S_IXOTH }; | ||
15122 | |||
15123 | /* Do we already know with no extra syscalls? */ | ||
15124 | if (!S_ISREG(statb->st_mode)) | ||
15125 | return 0; /* not a regular file */ | ||
15126 | if ((statb->st_mode & ANY_IX) == 0) | ||
15127 | return 0; /* no one can execute */ | ||
15128 | if ((statb->st_mode & ANY_IX) == ANY_IX) | ||
15129 | return 1; /* anyone can execute */ | ||
15130 | |||
15131 | /* Executability depends on our euid/egid/supplementary groups */ | ||
15132 | stmode = S_IXOTH; | ||
15133 | euid = get_cached_euid(&groupinfo.euid); | ||
15134 | if (euid == 0) | ||
15135 | /* for root user, any X bit is good enough */ | ||
15136 | stmode = ANY_IX; | ||
15137 | else if (statb->st_uid == euid) | ||
15138 | stmode = S_IXUSR; | ||
15139 | else if (statb->st_gid == get_cached_egid(&groupinfo.egid)) | ||
15140 | stmode = S_IXGRP; | ||
15141 | else if (is_in_supplementary_groups(&groupinfo, statb->st_gid)) | ||
15142 | stmode = S_IXGRP; | ||
15143 | |||
15144 | return statb->st_mode & stmode; | ||
15145 | } | ||
15146 | |||
15104 | /* | 15147 | /* |
15105 | * Resolve a command name. If you change this routine, you may have to | 15148 | * Resolve a command name. If you change this routine, you may have to |
15106 | * change the shellexec routine as well. | 15149 | * change the shellexec routine as well. |
@@ -15128,9 +15171,12 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
15128 | if (errno == EINTR) | 15171 | if (errno == EINTR) |
15129 | continue; | 15172 | continue; |
15130 | #endif | 15173 | #endif |
15174 | absfail: | ||
15131 | entry->cmdtype = CMDUNKNOWN; | 15175 | entry->cmdtype = CMDUNKNOWN; |
15132 | return; | 15176 | return; |
15133 | } | 15177 | } |
15178 | if (!test_exec(/*name,*/ &statb)) | ||
15179 | goto absfail; | ||
15134 | } | 15180 | } |
15135 | entry->cmdtype = CMDNORMAL; | 15181 | entry->cmdtype = CMDNORMAL; |
15136 | return; | 15182 | return; |
@@ -15275,9 +15321,6 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
15275 | e = errno; | 15321 | e = errno; |
15276 | goto loop; | 15322 | goto loop; |
15277 | } | 15323 | } |
15278 | e = EACCES; /* if we fail, this will be the error */ | ||
15279 | if (!S_ISREG(statb.st_mode)) | ||
15280 | continue; | ||
15281 | if (lpathopt) { /* this is a %func directory */ | 15324 | if (lpathopt) { /* this is a %func directory */ |
15282 | stalloc(len); | 15325 | stalloc(len); |
15283 | /* NB: stalloc will return space pointed by fullname | 15326 | /* NB: stalloc will return space pointed by fullname |
@@ -15290,6 +15333,9 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) | |||
15290 | stunalloc(fullname); | 15333 | stunalloc(fullname); |
15291 | goto success; | 15334 | goto success; |
15292 | } | 15335 | } |
15336 | e = EACCES; /* if we fail, this will be the error */ | ||
15337 | if (!test_exec(/*fullname,*/ &statb)) | ||
15338 | continue; | ||
15293 | TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); | 15339 | TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); |
15294 | if (!updatetbl) { | 15340 | if (!updatetbl) { |
15295 | entry->cmdtype = CMDNORMAL; | 15341 | entry->cmdtype = CMDNORMAL; |