]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib/env, ...: use getauxval(AT_SECURE) for SUID check
authorMax Kellermann <max.kellermann@ionos.com>
Sat, 10 May 2025 20:26:50 +0000 (22:26 +0200)
committerMax Kellermann <max.kellermann@ionos.com>
Sat, 10 May 2025 20:37:19 +0000 (22:37 +0200)
Comparing effective and real uid/gid is not a proper way to check for
SUID execution:

1. this does not consider file capabilities

2. this check breaks when NO_NEW_PRIVS is used as the Linux kernel
   resets effective ids during execve(); this means the check is
   false, but the process still has raised capabilities

For more details about the NO_NEW_PRIVS problem, check this post and
the surrounding thread:

 https://lore.kernel.org/lkml/20250509184105.840928-1-max.kellermann@ionos.com/

Signed-off-by: Max Kellermann <max.kellermann@ionos.com>
include/debug.h
lib/env.c
libmount/src/context.c
login-utils/chfn.c
login-utils/chsh.c
login-utils/su-common.c
sys-utils/swapon.c
term-utils/wall.c
text-utils/more.c

index 15b09d07affbf854397b35cb84c6293cd0248c42..a59de3442bac9c715ad71acf9c838fa3e5770b75 100644 (file)
@@ -36,6 +36,7 @@
 
 #include <stdarg.h>
 #include <string.h>
+#include <sys/auxv.h> // for getauxval()
 
 struct ul_debug_maskname {
        const char *name;
@@ -89,7 +90,7 @@ struct ul_debug_maskname {
                } else \
                        lib ## _debug_mask = mask; \
                if (lib ## _debug_mask) { \
-                       if (getuid() != geteuid() || getgid() != getegid()) { \
+                       if (getauxval(AT_SECURE)) { \
                                lib ## _debug_mask |= __UL_DEBUG_FL_NOADDR; \
                                fprintf(stderr, "%d: %s: don't print memory addresses (SUID executable).\n", getpid(), # lib); \
                        } \
index 0874fe482b83b0c020d28f6e4901b35c1f1ed5ca..3fc4f2e21e541b7ab94c6b5567ba8526c61a2e02 100644 (file)
--- a/lib/env.c
+++ b/lib/env.c
@@ -16,6 +16,7 @@
 #include <sys/syscall.h>
 #endif
 #include <unistd.h>
+#include <sys/auxv.h> // for getauxval()
 #include <sys/types.h>
 
 #include "env.h"
@@ -260,7 +261,7 @@ void sanitize_env(void)
 
 char *safe_getenv(const char *arg)
 {
-       if ((getuid() != geteuid()) || (getgid() != getegid()))
+       if (getauxval(AT_SECURE))
                return NULL;
 #ifdef HAVE_PRCTL
        if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
index 15a8ad3bbd0f5173f869834ddfce5dbd87bf5c3a..84e98aa3f06b47f3a6705128d83b98ed509d2b88 100644 (file)
@@ -42,6 +42,7 @@
 #include "match.h"
 
 #include <stdarg.h>
+#include <sys/auxv.h> // for getauxval()
 #include <sys/wait.h>
 
 #include "mount-api-utils.h"
 struct libmnt_context *mnt_new_context(void)
 {
        struct libmnt_context *cxt;
-       uid_t ruid, euid;
+       uid_t ruid;
 
        cxt = calloc(1, sizeof(*cxt));
        if (!cxt)
                return NULL;
 
        ruid = getuid();
-       euid = geteuid();
 
        mnt_context_reset_status(cxt);
 
@@ -77,7 +77,7 @@ struct libmnt_context *mnt_new_context(void)
        INIT_LIST_HEAD(&cxt->hooksets_datas);
 
        /* if we're really root and aren't running setuid */
-       cxt->restricted = (uid_t) 0 == ruid && ruid == euid ? 0 : 1;
+       cxt->restricted = (uid_t) 0 == ruid && !getauxval(AT_SECURE) ? 0 : 1;
 
        cxt->noautofs = 0;
 
index 7067ffaf27e9c9f72091ad1157221a5bd9aa1b25..adfa3d63a873bc09093880904b7eb9c7e90b2520 100644 (file)
@@ -29,6 +29,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/auxv.h> // for getauxval()
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -269,7 +270,7 @@ static void get_login_defs(struct chfn_control *ctl)
        int broken = 0;
 
        /* real root does not have restrictions */
-       if (geteuid() == getuid() && getuid() == 0) {
+       if (!getauxval(AT_SECURE) && getuid() == 0) {
                ctl->allow_fullname = ctl->allow_room = ctl->allow_work = ctl->allow_home = 1;
                return;
        }
@@ -449,7 +450,7 @@ int main(int argc, char **argv)
 
 #ifdef HAVE_LIBUSER
        /* If we're setuid and not really root, disallow the password change. */
-       if (geteuid() != getuid() && uid != ctl.pw->pw_uid) {
+       if (getauxval(AT_SECURE) && uid != ctl.pw->pw_uid) {
 #else
        if (uid != 0 && uid != ctl.pw->pw_uid) {
 #endif
index 19f0915348e2e99573fbcd0a2ed44a0daa88531f..490d51864dd6b30d900f6415e51bc562090e44c3 100644 (file)
@@ -29,6 +29,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/auxv.h> // for getauxval()
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -243,7 +244,7 @@ int main(int argc, char **argv)
        /* reality check */
 #ifdef HAVE_LIBUSER
        /* If we're setuid and not really root, disallow the password change. */
-       if (geteuid() != getuid() && uid != pw->pw_uid) {
+       if (getauxval(AT_SECURE) && uid != pw->pw_uid) {
 #else
        if (uid != 0 && uid != pw->pw_uid) {
 #endif
index cf10caa6f42bd2d21d7895fff7cc5a9eb3628a22..2df10ee31265a47183e140f6fd650803afef8d70 100644 (file)
@@ -23,6 +23,7 @@
  */
 #include <stdio.h>
 #include <getopt.h>
+#include <sys/auxv.h> // for getauxval()
 #include <sys/types.h>
 #include <pwd.h>
 #include <grp.h>
@@ -939,10 +940,9 @@ static void load_config(void *data)
 static int is_not_root(void)
 {
        const uid_t ruid = getuid();
-       const uid_t euid = geteuid();
 
        /* if we're really root and aren't running setuid */
-       return (uid_t) 0 == ruid && ruid == euid ? 0 : 1;
+       return (uid_t) 0 == ruid && !getauxval(AT_SECURE) ? 0 : 1;
 }
 
 /* Don't rely on PAM and reset the most important limits. */
index c761b85d0e8a464bf373603a2cbe078521ca79f4..0a8c40407d67d097d76ab588de9f64b2d28e28ef 100644 (file)
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <sys/auxv.h> // for getauxval()
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <fcntl.h>
@@ -348,7 +349,7 @@ static int swap_reinitialize(struct swap_device *dev)
                return -1;
 
        case 0: /* child */
-               if (geteuid() != getuid() && drop_permissions() != 0)
+               if (getauxval(AT_SECURE) && drop_permissions() != 0)
                        exit(EXIT_FAILURE);
 
                cmd[idx++] = "mkswap";
index 22c3918bb3e64ab88a719cc7cb5d350ea2f08798..fbd8e54fbe23dfd8f233de7159dd193f0062ea87 100644 (file)
@@ -42,6 +42,7 @@
  *
  */
 
+#include <sys/auxv.h> // for getauxval()
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/time.h>
@@ -414,7 +415,7 @@ static char *makemsg(char *fname, char **mvec, int mvecsz,
                         * instead of "wall file".
                         */
                        uid_t uid = getuid();
-                       if (uid && (uid != geteuid() || getgid() != getegid()))
+                       if (uid && getauxval(AT_SECURE))
                                errx(EXIT_FAILURE, _("will not read %s - use stdin."),
                                     fname);
 
index 1ddfcaa4ceebda99888a9600ae7ad5308257a401..22f01ba24a3c4a435a6f8e91407589d9ea5957a9 100644 (file)
@@ -50,6 +50,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <sys/auxv.h> // for getauxval()
 #include <sys/param.h>
 #include <ctype.h>
 #include <signal.h>
@@ -1273,7 +1274,7 @@ static void __attribute__((__format__ (__printf__, 3, 4)))
                }
                va_end(argp);
 
-               if ((geteuid() != getuid() || getegid() != getgid())
+               if (getauxval(AT_SECURE)
                    && drop_permissions() != 0)
                        err(EXIT_FAILURE, _("drop permissions failed"));