]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
Do not mistake a regular user process for a namespaced one 212/head
authorTomas Mraz <tmraz@fedoraproject.org>
Mon, 20 Jan 2020 12:58:07 +0000 (13:58 +0100)
committerTomas Mraz <tmraz@fedoraproject.org>
Tue, 21 Jan 2020 08:16:10 +0000 (09:16 +0100)
In case there is a regular user with a process running on a system
with uid falling into a namespaced uid range of another user.
The user with the colliding namespaced uid range will not be
allowed to be deleted without forcing the action with -f.

The user_busy() is adjusted to check whether the suspected process
is really a namespaced process in a different namespace.

libmisc/user_busy.c

index b0867568c0961f7cb7ae7b99a9f3227d57d5e65f..324bb94651640c373a9cb5b352ec33bde06512c8 100644 (file)
@@ -39,6 +39,7 @@
 #include <sys/types.h>
 #include <dirent.h>
 #include <fcntl.h>
+#include <unistd.h>
 #include "defines.h"
 #include "prototypes.h"
 #ifdef ENABLE_SUBIDS
@@ -106,6 +107,31 @@ static int user_busy_utmp (const char *name)
 #endif                         /* !__linux__ */
 
 #ifdef __linux__
+#ifdef ENABLE_SUBIDS
+#define in_parentuid_range(uid) ((uid) >= parentuid && (uid) < parentuid + range)
+static int different_namespace (const char *sname)
+{
+       /* 41: /proc/xxxxxxxxxx/task/xxxxxxxxxx/ns/user + \0 */
+       char path[41];
+       char buf[512], buf2[512];
+       ssize_t llen1, llen2;
+
+       snprintf (path, 41, "/proc/%s/ns/user", sname);
+
+       if ((llen1 = readlink (path, buf, sizeof(buf))) == -1)
+               return 0;
+
+       if ((llen2 = readlink ("/proc/self/ns/user", buf2, sizeof(buf2))) == -1)
+               return 0;
+
+       if (llen1 == llen2 && memcmp (buf, buf2, llen1) == 0)
+               return 0; /* same namespace */
+
+       return 1;
+}
+#endif                          /* ENABLE_SUBIDS */
+
+
 static int check_status (const char *name, const char *sname, uid_t uid)
 {
        /* 40: /proc/xxxxxxxxxx/task/xxxxxxxxxx/status + \0 */
@@ -114,7 +140,6 @@ static int check_status (const char *name, const char *sname, uid_t uid)
        FILE *sfile;
 
        snprintf (status, 40, "/proc/%s/status", sname);
-       status[39] = '\0';
 
        sfile = fopen (status, "r");
        if (NULL == sfile) {
@@ -123,26 +148,29 @@ static int check_status (const char *name, const char *sname, uid_t uid)
        while (fgets (line, sizeof (line), sfile) == line) {
                if (strncmp (line, "Uid:\t", 5) == 0) {
                        unsigned long ruid, euid, suid;
+
                        assert (uid == (unsigned long) uid);
+                       (void) fclose (sfile);
                        if (sscanf (line,
                                    "Uid:\t%lu\t%lu\t%lu\n",
                                    &ruid, &euid, &suid) == 3) {
                                if (   (ruid == (unsigned long) uid)
                                    || (euid == (unsigned long) uid)
-                                   || (suid == (unsigned long) uid)
+                                   || (suid == (unsigned long) uid) ) {
+                                       return 1;
+                               }
 #ifdef ENABLE_SUBIDS
-                                   || have_sub_uids(name, ruid, 1)
-                                   || have_sub_uids(name, euid, 1)
-                                   || have_sub_uids(name, suid, 1)
-#endif                         /* ENABLE_SUBIDS */
+                               if (    different_namespace (sname)
+                                    && (   have_sub_uids(name, ruid, 1)
+                                        || have_sub_uids(name, euid, 1)
+                                        || have_sub_uids(name, suid, 1))
                                   ) {
-                                       (void) fclose (sfile);
                                        return 1;
                                }
+#endif                         /* ENABLE_SUBIDS */
                        } else {
                                /* Ignore errors. This is just a best effort. */
                        }
-                       (void) fclose (sfile);
                        return 0;
                }
        }