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 <vda.linux@googlemail.com>
This commit is contained in:
parent
d26e958725
commit
96b0607302
4 changed files with 30 additions and 10 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue