]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nspawn: tighten userns UID shift/range checks
authorLennart Poettering <lennart@poettering.net>
Tue, 27 Apr 2021 15:25:51 +0000 (17:25 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 7 May 2021 20:43:48 +0000 (22:43 +0200)
Let's add a helper that ensures the UID shift/range parameters actually
fit together.

src/basic/namespace-util.h
src/nspawn/nspawn-settings.c
src/nspawn/nspawn.c

index daa9accda378240ed6e66c419bc64916f7a1c3d3..39a6a46d1f99f42b9c3b3610f8ba90e382d3421b 100644 (file)
@@ -9,3 +9,18 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
 int fd_is_ns(int fd, unsigned long nsflag);
 
 int detach_mount_namespace(void);
+
+static inline bool userns_shift_range_valid(uid_t shift, uid_t range) {
+        /* Checks that the specified userns range makes sense, i.e. contains at least one UID, and the end
+         * doesn't overflow uid_t. */
+
+        assert_cc((uid_t) -1 > 0); /* verify that uid_t is unsigned */
+
+        if (range <= 0)
+                return false;
+
+        if (shift > (uid_t) -1 - range)
+                return false;
+
+        return true;
+}
index ebd83ec2ec90618219347b5b8198b8eaf16455ab..d5a0a675efd97c62423e4bb2901a26372b0fe192 100644 (file)
@@ -5,6 +5,7 @@
 #include "conf-parser.h"
 #include "cpu-set-util.h"
 #include "hostname-util.h"
+#include "namespace-util.h"
 #include "nspawn-network.h"
 #include "nspawn-settings.h"
 #include "parse-util.h"
@@ -611,7 +612,7 @@ int config_parse_private_users(
                         range++;
 
                         r = safe_atou32(range, &rn);
-                        if (r < 0 || rn <= 0) {
+                        if (r < 0) {
                                 log_syntax(unit, LOG_WARNING, filename, line, r, "UID/GID range invalid, ignoring: %s", range);
                                 return 0;
                         }
@@ -626,6 +627,11 @@ int config_parse_private_users(
                         return 0;
                 }
 
+                if (!userns_shift_range_valid(sh, rn)) {
+                        log_syntax(unit, LOG_WARNING, filename, line, 0, "UID/GID shift and range combination invalid, ignoring: %s", range);
+                        return 0;
+                }
+
                 settings->userns_mode = USER_NAMESPACE_FIXED;
                 settings->uid_shift = sh;
                 settings->uid_range = rn;
index 38d6eeacc7e0563aedb118154af6009cddc29c62..b5e5474231e15da111ba75702bf26968b709f834 100644 (file)
@@ -1259,11 +1259,10 @@ static int parse_argv(int argc, char *argv[]) {
                                         return log_error_errno(r, "Failed to parse UID \"%s\": %m", optarg);
 
                                 arg_userns_mode = USER_NAMESPACE_FIXED;
-                        }
 
-                        if (arg_uid_range <= 0)
-                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                       "UID range cannot be 0.");
+                                if (!userns_shift_range_valid(arg_uid_shift, arg_uid_range))
+                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "UID range cannot be empty or go beyond " UID_FMT ".", UID_INVALID);
+                        }
 
                         arg_settings_mask |= SETTING_USERNS;
                         break;
@@ -3068,9 +3067,8 @@ static int determine_uid_shift(const char *directory) {
                 arg_uid_range = UINT32_C(0x10000);
         }
 
-        if (arg_uid_shift > UID_INVALID - arg_uid_range)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "UID base too high for UID range.");
+        if (!userns_shift_range_valid(arg_uid_shift, arg_uid_range))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "UID base too high for UID range.");
 
         return 0;
 }