[LTP] [PATCH v1 2/3] tst_cgroup: Add safe_cg_open and safe_cg_fchown functions

xuyang2018.jy@fujitsu.com xuyang2018.jy@fujitsu.com
Tue Aug 23 09:10:13 CEST 2022


Hi Richard

> Hello,
> 
> OK, I see the new patches. However I just realised these tests are part
> of test_cgcore. These are not related to memcontrol. They should go in
> controllers/cgroup/core01.c.
> 
> Let's start at the beginning and look at the original selftest.
> 
> static int test_cgcore_lesser_euid_open(const char *root)
> {
> 	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;
> 	uid_t saved_uid;
> 
> 	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;
> 
> So we create two subgroups this translates to
> 
> cg_child_a = tst_cg_group_mk(tst_cg, 'a');
> cg_child_b = tst_cg_group_mk(tst_cg, 'b');
> 
> 
> 	if (cg_enter_current(cg_test_a))
> 		goto cleanup;
> 
> This writes "0" to the cgroup.procs file which I guess is a shortcut for
> writing the current processes PID. We have to be careful here incase
> this behaviour is different on V1. Probably this translates to
> 
> SAFE_CG_PRINT(cg_child_a, "cgroup.procs", "0");
> 
> It's not clear why the current PID is moved to this CG. It may be to
> ensure we have permission to move to a sibling CGroup and to eliminate
> other possible reasons for getting EACCES later on.

Yes, it's not clear.

But from kernel commit[1], it just check open fd's perms instead of 
current. So I don't use a and b two cgroup .  Also, it indeed fail on
unfixed kernel  by using only one a cgrpup.

[1]https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=1756d7994 

> 
> 	if (chown(cg_test_a_procs, test_euid, -1) ||
> 	    chown(cg_test_b_procs, test_euid, -1))
> 		goto cleanup;
> 
> Then the procs files are chowned to nobody. I see no reason this
> function can not be implemented in the same way safe_cg_printf is. We
> don't need to check which controller the file belongs to, just chown all
> of them.
> 
> 	saved_uid = geteuid();
> 	if (seteuid(test_euid))
> 		goto cleanup;

Yes, we can chown all cgroup procs files ie SAFE_CG_PRINTF did.

> 
> Then the current procs effective uid is changed. We need to make sure to
> set this back before doing cleanup (or fork like you did originally).
> 
> 	cg_test_b_procs_fd = open(cg_test_b_procs, O_RDWR);
> 
> 	if (seteuid(saved_uid))
> 		goto cleanup;
> 
> Then the file is opened and the euid set back
> 
> 	if (cg_test_b_procs_fd < 0)
> 		goto cleanup;
> 
> 	if (write(cg_test_b_procs_fd, "0", 1) >= 0 || errno != EACCES)
> 		goto cleanup;
> 
> Then we try to move to CG B and expect to get EACCES (because of the
> permissions present when opening the file).
> 
> 	ret = KSFT_PASS;
> ...
> 
> 
> Probably we want to run this test on any controllers which are
> available. Currently the API doesn't support that. We need some way of
> specifying that the test will use any available controllers in
> tst_cg_require and/or tst_test.

I will move this case into cgroup/cg_core01.c, kernel selftest seems use 
memory controller, I guess we can also use memory controller because it 
is most common.
> 
> Then we need to handle setting the euid between open and writing which
> stops us from using safe_cg_printf.
> 
> Probably the API shouldn't try to handle stuff this wierd. Instead we
> can create a function like
> 
> int n = tst_cg_group_dirfds(int *dirfds)
> 
> which copies tst_cgroup_group.dirs[i].dir_fd into dirfds (which can be
> statically allocated in the test code if we export CTRLS_MAX).
> 
> Then we can do
> 
> seteuid(nobody);
> 
> for (i = 0; i < n; i++) {
>      procfds[i] = openat(dirfds[i], "cgroup.procs")
> }
> 
> seteuid(saved_euid);
> 
> for (i = 0; i < n; i++) {
>      ret = write(procfds[i], "0", 1);
>      if (ret >= 0)
>         tst_res(TFAIL...)
>      ...
> 
>      close(procfds[i]);
> }
> 
> and whatever else is required by tests which are doing something unusual
> with the CG hierarchy.

OK. Will  try.

Best Regards
Yang Xu
> 


More information about the ltp mailing list