All of lore.kernel.org
 help / color / mirror / Atom feed
From: Petr Vorel <pvorel@suse.cz>
To: ltp@lists.linux.it
Subject: [LTP] [ltp][PATCH v3] Add ltp pivot_root test
Date: Tue, 19 Mar 2019 10:11:36 +0100	[thread overview]
Message-ID: <20190319091136.GC26794@dell5510> (raw)
In-Reply-To: <20190305184455.93440-1-paullawrence@google.com>

Hi Paul,

> Fixed too long line
> Added const to static struct test_case
> Made fail with TCONF when HAVE_LIBCAP not defined

> Signed-off-by: Paul Lawrence <paullawrence@google.com>
> ---

LGTM, with some cleanup below.

Kind regards,
Petr

...
> +++ b/testcases/kernel/syscalls/pivot_root/pivot_root01.c
> @@ -0,0 +1,200 @@
> +/*
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Copyright (c) 2019 Google, Inc.
> + */
nit: correct form is to have SPDX at the first line, otherwise checkpatch.pl
(from kernel) complains.
// SPDX-License-Identifier: GPL-2.0-or-later

> +
> +#define _GNU_SOURCE
> +
> +#include <config.h>
nit: please use
#include "config.h"

> +
> +#include <errno.h>
> +#include <linux/unistd.h>
> +#include <sched.h>
> +
> +#include <sys/mount.h>
> +#include <stdlib.h>
> +
> +#include "tst_test.h"
> +
> +#ifdef HAVE_LIBCAP
> +#include <sys/capability.h>
> +#endif
> +
> +static const char* chroot_dir = "chroot";
> +static const char* new_root = "/new_root";
> +static const char* put_old = "/new_root/put_old";
> +static const char* put_old_fs = "/put_old_fs";
> +static const char* put_old_bad = "/put_old_fs/put_old";
nit: can you please use 'char *foo' instead of 'char* foo'?
When actual variable is not needed I'd use definitions
#define CHROOT_DIR "chroot"
...

> +
> +/*
> + * Test consists of a series of steps that allow pivot_root to succeed, which
> + * is run when param is NORMAL. All other values tweak one of the steps to
> + * induce a failure, and check the errno is as expected.
> + */
> +#define NORMAL 0
> +
> +/*
> + * EBUSY
> + * new_root or put_old are on the current root file system
> + */
> +#define NEW_ROOT_ON_CURRENT_ROOT 1
> +
> +/*
> + * EINVAL
> + * put_old is not underneath new_root
> + * Note: if put_old and new_root are on the same fs,
> + * pivot_root fails with EBUSY before testing reachability
> + */
> +#define PUT_OLD_NOT_UNDERNEATH_NEW_ROOT 2
> +
> +/*
> + * ENOTDIR
> + * new_root or put_old is not a directory
> + */
> +#define PUT_OLD_NOT_DIR 3
> +
> +/*
> + * EPERM
> + * The calling process does not have the CAP_SYS_ADMIN capability.
> + */
> +#define NO_CAP_SYS_ADMIN 4
We usually use enum for it (see ppoll01.c).
> +
> +static const struct test_case {
> +	int test_case;
> +	int expected_error;
> +} test_cases[] = {
> +	{NORMAL, 0},
> +	{NEW_ROOT_ON_CURRENT_ROOT, EBUSY},
> +	{PUT_OLD_NOT_UNDERNEATH_NEW_ROOT, EINVAL},
> +	{PUT_OLD_NOT_DIR, ENOTDIR},
> +	{NO_CAP_SYS_ADMIN, EPERM},
> +};
> +
> +#ifdef HAVE_LIBCAP
> +static void drop_cap_sys_admin(void)
> +{
> +	cap_value_t cap_value[] = { CAP_SYS_ADMIN };
> +	cap_t cap = cap_get_proc();
> +	if (!cap)
> +		tst_brk(TFAIL | TERRNO, "cap_get_proc failed");
> +
> +	if (cap_set_flag(cap, CAP_EFFECTIVE, 1, cap_value, CAP_CLEAR))
> +		tst_brk(TFAIL | TERRNO, "cap_set_flag failed");
> +
> +	if (cap_set_proc(cap))
> +		tst_brk(TFAIL | TERRNO, "cap_set_proc failed");
> +}
> +#endif
> +
> +#ifdef HAVE_UNSHARE
> +static void run(unsigned int test_case)
> +{
> +	/* Work in child process - needed to undo unshare and chroot */
> +	if (SAFE_FORK()) {
> +		tst_reap_children();
> +		return;
> +	}
> +
> +	/* pivot_root requires no shared mounts exist in process namespace */
> +	TEST(unshare(CLONE_NEWNS | CLONE_FS));
> +	if (TST_RET == -1)
> +		tst_brk(TFAIL | TERRNO, "unshare failed");
> +
> +	/*
> +	 * Create an initial root dir. pivot_root doesn't work if the initial root
> +	 * dir is a initramfs, so use chroot to create a safe environment
> +	 */
> +	SAFE_MOUNT("none", "/", NULL, MS_REC|MS_PRIVATE, NULL);
> +	SAFE_MOUNT("none", chroot_dir, "tmpfs", 0, 0);
> +	SAFE_CHROOT(chroot_dir);
> +
> +	/* Create our new root location */
> +	SAFE_MKDIR(new_root, 0777);
> +
> +	/*
> +	 * pivot_root only works if new_root is a mount point, so mount a tmpfs
> +	 * unless testing for that fail mode
> +	 */
> +	if (test_cases[test_case].test_case != NEW_ROOT_ON_CURRENT_ROOT)
> +		SAFE_MOUNT("none", new_root, "tmpfs", 0, 0);
> +
> +	/*
> +	 * Create put_old under new_root, unless testing for that specific fail
> +	 * mode
> +	 */
> +	const char* actual_put_old = NULL;
> +	if (test_cases[test_case].test_case == PUT_OLD_NOT_UNDERNEATH_NEW_ROOT) {
> +		actual_put_old = put_old_bad;
> +		SAFE_MKDIR(put_old_fs, 0777);
> +		SAFE_MOUNT("none", put_old_fs, "tmpfs", 0, 0);
> +		SAFE_MKDIR(put_old_bad, 0777);
> +	} else {
> +		actual_put_old = put_old;
> +
> +		/* put_old must be a directory for success */
> +		if (test_cases[test_case].test_case == PUT_OLD_NOT_DIR)
> +			SAFE_CREAT(put_old, 0777);
> +		else
> +			SAFE_MKDIR(put_old, 0777);
> +	}
> +
> +	if (test_cases[test_case].test_case == NO_CAP_SYS_ADMIN)
> +#ifdef HAVE_LIBCAP
> +		drop_cap_sys_admin();
> +#else
> +		tst_brk(TCONF,
> +			"System doesn't have POSIX capabilities support");
> +#endif
> +
> +	/* Test the syscall */
nit: I'd be for removing this and other comments (it's obvious).
> +	TEST(syscall(__NR_pivot_root, new_root, actual_put_old));
> +
> +	/* If NORMAL it should have succeeded */
> +	if (test_cases[test_case].test_case == NORMAL) {
> +		if (TST_RET) {
> +			tst_res(TFAIL | TERRNO, "pivot_root failed");
> +			exit(TBROK);
> +		} else {
> +			tst_res(TPASS, "pivot_root succeeded");
> +			exit(TPASS);
> +		}
> +	}
> +
> +	/* pivot_root is expected to fail */
> +	if (TST_RET == 0) {
> +		tst_res(TFAIL, "pivot_root succeeded unexpectedly");
> +		exit(TBROK);
> +	}
> +
> +	/* Check error code is correct */
> +	if (errno != test_cases[test_case].expected_error) {
> +		tst_res(TFAIL | TERRNO,	"pivot_root failed with wrong errno");
> +		exit(TBROK);
> +	}
> +
> +	tst_res(TPASS, "pivot_root failed as expected with %s",
> +		strerror(errno));
> +	exit(TPASS);
> +}
> +
> +#else
> +static void run(void)
> +{
> +	tst_brk(TCONF, NULL, "unshare is undefined.");
Here NULL is copy paste error (that cleanup parameter is from legacy API, here
suppress the message).
We use TST_TEST_TCONF for cases like this.
+ Please guard everything, otherwise we get "defined but not used".

> +}
> +#endif
> +
> +static void setup(void)
> +{
> +	SAFE_MKDIR(chroot_dir, 0777);
> +}
> +
> +static struct tst_test test = {
> +	.test = run,
> +	.tcnt = ARRAY_SIZE(test_cases),
> +	.needs_tmpdir = 1,
> +	.needs_root = 1,
> +	.forks_child = 1,
> +	.setup = setup,
> +};


Kind regards,
Petr

  parent reply	other threads:[~2019-03-19  9:11 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-05 18:44 [LTP] [ltp][PATCH v3] Add ltp pivot_root test Paul Lawrence
2019-03-05 21:59 ` Matthias Maennich
2019-03-19  9:11 ` Petr Vorel [this message]
2019-03-19 15:45   ` Cyril Hrubis
2019-03-19 15:55 ` Cyril Hrubis

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190319091136.GC26794@dell5510 \
    --to=pvorel@suse.cz \
    --cc=ltp@lists.linux.it \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.