From cb65f0d0e966464612b6fa306260c4135efad60f Mon Sep 17 00:00:00 2001 From: Grisha Levit Date: Fri, 30 Jun 2023 03:05:21 -0400 Subject: [PATCH] avoid calling setgid when ids already match On some Android versions attemptig to set the current egid causes a SIGSYS to be sent even when ids already match. Avoid calling the sete[gu]id functions when it would be a noop. --- shell.c | 62 +++++++++++++++++++++++++++++++++++++++++---------------- shell.h | 6 ++++++ 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/shell.c b/shell.c index 9f1934d2..9b41203f 100644 --- a/shell.c +++ b/shell.c @@ -117,7 +117,14 @@ COMMAND *global_command = (COMMAND *)NULL; /* Information about the current user. */ struct user_info current_user = { - (uid_t)-1, (uid_t)-1, (gid_t)-1, (gid_t)-1, + (uid_t)-1, (uid_t)-1, +#if HAVE_SETRESUID + (uid_t)-1, +#endif + (gid_t)-1, (gid_t)-1, +#if HAVE_SETRESGID + (gid_t)-1, +#endif (char *)NULL, (char *)NULL, (char *)NULL }; @@ -1298,7 +1305,21 @@ uidget (void) { uid_t u; - u = getuid (); + u = current_user.uid; + +#if HAVE_SETRESUID + (void) getresuid (¤t_user.uid, ¤t_user.euid, ¤t_user.suid); +#else + current_user.uid = getuid (); + current_user.euid = geteuid (); +#endif +#if HAVE_SETRESGID + (void) getresgid (¤t_user.gid, ¤t_user.egid, ¤t_user.sgid); +#else + current_user.gid = getgid (); + current_user.egid = getegid (); +#endif + if (current_user.uid != u) { FREE (current_user.user_name); @@ -1306,10 +1327,6 @@ uidget (void) FREE (current_user.home_dir); current_user.user_name = current_user.shell = current_user.home_dir = NULL; } - current_user.uid = u; - current_user.gid = getgid (); - current_user.euid = geteuid (); - current_user.egid = getegid (); /* See whether or not we are running setuid or setgid. */ return (current_user.uid != current_user.euid) || @@ -1322,27 +1339,38 @@ disable_priv_mode (void) int e; #if HAVE_SETRESUID - if (setresuid (current_user.uid, current_user.uid, current_user.uid) < 0) + if (current_user.euid != current_user.uid || current_user.suid != current_user.uid) + if (setresuid (current_user.uid, current_user.uid, current_user.uid) < 0) #else - if (setuid (current_user.uid) < 0) + if (current_user.euid != current_user.uid) + if (setuid (current_user.uid) < 0) #endif - { - e = errno; - sys_error (_("cannot set uid to %d: effective uid %d"), current_user.uid, current_user.euid); + { + e = errno; + sys_error (_("cannot set uid to %d: effective uid %d"), current_user.uid, current_user.euid); #if defined (EXIT_ON_SETUID_FAILURE) - if (e == EAGAIN) - exit (e); + if (e == EAGAIN) + exit (e); #endif - } + } + #if HAVE_SETRESGID - if (setresgid (current_user.gid, current_user.gid, current_user.gid) < 0) + if (current_user.egid != current_user.gid || current_user.sgid != current_user.gid) + if (setresgid (current_user.gid, current_user.gid, current_user.gid) < 0) #else - if (setgid (current_user.gid) < 0) + if (current_user.egid != current_user.gid) + if (setgid (current_user.gid) < 0) #endif - sys_error (_("cannot set gid to %d: effective gid %d"), current_user.gid, current_user.egid); + sys_error (_("cannot set gid to %d: effective gid %d"), current_user.gid, current_user.egid); current_user.euid = current_user.uid; +#if defined (HAVE_SETRESUID) + current_user.suid = current_user.uid; +#endif current_user.egid = current_user.gid; +#if defined (HAVE_SETRESUID) + current_user.sgid = current_user.gid; +#endif } #if defined (WORDEXP_OPTION) diff --git a/shell.h b/shell.h index 055ba9f5..6315085d 100644 --- a/shell.h +++ b/shell.h @@ -149,7 +149,13 @@ struct fd_bitmap { /* Information about the current user. */ struct user_info { uid_t uid, euid; +#if defined (HAVE_SETRESUID) + uid_t suid; +#endif gid_t gid, egid; +#if defined (HAVE_SETRESGID) + gid_t sgid; +#endif char *user_name; char *shell; /* shell from the password file */ char *home_dir; -- 2.41.0