1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-10 16:58:28 +03:00

cgroup: turn device cgroup controller "rwm" strings into proper flags

We generally prefer dealing with parsed data instead of original
strings, do so for the "rwm" strings too. We have to convert this to
flags for the primary backend implementation (BPF) anyway, hence we
can do this early to have simpler, shorter and more normalized code.
This commit is contained in:
Lennart Poettering 2023-10-10 16:01:16 +02:00 committed by Luca Boccassi
parent 8e3fb774ae
commit a104481144
11 changed files with 178 additions and 137 deletions

View File

@ -2629,9 +2629,9 @@ static int get_security_info(Unit *u, ExecContext *c, CGroupContext *g, Security
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();
}

View File

@ -16,45 +16,25 @@
#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'));
@ -62,7 +42,7 @@ static int bpf_prog_allow_list_device(
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 */
@ -71,7 +51,7 @@ static int bpf_prog_allow_list_device(
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));
@ -85,17 +65,15 @@ static int bpf_prog_allow_list_major(
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'));
@ -103,7 +81,7 @@ static int bpf_prog_allow_list_major(
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 */
@ -111,7 +89,7 @@ static int bpf_prog_allow_list_major(
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));
@ -124,17 +102,15 @@ static int bpf_prog_allow_list_major(
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'));
@ -142,14 +118,14 @@ static int bpf_prog_allow_list_class(
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));
@ -333,7 +309,7 @@ static int allow_list_device_pattern(
char type,
const unsigned *maj,
const unsigned *min,
const char *acc) {
CGroupDevicePermissions p) {
assert(IN_SET(type, 'b', 'c'));
@ -342,22 +318,22 @@ static int allow_list_device_pattern(
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. */
@ -375,17 +351,16 @@ int bpf_devices_allow_list_device(
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
@ -407,7 +382,7 @@ int bpf_devices_allow_list_device(
}
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(
@ -415,23 +390,23 @@ 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;
@ -488,7 +463,7 @@ int bpf_devices_allow_list_major(
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)
@ -516,13 +491,13 @@ int bpf_devices_allow_list_static(
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;

View File

@ -16,6 +16,6 @@ int bpf_devices_apply_policy(
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);

View File

@ -455,6 +455,46 @@ static char *format_cgroup_memory_limit_comparison(char *buf, size_t l, Unit *u,
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;
@ -590,10 +630,10 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
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,
@ -704,13 +744,16 @@ void cgroup_context_dump_socket_bind_item(const CGroupSocketBindItem *item, FILE
}
}
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)
@ -722,9 +765,7 @@ int cgroup_context_add_device_allow(CGroupContext *c, const char *dev, const cha
*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);
@ -733,21 +774,21 @@ int cgroup_context_add_device_allow(CGroupContext *c, const char *dev, const cha
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) {
@ -1520,25 +1561,17 @@ static int cgroup_apply_devices(Unit *u) {
bool any = allow_list_static;
LIST_FOREACH(device_allow, a, c->device_allow) {
char acc[4], *val;
unsigned k = 0;
const char *val;
if (a->r)
acc[k++] = 'r';
if (a->w)
acc[k++] = 'w';
if (a->m)
acc[k++] = 'm';
if (k == 0)
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;

View File

@ -59,12 +59,20 @@ typedef enum FreezerAction {
_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 {
@ -282,8 +290,8 @@ static inline bool cgroup_context_want_memory_pressure(const CGroupContext *c) {
(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);
@ -388,3 +396,6 @@ FreezerAction freezer_action_from_string(const char *s) _pure_;
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_;

View File

@ -281,19 +281,7 @@ static int property_get_device_allow(
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;
}
@ -1828,17 +1816,21 @@ int bus_cgroup_set_property(
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;
}
@ -1869,7 +1861,7 @@ int bus_cgroup_set_property(
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)

View File

@ -343,9 +343,9 @@ static int exec_cgroup_context_serialize(const CGroupContext *c, FILE *f) {
}
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;
}
@ -787,16 +787,19 @@ static int exec_cgroup_context_deserialize(CGroupContext *c, FILE *f) {
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="))) {

View File

@ -4151,6 +4151,7 @@ int config_parse_device_allow(
void *userdata) {
_cleanup_free_ char *path = NULL, *resolved = NULL;
CGroupDevicePermissions permissions;
CGroupContext *c = data;
const char *p = rvalue;
int r;
@ -4190,12 +4191,13 @@ int config_parse_device_allow(
}
}
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(

View File

@ -4370,12 +4370,12 @@ int unit_patch_contexts(Unit *u) {
/* 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;
}
@ -4390,14 +4390,14 @@ int unit_patch_contexts(Unit *u) {
}
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;
}

View File

@ -61,13 +61,13 @@ static void test_policy_strict(const char *cgroup_path, BPFProgram **installed_p
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);
@ -138,7 +138,7 @@ static void test_policy_allow_list_major(const char *pattern, const char *cgroup
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);
@ -197,7 +197,7 @@ static void test_policy_allow_list_major_star(char type, const char *cgroup_path
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);
@ -229,7 +229,7 @@ static void test_policy_empty(bool add_mismatched, const char *cgroup_path, BPFP
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);
}

View File

@ -156,4 +156,29 @@ TEST(cg_mask_to_string) {
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);