LIST_FOREACH(device_allow, a, g->device_allow)
if (strv_extendf(&info->device_allow,
- "%s:%s%s%s",
+ "%s:%s",
a->path,
- a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "") < 0)
+ cgroup_device_permissions_to_string(a->permissions)) < 0)
return log_oom();
}
#define PASS_JUMP_OFF 4096
-static int bpf_access_type(const char *acc) {
- int r = 0;
-
- assert(acc);
-
- for (; *acc; acc++)
- switch (*acc) {
- case 'r':
- r |= BPF_DEVCG_ACC_READ;
- break;
- case 'w':
- r |= BPF_DEVCG_ACC_WRITE;
- break;
- case 'm':
- r |= BPF_DEVCG_ACC_MKNOD;
- break;
- default:
- return -EINVAL;
- }
-
- return r;
-}
+/* Ensure the high level flags we use and the low-level BPF flags exposed on the kernel are defined the same way */
+assert_cc((unsigned) BPF_DEVCG_ACC_MKNOD == (unsigned) CGROUP_DEVICE_MKNOD);
+assert_cc((unsigned) BPF_DEVCG_ACC_READ == (unsigned) CGROUP_DEVICE_READ);
+assert_cc((unsigned) BPF_DEVCG_ACC_WRITE == (unsigned) CGROUP_DEVICE_WRITE);
static int bpf_prog_allow_list_device(
BPFProgram *prog,
char type,
int major,
int minor,
- const char *acc) {
+ CGroupDevicePermissions p) {
- int r, access;
+ int r;
assert(prog);
- assert(acc);
- log_trace("%s: %c %d:%d %s", __func__, type, major, minor, acc);
+ log_trace("%s: %c %d:%d %s", __func__, type, major, minor, cgroup_device_permissions_to_string(p));
- access = bpf_access_type(acc);
- if (access <= 0)
+ if (p <= 0 || p >= _CGROUP_DEVICE_PERMISSIONS_MAX)
return -EINVAL;
assert(IN_SET(type, 'b', 'c'));
const struct bpf_insn insn[] = {
BPF_MOV32_REG(BPF_REG_1, BPF_REG_3),
- BPF_ALU32_IMM(BPF_AND, BPF_REG_1, access),
+ BPF_ALU32_IMM(BPF_AND, BPF_REG_1, p),
BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 4), /* compare access type */
BPF_JMP_IMM(BPF_JNE, BPF_REG_2, bpf_type, 3), /* compare device type */
BPF_JMP_A(PASS_JUMP_OFF), /* jump to PASS */
};
- if (FLAGS_SET(access, BPF_DEVCG_ACC_READ | BPF_DEVCG_ACC_WRITE | BPF_DEVCG_ACC_MKNOD))
+ if (p == _CGROUP_DEVICE_PERMISSIONS_ALL)
r = bpf_program_add_instructions(prog, insn + 3, ELEMENTSOF(insn) - 3);
else
r = bpf_program_add_instructions(prog, insn, ELEMENTSOF(insn));
BPFProgram *prog,
char type,
int major,
- const char *acc) {
+ CGroupDevicePermissions p) {
- int r, access;
+ int r;
assert(prog);
- assert(acc);
- log_trace("%s: %c %d:* %s", __func__, type, major, acc);
+ log_trace("%s: %c %d:* %s", __func__, type, major, cgroup_device_permissions_to_string(p));
- access = bpf_access_type(acc);
- if (access <= 0)
+ if (p <= 0 || p >= _CGROUP_DEVICE_PERMISSIONS_MAX)
return -EINVAL;
assert(IN_SET(type, 'b', 'c'));
const struct bpf_insn insn[] = {
BPF_MOV32_REG(BPF_REG_1, BPF_REG_3),
- BPF_ALU32_IMM(BPF_AND, BPF_REG_1, access),
+ BPF_ALU32_IMM(BPF_AND, BPF_REG_1, p),
BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 3), /* compare access type */
BPF_JMP_IMM(BPF_JNE, BPF_REG_2, bpf_type, 2), /* compare device type */
BPF_JMP_A(PASS_JUMP_OFF), /* jump to PASS */
};
- if (FLAGS_SET(access, BPF_DEVCG_ACC_READ | BPF_DEVCG_ACC_WRITE | BPF_DEVCG_ACC_MKNOD))
+ if (p == _CGROUP_DEVICE_PERMISSIONS_ALL)
r = bpf_program_add_instructions(prog, insn + 3, ELEMENTSOF(insn) - 3);
else
r = bpf_program_add_instructions(prog, insn, ELEMENTSOF(insn));
static int bpf_prog_allow_list_class(
BPFProgram *prog,
char type,
- const char *acc) {
+ CGroupDevicePermissions p) {
- int r, access;
+ int r;
assert(prog);
- assert(acc);
- log_trace("%s: %c *:* %s", __func__, type, acc);
+ log_trace("%s: %c *:* %s", __func__, type, cgroup_device_permissions_to_string(p));
- access = bpf_access_type(acc);
- if (access <= 0)
+ if (p <= 0 || p >= _CGROUP_DEVICE_PERMISSIONS_MAX)
return -EINVAL;
assert(IN_SET(type, 'b', 'c'));
const struct bpf_insn insn[] = {
BPF_MOV32_REG(BPF_REG_1, BPF_REG_3),
- BPF_ALU32_IMM(BPF_AND, BPF_REG_1, access),
+ BPF_ALU32_IMM(BPF_AND, BPF_REG_1, p),
BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, 2), /* compare access type */
BPF_JMP_IMM(BPF_JNE, BPF_REG_2, bpf_type, 1), /* compare device type */
BPF_JMP_A(PASS_JUMP_OFF), /* jump to PASS */
};
- if (FLAGS_SET(access, BPF_DEVCG_ACC_READ | BPF_DEVCG_ACC_WRITE | BPF_DEVCG_ACC_MKNOD))
+ if (p == _CGROUP_DEVICE_PERMISSIONS_ALL)
r = bpf_program_add_instructions(prog, insn + 3, ELEMENTSOF(insn) - 3);
else
r = bpf_program_add_instructions(prog, insn, ELEMENTSOF(insn));
char type,
const unsigned *maj,
const unsigned *min,
- const char *acc) {
+ CGroupDevicePermissions p) {
assert(IN_SET(type, 'b', 'c'));
return 0;
if (maj && min)
- return bpf_prog_allow_list_device(prog, type, *maj, *min, acc);
+ return bpf_prog_allow_list_device(prog, type, *maj, *min, p);
else if (maj)
- return bpf_prog_allow_list_major(prog, type, *maj, acc);
+ return bpf_prog_allow_list_major(prog, type, *maj, p);
else
- return bpf_prog_allow_list_class(prog, type, acc);
+ return bpf_prog_allow_list_class(prog, type, p);
} else {
char buf[2+DECIMAL_STR_MAX(unsigned)*2+2+4];
int r;
if (maj && min)
- xsprintf(buf, "%c %u:%u %s", type, *maj, *min, acc);
+ xsprintf(buf, "%c %u:%u %s", type, *maj, *min, cgroup_device_permissions_to_string(p));
else if (maj)
- xsprintf(buf, "%c %u:* %s", type, *maj, acc);
+ xsprintf(buf, "%c %u:* %s", type, *maj, cgroup_device_permissions_to_string(p));
else
- xsprintf(buf, "%c *:* %s", type, acc);
+ xsprintf(buf, "%c *:* %s", type, cgroup_device_permissions_to_string(p));
/* Changing the devices list of a populated cgroup might result in EINVAL, hence ignore
* EINVAL here. */
BPFProgram *prog,
const char *path,
const char *node,
- const char *acc) {
+ CGroupDevicePermissions p) {
mode_t mode;
dev_t rdev;
int r;
assert(path);
- assert(acc);
- assert(strlen(acc) <= 3);
+ assert(p >= 0 && p < _CGROUP_DEVICE_PERMISSIONS_MAX);
- log_trace("%s: %s %s", __func__, node, acc);
+ log_trace("%s: %s %s", __func__, node, cgroup_device_permissions_to_string(p));
/* Some special handling for /dev/block/%u:%u, /dev/char/%u:%u, /run/systemd/inaccessible/chr and
* /run/systemd/inaccessible/blk paths. Instead of stat()ing these we parse out the major/minor directly. This
}
unsigned maj = major(rdev), min = minor(rdev);
- return allow_list_device_pattern(prog, path, S_ISCHR(mode) ? 'c' : 'b', &maj, &min, acc);
+ return allow_list_device_pattern(prog, path, S_ISCHR(mode) ? 'c' : 'b', &maj, &min, p);
}
int bpf_devices_allow_list_major(
const char *path,
const char *name,
char type,
- const char *acc) {
+ CGroupDevicePermissions permissions) {
unsigned maj;
int r;
assert(path);
- assert(acc);
assert(IN_SET(type, 'b', 'c'));
+ assert(permissions >= 0 && permissions < _CGROUP_DEVICE_PERMISSIONS_MAX);
if (streq(name, "*"))
/* If the name is a wildcard, then apply this list to all devices of this type */
- return allow_list_device_pattern(prog, path, type, NULL, NULL, acc);
+ return allow_list_device_pattern(prog, path, type, NULL, NULL, permissions);
if (safe_atou(name, &maj) >= 0 && DEVICE_MAJOR_VALID(maj))
/* The name is numeric and suitable as major. In that case, let's take its major, and create
* the entry directly. */
- return allow_list_device_pattern(prog, path, type, &maj, NULL, acc);
+ return allow_list_device_pattern(prog, path, type, &maj, NULL, permissions);
_cleanup_fclose_ FILE *f = NULL;
bool good = false, any = false;
continue;
any = true;
- (void) allow_list_device_pattern(prog, path, type, &maj, NULL, acc);
+ (void) allow_list_device_pattern(prog, path, type, &maj, NULL, permissions);
}
if (!any)
int r = 0, k;
NULSTR_FOREACH_PAIR(node, acc, auto_devices) {
- k = bpf_devices_allow_list_device(prog, path, node, acc);
+ k = bpf_devices_allow_list_device(prog, path, node, cgroup_device_permissions_from_string(acc));
if (r >= 0 && k < 0)
r = k;
}
/* PTS (/dev/pts) devices may not be duplicated, but accessed */
- k = bpf_devices_allow_list_major(prog, path, "pts", 'c', "rw");
+ k = bpf_devices_allow_list_major(prog, path, "pts", 'c', CGROUP_DEVICE_READ|CGROUP_DEVICE_WRITE);
if (r >= 0 && k < 0)
r = k;
BPFProgram **prog_installed);
int bpf_devices_supported(void);
-int bpf_devices_allow_list_device(BPFProgram *prog, const char *path, const char *node, const char *acc);
-int bpf_devices_allow_list_major(BPFProgram *prog, const char *path, const char *name, char type, const char *acc);
+int bpf_devices_allow_list_device(BPFProgram *prog, const char *path, const char *node, CGroupDevicePermissions p);
+int bpf_devices_allow_list_major(BPFProgram *prog, const char *path, const char *name, char type, CGroupDevicePermissions p);
int bpf_devices_allow_list_static(BPFProgram *prog, const char *path);
return buf;
}
+const char *cgroup_device_permissions_to_string(CGroupDevicePermissions p) {
+ static const char *table[_CGROUP_DEVICE_PERMISSIONS_MAX] = {
+ /* Lets simply define a table with every possible combination. As long as those are just 8 we
+ * can get away with it. If this ever grows to more we need to revisit this logic though. */
+ [0] = "",
+ [CGROUP_DEVICE_READ] = "r",
+ [CGROUP_DEVICE_WRITE] = "w",
+ [CGROUP_DEVICE_MKNOD] = "m",
+ [CGROUP_DEVICE_READ|CGROUP_DEVICE_WRITE] = "rw",
+ [CGROUP_DEVICE_READ|CGROUP_DEVICE_MKNOD] = "rm",
+ [CGROUP_DEVICE_WRITE|CGROUP_DEVICE_MKNOD] = "wm",
+ [CGROUP_DEVICE_READ|CGROUP_DEVICE_WRITE|CGROUP_DEVICE_MKNOD] = "rwm",
+ };
+
+ if (p < 0 || p >= _CGROUP_DEVICE_PERMISSIONS_MAX)
+ return NULL;
+
+ return table[p];
+}
+
+CGroupDevicePermissions cgroup_device_permissions_from_string(const char *s) {
+ CGroupDevicePermissions p = 0;
+
+ if (!s)
+ return _CGROUP_DEVICE_PERMISSIONS_INVALID;
+
+ for (const char *c = s; *c; c++) {
+ if (*c == 'r')
+ p |= CGROUP_DEVICE_READ;
+ else if (*c == 'w')
+ p |= CGROUP_DEVICE_WRITE;
+ else if (*c == 'm')
+ p |= CGROUP_DEVICE_MKNOD;
+ else
+ return _CGROUP_DEVICE_PERMISSIONS_INVALID;
+ }
+
+ return p;
+}
+
void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
_cleanup_free_ char *disable_controllers_str = NULL, *delegate_controllers_str = NULL, *cpuset_cpus = NULL, *cpuset_mems = NULL, *startup_cpuset_cpus = NULL, *startup_cpuset_mems = NULL;
CGroupContext *c;
LIST_FOREACH(device_allow, a, c->device_allow)
fprintf(f,
- "%sDeviceAllow: %s %s%s%s\n",
+ "%sDeviceAllow: %s %s\n",
prefix,
a->path,
- a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
+ cgroup_device_permissions_to_string(a->permissions));
LIST_FOREACH(device_weights, iw, c->io_device_weights)
fprintf(f,
}
}
-int cgroup_context_add_device_allow(CGroupContext *c, const char *dev, const char *mode) {
+int cgroup_context_add_device_allow(CGroupContext *c, const char *dev, CGroupDevicePermissions p) {
_cleanup_free_ CGroupDeviceAllow *a = NULL;
_cleanup_free_ char *d = NULL;
assert(c);
assert(dev);
- assert(isempty(mode) || in_charset(mode, "rwm"));
+ assert(p >= 0 && p < _CGROUP_DEVICE_PERMISSIONS_MAX);
+
+ if (p == 0)
+ p = _CGROUP_DEVICE_PERMISSIONS_ALL;
a = new(CGroupDeviceAllow, 1);
if (!a)
*a = (CGroupDeviceAllow) {
.path = TAKE_PTR(d),
- .r = isempty(mode) || strchr(mode, 'r'),
- .w = isempty(mode) || strchr(mode, 'w'),
- .m = isempty(mode) || strchr(mode, 'm'),
+ .permissions = p,
};
LIST_PREPEND(device_allow, c->device_allow, a);
return 0;
}
-int cgroup_context_add_or_update_device_allow(CGroupContext *c, const char *dev, const char *mode) {
+int cgroup_context_add_or_update_device_allow(CGroupContext *c, const char *dev, CGroupDevicePermissions p) {
assert(c);
assert(dev);
- assert(isempty(mode) || in_charset(mode, "rwm"));
+ assert(p >= 0 && p < _CGROUP_DEVICE_PERMISSIONS_MAX);
+
+ if (p == 0)
+ p = _CGROUP_DEVICE_PERMISSIONS_ALL;
LIST_FOREACH(device_allow, b, c->device_allow)
if (path_equal(b->path, dev)) {
- b->r = isempty(mode) || strchr(mode, 'r');
- b->w = isempty(mode) || strchr(mode, 'w');
- b->m = isempty(mode) || strchr(mode, 'm');
-
+ b->permissions = p;
return 0;
}
- return cgroup_context_add_device_allow(c, dev, mode);
+ return cgroup_context_add_device_allow(c, dev, p);
}
int cgroup_context_add_bpf_foreign_program(CGroupContext *c, uint32_t attach_type, const char *bpffs_path) {
bool any = allow_list_static;
LIST_FOREACH(device_allow, a, c->device_allow) {
- char acc[4], *val;
- unsigned k = 0;
-
- if (a->r)
- acc[k++] = 'r';
- if (a->w)
- acc[k++] = 'w';
- if (a->m)
- acc[k++] = 'm';
- if (k == 0)
+ const char *val;
+
+ if (a->permissions == 0)
continue;
- acc[k++] = 0;
if (path_startswith(a->path, "/dev/"))
- r = bpf_devices_allow_list_device(prog, path, a->path, acc);
+ r = bpf_devices_allow_list_device(prog, path, a->path, a->permissions);
else if ((val = startswith(a->path, "block-")))
- r = bpf_devices_allow_list_major(prog, path, val, 'b', acc);
+ r = bpf_devices_allow_list_major(prog, path, val, 'b', a->permissions);
else if ((val = startswith(a->path, "char-")))
- r = bpf_devices_allow_list_major(prog, path, val, 'c', acc);
+ r = bpf_devices_allow_list_major(prog, path, val, 'c', a->permissions);
else {
log_unit_debug(u, "Ignoring device '%s' while writing cgroup attribute.", a->path);
continue;
_FREEZER_ACTION_INVALID = -EINVAL,
} FreezerAction;
+typedef enum CGroupDevicePermissions {
+ /* We reuse the same bit meanings the kernel's BPF_DEVCG_ACC_xyz definitions use */
+ CGROUP_DEVICE_MKNOD = 1 << 0,
+ CGROUP_DEVICE_READ = 1 << 1,
+ CGROUP_DEVICE_WRITE = 1 << 2,
+ _CGROUP_DEVICE_PERMISSIONS_MAX = 1 << 3,
+ _CGROUP_DEVICE_PERMISSIONS_ALL = _CGROUP_DEVICE_PERMISSIONS_MAX - 1,
+ _CGROUP_DEVICE_PERMISSIONS_INVALID = -EINVAL,
+} CGroupDevicePermissions;
+
struct CGroupDeviceAllow {
LIST_FIELDS(CGroupDeviceAllow, device_allow);
char *path;
- bool r:1;
- bool w:1;
- bool m:1;
+ CGroupDevicePermissions permissions;
};
struct CGroupIODeviceWeight {
(c->memory_pressure_watch == CGROUP_PRESSURE_WATCH_AUTO && c->memory_accounting);
}
-int cgroup_context_add_device_allow(CGroupContext *c, const char *dev, const char *mode);
-int cgroup_context_add_or_update_device_allow(CGroupContext *c, const char *dev, const char *mode);
+int cgroup_context_add_device_allow(CGroupContext *c, const char *dev, CGroupDevicePermissions p);
+int cgroup_context_add_or_update_device_allow(CGroupContext *c, const char *dev, CGroupDevicePermissions p);
int cgroup_context_add_bpf_foreign_program(CGroupContext *c, uint32_t attach_type, const char *path);
void unit_modify_nft_set(Unit *u, bool add);
const char* cgroup_pressure_watch_to_string(CGroupPressureWatch a) _const_;
CGroupPressureWatch cgroup_pressure_watch_from_string(const char *s) _pure_;
+
+const char *cgroup_device_permissions_to_string(CGroupDevicePermissions p) _const_;
+CGroupDevicePermissions cgroup_device_permissions_from_string(const char *s) _pure_;
return r;
LIST_FOREACH(device_allow, a, c->device_allow) {
- unsigned k = 0;
- char rwm[4];
-
- if (a->r)
- rwm[k++] = 'r';
- if (a->w)
- rwm[k++] = 'w';
- if (a->m)
- rwm[k++] = 'm';
-
- rwm[k] = 0;
-
- r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
+ r = sd_bus_message_append(reply, "(ss)", a->path, cgroup_device_permissions_to_string(a->permissions));
if (r < 0)
return r;
}
return r;
while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
+ CGroupDevicePermissions p;
if (!valid_device_allow_pattern(path) || strpbrk(path, WHITESPACE))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires device node or pattern");
if (isempty(rwm))
- rwm = "rwm";
- else if (!in_charset(rwm, "rwm"))
- return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
+ p = _CGROUP_DEVICE_PERMISSIONS_ALL;
+ else {
+ p = cgroup_device_permissions_from_string(rwm);
+ if (p < 0)
+ return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "DeviceAllow= requires combination of rwm flags");
+ }
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
- r = cgroup_context_add_or_update_device_allow(c, path, rwm);
+ r = cgroup_context_add_or_update_device_allow(c, path, p);
if (r < 0)
return r;
}
fputs("DeviceAllow=\n", f);
LIST_FOREACH(device_allow, a, c->device_allow)
- fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
+ fprintf(f, "DeviceAllow=%s %s\n", a->path, cgroup_device_permissions_to_string(a->permissions));
r = memstream_finalize(&m, &buf, NULL);
if (r < 0)
}
LIST_FOREACH(device_allow, a, c->device_allow) {
- r = serialize_item_format(f, "exec-cgroup-context-device-allow", "%s %s%s%s",
+ r = serialize_item_format(f, "exec-cgroup-context-device-allow", "%s %s",
a->path,
- a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
+ cgroup_device_permissions_to_string(a->permissions));
if (r < 0)
return r;
}
return r;
} else if ((val = startswith(l, "exec-cgroup-context-device-allow="))) {
_cleanup_free_ char *path = NULL, *rwm = NULL;
+ CGroupDevicePermissions p;
r = extract_many_words(&val, " ", 0, &path, &rwm, NULL);
if (r < 0)
return r;
if (r == 0)
return -EINVAL;
- if (!isempty(rwm) && !in_charset(rwm, "rwm"))
- return -EINVAL;
- r = cgroup_context_add_or_update_device_allow(c, path, rwm);
+ p = isempty(rwm) ? 0 : cgroup_device_permissions_from_string(rwm);
+ if (p < 0)
+ return p;
+
+ r = cgroup_context_add_or_update_device_allow(c, path, p);
if (r < 0)
return r;
} else if ((val = startswith(l, "exec-cgroup-context-io-device-weight="))) {
void *userdata) {
_cleanup_free_ char *path = NULL, *resolved = NULL;
+ CGroupDevicePermissions permissions;
CGroupContext *c = data;
const char *p = rvalue;
int r;
}
}
- if (!isempty(p) && !in_charset(p, "rwm")) {
- log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid device rights '%s', ignoring.", p);
+ permissions = isempty(p) ? 0 : cgroup_device_permissions_from_string(p);
+ if (permissions < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, permissions, "Invalid device rights '%s', ignoring.", p);
return 0;
}
- return cgroup_context_add_device_allow(c, resolved, p);
+ return cgroup_context_add_device_allow(c, resolved, permissions);
}
int config_parse_io_device_weight(
/* When RootImage= or MountImages= is specified, the following devices are touched. */
FOREACH_STRING(p, "/dev/loop-control", "/dev/mapper/control") {
- r = cgroup_context_add_device_allow(cc, p, "rw");
+ r = cgroup_context_add_device_allow(cc, p, CGROUP_DEVICE_READ|CGROUP_DEVICE_WRITE);
if (r < 0)
return r;
}
FOREACH_STRING(p, "block-loop", "block-blkext", "block-device-mapper") {
- r = cgroup_context_add_device_allow(cc, p, "rwm");
+ r = cgroup_context_add_device_allow(cc, p, CGROUP_DEVICE_READ|CGROUP_DEVICE_WRITE|CGROUP_DEVICE_MKNOD);
if (r < 0)
return r;
}
}
if (ec->protect_clock) {
- r = cgroup_context_add_device_allow(cc, "char-rtc", "r");
+ r = cgroup_context_add_device_allow(cc, "char-rtc", CGROUP_DEVICE_READ);
if (r < 0)
return r;
}
/* If there are encrypted credentials we might need to access the TPM. */
if (exec_context_has_encrypted_credentials(ec)) {
- r = cgroup_context_add_device_allow(cc, "char-tpm", "rw");
+ r = cgroup_context_add_device_allow(cc, "char-tpm", CGROUP_DEVICE_READ|CGROUP_DEVICE_WRITE);
if (r < 0)
return r;
}
r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
assert_se(r >= 0);
- r = bpf_devices_allow_list_device(prog, cgroup_path, "/dev/null", "rw");
+ r = bpf_devices_allow_list_device(prog, cgroup_path, "/dev/null", CGROUP_DEVICE_READ|CGROUP_DEVICE_WRITE);
assert_se(r >= 0);
- r = bpf_devices_allow_list_device(prog, cgroup_path, "/dev/random", "r");
+ r = bpf_devices_allow_list_device(prog, cgroup_path, "/dev/random", CGROUP_DEVICE_READ);
assert_se(r >= 0);
- r = bpf_devices_allow_list_device(prog, cgroup_path, "/dev/zero", "w");
+ r = bpf_devices_allow_list_device(prog, cgroup_path, "/dev/zero", CGROUP_DEVICE_WRITE);
assert_se(r >= 0);
r = bpf_devices_apply_policy(&prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
assert_se(r >= 0);
- r = bpf_devices_allow_list_major(prog, cgroup_path, pattern, 'c', "rw");
+ r = bpf_devices_allow_list_major(prog, cgroup_path, pattern, 'c', CGROUP_DEVICE_READ|CGROUP_DEVICE_WRITE);
assert_se(r >= 0);
r = bpf_devices_apply_policy(&prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, true);
assert_se(r >= 0);
- r = bpf_devices_allow_list_major(prog, cgroup_path, "*", type, "rw");
+ r = bpf_devices_allow_list_major(prog, cgroup_path, "*", type, CGROUP_DEVICE_READ|CGROUP_DEVICE_WRITE);
assert_se(r >= 0);
r = bpf_devices_apply_policy(&prog, CGROUP_DEVICE_POLICY_STRICT, true, cgroup_path, installed_prog);
assert_se(r >= 0);
if (add_mismatched) {
- r = bpf_devices_allow_list_major(prog, cgroup_path, "foobarxxx", 'c', "rw");
+ r = bpf_devices_allow_list_major(prog, cgroup_path, "foobarxxx", 'c', CGROUP_DEVICE_READ|CGROUP_DEVICE_WRITE);
assert_se(r < 0);
}
test_cg_mask_to_string_one(CGROUP_MASK_IO|CGROUP_MASK_BLKIO, "io blkio");
}
+static void cgroup_device_permissions_test_normalize(const char *a, const char *b) {
+ assert_se(streq_ptr(cgroup_device_permissions_to_string(cgroup_device_permissions_from_string(a)), b));
+}
+
+TEST(cgroup_device_permissions) {
+ for (CGroupDevicePermissions p = 0; p < _CGROUP_DEVICE_PERMISSIONS_MAX; p++) {
+ const char *s;
+
+ assert_se(s = cgroup_device_permissions_to_string(p));
+ assert_se(cgroup_device_permissions_from_string(s) == p);
+ }
+
+ cgroup_device_permissions_test_normalize("", "");
+ cgroup_device_permissions_test_normalize("rw", "rw");
+ cgroup_device_permissions_test_normalize("wr", "rw");
+ cgroup_device_permissions_test_normalize("wwrr", "rw");
+ cgroup_device_permissions_test_normalize("mmmmmmmmmmmmmm", "m");
+ cgroup_device_permissions_test_normalize("mmmmrrrrmmmwwmwmwmwmwmrmrmr", "rwm");
+
+ assert_se(cgroup_device_permissions_from_string(NULL) == -EINVAL);
+ assert_se(cgroup_device_permissions_from_string("rwq") == -EINVAL);
+ assert_se(cgroup_device_permissions_from_string("RW") == -EINVAL);
+ assert_se(cgroup_device_permissions_from_string("") == 0);
+}
+
DEFINE_TEST_MAIN(LOG_DEBUG);