[PATCH 3/3] selftests: check O_ATROOT and AT_FDROOT flags

From: Andrey Vagin
Date: Wed Jul 20 2016 - 16:44:06 EST


These flags mean that the first argument "dirfd" of *at syscall-s set as
root for the current operation.

With these flags absolute symlinks have to be resolved relative to
dirfd.

This test create a file and an absolute symlink on it, which can be
resoled only if a proper root is set.

Signed-off-by: Andrey Vagin <avagin@xxxxxxxxxx>
---
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/lookup/.gitignore | 1 +
tools/testing/selftests/lookup/Makefile | 8 +++
tools/testing/selftests/lookup/lookup_at_root.c | 71 +++++++++++++++++++++++++
tools/testing/selftests/lookup/run.sh | 14 +++++
5 files changed, 95 insertions(+)
create mode 100644 tools/testing/selftests/lookup/.gitignore
create mode 100644 tools/testing/selftests/lookup/Makefile
create mode 100644 tools/testing/selftests/lookup/lookup_at_root.c
create mode 100755 tools/testing/selftests/lookup/run.sh

diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index ff9e5f2..72555c8 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -9,6 +9,7 @@ TARGETS += futex
TARGETS += ipc
TARGETS += kcmp
TARGETS += lib
+TARGETS += lookup
TARGETS += membarrier
TARGETS += memfd
TARGETS += memory-hotplug
diff --git a/tools/testing/selftests/lookup/.gitignore b/tools/testing/selftests/lookup/.gitignore
new file mode 100644
index 0000000..c9a963f
--- /dev/null
+++ b/tools/testing/selftests/lookup/.gitignore
@@ -0,0 +1 @@
+lookup_at_root
diff --git a/tools/testing/selftests/lookup/Makefile b/tools/testing/selftests/lookup/Makefile
new file mode 100644
index 0000000..042b26f
--- /dev/null
+++ b/tools/testing/selftests/lookup/Makefile
@@ -0,0 +1,8 @@
+TEST_PROGS := run.sh
+
+all: lookup_at_root
+
+clean:
+ $(RM) lookup_at_root
+include ../lib.mk
+
diff --git a/tools/testing/selftests/lookup/lookup_at_root.c b/tools/testing/selftests/lookup/lookup_at_root.c
new file mode 100644
index 0000000..6723dc8
--- /dev/null
+++ b/tools/testing/selftests/lookup/lookup_at_root.c
@@ -0,0 +1,71 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/prctl.h>
+#include <linux/limits.h>
+
+#define pr_err(fmt, ...) \
+ ({ \
+ fprintf(stderr, "%s:%d:" fmt ": %m\n", \
+ __func__, __LINE__, ##__VA_ARGS__); \
+ 1; \
+ })
+
+#ifndef O_ATROOT
+#define O_ATROOT 040000000 /* dfd is a root */
+#endif
+#ifndef AT_FDROOT
+#define AT_FDROOT 0x2000 /* Resolve a path as if dirfd is root */
+#endif
+
+int main(int argc, char **argv)
+{
+ struct stat st;
+ int fd, dfd;
+ char path[PATH_MAX];
+
+ dfd = open(argv[1], O_RDONLY);
+ if (dfd < 0)
+ return pr_err("open");
+
+ snprintf(path, sizeof(path), "%s/test", argv[1]);
+ if (mkdir(path, 755))
+ return pr_err("mkdir");
+
+ if (symlinkat("/test", dfd, "./test.link"))
+ return pr_err("symlinkat");
+
+ fd = openat(dfd, "test.link", O_RDONLY | O_ATROOT);
+ if (fd < 0)
+ return pr_err("open");
+
+ if (fchdir(dfd))
+ return pr_err("fchdir");
+
+ fd = openat(AT_FDCWD, "test.link", O_RDONLY | O_ATROOT);
+ if (fd < 0)
+ return pr_err("open");
+ close(fd);
+
+ fd = openat(AT_FDCWD, "/test.link", O_RDONLY | O_ATROOT);
+ if (fd < 0)
+ return pr_err("open");
+ close(fd);
+
+ if (fstatat(AT_FDCWD, "test.link", &st, AT_FDROOT))
+ return pr_err("fstatat");
+ if (fstatat(dfd, "test.link", &st, AT_FDROOT))
+ return pr_err("fstatat");
+ if (mknodat(dfd, "./test/test.file", 0644 | S_IFREG, 0))
+ return pr_err("mknod");
+ if (linkat(dfd, "./test.link/test.file",
+ dfd, "./test.link/test.file.link", AT_FDROOT))
+ return pr_err("linkat");
+ if (unlinkat(dfd, "./test.link/test.file.link", AT_FDROOT))
+ return pr_err("unlinkat");
+
+ return 0;
+}
diff --git a/tools/testing/selftests/lookup/run.sh b/tools/testing/selftests/lookup/run.sh
new file mode 100755
index 0000000..86cc51b
--- /dev/null
+++ b/tools/testing/selftests/lookup/run.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+set -e
+
+test_dir=`mktemp -d /tmp/lookup_test.XXXXXX`
+mount -t tmpfs lookup_at_root $test_dir
+
+ret=0
+./lookup_at_root $test_dir || ret=$?
+
+umount $test_dir
+rmdir $test_dir
+
+exit $ret
--
2.5.5