From 222802e83362eabd4c631897ff7db5e85955d7c5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Oct 2024 19:08:10 +0200 Subject: test: code shrink function old new delta nexpr 813 800 -13 Signed-off-by: Denys Vlasenko --- coreutils/test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'coreutils') diff --git a/coreutils/test.c b/coreutils/test.c index 008d90b25..7df7d0fc8 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -760,7 +760,7 @@ static int filstat(char *nm, enum token mode) return ((s.st_mode & i) != 0); } if (mode == FILGZ) - return s.st_size > 0L; + return s.st_size != 0L; /* shorter than "> 0" test */ if (mode == FILUID) return s.st_uid == geteuid(); if (mode == FILGID) -- cgit v1.2.3-55-g6feb From bb5525613ec109aa30d2cb1db84e18aa0b084576 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Oct 2024 19:24:06 +0200 Subject: test: Invert return value of test_eaccess and rename it to test_st_mode From dash: From: herbert Date: Wed, 2 Mar 2005 22:14:54 +1100 Invert return value of test_eaccess and rename it to test_st_mode. function old new delta nexpr 800 766 -34 Signed-off-by: Denys Vlasenko --- coreutils/test.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) (limited to 'coreutils') diff --git a/coreutils/test.c b/coreutils/test.c index 7df7d0fc8..c02c92745 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -665,34 +665,29 @@ static int is_a_group_member(gid_t gid) return 0; } - -/* Do the same thing access(2) does, but use the effective uid and gid, - and don't make the mistake of telling root that any file is - executable. */ -static int test_eaccess(struct stat *st, int mode) +/* + * Similar to what access(2) does, but uses the effective uid and gid. + * Doesn't make the mistake of telling root that any file is executable. + * Returns non-zero if the file is accessible. + */ +static int test_st_mode(struct stat *st, int mode) { unsigned int euid = geteuid(); if (euid == 0) { /* Root can read or write any file. */ if (mode != X_OK) - return 0; + return 1; /* Root can execute any file that has any one of the execute * bits set. */ - if (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) - return 0; - } - - if (st->st_uid == euid) /* owner */ + mode = S_IXUSR | S_IXGRP | S_IXOTH; + } else if (st->st_uid == euid) /* owner */ mode <<= 6; else if (is_a_group_member(st->st_gid)) mode <<= 3; - if (st->st_mode & mode) - return 0; - - return -1; + return st->st_mode & mode; } @@ -722,7 +717,7 @@ static int filstat(char *nm, enum token mode) i = W_OK; if (mode == FILEX) i = X_OK; - return test_eaccess(&s, i) == 0; + return test_st_mode(&s, i); } if (is_file_type(mode)) { if (mode == FILREG) -- cgit v1.2.3-55-g6feb From 748b1681549067f2e27ab2b9102ef9352cfa8a4c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Oct 2024 01:20:43 +0200 Subject: libbb: move is_in_supplementary_groups() from test to libbb function old new delta is_in_supplementary_groups - 54 +54 nexpr 766 721 -45 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/1 up/down: 54/-45) Total: 9 bytes Signed-off-by: Denys Vlasenko --- coreutils/test.c | 20 +------------------- include/libbb.h | 5 +++++ libbb/bb_getgroups.c | 20 ++++++++++++++++++++ 3 files changed, 26 insertions(+), 19 deletions(-) (limited to 'coreutils') diff --git a/coreutils/test.c b/coreutils/test.c index c02c92745..874285704 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -637,32 +637,14 @@ static int binop(void) /*return 1; - NOTREACHED */ } -static void initialize_group_array(void) -{ - group_array = bb_getgroups(&ngroups, NULL); -} - /* Return non-zero if GID is one that we have in our groups list. */ -//XXX: FIXME: duplicate of existing libbb function? -// see toplevel TODO file: -// possible code duplication ingroup() and is_a_group_member() static int is_a_group_member(gid_t gid) { - int i; - /* Short-circuit if possible, maybe saving a call to getgroups(). */ if (gid == getgid() || gid == getegid()) return 1; - if (ngroups == 0) - initialize_group_array(); - - /* Search through the list looking for GID. */ - for (i = 0; i < ngroups; i++) - if (gid == group_array[i]) - return 1; - - return 0; + return is_in_supplementary_groups(&ngroups, &group_array, gid); } /* diff --git a/include/libbb.h b/include/libbb.h index 67e7bf7b9..e06aef08e 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1201,6 +1201,11 @@ void die_if_bad_username(const char* name) FAST_FUNC; * Dies on errors (on Linux, only xrealloc can cause this, not internal getgroups call). */ gid_t *bb_getgroups(int *ngroups, gid_t *group_array) FAST_FUNC; +/* + * True if GID is in our getgroups() result. + * getgroups() is cached in group_array[], to makse successive calls faster. + */ +int FAST_FUNC is_in_supplementary_groups(int *pngroups, gid_t **pgroup_array, gid_t gid); #if ENABLE_FEATURE_UTMP void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname); diff --git a/libbb/bb_getgroups.c b/libbb/bb_getgroups.c index 5d83c729a..f030d5eac 100644 --- a/libbb/bb_getgroups.c +++ b/libbb/bb_getgroups.c @@ -45,3 +45,23 @@ gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array) *ngroups = n; return group_array; } + +/* Return non-zero if GID is in our supplementary group list. */ +int FAST_FUNC is_in_supplementary_groups(int *pngroups, gid_t **pgroup_array, gid_t gid) +{ + int i; + int ngroups; + gid_t *group_array; + + if (*pngroups == 0) + *pgroup_array = bb_getgroups(pngroups, NULL); + ngroups = *pngroups; + group_array = *pgroup_array; + + /* Search through the list looking for GID. */ + for (i = 0; i < ngroups; i++) + if (gid == group_array[i]) + return 1; + + return 0; +} -- cgit v1.2.3-55-g6feb From 4c1d645c86f4e7a380d96f9ba962f8b270f595dc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Oct 2024 06:36:00 +0200 Subject: libbb: simplify parameter passing in is_in_supplementary_groups() function old new delta is_in_supplementary_groups 54 52 -2 nexpr 721 718 -3 test_exec 125 119 -6 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-11) Total: -11 bytes Signed-off-by: Denys Vlasenko --- coreutils/test.c | 26 ++++++++++++++++++-------- include/libbb.h | 10 ++++++++-- libbb/bb_getgroups.c | 10 +++++----- shell/ash.c | 8 +++----- 4 files changed, 34 insertions(+), 20 deletions(-) (limited to 'coreutils') diff --git a/coreutils/test.c b/coreutils/test.c index 874285704..96462d3a2 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -426,8 +426,7 @@ struct test_statics { /* set only by check_operator(), either to bogus struct * or points to matching operator_t struct. Never NULL. */ const struct operator_t *last_operator; - gid_t *group_array; - int ngroups; + struct cached_groupinfo groupinfo; #if BASH_TEST2 bool bash_test2; #endif @@ -440,8 +439,7 @@ extern struct test_statics *BB_GLOBAL_CONST test_ptr_to_statics; #define S (*test_ptr_to_statics) #define args (S.args ) #define last_operator (S.last_operator) -#define group_array (S.group_array ) -#define ngroups (S.ngroups ) +#define groupinfo (S.groupinfo ) #define bash_test2 (S.bash_test2 ) #define leaving (S.leaving ) @@ -449,7 +447,7 @@ extern struct test_statics *BB_GLOBAL_CONST test_ptr_to_statics; XZALLOC_CONST_PTR(&test_ptr_to_statics, sizeof(S)); \ } while (0) #define DEINIT_S() do { \ - free(group_array); \ + free(groupinfo.supplementary_array); \ free(test_ptr_to_statics); \ } while (0) @@ -644,7 +642,7 @@ static int is_a_group_member(gid_t gid) if (gid == getgid() || gid == getegid()) return 1; - return is_in_supplementary_groups(&ngroups, &group_array, gid); + return is_in_supplementary_groups(&groupinfo, gid); } /* @@ -654,8 +652,20 @@ static int is_a_group_member(gid_t gid) */ static int test_st_mode(struct stat *st, int mode) { - unsigned int euid = geteuid(); - + enum { ANY_IX = S_IXUSR | S_IXGRP | S_IXOTH }; + unsigned euid; + +//TODO if (mode == X_OK) { +// /* Do we already know with no extra syscalls? */ +// if (!S_ISREG(st->st_mode)) +// return 0; /* not a regular file */ +// if ((st->st_mode & ANY_IX) == 0) +// return 0; /* no one can execute */ +// if ((st->st_mode & ANY_IX) == ANY_IX) +// return 1; /* anyone can execute */ +// } + + euid = geteuid(); if (euid == 0) { /* Root can read or write any file. */ if (mode != X_OK) diff --git a/include/libbb.h b/include/libbb.h index e06aef08e..99bbf623b 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1203,9 +1203,15 @@ void die_if_bad_username(const char* name) FAST_FUNC; gid_t *bb_getgroups(int *ngroups, gid_t *group_array) FAST_FUNC; /* * True if GID is in our getgroups() result. - * getgroups() is cached in group_array[], to makse successive calls faster. + * getgroups() is cached in supplementary_array[], to make successive calls faster. */ -int FAST_FUNC is_in_supplementary_groups(int *pngroups, gid_t **pgroup_array, gid_t gid); +struct cached_groupinfo { + //TODO? gid_t egid; + int ngroups; + gid_t *supplementary_array; +}; +//TODO? int FAST_FUNC get_cached_egid(gid_t *egid); +int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid); #if ENABLE_FEATURE_UTMP void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname); diff --git a/libbb/bb_getgroups.c b/libbb/bb_getgroups.c index f030d5eac..d9bbe95c3 100644 --- a/libbb/bb_getgroups.c +++ b/libbb/bb_getgroups.c @@ -47,16 +47,16 @@ gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array) } /* Return non-zero if GID is in our supplementary group list. */ -int FAST_FUNC is_in_supplementary_groups(int *pngroups, gid_t **pgroup_array, gid_t gid) +int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid) { int i; int ngroups; gid_t *group_array; - if (*pngroups == 0) - *pgroup_array = bb_getgroups(pngroups, NULL); - ngroups = *pngroups; - group_array = *pgroup_array; + if (groupinfo->ngroups == 0) + groupinfo->supplementary_array = bb_getgroups(&groupinfo->ngroups, NULL); + ngroups = groupinfo->ngroups; + group_array = groupinfo->supplementary_array; /* Search through the list looking for GID. */ for (i = 0; i < ngroups; i++) diff --git a/shell/ash.c b/shell/ash.c index 984a71f07..fa57511a7 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -493,8 +493,7 @@ struct globals_misc { /* Rarely referenced stuff */ /* Cached supplementary group array (for testing executable'ity of files) */ - int ngroups; - gid_t *group_array; + struct cached_groupinfo groupinfo; #if ENABLE_ASH_RANDOM_SUPPORT random_t random_gen; @@ -528,8 +527,7 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; #define may_have_traps (G_misc.may_have_traps ) #define trap (G_misc.trap ) #define trap_ptr (G_misc.trap_ptr ) -#define ngroups (G_misc.ngroups ) -#define group_array (G_misc.group_array) +#define groupinfo (G_misc.groupinfo ) #define random_gen (G_misc.random_gen ) #define backgndpid (G_misc.backgndpid ) #define INIT_G_misc() do { \ @@ -13821,7 +13819,7 @@ static int test_exec(/*const char *fullname,*/ struct stat *statb) stmode = S_IXUSR; else if (statb->st_gid == getegid()) stmode = S_IXGRP; - else if (is_in_supplementary_groups(&ngroups, &group_array, statb->st_gid)) + else if (is_in_supplementary_groups(&groupinfo, statb->st_gid)) stmode = S_IXGRP; return statb->st_mode & stmode; -- cgit v1.2.3-55-g6feb From d26e9587252fdf4774a05e351b86d3a18c46384e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Oct 2024 07:14:27 +0200 Subject: ash: make "test -x" use cached groupinfo function old new delta test_main2 - 407 +407 testcmd 10 23 +13 test_main 418 56 -362 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/1 up/down: 420/-362) Total: 58 bytes Signed-off-by: Denys Vlasenko --- coreutils/test.c | 21 +++++++++++++++++---- include/libbb.h | 1 + shell/ash.c | 3 +-- 3 files changed, 19 insertions(+), 6 deletions(-) (limited to 'coreutils') diff --git a/coreutils/test.c b/coreutils/test.c index 96462d3a2..ad777953f 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -426,7 +426,7 @@ struct test_statics { /* set only by check_operator(), either to bogus struct * or points to matching operator_t struct. Never NULL. */ const struct operator_t *last_operator; - struct cached_groupinfo groupinfo; + struct cached_groupinfo *groupinfo; #if BASH_TEST2 bool bash_test2; #endif @@ -447,7 +447,6 @@ extern struct test_statics *BB_GLOBAL_CONST test_ptr_to_statics; XZALLOC_CONST_PTR(&test_ptr_to_statics, sizeof(S)); \ } while (0) #define DEINIT_S() do { \ - free(groupinfo.supplementary_array); \ free(test_ptr_to_statics); \ } while (0) @@ -642,7 +641,7 @@ static int is_a_group_member(gid_t gid) if (gid == getgid() || gid == getegid()) return 1; - return is_in_supplementary_groups(&groupinfo, gid); + return is_in_supplementary_groups(groupinfo, gid); } /* @@ -878,7 +877,7 @@ static number_t primary(enum token n) } -int test_main(int argc, char **argv) +int FAST_FUNC test_main2(struct cached_groupinfo *pgroupinfo, int argc, char **argv) { int res; const char *arg0; @@ -911,6 +910,7 @@ int test_main(int argc, char **argv) /* We must do DEINIT_S() prior to returning */ INIT_S(); + groupinfo = pgroupinfo; #if BASH_TEST2 bash_test2 = bt2; @@ -1013,3 +1013,16 @@ int test_main(int argc, char **argv) DEINIT_S(); return res; } + +int test_main(int argc, char **argv) +{ + struct cached_groupinfo info; + int r; + + info.ngroups = 0; + info.supplementary_array = NULL; + r = test_main2(&info, argc, argv); + free(info.supplementary_array); + + return r; +} diff --git a/include/libbb.h b/include/libbb.h index 99bbf623b..8748464ed 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1550,6 +1550,7 @@ int test_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE #endif ; +int FAST_FUNC test_main2(struct cached_groupinfo *pgroupinfo, int argc, char **argv); int kill_main(int argc, char **argv) #if ENABLE_KILL || ENABLE_KILLALL || ENABLE_KILLALL5 MAIN_EXTERNALLY_VISIBLE diff --git a/shell/ash.c b/shell/ash.c index fa57511a7..a6bb9894c 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -10175,8 +10175,7 @@ static int FAST_FUNC echocmd(int argc, char **argv) { return echo_main(argc, a static int FAST_FUNC printfcmd(int argc, char **argv) { return printf_main(argc, argv); } #endif #if ENABLE_ASH_TEST || BASH_TEST2 -static int FAST_FUNC testcmd(int argc, char **argv) { return test_main(argc, argv); } -// TODO: pass &ngroups and &group_array addresses to test_main to use cached supplementary groups +static int FAST_FUNC testcmd(int argc, char **argv) { return test_main2(&groupinfo, argc, argv); } #endif #if ENABLE_ASH_SLEEP static int FAST_FUNC sleepcmd(int argc, char **argv) { return sleep_main(argc, argv); } -- cgit v1.2.3-55-g6feb From 96b0607302500ed201a7816282efbaa8f990aa33 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Oct 2024 07:28:44 +0200 Subject: ash: cache more of uid/gid syscalls Testcase: setuidgid 1:1 strace ash -c 'test -x TODO; test -x TODO; echo $?' should show that second "test -x" does not query ids again. function old new delta ash_main 1236 1256 +20 get_cached_euid - 19 +19 get_cached_egid - 19 +19 test_main 56 72 +16 test_exec 119 135 +16 is_in_supplementary_groups 52 57 +5 nexpr 718 702 -16 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 4/1 up/down: 95/-16) Total: 79 bytes Signed-off-by: Denys Vlasenko --- coreutils/test.c | 11 +++++++---- include/libbb.h | 6 ++++-- libbb/bb_getgroups.c | 14 ++++++++++++++ shell/ash.c | 9 +++++---- 4 files changed, 30 insertions(+), 10 deletions(-) (limited to 'coreutils') diff --git a/coreutils/test.c b/coreutils/test.c index ad777953f..6085d6663 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -638,7 +638,7 @@ static int binop(void) static int is_a_group_member(gid_t gid) { /* Short-circuit if possible, maybe saving a call to getgroups(). */ - if (gid == getgid() || gid == getegid()) + if (gid == get_cached_egid(&groupinfo->egid)) return 1; return is_in_supplementary_groups(groupinfo, gid); @@ -656,15 +656,16 @@ static int test_st_mode(struct stat *st, int mode) //TODO if (mode == X_OK) { // /* Do we already know with no extra syscalls? */ -// if (!S_ISREG(st->st_mode)) -// return 0; /* not a regular file */ +// //if (!S_ISREG(st->st_mode)) +// // return 0; /* not a regular file */ +// // ^^^ bash does not check this // if ((st->st_mode & ANY_IX) == 0) // return 0; /* no one can execute */ // if ((st->st_mode & ANY_IX) == ANY_IX) // return 1; /* anyone can execute */ // } - euid = geteuid(); + euid = get_cached_euid(&groupinfo->euid); if (euid == 0) { /* Root can read or write any file. */ if (mode != X_OK) @@ -1019,6 +1020,8 @@ int test_main(int argc, char **argv) struct cached_groupinfo info; int r; + info.euid = -1; + info.egid = -1; info.ngroups = 0; info.supplementary_array = NULL; r = test_main2(&info, argc, argv); diff --git a/include/libbb.h b/include/libbb.h index 8748464ed..f5f8e1635 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1206,11 +1206,13 @@ gid_t *bb_getgroups(int *ngroups, gid_t *group_array) FAST_FUNC; * getgroups() is cached in supplementary_array[], to make successive calls faster. */ struct cached_groupinfo { - //TODO? gid_t egid; + uid_t euid; + gid_t egid; int ngroups; gid_t *supplementary_array; }; -//TODO? int FAST_FUNC get_cached_egid(gid_t *egid); +uid_t FAST_FUNC get_cached_euid(uid_t *euid); +gid_t FAST_FUNC get_cached_egid(gid_t *egid); int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid); #if ENABLE_FEATURE_UTMP diff --git a/libbb/bb_getgroups.c b/libbb/bb_getgroups.c index d9bbe95c3..31cff2b41 100644 --- a/libbb/bb_getgroups.c +++ b/libbb/bb_getgroups.c @@ -46,6 +46,20 @@ gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array) return group_array; } +uid_t FAST_FUNC get_cached_euid(uid_t *euid) +{ + if (*euid == (uid_t)-1) + *euid = geteuid(); + return *euid; +} + +gid_t FAST_FUNC get_cached_egid(gid_t *egid) +{ + if (*egid == (gid_t)-1) + *egid = getegid(); + return *egid; +} + /* Return non-zero if GID is in our supplementary group list. */ int FAST_FUNC is_in_supplementary_groups(struct cached_groupinfo *groupinfo, gid_t gid) { diff --git a/shell/ash.c b/shell/ash.c index a6bb9894c..9173b8608 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -536,6 +536,8 @@ extern struct globals_misc *BB_GLOBAL_CONST ash_ptr_to_globals_misc; curdir = nullstr; \ physdir = nullstr; \ trap_ptr = trap; \ + groupinfo.euid = -1; \ + groupinfo.egid = -1; \ } while (0) @@ -2319,7 +2321,7 @@ initvar(void) #if ENABLE_FEATURE_EDITING && ENABLE_FEATURE_EDITING_FANCY_PROMPT vps1.var_text = "PS1=\\w \\$ "; #else - if (!geteuid()) + if (!get_cached_euid(&groupinfo.euid)); vps1.var_text = "PS1=# "; #endif vp = varinit; @@ -13809,14 +13811,13 @@ static int test_exec(/*const char *fullname,*/ struct stat *statb) /* Executability depends on our euid/egid/supplementary groups */ stmode = S_IXOTH; - euid = geteuid(); -//TODO: cache euid? + euid = get_cached_euid(&groupinfo.euid); if (euid == 0) /* for root user, any X bit is good enough */ stmode = ANY_IX; else if (statb->st_uid == euid) stmode = S_IXUSR; - else if (statb->st_gid == getegid()) + else if (statb->st_gid == get_cached_egid(&groupinfo.egid)) stmode = S_IXGRP; else if (is_in_supplementary_groups(&groupinfo, statb->st_gid)) stmode = S_IXGRP; -- cgit v1.2.3-55-g6feb From 0929a129fc75c556de67877491281e0bc3ef3edd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Oct 2024 07:33:58 +0200 Subject: test: -x can return 0/1 early if all X bits are the same function old new delta nexpr 702 725 +23 Signed-off-by: Denys Vlasenko --- coreutils/test.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'coreutils') diff --git a/coreutils/test.c b/coreutils/test.c index 6085d6663..b63e33cc0 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -654,16 +654,16 @@ static int test_st_mode(struct stat *st, int mode) enum { ANY_IX = S_IXUSR | S_IXGRP | S_IXOTH }; unsigned euid; -//TODO if (mode == X_OK) { -// /* Do we already know with no extra syscalls? */ -// //if (!S_ISREG(st->st_mode)) -// // return 0; /* not a regular file */ -// // ^^^ bash does not check this -// if ((st->st_mode & ANY_IX) == 0) -// return 0; /* no one can execute */ -// if ((st->st_mode & ANY_IX) == ANY_IX) -// return 1; /* anyone can execute */ -// } + if (mode == X_OK) { + /* Do we already know with no extra syscalls? */ + //if (!S_ISREG(st->st_mode)) + // return 0; /* not a regular file */ + // ^^^ bash 5.2.15 "test -x" does not check this! + if ((st->st_mode & ANY_IX) == 0) + return 0; /* no one can execute */ + if ((st->st_mode & ANY_IX) == ANY_IX) + return 1; /* anyone can execute */ + } euid = get_cached_euid(&groupinfo->euid); if (euid == 0) { -- cgit v1.2.3-55-g6feb