]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/nspawn/nspawn-oci.c
license: LGPL-2.1+ -> LGPL-2.1-or-later
[thirdparty/systemd.git] / src / nspawn / nspawn-oci.c
index ef67731339ffd3a851f2540b810a3554002e207f..ca708be7556b66b90b8256876f2c68a39090ea30 100644 (file)
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <linux/oom.h>
 #if HAVE_SECCOMP
  * cgrouspv1 crap: kernel, kernelTCP, swapiness, disableOOMKiller, swap, devices, leafWeight
  * general: it shouldn't leak lower level abstractions this obviously
  * unmanagable cgroups stuff: realtimeRuntime/realtimePeriod
- * needs to say what happense when some option is not specified, i.e. which defautls apply
+ * needs to say what happense when some option is not specified, i.e. which defaults apply
  * no architecture? no personality?
  * seccomp example and logic is simply broken: there's no constant "SCMP_ACT_ERRNO".
  * spec should say what to do with unknown props
  * /bin/mount regarding NFS and FUSE required?
  * what does terminal=false mean?
- * sysctl inside or outside? whitelisting?
+ * sysctl inside or outside? allow-listing?
  * swapiness typo -> swappiness
  *
  * Unsupported:
@@ -172,24 +172,13 @@ static int oci_env(const char *name, JsonVariant *v, JsonDispatchFlags flags, vo
 static int oci_args(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
         _cleanup_strv_free_ char **l = NULL;
         char ***value = userdata;
-        JsonVariant *e;
         int r;
 
         assert(value);
 
-        JSON_VARIANT_ARRAY_FOREACH(e, v) {
-                const char *n;
-
-                if (!json_variant_is_string(e))
-                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
-                                        "Argument is not a string.");
-
-                assert_se(n = json_variant_string(e));
-
-                r = strv_extend(&l, n);
-                if (r < 0)
-                        return log_oom();
-        }
+        r = json_variant_strv(v, &l);
+        if (r < 0)
+                return json_log(v, flags, r, "Cannot parse arguments as list of strings: %m");
 
         if (strv_isempty(l))
                 return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
@@ -671,10 +660,9 @@ static int oci_namespaces(const char *name, JsonVariant *v, JsonDispatchFlags fl
                         s->network_namespace_path = data.path;
                 }
 
-                if (FLAGS_SET(n, data.type)) {
+                if (FLAGS_SET(n, data.type))
                         return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL),
                                         "Duplicate namespace specification, refusing.");
-                }
 
                 n |= data.type;
         }
@@ -1040,39 +1028,40 @@ static int oci_cgroup_devices(const char *name, JsonVariant *v, JsonDispatchFlag
                         return r;
 
                 if (!data.allow) {
-                        /* The fact that OCI allows 'deny' entries makes really no sense, as 'allow' vs. 'deny' for the
-                         * devices cgroup controller is really not about whitelisting and blacklisting but about adding
-                         * and removing entries from the whitelist. Since we always start out with an empty whitelist
-                         * we hence ignore the whole thing, as removing entries which don't exist make no sense. We'll
-                         * log about this, since this is really borked in the spec, with one exception: the entry
-                         * that's supposed to drop the kernel's default we ignore silently */
+                        /* The fact that OCI allows 'deny' entries makes really no sense, as 'allow'
+                         * vs. 'deny' for the devices cgroup controller is really not about allow-listing and
+                         * deny-listing but about adding and removing entries from the allow list. Since we
+                         * always start out with an empty allow list we hence ignore the whole thing, as
+                         * removing entries which don't exist make no sense. We'll log about this, since this
+                         * is really borked in the spec, with one exception: the entry that's supposed to
+                         * drop the kernel's default we ignore silently */
 
                         if (!data.r || !data.w || !data.m || data.type != 0 || data.major != (unsigned) -1 || data.minor != (unsigned) -1)
-                                json_log(v, flags|JSON_WARNING, 0, "Devices cgroup whitelist with arbitrary 'allow' entries not supported, ignoring.");
+                                json_log(v, flags|JSON_WARNING, 0, "Devices cgroup allow list with arbitrary 'allow' entries not supported, ignoring.");
 
                         /* We ignore the 'deny' entry as for us that's implied */
                         continue;
                 }
 
                 if (!data.r && !data.w && !data.m) {
-                        json_log(v, flags|LOG_WARNING, 0, "Device cgroup whitelist entry with no effect found, ignoring.");
+                        json_log(v, flags|LOG_WARNING, 0, "Device cgroup allow list entry with no effect found, ignoring.");
                         continue;
                 }
 
                 if (data.minor != (unsigned) -1 && data.major == (unsigned) -1)
                         return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
-                                        "Device cgroup whitelist entries with minors but no majors not supported.");
+                                        "Device cgroup allow list entries with minors but no majors not supported.");
 
                 if (data.major != (unsigned) -1 && data.type == 0)
                         return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
-                                        "Device cgroup whitelist entries with majors but no device node type not supported.");
+                                        "Device cgroup allow list entries with majors but no device node type not supported.");
 
                 if (data.type == 0) {
-                        if (data.r && data.w && data.m) /* a catchall whitelist entry means we are looking at a noop */
+                        if (data.r && data.w && data.m) /* a catchall allow list entry means we are looking at a noop */
                                 noop = true;
                         else
                                 return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
-                                                "Device cgroup whitelist entries with no type not supported.");
+                                                "Device cgroup allow list entries with no type not supported.");
                 }
 
                 a = reallocarray(list, n_list + 1, sizeof(struct device_data));
@@ -1705,6 +1694,9 @@ static int oci_seccomp_arch_from_string(const char *name, uint32_t *ret) {
                 { "SCMP_ARCH_PPC",         SCMP_ARCH_PPC         },
                 { "SCMP_ARCH_PPC64",       SCMP_ARCH_PPC64       },
                 { "SCMP_ARCH_PPC64LE",     SCMP_ARCH_PPC64LE     },
+#ifdef SCMP_ARCH_RISCV64
+                { "SCMP_ARCH_RISCV64",     SCMP_ARCH_RISCV64     },
+#endif
                 { "SCMP_ARCH_S390",        SCMP_ARCH_S390        },
                 { "SCMP_ARCH_S390X",       SCMP_ARCH_S390X       },
                 { "SCMP_ARCH_X32",         SCMP_ARCH_X32         },
@@ -2092,13 +2084,9 @@ static int oci_hook_timeout(const char *name, JsonVariant *v, JsonDispatchFlags
         uintmax_t k;
 
         k = json_variant_unsigned(v);
-        if (k == 0)
-                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
-                                "Hook timeout cannot be zero.");
-
-        if (k > (UINT64_MAX-1/USEC_PER_SEC))
-                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
-                                "Hook timeout too large.");
+        if (k == 0 || k > (UINT64_MAX-1)/USEC_PER_SEC)
+                return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
+                                "Hook timeout value out of range.");
 
         *u = k * USEC_PER_SEC;
         return 0;
@@ -2218,7 +2206,7 @@ int oci_load(FILE *f, const char *bundle, Settings **ret) {
 
         path = strjoina(bundle, "/config.json");
 
-        r = json_parse_file(f, path, &oci, &line, &column);
+        r = json_parse_file(f, path, 0, &oci, &line, &column);
         if (r < 0) {
                 if (line != 0 && column != 0)
                         return log_error_errno(r, "Failed to parse '%s' at %u:%u: %m", path, line, column);
@@ -2227,14 +2215,14 @@ int oci_load(FILE *f, const char *bundle, Settings **ret) {
         }
 
         v = json_variant_by_key(oci, "ociVersion");
-        if (!v) {
-                log_error("JSON file '%s' is not an OCI bundle configuration file. Refusing.", path);
-                return -EINVAL;
-        }
-        if (!streq_ptr(json_variant_string(v), "1.0.0")) {
-                log_error("OCI bundle version not supported: %s", strna(json_variant_string(v)));
-                return -EINVAL;
-        }
+        if (!v)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "JSON file '%s' is not an OCI bundle configuration file. Refusing.",
+                                       path);
+        if (!streq_ptr(json_variant_string(v), "1.0.0"))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "OCI bundle version not supported: %s",
+                                       strna(json_variant_string(v)));
 
         // {
         //         _cleanup_free_ char *formatted = NULL;