Skip to content

Commit

Permalink
selftests: cgroup: Test open-time cgroup namespace usage for migratio…
Browse files Browse the repository at this point in the history
…n 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]>
  • Loading branch information
htejun committed Jan 6, 2022
1 parent 613e040 commit bf35a78
Showing 1 changed file with 97 additions and 0 deletions.
97 changes: 97 additions & 0 deletions tools/testing/selftests/cgroup/test_core.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 */

#define _GNU_SOURCE
#include <linux/limits.h>
#include <linux/sched.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <sched.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
Expand Down Expand Up @@ -741,6 +744,99 @@ static int test_cgcore_lesser_euid_open(const char *root)
return ret;
}

struct lesser_ns_open_thread_arg {
const char *path;
int fd;
int err;
};

static int lesser_ns_open_thread_fn(void *arg)
{
struct lesser_ns_open_thread_arg *targ = arg;

targ->fd = open(targ->path, O_RDWR);
targ->err = errno;
return 0;
}

/*
* cgroup migration permission check should be performed based on the cgroup
* namespace at the time of open instead of write.
*/
static int test_cgcore_lesser_ns_open(const char *root)
{
static char stack[65536];
const uid_t test_euid = 65534; /* usually nobody, any !root is fine */
int ret = KSFT_FAIL;
char *cg_test_a = NULL, *cg_test_b = NULL;
char *cg_test_a_procs = NULL, *cg_test_b_procs = NULL;
int cg_test_b_procs_fd = -1;
struct lesser_ns_open_thread_arg targ = { .fd = -1 };
pid_t pid;
int status;

cg_test_a = cg_name(root, "cg_test_a");
cg_test_b = cg_name(root, "cg_test_b");

if (!cg_test_a || !cg_test_b)
goto cleanup;

cg_test_a_procs = cg_name(cg_test_a, "cgroup.procs");
cg_test_b_procs = cg_name(cg_test_b, "cgroup.procs");

if (!cg_test_a_procs || !cg_test_b_procs)
goto cleanup;

if (cg_create(cg_test_a) || cg_create(cg_test_b))
goto cleanup;

if (cg_enter_current(cg_test_b))
goto cleanup;

if (chown(cg_test_a_procs, test_euid, -1) ||
chown(cg_test_b_procs, test_euid, -1))
goto cleanup;

targ.path = cg_test_b_procs;
pid = clone(lesser_ns_open_thread_fn, stack + sizeof(stack),
CLONE_NEWCGROUP | CLONE_FILES | CLONE_VM | SIGCHLD,
&targ);
if (pid < 0)
goto cleanup;

if (waitpid(pid, &status, 0) < 0)
goto cleanup;

if (!WIFEXITED(status))
goto cleanup;

cg_test_b_procs_fd = targ.fd;
if (cg_test_b_procs_fd < 0)
goto cleanup;

if (cg_enter_current(cg_test_a))
goto cleanup;

if ((status = write(cg_test_b_procs_fd, "0", 1)) >= 0 || errno != ENOENT)
goto cleanup;

ret = KSFT_PASS;

cleanup:
cg_enter_current(root);
if (cg_test_b_procs_fd >= 0)
close(cg_test_b_procs_fd);
if (cg_test_b)
cg_destroy(cg_test_b);
if (cg_test_a)
cg_destroy(cg_test_a);
free(cg_test_b_procs);
free(cg_test_a_procs);
free(cg_test_b);
free(cg_test_a);
return ret;
}

#define T(x) { x, #x }
struct corecg_test {
int (*fn)(const char *root);
Expand All @@ -757,6 +853,7 @@ struct corecg_test {
T(test_cgcore_thread_migration),
T(test_cgcore_destroy),
T(test_cgcore_lesser_euid_open),
T(test_cgcore_lesser_ns_open),
};
#undef T

Expand Down

0 comments on commit bf35a78

Please sign in to comment.