linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Dave Chinner <david@fromorbit.com>
To: David Drysdale <drysdale@google.com>
Cc: linux-kernel@vger.kernel.org,
	Alexander Viro <viro@zeniv.linux.org.uk>,
	Kees Cook <keescook@chromium.org>,
	"Eric W. Biederman" <ebiederm@xmission.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Meredydd Luff <meredydd@senatehouse.org>,
	Will Drewry <wad@chromium.org>,
	Jorge Lucangeli Obes <jorgelo@google.com>,
	Ricky Zhou <rickyz@google.com>, Lee Campbell <leecam@google.com>,
	Julien Tinnes <jln@google.com>,
	Mike Depinet <mdepinet@google.com>,
	James Morris <james.l.morris@oracle.com>,
	Andy Lutomirski <luto@amacapital.net>,
	Paolo Bonzini <pbonzini@redhat.com>,
	Paul Moore <paul@paul-moore.com>,
	Christoph Hellwig <hch@infradead.org>,
	linux-api@vger.kernel.org, linux-security-module@vger.kernel.org,
	fstests@vger.kernel.org
Subject: Re: [PATCHv2 2/3] selftests: Add test of O_BENEATH & openat(2)
Date: Tue, 11 Nov 2014 16:36:41 +1100	[thread overview]
Message-ID: <20141111053641.GR23575@dastard> (raw)
In-Reply-To: <1415094884-18349-3-git-send-email-drysdale@google.com>

[cc fstests@vger.kernel.org]

On Tue, Nov 04, 2014 at 09:54:43AM +0000, David Drysdale wrote:
> Add simple tests of openat(2) variations, including examples that
> check the new O_BENEATH flag.
> 
> Signed-off-by: David Drysdale <drysdale@google.com>

Wouldn't this be better added to fstests? That's the regression
test suite used by filesystem developers and most distro QA
organisations and where the fs developers aggregate all their new
regression tests.

IMO, the fewer places we aggregate VFS/filesystem tests the better.
I really don't think the kernel tree is the best place for adding
VFS behavioural tests because it has none of the infrastructure
around it to test arbitrary filesystems and configurations and hence
is not particularly useful to the people whoa re likely to notice
and care about fs regression tests suddenly breaking.

As an example, the recent renameat() syscall additions (e.g.
RENAME_EXCHANGE, RENAME_NOREPLACE) have unit tests in fstests, so
these new O_BENEATH tests should really follow the same model...

Cheers,

Dave.

> ---
>  tools/testing/selftests/Makefile          |   1 +
>  tools/testing/selftests/openat/.gitignore |   4 +
>  tools/testing/selftests/openat/Makefile   |  28 +++++
>  tools/testing/selftests/openat/openat.c   | 180 ++++++++++++++++++++++++++++++
>  4 files changed, 213 insertions(+)
>  create mode 100644 tools/testing/selftests/openat/.gitignore
>  create mode 100644 tools/testing/selftests/openat/Makefile
>  create mode 100644 tools/testing/selftests/openat/openat.c
> 
> diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
> index 36ff2e4c7b6f..812e973233d2 100644
> --- a/tools/testing/selftests/Makefile
> +++ b/tools/testing/selftests/Makefile
> @@ -14,6 +14,7 @@ TARGETS += powerpc
>  TARGETS += user
>  TARGETS += sysctl
>  TARGETS += firmware
> +TARGETS += openat
> 
>  TARGETS_HOTPLUG = cpu-hotplug
>  TARGETS_HOTPLUG += memory-hotplug
> diff --git a/tools/testing/selftests/openat/.gitignore b/tools/testing/selftests/openat/.gitignore
> new file mode 100644
> index 000000000000..835b2dcd8678
> --- /dev/null
> +++ b/tools/testing/selftests/openat/.gitignore
> @@ -0,0 +1,4 @@
> +openat
> +subdir
> +topfile
> +symlinkdown
> \ No newline at end of file
> diff --git a/tools/testing/selftests/openat/Makefile b/tools/testing/selftests/openat/Makefile
> new file mode 100644
> index 000000000000..84cd06e7ee82
> --- /dev/null
> +++ b/tools/testing/selftests/openat/Makefile
> @@ -0,0 +1,28 @@
> +CC = $(CROSS_COMPILE)gcc
> +CFLAGS = -Wall
> +BINARIES = openat
> +DEPS = subdir topfile symlinkdown subdir/bottomfile subdir/symlinkup subdir/symlinkout subdir/symlinkin
> +all: $(BINARIES) $(DEPS)
> +
> +subdir:
> +	mkdir -p subdir
> +topfile:
> +	echo 0123456789 > $@
> +subdir/bottomfile: | subdir
> +	echo 0123456789 > $@
> +subdir/symlinkup: | subdir
> +	ln -s ../topfile $@
> +subdir/symlinkout: | subdir
> +	ln -s /etc/passwd $@
> +subdir/symlinkin: | subdir
> +	ln -s bottomfile $@
> +symlinkdown:
> +	ln -s subdir/bottomfile $@
> +%: %.c
> +	$(CC) $(CFLAGS) -o $@ $^
> +
> +run_tests: all
> +	./openat
> +
> +clean:
> +	rm -rf $(BINARIES) $(DEPS)
> diff --git a/tools/testing/selftests/openat/openat.c b/tools/testing/selftests/openat/openat.c
> new file mode 100644
> index 000000000000..0c030cbd10dc
> --- /dev/null
> +++ b/tools/testing/selftests/openat/openat.c
> @@ -0,0 +1,180 @@
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <sys/syscall.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <errno.h>
> +
> +#include <linux/fcntl.h>
> +
> +/* Bypass glibc */
> +static int openat_(int dirfd, const char *pathname, int flags)
> +{
> +	return syscall(__NR_openat, dirfd, pathname, flags);
> +}
> +
> +static int openat_or_die(int dfd, const char *path, int flags)
> +{
> +	int fd = openat_(dfd, path, flags);
> +
> +	if (fd < 0) {
> +		printf("Failed to openat(%d, '%s'); "
> +			"check prerequisites are available\n", dfd, path);
> +		exit(1);
> +	}
> +	return fd;
> +}
> +
> +static int check_openat(int dfd, const char *path, int flags)
> +{
> +	int rc;
> +	int fd;
> +	char buffer[4];
> +
> +	errno = 0;
> +	printf("Check success of openat(%d, '%s', %x)... ",
> +	       dfd, path?:"(null)", flags);
> +	fd = openat_(dfd, path, flags);
> +	if (fd < 0) {
> +		printf("[FAIL]: openat() failed, rc=%d errno=%d (%s)\n",
> +			fd, errno, strerror(errno));
> +		return 1;
> +	}
> +	errno = 0;
> +	rc = read(fd, buffer, sizeof(buffer));
> +	if (rc < 0) {
> +		printf("[FAIL]: read() failed, rc=%d errno=%d (%s)\n",
> +			rc, errno, strerror(errno));
> +		return 1;
> +	}
> +	close(fd);
> +	printf("[OK]\n");
> +	return 0;
> +}
> +
> +#define check_openat_fail(dfd, path, flags, errno)	\
> +	_check_openat_fail(dfd, path, flags, errno, #errno)
> +static int _check_openat_fail(int dfd, const char *path, int flags,
> +			      int expected_errno, const char *errno_str)
> +{
> +	int rc;
> +
> +	errno = 0;
> +	printf("Check failure of openat(%d, '%s', %x) with %s... ",
> +		dfd, path?:"(null)", flags, errno_str);
> +	rc = openat_(dfd, path, flags);
> +	if (rc > 0) {
> +		printf("[FAIL] (unexpected success from openat(2))\n");
> +		close(rc);
> +		return 1;
> +	}
> +	if (errno != expected_errno) {
> +		printf("[FAIL] (expected errno %d (%s) not %d (%s)\n",
> +			expected_errno, strerror(expected_errno),
> +			errno, strerror(errno));
> +		return 1;
> +	}
> +	printf("[OK]\n");
> +	return 0;
> +}
> +
> +int check_proc(void)
> +{
> +	int proc_dfd = openat_(AT_FDCWD, "/proc/self", O_RDONLY);
> +	int fail = 0;
> +
> +	if (proc_dfd < 0) {
> +		printf("'/proc/self' unavailable (errno=%d '%s'), skipping\n",
> +			errno, strerror(errno));
> +		return 1;
> +	}
> +	fail |= check_openat(proc_dfd, "root/etc/passwd", O_RDONLY);
> +#ifdef O_BENEATH
> +	fail |= check_openat_fail(proc_dfd, "root/etc/passwd",
> +				  O_RDONLY|O_BENEATH, EPERM);
> +#endif
> +	return fail;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	int fail = 0;
> +	int dot_dfd = openat_or_die(AT_FDCWD, ".", O_RDONLY);
> +	int subdir_dfd = openat_or_die(AT_FDCWD, "subdir", O_RDONLY);
> +	int file_fd = openat_or_die(AT_FDCWD, "topfile", O_RDONLY);
> +
> +	/* Sanity check normal behavior */
> +	fail |= check_openat(AT_FDCWD, "topfile", O_RDONLY);
> +	fail |= check_openat(AT_FDCWD, "subdir/bottomfile", O_RDONLY);
> +
> +	fail |= check_openat(dot_dfd, "topfile", O_RDONLY);
> +	fail |= check_openat(dot_dfd, "subdir/bottomfile", O_RDONLY);
> +	fail |= check_openat(dot_dfd, "subdir/../topfile", O_RDONLY);
> +
> +	fail |= check_openat(subdir_dfd, "../topfile", O_RDONLY);
> +	fail |= check_openat(subdir_dfd, "bottomfile", O_RDONLY);
> +	fail |= check_openat(subdir_dfd, "../subdir/bottomfile", O_RDONLY);
> +	fail |= check_openat(subdir_dfd, "symlinkup", O_RDONLY);
> +	fail |= check_openat(subdir_dfd, "symlinkout", O_RDONLY);
> +
> +	fail |= check_openat(AT_FDCWD, "/etc/passwd", O_RDONLY);
> +	fail |= check_openat(dot_dfd, "/etc/passwd", O_RDONLY);
> +	fail |= check_openat(subdir_dfd, "/etc/passwd", O_RDONLY);
> +
> +	fail |= check_openat_fail(AT_FDCWD, "bogus", O_RDONLY, ENOENT);
> +	fail |= check_openat_fail(dot_dfd, "bogus", O_RDONLY, ENOENT);
> +	fail |= check_openat_fail(999, "bogus", O_RDONLY, EBADF);
> +	fail |= check_openat_fail(file_fd, "bogus", O_RDONLY, ENOTDIR);
> +
> +#ifdef O_BENEATH
> +	/* Test out O_BENEATH */
> +	fail |= check_openat(AT_FDCWD, "topfile", O_RDONLY|O_BENEATH);
> +	fail |= check_openat(AT_FDCWD, "subdir/bottomfile",
> +			     O_RDONLY|O_BENEATH);
> +
> +	fail |= check_openat(dot_dfd, "topfile", O_RDONLY|O_BENEATH);
> +	fail |= check_openat(dot_dfd, "subdir/bottomfile",
> +			     O_RDONLY|O_BENEATH);
> +	fail |= check_openat(subdir_dfd, "bottomfile", O_RDONLY|O_BENEATH);
> +
> +	/* Symlinks without .. or leading / are OK */
> +	fail |= check_openat(dot_dfd, "symlinkdown", O_RDONLY|O_BENEATH);
> +	fail |= check_openat(dot_dfd, "subdir/symlinkin", O_RDONLY|O_BENEATH);
> +	fail |= check_openat(subdir_dfd, "symlinkin", O_RDONLY|O_BENEATH);
> +	/* ... unless of course we specify O_NOFOLLOW */
> +	fail |= check_openat_fail(dot_dfd, "symlinkdown",
> +				  O_RDONLY|O_BENEATH|O_NOFOLLOW, ELOOP);
> +	fail |= check_openat_fail(dot_dfd, "subdir/symlinkin",
> +				  O_RDONLY|O_BENEATH|O_NOFOLLOW, ELOOP);
> +	fail |= check_openat_fail(subdir_dfd, "symlinkin",
> +				  O_RDONLY|O_BENEATH|O_NOFOLLOW, ELOOP);
> +
> +	/* Can't open paths with ".." in them */
> +	fail |= check_openat_fail(dot_dfd, "subdir/../topfile",
> +				O_RDONLY|O_BENEATH, EPERM);
> +	fail |= check_openat_fail(subdir_dfd, "../topfile",
> +				  O_RDONLY|O_BENEATH, EPERM);
> +	fail |= check_openat_fail(subdir_dfd, "../subdir/bottomfile",
> +				O_RDONLY|O_BENEATH, EPERM);
> +
> +	/* Can't open paths starting with "/" */
> +	fail |= check_openat_fail(AT_FDCWD, "/etc/passwd",
> +				  O_RDONLY|O_BENEATH, EPERM);
> +	fail |= check_openat_fail(dot_dfd, "/etc/passwd",
> +				  O_RDONLY|O_BENEATH, EPERM);
> +	fail |= check_openat_fail(subdir_dfd, "/etc/passwd",
> +				  O_RDONLY|O_BENEATH, EPERM);
> +	/* Can't sneak around constraints with symlinks */
> +	fail |= check_openat_fail(subdir_dfd, "symlinkup",
> +				  O_RDONLY|O_BENEATH, EPERM);
> +	fail |= check_openat_fail(subdir_dfd, "symlinkout",
> +				  O_RDONLY|O_BENEATH, EPERM);
> +#else
> +	printf("Skipping O_BENEATH tests due to missing #define\n");
> +#endif
> +	fail |= check_proc();
> +
> +	return fail ? -1 : 0;
> +}
> --
> 2.1.0.rc2.206.gedb03e5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

-- 
Dave Chinner
david@fromorbit.com

  parent reply	other threads:[~2014-11-11  5:36 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-11-04  9:54 [PATCHv2 0/3] fs: add O_BENEATH flag to openat(2) David Drysdale
2014-11-04  9:54 ` [PATCHv2 1/3] " David Drysdale
2014-11-04  9:54 ` [PATCHv2 2/3] selftests: Add test of O_BENEATH & openat(2) David Drysdale
2014-11-04 18:47   ` Kees Cook
2014-11-11  5:36   ` Dave Chinner [this message]
2014-11-21 14:19     ` David Drysdale
2014-12-12  0:05       ` Dave Chinner
2014-11-04  9:54 ` [PATCHv2 man-pages 3/3] open.2: describe O_BENEATH flag David Drysdale

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=20141111053641.GR23575@dastard \
    --to=david@fromorbit.com \
    --cc=drysdale@google.com \
    --cc=ebiederm@xmission.com \
    --cc=fstests@vger.kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=hch@infradead.org \
    --cc=james.l.morris@oracle.com \
    --cc=jln@google.com \
    --cc=jorgelo@google.com \
    --cc=keescook@chromium.org \
    --cc=leecam@google.com \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=luto@amacapital.net \
    --cc=mdepinet@google.com \
    --cc=meredydd@senatehouse.org \
    --cc=paul@paul-moore.com \
    --cc=pbonzini@redhat.com \
    --cc=rickyz@google.com \
    --cc=viro@zeniv.linux.org.uk \
    --cc=wad@chromium.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).