diff options
| author | Ron Yorston <rmy@pobox.com> | 2024-10-08 08:46:53 +0100 |
|---|---|---|
| committer | Ron Yorston <rmy@pobox.com> | 2024-10-08 08:47:44 +0100 |
| commit | 2fe27c6dbf3c752edbfddfd48c15bab55b3ab8de (patch) | |
| tree | 3d907c63f92be35ef96dde01fedf6cf6b7a8e14c | |
| parent | 5b30de8fba414f75cb25faebf5cd8f391e1deb75 (diff) | |
| parent | 0929a129fc75c556de67877491281e0bc3ef3edd (diff) | |
| download | busybox-w32-2fe27c6dbf3c752edbfddfd48c15bab55b3ab8de.tar.gz busybox-w32-2fe27c6dbf3c752edbfddfd48c15bab55b3ab8de.tar.bz2 busybox-w32-2fe27c6dbf3c752edbfddfd48c15bab55b3ab8de.zip | |
Merge branch 'busybox' into merge
| -rw-r--r-- | coreutils/test.c | 91 | ||||
| -rw-r--r-- | include/libbb.h | 14 | ||||
| -rw-r--r-- | libbb/bb_getgroups.c | 34 | ||||
| -rw-r--r-- | libbb/hash_md5_sha.c | 2 | ||||
| -rw-r--r-- | networking/libiproute/iplink.c | 21 | ||||
| -rw-r--r-- | shell/ash.c | 56 |
6 files changed, 169 insertions, 49 deletions
diff --git a/coreutils/test.c b/coreutils/test.c index 008d90b25..b63e33cc0 100644 --- a/coreutils/test.c +++ b/coreutils/test.c | |||
| @@ -426,8 +426,7 @@ struct test_statics { | |||
| 426 | /* set only by check_operator(), either to bogus struct | 426 | /* set only by check_operator(), either to bogus struct |
| 427 | * or points to matching operator_t struct. Never NULL. */ | 427 | * or points to matching operator_t struct. Never NULL. */ |
| 428 | const struct operator_t *last_operator; | 428 | const struct operator_t *last_operator; |
| 429 | gid_t *group_array; | 429 | struct cached_groupinfo *groupinfo; |
| 430 | int ngroups; | ||
| 431 | #if BASH_TEST2 | 430 | #if BASH_TEST2 |
| 432 | bool bash_test2; | 431 | bool bash_test2; |
| 433 | #endif | 432 | #endif |
| @@ -440,8 +439,7 @@ extern struct test_statics *BB_GLOBAL_CONST test_ptr_to_statics; | |||
| 440 | #define S (*test_ptr_to_statics) | 439 | #define S (*test_ptr_to_statics) |
| 441 | #define args (S.args ) | 440 | #define args (S.args ) |
| 442 | #define last_operator (S.last_operator) | 441 | #define last_operator (S.last_operator) |
| 443 | #define group_array (S.group_array ) | 442 | #define groupinfo (S.groupinfo ) |
| 444 | #define ngroups (S.ngroups ) | ||
| 445 | #define bash_test2 (S.bash_test2 ) | 443 | #define bash_test2 (S.bash_test2 ) |
| 446 | #define leaving (S.leaving ) | 444 | #define leaving (S.leaving ) |
| 447 | 445 | ||
| @@ -449,7 +447,6 @@ extern struct test_statics *BB_GLOBAL_CONST test_ptr_to_statics; | |||
| 449 | XZALLOC_CONST_PTR(&test_ptr_to_statics, sizeof(S)); \ | 447 | XZALLOC_CONST_PTR(&test_ptr_to_statics, sizeof(S)); \ |
| 450 | } while (0) | 448 | } while (0) |
| 451 | #define DEINIT_S() do { \ | 449 | #define DEINIT_S() do { \ |
| 452 | free(group_array); \ | ||
| 453 | free(test_ptr_to_statics); \ | 450 | free(test_ptr_to_statics); \ |
| 454 | } while (0) | 451 | } while (0) |
| 455 | 452 | ||
| @@ -637,62 +634,52 @@ static int binop(void) | |||
| 637 | /*return 1; - NOTREACHED */ | 634 | /*return 1; - NOTREACHED */ |
| 638 | } | 635 | } |
| 639 | 636 | ||
| 640 | static void initialize_group_array(void) | ||
| 641 | { | ||
| 642 | group_array = bb_getgroups(&ngroups, NULL); | ||
| 643 | } | ||
| 644 | |||
| 645 | /* Return non-zero if GID is one that we have in our groups list. */ | 637 | /* Return non-zero if GID is one that we have in our groups list. */ |
| 646 | //XXX: FIXME: duplicate of existing libbb function? | ||
| 647 | // see toplevel TODO file: | ||
| 648 | // possible code duplication ingroup() and is_a_group_member() | ||
| 649 | static int is_a_group_member(gid_t gid) | 638 | static int is_a_group_member(gid_t gid) |
| 650 | { | 639 | { |
| 651 | int i; | ||
| 652 | |||
| 653 | /* Short-circuit if possible, maybe saving a call to getgroups(). */ | 640 | /* Short-circuit if possible, maybe saving a call to getgroups(). */ |
| 654 | if (gid == getgid() || gid == getegid()) | 641 | if (gid == get_cached_egid(&groupinfo->egid)) |
| 655 | return 1; | 642 | return 1; |
| 656 | 643 | ||
| 657 | if (ngroups == 0) | 644 | return is_in_supplementary_groups(groupinfo, gid); |
| 658 | initialize_group_array(); | ||
| 659 | |||
| 660 | /* Search through the list looking for GID. */ | ||
| 661 | for (i = 0; i < ngroups; i++) | ||
| 662 | if (gid == group_array[i]) | ||
| 663 | return 1; | ||
| 664 | |||
| 665 | return 0; | ||
| 666 | } | 645 | } |
| 667 | 646 | ||
| 668 | 647 | /* | |
| 669 | /* Do the same thing access(2) does, but use the effective uid and gid, | 648 | * Similar to what access(2) does, but uses the effective uid and gid. |
| 670 | and don't make the mistake of telling root that any file is | 649 | * Doesn't make the mistake of telling root that any file is executable. |
| 671 | executable. */ | 650 | * Returns non-zero if the file is accessible. |
| 672 | static int test_eaccess(struct stat *st, int mode) | 651 | */ |
| 652 | static int test_st_mode(struct stat *st, int mode) | ||
| 673 | { | 653 | { |
| 674 | unsigned int euid = geteuid(); | 654 | enum { ANY_IX = S_IXUSR | S_IXGRP | S_IXOTH }; |
| 655 | unsigned euid; | ||
| 656 | |||
| 657 | if (mode == X_OK) { | ||
| 658 | /* Do we already know with no extra syscalls? */ | ||
| 659 | //if (!S_ISREG(st->st_mode)) | ||
| 660 | // return 0; /* not a regular file */ | ||
| 661 | // ^^^ bash 5.2.15 "test -x" does not check this! | ||
| 662 | if ((st->st_mode & ANY_IX) == 0) | ||
| 663 | return 0; /* no one can execute */ | ||
| 664 | if ((st->st_mode & ANY_IX) == ANY_IX) | ||
| 665 | return 1; /* anyone can execute */ | ||
| 666 | } | ||
| 675 | 667 | ||
| 668 | euid = get_cached_euid(&groupinfo->euid); | ||
| 676 | if (euid == 0) { | 669 | if (euid == 0) { |
| 677 | /* Root can read or write any file. */ | 670 | /* Root can read or write any file. */ |
| 678 | if (mode != X_OK) | 671 | if (mode != X_OK) |
| 679 | return 0; | 672 | return 1; |
| 680 | 673 | ||
| 681 | /* Root can execute any file that has any one of the execute | 674 | /* Root can execute any file that has any one of the execute |
| 682 | * bits set. */ | 675 | * bits set. */ |
| 683 | if (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) | 676 | mode = S_IXUSR | S_IXGRP | S_IXOTH; |
| 684 | return 0; | 677 | } else if (st->st_uid == euid) /* owner */ |
| 685 | } | ||
| 686 | |||
| 687 | if (st->st_uid == euid) /* owner */ | ||
| 688 | mode <<= 6; | 678 | mode <<= 6; |
| 689 | else if (is_a_group_member(st->st_gid)) | 679 | else if (is_a_group_member(st->st_gid)) |
| 690 | mode <<= 3; | 680 | mode <<= 3; |
| 691 | 681 | ||
| 692 | if (st->st_mode & mode) | 682 | return st->st_mode & mode; |
| 693 | return 0; | ||
| 694 | |||
| 695 | return -1; | ||
| 696 | } | 683 | } |
| 697 | 684 | ||
| 698 | 685 | ||
| @@ -722,7 +709,7 @@ static int filstat(char *nm, enum token mode) | |||
| 722 | i = W_OK; | 709 | i = W_OK; |
| 723 | if (mode == FILEX) | 710 | if (mode == FILEX) |
| 724 | i = X_OK; | 711 | i = X_OK; |
| 725 | return test_eaccess(&s, i) == 0; | 712 | return test_st_mode(&s, i); |
| 726 | } | 713 | } |
| 727 | if (is_file_type(mode)) { | 714 | if (is_file_type(mode)) { |
| 728 | if (mode == FILREG) | 715 | if (mode == FILREG) |
| @@ -760,7 +747,7 @@ static int filstat(char *nm, enum token mode) | |||
| 760 | return ((s.st_mode & i) != 0); | 747 | return ((s.st_mode & i) != 0); |
| 761 | } | 748 | } |
| 762 | if (mode == FILGZ) | 749 | if (mode == FILGZ) |
| 763 | return s.st_size > 0L; | 750 | return s.st_size != 0L; /* shorter than "> 0" test */ |
| 764 | if (mode == FILUID) | 751 | if (mode == FILUID) |
| 765 | return s.st_uid == geteuid(); | 752 | return s.st_uid == geteuid(); |
| 766 | if (mode == FILGID) | 753 | if (mode == FILGID) |
| @@ -891,7 +878,7 @@ static number_t primary(enum token n) | |||
| 891 | } | 878 | } |
| 892 | 879 | ||
| 893 | 880 | ||
| 894 | int test_main(int argc, char **argv) | 881 | int FAST_FUNC test_main2(struct cached_groupinfo *pgroupinfo, int argc, char **argv) |
| 895 | { | 882 | { |
| 896 | int res; | 883 | int res; |
| 897 | const char *arg0; | 884 | const char *arg0; |
| @@ -924,6 +911,7 @@ int test_main(int argc, char **argv) | |||
| 924 | 911 | ||
| 925 | /* We must do DEINIT_S() prior to returning */ | 912 | /* We must do DEINIT_S() prior to returning */ |
| 926 | INIT_S(); | 913 | INIT_S(); |
| 914 | groupinfo = pgroupinfo; | ||
| 927 | 915 | ||
| 928 | #if BASH_TEST2 | 916 | #if BASH_TEST2 |
| 929 | bash_test2 = bt2; | 917 | bash_test2 = bt2; |
| @@ -1026,3 +1014,18 @@ int test_main(int argc, char **argv) | |||
| 1026 | DEINIT_S(); | 1014 | DEINIT_S(); |
| 1027 | return res; | 1015 | return res; |
| 1028 | } | 1016 | } |
| 1017 | |||
| 1018 | int test_main(int argc, char **argv) | ||
| 1019 | { | ||
| 1020 | struct cached_groupinfo info; | ||
| 1021 | int r; | ||
| 1022 | |||
| 1023 | info.euid = -1; | ||
| 1024 | info.egid = -1; | ||
| 1025 | info.ngroups = 0; | ||
| 1026 | info.supplementary_array = NULL; | ||
| 1027 | r = test_main2(&info, argc, argv); | ||
| 1028 | free(info.supplementary_array); | ||
| 1029 | |||
| 1030 | return r; | ||
| 1031 | } | ||
diff --git a/include/libbb.h b/include/libbb.h index b68f9b684..ff4a67481 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
| @@ -1261,6 +1261,19 @@ void die_if_bad_username(const char* name) FAST_FUNC; | |||
| 1261 | * Dies on errors (on Linux, only xrealloc can cause this, not internal getgroups call). | 1261 | * Dies on errors (on Linux, only xrealloc can cause this, not internal getgroups call). |
| 1262 | */ | 1262 | */ |
| 1263 | gid_t *bb_getgroups(int *ngroups, gid_t *group_array) FAST_FUNC; | 1263 | gid_t *bb_getgroups(int *ngroups, gid_t *group_array) FAST_FUNC; |
| 1264 | /* | ||
| 1265 | * True if GID is in our getgroups() result. | ||
| 1266 | * getgroups() is cached in supplementary_array[], to make successive calls faster. | ||
| 1267 | */ | ||
| 1268 | struct cached_groupinfo { | ||
| 1269 | uid_t euid; | ||
| 1270 | gid_t egid; | ||
| 1271 | int ngroups; | ||
| 1272 | gid_t *supplementary_array; | ||
| 1273 | }; | ||
| 1274 | uid_t FAST_FUNC get_cached_euid(uid_t *euid); | ||
| 1275 | gid_t FAST_FUNC get_cached_egid(gid_t *egid); | ||
| 1276 | int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid); | ||
| 1264 | 1277 | ||
| 1265 | #if ENABLE_FEATURE_UTMP | 1278 | #if ENABLE_FEATURE_UTMP |
| 1266 | void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname); | 1279 | void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname); |
| @@ -1612,6 +1625,7 @@ int test_main(int argc, char **argv) | |||
| 1612 | MAIN_EXTERNALLY_VISIBLE | 1625 | MAIN_EXTERNALLY_VISIBLE |
| 1613 | #endif | 1626 | #endif |
| 1614 | ; | 1627 | ; |
| 1628 | int FAST_FUNC test_main2(struct cached_groupinfo *pgroupinfo, int argc, char **argv); | ||
| 1615 | int kill_main(int argc, char **argv) | 1629 | int kill_main(int argc, char **argv) |
| 1616 | #if ENABLE_KILL || ENABLE_KILLALL || ENABLE_KILLALL5 | 1630 | #if ENABLE_KILL || ENABLE_KILLALL || ENABLE_KILLALL5 |
| 1617 | MAIN_EXTERNALLY_VISIBLE | 1631 | MAIN_EXTERNALLY_VISIBLE |
diff --git a/libbb/bb_getgroups.c b/libbb/bb_getgroups.c index 5d83c729a..31cff2b41 100644 --- a/libbb/bb_getgroups.c +++ b/libbb/bb_getgroups.c | |||
| @@ -45,3 +45,37 @@ gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array) | |||
| 45 | *ngroups = n; | 45 | *ngroups = n; |
| 46 | return group_array; | 46 | return group_array; |
| 47 | } | 47 | } |
| 48 | |||
| 49 | uid_t FAST_FUNC get_cached_euid(uid_t *euid) | ||
| 50 | { | ||
| 51 | if (*euid == (uid_t)-1) | ||
| 52 | *euid = geteuid(); | ||
| 53 | return *euid; | ||
| 54 | } | ||
| 55 | |||
| 56 | gid_t FAST_FUNC get_cached_egid(gid_t *egid) | ||
| 57 | { | ||
| 58 | if (*egid == (gid_t)-1) | ||
| 59 | *egid = getegid(); | ||
| 60 | return *egid; | ||
| 61 | } | ||
| 62 | |||
| 63 | /* Return non-zero if GID is in our supplementary group list. */ | ||
| 64 | int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid) | ||
| 65 | { | ||
| 66 | int i; | ||
| 67 | int ngroups; | ||
| 68 | gid_t *group_array; | ||
| 69 | |||
| 70 | if (groupinfo->ngroups == 0) | ||
| 71 | groupinfo->supplementary_array = bb_getgroups(&groupinfo->ngroups, NULL); | ||
| 72 | ngroups = groupinfo->ngroups; | ||
| 73 | group_array = groupinfo->supplementary_array; | ||
| 74 | |||
| 75 | /* Search through the list looking for GID. */ | ||
| 76 | for (i = 0; i < ngroups; i++) | ||
| 77 | if (gid == group_array[i]) | ||
| 78 | return 1; | ||
| 79 | |||
| 80 | return 0; | ||
| 81 | } | ||
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index 57a801459..75a61c32c 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c | |||
| @@ -1313,7 +1313,9 @@ unsigned FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf) | |||
| 1313 | hash_size = 8; | 1313 | hash_size = 8; |
| 1314 | if (ctx->process_block == sha1_process_block64 | 1314 | if (ctx->process_block == sha1_process_block64 |
| 1315 | #if ENABLE_SHA1_HWACCEL | 1315 | #if ENABLE_SHA1_HWACCEL |
| 1316 | # if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) | ||
| 1316 | || ctx->process_block == sha1_process_block64_shaNI | 1317 | || ctx->process_block == sha1_process_block64_shaNI |
| 1318 | # endif | ||
| 1317 | #endif | 1319 | #endif |
| 1318 | ) { | 1320 | ) { |
| 1319 | hash_size = 5; | 1321 | hash_size = 5; |
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index 37ed114bc..67602a466 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c | |||
| @@ -51,6 +51,27 @@ struct ifla_vlan_flags { | |||
| 51 | }; | 51 | }; |
| 52 | #endif | 52 | #endif |
| 53 | 53 | ||
| 54 | #if ENABLE_FEATURE_IP_LINK_CAN | ||
| 55 | # ifndef CAN_CTRLMODE_ONE_SHOT | ||
| 56 | # define CAN_CTRLMODE_ONE_SHOT 0x08 /* One-Shot mode */ | ||
| 57 | # endif | ||
| 58 | # ifndef CAN_CTRLMODE_BERR_REPORTING | ||
| 59 | # define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */ | ||
| 60 | # endif | ||
| 61 | # ifndef CAN_CTRLMODE_FD | ||
| 62 | # define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */ | ||
| 63 | # endif | ||
| 64 | # ifndef CAN_CTRLMODE_PRESUME_ACK | ||
| 65 | # define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */ | ||
| 66 | # endif | ||
| 67 | # ifndef CAN_CTRLMODE_FD_NON_ISO | ||
| 68 | # define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */ | ||
| 69 | # endif | ||
| 70 | # ifndef IFLA_CAN_TERMINATION | ||
| 71 | # define IFLA_CAN_TERMINATION 11 | ||
| 72 | # endif | ||
| 73 | #endif | ||
| 74 | |||
| 54 | /* taken from linux/sockios.h */ | 75 | /* taken from linux/sockios.h */ |
| 55 | #define SIOCSIFNAME 0x8923 /* set interface name */ | 76 | #define SIOCSIFNAME 0x8923 /* set interface name */ |
| 56 | 77 | ||
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; |
