9f13c6
From fd4405b763d26649339069532e79bd45013c8c38 Mon Sep 17 00:00:00 2001
9f13c6
From: Tomas Mraz <tmraz@fedoraproject.org>
9f13c6
Date: Mon, 20 Jan 2020 13:58:07 +0100
9f13c6
Subject: [PATCH] Do not mistake a regular user process for a namespaced one
9f13c6
9f13c6
In case there is a regular user with a process running on a system
9f13c6
with uid falling into a namespaced uid range of another user.
9f13c6
The user with the colliding namespaced uid range will not be
9f13c6
allowed to be deleted without forcing the action with -f.
9f13c6
9f13c6
The user_busy() is adjusted to check whether the suspected process
9f13c6
is really a namespaced process in a different namespace.
9f13c6
---
9f13c6
 libmisc/user_busy.c | 44 ++++++++++++++++++++++++++++++++++++--------
9f13c6
 1 file changed, 36 insertions(+), 8 deletions(-)
9f13c6
9f13c6
diff --git a/libmisc/user_busy.c b/libmisc/user_busy.c
9f13c6
index b0867568..324bb946 100644
9f13c6
--- a/libmisc/user_busy.c
9f13c6
+++ b/libmisc/user_busy.c
9f13c6
@@ -39,6 +39,7 @@
9f13c6
 #include <sys/types.h>
9f13c6
 #include <dirent.h>
9f13c6
 #include <fcntl.h>
9f13c6
+#include <unistd.h>
9f13c6
 #include "defines.h"
9f13c6
 #include "prototypes.h"
9f13c6
 #ifdef ENABLE_SUBIDS
9f13c6
@@ -106,6 +107,31 @@ static int user_busy_utmp (const char *name)
9f13c6
 #endif				/* !__linux__ */
9f13c6
 
9f13c6
 #ifdef __linux__
9f13c6
+#ifdef ENABLE_SUBIDS
9f13c6
+#define in_parentuid_range(uid) ((uid) >= parentuid && (uid) < parentuid + range)
9f13c6
+static int different_namespace (const char *sname)
9f13c6
+{
9f13c6
+	/* 41: /proc/xxxxxxxxxx/task/xxxxxxxxxx/ns/user + \0 */
9f13c6
+	char path[41];
9f13c6
+	char buf[512], buf2[512];
9f13c6
+	ssize_t llen1, llen2;
9f13c6
+
9f13c6
+	snprintf (path, 41, "/proc/%s/ns/user", sname);
9f13c6
+
9f13c6
+	if ((llen1 = readlink (path, buf, sizeof(buf))) == -1)
9f13c6
+		return 0;
9f13c6
+
9f13c6
+	if ((llen2 = readlink ("/proc/self/ns/user", buf2, sizeof(buf2))) == -1)
9f13c6
+		return 0;
9f13c6
+
9f13c6
+	if (llen1 == llen2 && memcmp (buf, buf2, llen1) == 0)
9f13c6
+		return 0; /* same namespace */
9f13c6
+
9f13c6
+	return 1;
9f13c6
+}
9f13c6
+#endif                          /* ENABLE_SUBIDS */
9f13c6
+
9f13c6
+
9f13c6
 static int check_status (const char *name, const char *sname, uid_t uid)
9f13c6
 {
9f13c6
 	/* 40: /proc/xxxxxxxxxx/task/xxxxxxxxxx/status + \0 */
9f13c6
@@ -114,7 +140,6 @@ static int check_status (const char *name, const char *sname, uid_t uid)
9f13c6
 	FILE *sfile;
9f13c6
 
9f13c6
 	snprintf (status, 40, "/proc/%s/status", sname);
9f13c6
-	status[39] = '\0';
9f13c6
 
9f13c6
 	sfile = fopen (status, "r");
9f13c6
 	if (NULL == sfile) {
9f13c6
@@ -123,26 +148,29 @@ static int check_status (const char *name, const char *sname, uid_t uid)
9f13c6
 	while (fgets (line, sizeof (line), sfile) == line) {
9f13c6
 		if (strncmp (line, "Uid:\t", 5) == 0) {
9f13c6
 			unsigned long ruid, euid, suid;
9f13c6
+
9f13c6
 			assert (uid == (unsigned long) uid);
9f13c6
+			(void) fclose (sfile);
9f13c6
 			if (sscanf (line,
9f13c6
 			            "Uid:\t%lu\t%lu\t%lu\n",
9f13c6
 			            &ruid, &euid, &suid) == 3) {
9f13c6
 				if (   (ruid == (unsigned long) uid)
9f13c6
 				    || (euid == (unsigned long) uid)
9f13c6
-				    || (suid == (unsigned long) uid)
9f13c6
+				    || (suid == (unsigned long) uid) ) {
9f13c6
+					return 1;
9f13c6
+				}
9f13c6
 #ifdef ENABLE_SUBIDS
9f13c6
-				    || have_sub_uids(name, ruid, 1)
9f13c6
-				    || have_sub_uids(name, euid, 1)
9f13c6
-				    || have_sub_uids(name, suid, 1)
9f13c6
-#endif				/* ENABLE_SUBIDS */
9f13c6
+				if (    different_namespace (sname)
9f13c6
+				     && (   have_sub_uids(name, ruid, 1)
9f13c6
+				         || have_sub_uids(name, euid, 1)
9f13c6
+				         || have_sub_uids(name, suid, 1))
9f13c6
 				   ) {
9f13c6
-					(void) fclose (sfile);
9f13c6
 					return 1;
9f13c6
 				}
9f13c6
+#endif				/* ENABLE_SUBIDS */
9f13c6
 			} else {
9f13c6
 				/* Ignore errors. This is just a best effort. */
9f13c6
 			}
9f13c6
-			(void) fclose (sfile);
9f13c6
 			return 0;
9f13c6
 		}
9f13c6
 	}
9f13c6
-- 
9f13c6
2.25.2
9f13c6