return whitelist_device_pattern(prog, path, type, &maj, NULL, acc);
_cleanup_fclose_ FILE *f = NULL;
- bool good = false;
+ bool good = false, any = false;
f = fopen("/proc/devices", "re");
if (!f)
if (fnmatch(name, w, 0) != 0)
continue;
+ any = true;
(void) whitelist_device_pattern(prog, path, type, &maj, NULL, acc);
}
+ if (!any)
+ return log_debug_errno(SYNTHETIC_ERRNO(ENOENT),
+ "Device whitelist pattern \"%s\" did not match anything.", name);
+
return 0;
}
const char *path;
CGroupContext *c;
CGroupDeviceAllow *a;
+ CGroupDevicePolicy policy;
int r;
assert_se(c = unit_get_cgroup_context(u));
assert_se(path = u->cgroup_path);
+ policy = c->device_policy;
+
if (cg_all_unified() > 0) {
- r = bpf_devices_cgroup_init(&prog, c->device_policy, c->device_allow);
+ r = bpf_devices_cgroup_init(&prog, policy, c->device_allow);
if (r < 0)
return log_unit_warning_errno(u, r, "Failed to initialize device control bpf program: %m");
/* Changing the devices list of a populated cgroup might result in EINVAL, hence ignore
* EINVAL here. */
- if (c->device_allow || c->device_policy != CGROUP_DEVICE_POLICY_AUTO)
+ if (c->device_allow || policy != CGROUP_DEVICE_POLICY_AUTO)
r = cg_set_attribute("devices", path, "devices.deny", "a");
else
r = cg_set_attribute("devices", path, "devices.allow", "a");
"Failed to reset devices.allow/devices.deny: %m");
}
- if (c->device_policy == CGROUP_DEVICE_POLICY_CLOSED ||
- (c->device_policy == CGROUP_DEVICE_POLICY_AUTO && c->device_allow))
+ bool whitelist_static = policy == CGROUP_DEVICE_POLICY_CLOSED ||
+ (policy == CGROUP_DEVICE_POLICY_AUTO && c->device_allow);
+ if (whitelist_static)
(void) bpf_devices_whitelist_static(prog, path);
+ bool any = whitelist_static;
LIST_FOREACH(device_allow, a, c->device_allow) {
char acc[4], *val;
unsigned k = 0;
acc[k++] = 'w';
if (a->m)
acc[k++] = 'm';
-
if (k == 0)
continue;
-
acc[k++] = 0;
if (path_startswith(a->path, "/dev/"))
- (void) bpf_devices_whitelist_device(prog, path, a->path, acc);
+ r = bpf_devices_whitelist_device(prog, path, a->path, acc);
else if ((val = startswith(a->path, "block-")))
- (void) bpf_devices_whitelist_major(prog, path, val, 'b', acc);
+ r = bpf_devices_whitelist_major(prog, path, val, 'b', acc);
else if ((val = startswith(a->path, "char-")))
- (void) bpf_devices_whitelist_major(prog, path, val, 'c', acc);
- else
+ r = bpf_devices_whitelist_major(prog, path, val, 'c', acc);
+ else {
log_unit_debug(u, "Ignoring device '%s' while writing cgroup attribute.", a->path);
+ continue;
+ }
+
+ if (r >= 0)
+ any = true;
+ }
+
+ if (prog && !any) {
+ log_unit_warning_errno(u, SYNTHETIC_ERRNO(ENODEV), "No devices matched by device filter.");
+
+ /* The kernel verifier would reject a program we would build with the normal intro and outro
+ but no whitelisting rules (outro would contain an unreachable instruction for successful
+ return). */
+ policy = CGROUP_DEVICE_POLICY_STRICT;
}
- r = bpf_devices_apply_policy(prog, c->device_policy, c->device_allow, path, &u->bpf_device_control_installed);
+ r = bpf_devices_apply_policy(prog, policy, any, path, &u->bpf_device_control_installed);
if (r < 0) {
static bool warned = false;
assert_se(wrong == 0);
}
+static void test_policy_empty(bool add_mismatched, const char *cgroup_path, BPFProgram **installed_prog) {
+ _cleanup_(bpf_program_unrefp) BPFProgram *prog = NULL;
+ unsigned wrong = 0;
+ int r;
+
+ log_info("/* %s(add_mismatched=%s) */", __func__, yes_no(add_mismatched));
+
+ r = bpf_devices_cgroup_init(&prog, CGROUP_DEVICE_POLICY_STRICT, add_mismatched);
+ assert_se(r >= 0);
+
+ if (add_mismatched) {
+ r = bpf_devices_whitelist_major(prog, cgroup_path, "foobarxxx", 'c', "rw");
+ assert_se(r < 0);
+ }
+
+ r = bpf_devices_apply_policy(prog, CGROUP_DEVICE_POLICY_STRICT, false, cgroup_path, installed_prog);
+ assert_se(r >= 0);
+
+ {
+ _cleanup_close_ int fd;
+ const char *s = "/dev/null";
+
+ fd = open(s, O_CLOEXEC|O_RDWR|O_NOCTTY);
+ log_debug("open(%s, \"r\") = %d/%s", s, fd, fd < 0 ? errno_to_name(errno) : "-");
+ wrong += fd >= 0;
+ }
+
+ assert_se(wrong == 0);
+}
+
+
int main(int argc, char *argv[]) {
_cleanup_free_ char *cgroup = NULL, *parent = NULL;
_cleanup_(rmdir_and_freep) char *controller_path = NULL;
test_policy_whitelist_major_star('c', cgroup, &prog);
test_policy_whitelist_major_star('b', cgroup, &prog);
+ test_policy_empty(false, cgroup, &prog);
+ test_policy_empty(true, cgroup, &prog);
+
assert_se(parent = dirname_malloc(cgroup));
assert_se(cg_mask_supported(&supported) >= 0);