Skip to content

Commit 61ee2cc

Browse files
author
Alexei Starovoitov
committed
Merge branch 'remove-use-of-current-cgns-in-bpf_cgroup_from_id'
Kumar Kartikeya Dwivedi says: ==================== Remove use of current->cgns in bpf_cgroup_from_id bpf_cgroup_from_id currently ends up doing a check on whether the cgroup being looked up is a descendant of the root cgroup of the current task's cgroup namespace. This leads to unreliable results since this kfunc can be invoked from any arbitrary context, for any arbitrary value of current. Fix this by removing namespace-awarness in the kfunc, and include a test that detects such a case and fails without the fix. Changelog: ---------- v2 -> v3 v2: https://lore.kernel.org/bpf/[email protected] * Refactor cgroup_get_from_id into non-ns version. (Andrii) * Address nits from Eduard. v1 -> v2 v1: https://lore.kernel.org/bpf/[email protected] * Add Ack from Tejun. * Fix selftest to perform namespace migration and cgroup setup in a child process to avoid changing test_progs namespace. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents a9d4e9f + a8250d1 commit 61ee2cc

File tree

7 files changed

+126
-5
lines changed

7 files changed

+126
-5
lines changed

include/linux/cgroup.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,7 @@ static inline void cgroup_kthread_ready(void)
650650
}
651651

652652
void cgroup_path_from_kernfs_id(u64 id, char *buf, size_t buflen);
653+
struct cgroup *__cgroup_get_from_id(u64 id);
653654
struct cgroup *cgroup_get_from_id(u64 id);
654655
#else /* !CONFIG_CGROUPS */
655656

kernel/bpf/helpers.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2546,7 +2546,7 @@ __bpf_kfunc struct cgroup *bpf_cgroup_from_id(u64 cgid)
25462546
{
25472547
struct cgroup *cgrp;
25482548

2549-
cgrp = cgroup_get_from_id(cgid);
2549+
cgrp = __cgroup_get_from_id(cgid);
25502550
if (IS_ERR(cgrp))
25512551
return NULL;
25522552
return cgrp;

kernel/cgroup/cgroup.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6343,15 +6343,15 @@ void cgroup_path_from_kernfs_id(u64 id, char *buf, size_t buflen)
63436343
}
63446344

63456345
/*
6346-
* cgroup_get_from_id : get the cgroup associated with cgroup id
6346+
* __cgroup_get_from_id : get the cgroup associated with cgroup id
63476347
* @id: cgroup id
63486348
* On success return the cgrp or ERR_PTR on failure
6349-
* Only cgroups within current task's cgroup NS are valid.
6349+
* There are no cgroup NS restrictions.
63506350
*/
6351-
struct cgroup *cgroup_get_from_id(u64 id)
6351+
struct cgroup *__cgroup_get_from_id(u64 id)
63526352
{
63536353
struct kernfs_node *kn;
6354-
struct cgroup *cgrp, *root_cgrp;
6354+
struct cgroup *cgrp;
63556355

63566356
kn = kernfs_find_and_get_node_by_id(cgrp_dfl_root.kf_root, id);
63576357
if (!kn)
@@ -6373,6 +6373,22 @@ struct cgroup *cgroup_get_from_id(u64 id)
63736373

63746374
if (!cgrp)
63756375
return ERR_PTR(-ENOENT);
6376+
return cgrp;
6377+
}
6378+
6379+
/*
6380+
* cgroup_get_from_id : get the cgroup associated with cgroup id
6381+
* @id: cgroup id
6382+
* On success return the cgrp or ERR_PTR on failure
6383+
* Only cgroups within current task's cgroup NS are valid.
6384+
*/
6385+
struct cgroup *cgroup_get_from_id(u64 id)
6386+
{
6387+
struct cgroup *cgrp, *root_cgrp;
6388+
6389+
cgrp = __cgroup_get_from_id(id);
6390+
if (IS_ERR(cgrp))
6391+
return cgrp;
63766392

63776393
root_cgrp = current_cgns_cgroup_dfl();
63786394
if (!cgroup_is_descendant(cgrp, root_cgrp)) {

tools/testing/selftests/bpf/cgroup_helpers.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,26 @@ void remove_cgroup(const char *relative_path)
412412
log_err("rmdiring cgroup %s .. %s", relative_path, cgroup_path);
413413
}
414414

415+
/*
416+
* remove_cgroup_pid() - Remove a cgroup setup by process identified by PID
417+
* @relative_path: The cgroup path, relative to the workdir, to remove
418+
* @pid: PID to be used to find cgroup_path
419+
*
420+
* This function expects a cgroup to already be created, relative to the cgroup
421+
* work dir. It also expects the cgroup doesn't have any children or live
422+
* processes and it removes the cgroup.
423+
*
424+
* On failure, it will print an error to stderr.
425+
*/
426+
void remove_cgroup_pid(const char *relative_path, int pid)
427+
{
428+
char cgroup_path[PATH_MAX + 1];
429+
430+
format_cgroup_path_pid(cgroup_path, relative_path, pid);
431+
if (rmdir(cgroup_path))
432+
log_err("rmdiring cgroup %s .. %s", relative_path, cgroup_path);
433+
}
434+
415435
/**
416436
* create_and_get_cgroup() - Create a cgroup, relative to workdir, and get the FD
417437
* @relative_path: The cgroup path, relative to the workdir, to join

tools/testing/selftests/bpf/cgroup_helpers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ int cgroup_setup_and_join(const char *relative_path);
1919
int get_root_cgroup(void);
2020
int create_and_get_cgroup(const char *relative_path);
2121
void remove_cgroup(const char *relative_path);
22+
void remove_cgroup_pid(const char *relative_path, int pid);
2223
unsigned long long get_cgroup_id(const char *relative_path);
2324
int get_cgroup1_hierarchy_id(const char *subsys_name);
2425

tools/testing/selftests/bpf/prog_tests/cgrp_kfunc.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#define _GNU_SOURCE
55
#include <cgroup_helpers.h>
66
#include <test_progs.h>
7+
#include <sched.h>
8+
#include <sys/wait.h>
79

810
#include "cgrp_kfunc_failure.skel.h"
911
#include "cgrp_kfunc_success.skel.h"
@@ -87,6 +89,72 @@ static const char * const success_tests[] = {
8789
"test_cgrp_from_id",
8890
};
8991

92+
static void test_cgrp_from_id_ns(void)
93+
{
94+
LIBBPF_OPTS(bpf_test_run_opts, opts);
95+
struct cgrp_kfunc_success *skel;
96+
struct bpf_program *prog;
97+
int pid, pipe_fd[2];
98+
99+
skel = open_load_cgrp_kfunc_skel();
100+
if (!ASSERT_OK_PTR(skel, "open_load_skel"))
101+
return;
102+
103+
if (!ASSERT_OK(skel->bss->err, "pre_mkdir_err"))
104+
goto cleanup;
105+
106+
prog = skel->progs.test_cgrp_from_id_ns;
107+
108+
if (!ASSERT_OK(pipe(pipe_fd), "pipe"))
109+
goto cleanup;
110+
111+
pid = fork();
112+
if (!ASSERT_GE(pid, 0, "fork result")) {
113+
close(pipe_fd[0]);
114+
close(pipe_fd[1]);
115+
goto cleanup;
116+
}
117+
118+
if (pid == 0) {
119+
int ret = 0;
120+
121+
close(pipe_fd[0]);
122+
123+
if (!ASSERT_GE(cgroup_setup_and_join("cgrp_from_id_ns"), 0, "join cgroup"))
124+
exit(1);
125+
126+
if (!ASSERT_OK(unshare(CLONE_NEWCGROUP), "unshare cgns"))
127+
exit(1);
128+
129+
ret = bpf_prog_test_run_opts(bpf_program__fd(prog), &opts);
130+
if (!ASSERT_OK(ret, "test run ret"))
131+
exit(1);
132+
133+
if (!ASSERT_OK(opts.retval, "test run retval"))
134+
exit(1);
135+
136+
if (!ASSERT_EQ(write(pipe_fd[1], &ret, sizeof(ret)), sizeof(ret), "write pipe"))
137+
exit(1);
138+
139+
exit(0);
140+
} else {
141+
int res;
142+
143+
close(pipe_fd[1]);
144+
145+
ASSERT_EQ(read(pipe_fd[0], &res, sizeof(res)), sizeof(res), "read res");
146+
ASSERT_EQ(waitpid(pid, NULL, 0), pid, "wait on child");
147+
148+
remove_cgroup_pid("cgrp_from_id_ns", pid);
149+
150+
ASSERT_OK(res, "result from run");
151+
}
152+
153+
close(pipe_fd[0]);
154+
cleanup:
155+
cgrp_kfunc_success__destroy(skel);
156+
}
157+
90158
void test_cgrp_kfunc(void)
91159
{
92160
int i, err;
@@ -102,6 +170,9 @@ void test_cgrp_kfunc(void)
102170
run_success_test(success_tests[i]);
103171
}
104172

173+
if (test__start_subtest("test_cgrp_from_id_ns"))
174+
test_cgrp_from_id_ns();
175+
105176
RUN_TESTS(cgrp_kfunc_failure);
106177

107178
cleanup:

tools/testing/selftests/bpf/progs/cgrp_kfunc_success.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,15 @@ int BPF_PROG(test_cgrp_from_id, struct cgroup *cgrp, const char *path)
221221

222222
return 0;
223223
}
224+
225+
SEC("syscall")
226+
int test_cgrp_from_id_ns(void *ctx)
227+
{
228+
struct cgroup *cg;
229+
230+
cg = bpf_cgroup_from_id(1);
231+
if (!cg)
232+
return 42;
233+
bpf_cgroup_release(cg);
234+
return 0;
235+
}

0 commit comments

Comments
 (0)