summaryrefslogtreecommitdiff
path: root/jail
diff options
context:
space:
mode:
authorDaniel Golle <daniel@makrotopia.org>2021-05-28 18:17:35 +0200
committerDaniel Golle <daniel@makrotopia.org>2021-07-10 03:26:04 +0100
commit2dcefbd6094681dcbd2d7ff608590e74425a9220 (patch)
treeca34ec61d5ba71f84c58e511f0018f4d3c92f5a4 /jail
parent021ece84de430fca988acd6934f6046ea59d8c37 (diff)
downloadprocd-2dcefbd6094681dcbd2d7ff608590e74425a9220.tar.gz
jail: add support for cgroup devices as in OCI run-time spec
Implement eBPF generator to emulate cgroup-v1 devices.{allow,deny} as we got only cgroup-v2 available while the spec was written having cgroups-v1 in mind. Instead of literally emulating the legacy behavior, do like other runtimes do as well when running on cgroup-v2: simply translate each device rule into a bunch of eBPF instructions and then execute them in reverse order, prepended by some default rules covering /dev/null, /dev/random, /dev/tty, ... Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Diffstat (limited to 'jail')
-rw-r--r--jail/cgroups-bpf.c451
-rw-r--r--jail/cgroups-bpf.h20
-rw-r--r--jail/cgroups.c34
-rw-r--r--jail/jail.c11
4 files changed, 503 insertions, 13 deletions
diff --git a/jail/cgroups-bpf.c b/jail/cgroups-bpf.c
new file mode 100644
index 0000000..b0079d9
--- /dev/null
+++ b/jail/cgroups-bpf.c
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2021 Daniel Golle <daniel@makrotopia.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * somehow emulate devices.allow/devices.deny using eBPF
+ *
+ * OCI run-time spec defines the syntax for allowing/denying access
+ * to devices according to the definition of cgroup-v1 in the Kernel
+ * as described in Documentation/admin-guide/cgroup-v1.
+ */
+
+#include <assert.h>
+#include <linux/bpf.h>
+#include <sys/reg.h>
+#include <sys/syscall.h>
+
+#include <libubox/blobmsg.h>
+#include <libubox/blobmsg_json.h>
+#include <libubox/list.h>
+
+#include "cgroups.h"
+#include "cgroups-bpf.h"
+#include "log.h"
+
+static struct bpf_insn *program = NULL;
+static int bpf_total_insn = 0;
+static const char *license = "GPL";
+
+static int
+syscall_bpf (int cmd, union bpf_attr *attr, unsigned int size)
+{
+ return (int) syscall (__NR_bpf, cmd, attr, size);
+}
+
+/* from crun/src/libcrun/ebpf.c */
+#define BPF_ALU32_IMM(OP, DST, IMM) \
+ ((struct bpf_insn){ .code = BPF_ALU | BPF_OP (OP) | BPF_K, .dst_reg = DST, .src_reg = 0, .off = 0, .imm = IMM })
+
+#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \
+ ((struct bpf_insn){ \
+ .code = BPF_LDX | BPF_SIZE (SIZE) | BPF_MEM, .dst_reg = DST, .src_reg = SRC, .off = OFF, .imm = 0 })
+
+#define BPF_MOV64_REG(DST, SRC) \
+ ((struct bpf_insn){ .code = BPF_ALU64 | BPF_MOV | BPF_X, .dst_reg = DST, .src_reg = SRC, .off = 0, .imm = 0 })
+
+#define BPF_JMP_A(OFF) \
+ ((struct bpf_insn){ .code = BPF_JMP | BPF_JA, .dst_reg = 0, .src_reg = 0, .off = OFF, .imm = 0 })
+
+#define BPF_JMP_IMM(OP, DST, IMM, OFF) \
+ ((struct bpf_insn){ .code = BPF_JMP | BPF_OP (OP) | BPF_K, .dst_reg = DST, .src_reg = 0, .off = OFF, .imm = IMM })
+
+#define BPF_JMP_REG(OP, DST, SRC, OFF) \
+ ((struct bpf_insn){ .code = BPF_JMP | BPF_OP (OP) | BPF_X, .dst_reg = DST, .src_reg = SRC, .off = OFF, .imm = 0 })
+
+#define BPF_MOV64_IMM(DST, IMM) \
+ ((struct bpf_insn){ .code = BPF_ALU64 | BPF_MOV | BPF_K, .dst_reg = DST, .src_reg = 0, .off = 0, .imm = IMM })
+
+#define BPF_MOV32_REG(DST, SRC) \
+ ((struct bpf_insn){ .code = BPF_ALU | BPF_MOV | BPF_X, .dst_reg = DST, .src_reg = SRC, .off = 0, .imm = 0 })
+
+#define BPF_EXIT_INSN() \
+ ((struct bpf_insn){ .code = BPF_JMP | BPF_EXIT, .dst_reg = 0, .src_reg = 0, .off = 0, .imm = 0 })
+
+/* taken from systemd. */
+static const struct bpf_insn pre_insn[] = {
+ /* type -> R2. */
+ BPF_LDX_MEM (BPF_W, BPF_REG_2, BPF_REG_1, 0),
+ BPF_ALU32_IMM (BPF_AND, BPF_REG_2, 0xFFFF),
+ /* access -> R3. */
+ BPF_LDX_MEM (BPF_W, BPF_REG_3, BPF_REG_1, 0),
+ BPF_ALU32_IMM (BPF_RSH, BPF_REG_3, 16),
+ /* major -> R4. */
+ BPF_LDX_MEM (BPF_W, BPF_REG_4, BPF_REG_1, 4),
+ /* minor -> R5. */
+ BPF_LDX_MEM (BPF_W, BPF_REG_5, BPF_REG_1, 8),
+};
+
+enum {
+ OCI_LINUX_CGROUPS_DEVICES_ALLOW,
+ OCI_LINUX_CGROUPS_DEVICES_TYPE,
+ OCI_LINUX_CGROUPS_DEVICES_MAJOR,
+ OCI_LINUX_CGROUPS_DEVICES_MINOR,
+ OCI_LINUX_CGROUPS_DEVICES_ACCESS,
+ __OCI_LINUX_CGROUPS_DEVICES_MAX,
+};
+
+static const struct blobmsg_policy oci_linux_cgroups_devices_policy[] = {
+ [OCI_LINUX_CGROUPS_DEVICES_ALLOW] = { "allow", BLOBMSG_TYPE_BOOL },
+ [OCI_LINUX_CGROUPS_DEVICES_TYPE] = { "type", BLOBMSG_TYPE_STRING },
+ [OCI_LINUX_CGROUPS_DEVICES_MAJOR] = { "major", BLOBMSG_CAST_INT64 },
+ [OCI_LINUX_CGROUPS_DEVICES_MINOR] = { "minor", BLOBMSG_CAST_INT64 },
+ [OCI_LINUX_CGROUPS_DEVICES_ACCESS] = { "access", BLOBMSG_TYPE_STRING },
+};
+
+/*
+ * cgroup-v1 devices got a (default) behaviour and a list of exceptions.
+ * define datatypes similar to the legacy kernel code.
+ */
+#define DEVCG_DEV_ALL (BPF_DEVCG_DEV_BLOCK | BPF_DEVCG_DEV_CHAR)
+#define DEVCG_ACC_ALL (BPF_DEVCG_ACC_READ | BPF_DEVCG_ACC_WRITE | BPF_DEVCG_ACC_MKNOD)
+
+enum devcg_behavior {
+ DEVCG_DEFAULT_NONE,
+ DEVCG_DEFAULT_ALLOW,
+ DEVCG_DEFAULT_DENY,
+};
+
+struct dev_exception_item {
+ uint32_t major, minor;
+ short type;
+ short access;
+ struct list_head list;
+ bool allow;
+};
+
+/*
+ * add a bunch of default rules
+ */
+static int add_default_exceptions(struct list_head *exceptions)
+{
+ int i, ret = 0;
+ struct dev_exception_item *cur;
+ /* from crun/src/libcrun/cgroup.c */
+ const struct dev_exception_item defrules[] = {
+ /* always allow mknod */
+ { .allow = true, .type = BPF_DEVCG_DEV_CHAR, .major = ~0, .minor = ~0, .access = BPF_DEVCG_ACC_MKNOD },
+ { .allow = true, .type = BPF_DEVCG_DEV_BLOCK, .major = ~0, .minor = ~0, .access = BPF_DEVCG_ACC_MKNOD },
+ /* /dev/null */
+ { .allow = true, .type = BPF_DEVCG_DEV_CHAR, .major = 1, .minor = 3, .access = DEVCG_ACC_ALL },
+ /* /dev/random */
+ { .allow = true, .type = BPF_DEVCG_DEV_CHAR, .major = 1, .minor = 8, .access = DEVCG_ACC_ALL },
+ /* /dev/full */
+ { .allow = true, .type = BPF_DEVCG_DEV_CHAR, .major = 1, .minor = 7, .access = DEVCG_ACC_ALL },
+ /* /dev/tty */
+ { .allow = true, .type = BPF_DEVCG_DEV_CHAR, .major = 5, .minor = 0, .access = DEVCG_ACC_ALL },
+ /* /dev/zero */
+ { .allow = true, .type = BPF_DEVCG_DEV_CHAR, .major = 1, .minor = 5, .access = DEVCG_ACC_ALL },
+ /* /dev/urandom */
+ { .allow = true, .type = BPF_DEVCG_DEV_CHAR, .major = 1, .minor = 9, .access = DEVCG_ACC_ALL },
+ /* /dev/console */
+ { .allow = true, .type = BPF_DEVCG_DEV_CHAR, .major = 5, .minor = 1, .access = DEVCG_ACC_ALL },
+ /* /dev/pts/[0-255] */
+ { .allow = true, .type = BPF_DEVCG_DEV_CHAR, .major = 136, .minor = ~0, .access = DEVCG_ACC_ALL },
+ /* /dev/ptmx */
+ { .allow = true, .type = BPF_DEVCG_DEV_CHAR, .major = 5, .minor = 2, .access = DEVCG_ACC_ALL },
+ /* /dev/net/tun */
+ { .allow = true, .type = BPF_DEVCG_DEV_CHAR, .major = 10, .minor = 200, .access = DEVCG_ACC_ALL },
+ };
+
+ for (i = 0; i < (sizeof(defrules) / sizeof(struct dev_exception_item)); ++i) {
+ cur = malloc(sizeof(struct dev_exception_item));
+ if (!cur) {
+ ret = ENOMEM;
+ break;
+ }
+ /* add defaults to list in reverse order (last item will be first in list) */
+ memcpy(cur, &defrules[i], sizeof(struct dev_exception_item));
+ list_add(&cur->list, exceptions);
+ }
+
+ return ret;
+}
+
+/*
+ * free all exceptions in the list
+ */
+static void flush_exceptions(struct list_head *freelist)
+{
+ struct dev_exception_item *dl, *dln;
+
+ if (!list_empty(freelist))
+ list_for_each_entry_safe(dl, dln, freelist, list) {
+ list_del(&dl->list);
+ free(dl);
+ }
+}
+
+/*
+ * parse OCI cgroups devices and translate into cgroups-v2 eBPF program
+ */
+int parseOCIlinuxcgroups_devices(struct blob_attr *msg)
+{
+ struct blob_attr *tb[__OCI_LINUX_CGROUPS_DEVICES_MAX];
+ struct blob_attr *cur;
+ int rem, ret = 0;
+ int bpf_type, bpf_access;
+ unsigned char acidx;
+ bool allow = false,
+ has_access = false,
+ has_type = false,
+ has_major = false,
+ has_minor = false;
+ int total_ins = 0,
+ cur_ins = 0,
+ pre_insn_len = sizeof(pre_insn) / sizeof(struct bpf_insn),
+ next_ins;
+ char *access, *devtype;
+ uint32_t devmajor, devminor;
+ struct dev_exception_item *dl;
+ struct list_head exceptions;
+ enum devcg_behavior behavior = DEVCG_DEFAULT_ALLOW;
+ INIT_LIST_HEAD(&exceptions);
+
+ /* parse according to OCI spec */
+ blobmsg_for_each_attr(cur, msg, rem) {
+ blobmsg_parse(oci_linux_cgroups_devices_policy, __OCI_LINUX_CGROUPS_DEVICES_MAX,
+ tb, blobmsg_data(cur), blobmsg_len(cur));
+
+ if (!tb[OCI_LINUX_CGROUPS_DEVICES_ALLOW]) {
+ ret = EINVAL;
+ goto out;
+ }
+
+ allow = blobmsg_get_bool(tb[OCI_LINUX_CGROUPS_DEVICES_ALLOW]);
+
+ bpf_access = 0;
+ if (tb[OCI_LINUX_CGROUPS_DEVICES_ACCESS]) {
+ access = blobmsg_get_string(tb[OCI_LINUX_CGROUPS_DEVICES_ACCESS]);
+ if ((strlen(access) > 3) || (strlen(access) == 0)) {
+ ret = EINVAL;
+ goto out;
+ }
+
+ for (acidx = 0; acidx < strlen(access); ++acidx) {
+ switch (access[acidx]) {
+ case 'r':
+ bpf_access |= BPF_DEVCG_ACC_READ;
+ break;
+ case 'w':
+ bpf_access |= BPF_DEVCG_ACC_WRITE;
+ break;
+ case 'm':
+ bpf_access |= BPF_DEVCG_ACC_MKNOD;
+ break;
+ default:
+ ret = EINVAL;
+ goto out;
+ }
+ }
+ }
+
+ if (!bpf_access)
+ bpf_access = DEVCG_ACC_ALL;
+
+ bpf_type = 0;
+ if (tb[OCI_LINUX_CGROUPS_DEVICES_TYPE]) {
+ devtype = blobmsg_get_string(tb[OCI_LINUX_CGROUPS_DEVICES_TYPE]);
+
+ switch (devtype[0]) {
+ case 'c':
+ bpf_type = BPF_DEVCG_DEV_CHAR;
+ break;
+ case 'b':
+ bpf_type = BPF_DEVCG_DEV_BLOCK;
+ break;
+ case 'a':
+ bpf_type = DEVCG_DEV_ALL;
+ break;
+ default:
+ ret = EINVAL;
+ goto out;
+ }
+ }
+
+ if (!bpf_type)
+ bpf_type = DEVCG_DEV_ALL;
+
+ if (tb[OCI_LINUX_CGROUPS_DEVICES_MAJOR])
+ devmajor = blobmsg_cast_u64(tb[OCI_LINUX_CGROUPS_DEVICES_MAJOR]);
+ else
+ devmajor = ~0;
+
+ if (tb[OCI_LINUX_CGROUPS_DEVICES_MINOR])
+ devminor = blobmsg_cast_u64(tb[OCI_LINUX_CGROUPS_DEVICES_MINOR]);
+ else
+ devminor = ~0;
+
+ if (bpf_type == DEVCG_DEV_ALL) {
+ /* wildcard => change default policy and flush all existing rules */
+ flush_exceptions(&exceptions);
+ behavior = allow?DEVCG_DEFAULT_ALLOW:DEVCG_DEFAULT_DENY;
+ } else {
+ /* allocate and populate record for exception */
+ dl = malloc(sizeof(struct dev_exception_item));
+ if (!dl) {
+ ret = ENOSPC;
+ break;
+ }
+ dl->allow = allow;
+ dl->type = bpf_type;
+ dl->access = bpf_access;
+ dl->major = devmajor;
+ dl->minor = devminor;
+
+ /* push to exceptions list, last goes first */
+ list_add(&dl->list, &exceptions);
+ }
+ }
+ if (ret)
+ goto out;
+
+ /* add default rules */
+ ret = add_default_exceptions(&exceptions);
+ if (ret)
+ goto out;
+
+ /* calculate number of instructions to allocate */
+ list_for_each_entry(dl, &exceptions, list) {
+ has_access = dl->access != DEVCG_ACC_ALL;
+ has_type = dl->type != DEVCG_DEV_ALL;
+ has_major = dl->major != ~0;
+ has_minor = dl->minor != ~0;
+
+ total_ins += (has_type ? 1 : 0) + (has_access ? 3 : 0) + (has_major ? 1 : 0) + (has_minor ? 1 : 0) + 2;
+ }
+
+ /* acccount for loader instructions */
+ total_ins += pre_insn_len;
+
+ /* final accept/deny block */
+ total_ins += 2;
+
+ /* allocate memory for eBPF program */
+ program = calloc(total_ins, sizeof(struct bpf_insn));
+ if (!program) {
+ ret = ENOMEM;
+ goto out;
+ }
+
+ /* copy program loader instructions */
+ memcpy(program, &pre_insn, sizeof(pre_insn));
+ cur_ins = pre_insn_len;
+
+ /* generate eBPF program */
+ list_for_each_entry(dl, &exceptions, list) {
+ has_access = dl->access != DEVCG_ACC_ALL;
+ has_type = dl->type != DEVCG_DEV_ALL;
+ has_major = dl->major != ~0;
+ has_minor = dl->minor != ~0;
+
+ next_ins = (has_type ? 1 : 0) + (has_access ? 3 : 0) + (has_major ? 1 : 0) + (has_minor ? 1 : 0) + 1;
+
+ if (has_type) {
+ program[cur_ins++] = BPF_JMP_IMM(BPF_JNE, BPF_REG_2, dl->type, next_ins);
+ --next_ins;
+ }
+
+ if (has_access) {
+ program[cur_ins++] = BPF_MOV32_REG(BPF_REG_1, BPF_REG_3);
+ program[cur_ins++] = BPF_ALU32_IMM(BPF_AND, BPF_REG_1, dl->access);
+ program[cur_ins++] = BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, next_ins - 2);
+ next_ins -= 3;
+ }
+
+ if (has_major) {
+ program[cur_ins++] = BPF_JMP_IMM(BPF_JNE, BPF_REG_4, dl->major, next_ins);
+ --next_ins;
+ }
+
+ if (has_minor) {
+ program[cur_ins++] = BPF_JMP_IMM(BPF_JNE, BPF_REG_5, dl->minor, next_ins);
+ --next_ins;
+ }
+
+ program[cur_ins++] = BPF_MOV64_IMM(BPF_REG_0, dl->allow ? 1 : 0);
+ program[cur_ins++] = BPF_EXIT_INSN();
+ }
+
+ /* default behavior */
+ program[cur_ins++] = BPF_MOV64_IMM(BPF_REG_0, (behavior == DEVCG_DEFAULT_ALLOW)?1:0);
+ program[cur_ins++] = BPF_EXIT_INSN();
+
+ if (debug) {
+ fprintf(stderr, "cgroup devices:\na > devices.%s\n",
+ (behavior == DEVCG_DEFAULT_ALLOW)?"allow":"deny");
+
+ list_for_each_entry(dl, &exceptions, list)
+ fprintf(stderr, "%c %d:%d %s%s%s > devices.%s\n",
+ (dl->type == DEVCG_DEV_ALL)?'a':
+ (dl->type == BPF_DEVCG_DEV_CHAR)?'c':'b',
+ (dl->major == ~0)?-1:dl->major,
+ (dl->minor == ~0)?-1:dl->minor,
+ (dl->access & BPF_DEVCG_ACC_READ)?"r":"",
+ (dl->access & BPF_DEVCG_ACC_WRITE)?"w":"",
+ (dl->access & BPF_DEVCG_ACC_MKNOD)?"m":"",
+ (dl->allow)?"allow":"deny");
+
+ fprintf(stderr, "generated cgroup-devices eBPF program:\n");
+ fprintf(stderr, " [idx]\tcode\t dest\t src\t off\t imm\n");
+ for (cur_ins=0; cur_ins<total_ins; cur_ins++)
+ fprintf(stderr, " [%03d]\t%02hhx\t%3hhu\t%3hhu\t%04hx\t%d\n", cur_ins,
+ program[cur_ins].code,
+ program[cur_ins].dst_reg,
+ program[cur_ins].src_reg,
+ program[cur_ins].off,
+ program[cur_ins].imm);
+ }
+
+ assert(cur_ins == total_ins);
+ bpf_total_insn = total_ins;
+ ret = 0;
+
+out:
+ flush_exceptions(&exceptions);
+ return ret;
+}
+
+/*
+ * attach eBPF program to cgroup
+ */
+int attach_cgroups_ebpf(int cgroup_dirfd) {
+ int prog_fd;
+#if ( __WORDSIZE == 64 )
+ uint64_t program_ptr = (uint64_t)program;
+ uint64_t license_ptr = (uint64_t)license;
+#elif ( __WORDSIZE == 32 )
+ uint32_t program_ptr = (uint32_t)program;
+ uint32_t license_ptr = (uint32_t)license;
+#else
+#error
+#endif
+ union bpf_attr load_attr = {
+ .prog_type = BPF_PROG_TYPE_CGROUP_DEVICE,
+ .license = license_ptr,
+ .insns = program_ptr,
+ .insn_cnt = bpf_total_insn,
+ };
+
+ if (!program)
+ return 0;
+
+ prog_fd = syscall_bpf(BPF_PROG_LOAD, &load_attr, sizeof(load_attr));
+ if (prog_fd < 0)
+ return EIO;
+
+ union bpf_attr attach_attr = {
+ .attach_type = BPF_CGROUP_DEVICE,
+ .target_fd = cgroup_dirfd,
+ .attach_bpf_fd = prog_fd,
+ };
+
+ return syscall_bpf(BPF_PROG_ATTACH, &attach_attr, sizeof (attach_attr));
+}
diff --git a/jail/cgroups-bpf.h b/jail/cgroups-bpf.h
new file mode 100644
index 0000000..7f33d85
--- /dev/null
+++ b/jail/cgroups-bpf.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2021 Daniel Golle <daniel@makrotopia.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _JAIL_CGROUPS_BPF_H
+#define _JAIL_CGROUPS_BPF_H
+
+int parseOCIlinuxcgroups_devices(struct blob_attr *msg);
+int attach_cgroups_ebpf(int cgroup_dirfd);
+
+#endif
diff --git a/jail/cgroups.c b/jail/cgroups.c
index 68bd189..185d18f 100644
--- a/jail/cgroups.c
+++ b/jail/cgroups.c
@@ -16,7 +16,6 @@
* https://github.com/containers/crun/blob/0.14.1/crun.1.md#cgroup-v2
*
* ToDo:
- * - convert cgroup1 devices to eBPF program
* - convert cgroup1 net_prio and net_cls to eBPF program
* - rdma (anyone?) intelrdt (anyone?)
*/
@@ -43,6 +42,7 @@
#include "log.h"
#include "cgroups.h"
+#include "cgroups-bpf.h"
#define CGROUP_ROOT "/sys/fs/cgroup/"
#define CGROUP_IO_WEIGHT_MAX 10000
@@ -197,11 +197,22 @@ void cgroups_apply(pid_t pid)
close(fd);
}
+ int dirfd = open(cgroup_path, O_DIRECTORY);
+ if (dirfd < 0) {
+ ERROR("can't open %s: %m\n", cgroup_path);
+ } else {
+ attach_cgroups_ebpf(dirfd);
+ close(dirfd);
+ }
+
snprintf(ent, maxlen, "%s/%s", cgroup_path, "cgroup.procs");
fd = open(ent, O_WRONLY);
- assert(fd != -1);
- dprintf(fd, "%d", pid);
- close(fd);
+ if (fd < 0) {
+ ERROR("can't open %s: %m\n", cgroup_path);
+ } else {
+ dprintf(fd, "%d", pid);
+ close(fd);
+ }
free(ent);
}
@@ -349,7 +360,8 @@ static int parseOCIlinuxcgroups_legacy_blockio(struct blob_attr *msg)
numweightstrs = 0;
if (weight > -1)
- asprintf(&weightstrs[numweightstrs++], "default %d", weight);
+ if (asprintf(&weightstrs[numweightstrs++], "default %d", weight) < 0)
+ return ENOMEM;
blobmsg_for_each_attr(cur, tb[OCI_LINUX_CGROUPS_BLOCKIO_WEIGHTDEVICE], rem) {
uint64_t major, minor;
@@ -382,7 +394,8 @@ static int parseOCIlinuxcgroups_legacy_blockio(struct blob_attr *msg)
major = blobmsg_cast_u64(tbwd[OCI_LINUX_CGROUPS_BLOCKIO_WEIGHTDEVICE_MAJOR]);
minor = blobmsg_cast_u64(tbwd[OCI_LINUX_CGROUPS_BLOCKIO_WEIGHTDEVICE_MINOR]);
- asprintf(&weightstrs[numweightstrs++], "%" PRIu64 ":%" PRIu64 " %u", major, minor, devweight);
+ if (asprintf(&weightstrs[numweightstrs++], "%" PRIu64 ":%" PRIu64 " %u", major, minor, devweight) < 0)
+ return ENOMEM;
}
if (numweightstrs) {
@@ -785,8 +798,7 @@ int parseOCIlinuxcgroups(struct blob_attr *msg)
blobmsg_parse(oci_linux_cgroups_policy, __OCI_LINUX_CGROUPS_MAX, tb, blobmsg_data(msg), blobmsg_len(msg));
- if (tb[OCI_LINUX_CGROUPS_DEVICES] ||
- tb[OCI_LINUX_CGROUPS_HUGEPAGELIMITS] ||
+ if (tb[OCI_LINUX_CGROUPS_HUGEPAGELIMITS] ||
tb[OCI_LINUX_CGROUPS_INTELRDT] ||
tb[OCI_LINUX_CGROUPS_NETWORK] ||
tb[OCI_LINUX_CGROUPS_RDMA])
@@ -804,6 +816,12 @@ int parseOCIlinuxcgroups(struct blob_attr *msg)
return ret;
}
+ if (tb[OCI_LINUX_CGROUPS_DEVICES]) {
+ ret = parseOCIlinuxcgroups_devices(tb[OCI_LINUX_CGROUPS_DEVICES]);
+ if (ret)
+ return ret;
+ }
+
if (tb[OCI_LINUX_CGROUPS_MEMORY]) {
ret = parseOCIlinuxcgroups_legacy_memory(tb[OCI_LINUX_CGROUPS_MEMORY]);
if (ret)
diff --git a/jail/jail.c b/jail/jail.c
index ce4f50c..c350be2 100644
--- a/jail/jail.c
+++ b/jail/jail.c
@@ -514,8 +514,7 @@ static int apply_sysctl(const char *jail_root)
if (!opts.sysctl)
return 0;
- asprintf(&procdir, "%s/proc", jail_root);
- if (!procdir)
+ if (asprintf(&procdir, "%s/proc", jail_root) < 0)
return ENOMEM;
mkdir(procdir, 0700);
@@ -525,8 +524,7 @@ static int apply_sysctl(const char *jail_root)
cur = opts.sysctl;
while (*cur) {
- asprintf(&fname, "%s/sys/%s", procdir, (*cur)->entry);
- if (!fname)
+ if (asprintf(&fname, "%s/sys/%s", procdir, (*cur)->entry) < 0)
return ENOMEM;
DEBUG("sysctl: writing '%s' to %s\n", (*cur)->value, fname);
@@ -2581,7 +2579,10 @@ int main(int argc, char **argv)
ret=-1;
goto errout;
}
- asprintf(&jsonfile, "%s/config.json", opts.ocibundle);
+ if (asprintf(&jsonfile, "%s/config.json", opts.ocibundle) < 0) {
+ ret=-ENOMEM;
+ goto errout;
+ }
ocires = parseOCI(jsonfile);
free(jsonfile);
if (ocires) {