Skip to content

Commit bf35a78

Browse files
committed
selftests: cgroup: Test open-time cgroup namespace usage for migration checks
When a task is writing to an fd opened by a different task, the perm check should use the cgroup namespace of the latter task. Add a test for it. Tested-by: Michal Koutný <[email protected]> Signed-off-by: Tejun Heo <[email protected]>
1 parent 613e040 commit bf35a78

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

tools/testing/selftests/cgroup/test_core.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
/* SPDX-License-Identifier: GPL-2.0 */
22

3+
#define _GNU_SOURCE
34
#include <linux/limits.h>
5+
#include <linux/sched.h>
46
#include <sys/types.h>
57
#include <sys/mman.h>
68
#include <sys/wait.h>
79
#include <unistd.h>
810
#include <fcntl.h>
11+
#include <sched.h>
912
#include <stdio.h>
1013
#include <errno.h>
1114
#include <signal.h>
@@ -741,6 +744,99 @@ static int test_cgcore_lesser_euid_open(const char *root)
741744
return ret;
742745
}
743746

747+
struct lesser_ns_open_thread_arg {
748+
const char *path;
749+
int fd;
750+
int err;
751+
};
752+
753+
static int lesser_ns_open_thread_fn(void *arg)
754+
{
755+
struct lesser_ns_open_thread_arg *targ = arg;
756+
757+
targ->fd = open(targ->path, O_RDWR);
758+
targ->err = errno;
759+
return 0;
760+
}
761+
762+
/*
763+
* cgroup migration permission check should be performed based on the cgroup
764+
* namespace at the time of open instead of write.
765+
*/
766+
static int test_cgcore_lesser_ns_open(const char *root)
767+
{
768+
static char stack[65536];
769+
const uid_t test_euid = 65534; /* usually nobody, any !root is fine */
770+
int ret = KSFT_FAIL;
771+
char *cg_test_a = NULL, *cg_test_b = NULL;
772+
char *cg_test_a_procs = NULL, *cg_test_b_procs = NULL;
773+
int cg_test_b_procs_fd = -1;
774+
struct lesser_ns_open_thread_arg targ = { .fd = -1 };
775+
pid_t pid;
776+
int status;
777+
778+
cg_test_a = cg_name(root, "cg_test_a");
779+
cg_test_b = cg_name(root, "cg_test_b");
780+
781+
if (!cg_test_a || !cg_test_b)
782+
goto cleanup;
783+
784+
cg_test_a_procs = cg_name(cg_test_a, "cgroup.procs");
785+
cg_test_b_procs = cg_name(cg_test_b, "cgroup.procs");
786+
787+
if (!cg_test_a_procs || !cg_test_b_procs)
788+
goto cleanup;
789+
790+
if (cg_create(cg_test_a) || cg_create(cg_test_b))
791+
goto cleanup;
792+
793+
if (cg_enter_current(cg_test_b))
794+
goto cleanup;
795+
796+
if (chown(cg_test_a_procs, test_euid, -1) ||
797+
chown(cg_test_b_procs, test_euid, -1))
798+
goto cleanup;
799+
800+
targ.path = cg_test_b_procs;
801+
pid = clone(lesser_ns_open_thread_fn, stack + sizeof(stack),
802+
CLONE_NEWCGROUP | CLONE_FILES | CLONE_VM | SIGCHLD,
803+
&targ);
804+
if (pid < 0)
805+
goto cleanup;
806+
807+
if (waitpid(pid, &status, 0) < 0)
808+
goto cleanup;
809+
810+
if (!WIFEXITED(status))
811+
goto cleanup;
812+
813+
cg_test_b_procs_fd = targ.fd;
814+
if (cg_test_b_procs_fd < 0)
815+
goto cleanup;
816+
817+
if (cg_enter_current(cg_test_a))
818+
goto cleanup;
819+
820+
if ((status = write(cg_test_b_procs_fd, "0", 1)) >= 0 || errno != ENOENT)
821+
goto cleanup;
822+
823+
ret = KSFT_PASS;
824+
825+
cleanup:
826+
cg_enter_current(root);
827+
if (cg_test_b_procs_fd >= 0)
828+
close(cg_test_b_procs_fd);
829+
if (cg_test_b)
830+
cg_destroy(cg_test_b);
831+
if (cg_test_a)
832+
cg_destroy(cg_test_a);
833+
free(cg_test_b_procs);
834+
free(cg_test_a_procs);
835+
free(cg_test_b);
836+
free(cg_test_a);
837+
return ret;
838+
}
839+
744840
#define T(x) { x, #x }
745841
struct corecg_test {
746842
int (*fn)(const char *root);
@@ -757,6 +853,7 @@ struct corecg_test {
757853
T(test_cgcore_thread_migration),
758854
T(test_cgcore_destroy),
759855
T(test_cgcore_lesser_euid_open),
856+
T(test_cgcore_lesser_ns_open),
760857
};
761858
#undef T
762859

0 commit comments

Comments
 (0)