diff options
Diffstat (limited to 'test')
-rwxr-xr-x | test/test-acl.sh | 188 | ||||
-rw-r--r-- | test/test-chroot-symlink.c | 28 | ||||
-rwxr-xr-x | test/test-chroot-symlink.sh | 19 | ||||
-rw-r--r-- | test/test-fcntl.c | 58 | ||||
-rwxr-xr-x | test/test-fcntl.sh | 5 | ||||
-rw-r--r-- | test/test-fstat.c | 29 | ||||
-rwxr-xr-x | test/test-fstat.sh | 8 | ||||
-rw-r--r-- | test/test-openat.c | 58 | ||||
-rwxr-xr-x | test/test-openat.sh | 7 | ||||
-rwxr-xr-x | test/test-relative-from-root.sh | 14 | ||||
-rw-r--r-- | test/test-rename-fstat.c | 23 | ||||
-rwxr-xr-x | test/test-rename-fstat.sh | 12 | ||||
-rw-r--r-- | test/test-statx.c | 20 | ||||
-rwxr-xr-x | test/test-statx.sh | 6 | ||||
-rwxr-xr-x | test/test-umask.sh | 1 |
15 files changed, 476 insertions, 0 deletions
diff --git a/test/test-acl.sh b/test/test-acl.sh new file mode 100755 index 0000000..fb7d5ec --- /dev/null +++ b/test/test-acl.sh @@ -0,0 +1,188 @@ +#!/bin/bash +# +# SPDX-License-Identifier: LGPL-2.1-only +# + +# Return vals: 2 - Unable to run ACL commands, assertion failure +# 1 - Invalid return value +# 0 - Pass + +# NOTE: these test exclusively test setfacl -m + +set -u + +check_owner () { + local file="$1" + local expected="$2" + local msg="$3" + local actual=$(stat -c "%U" "$file") + if [ "$actual" != "$expected" ] + then + echo "$msg" "Fail, '$file' unexpected owner '$actual'" + exit 2 + fi +} + +check_group () { + local file="$1" + local expected="$2" + local msg="$3" + local actual=$(stat -c "%G" "$file") + if [ "$actual" != "$expected" ] + then + echo "$msg" "Fail, '$file' unexpected group '$actual'" + exit 2 + fi +} + +check_acl_contains () { + local file="$1" + local acl="$2" + local msg="$3" + IFS=',' read -ra acls <<< "$acl" + for pattern in "${acls[@]}"; do + result=$(getfacl -c "$file" | grep -o "^$pattern") + if [ "$result" != "$pattern" ] + then + echo "$msg" "Fail, did not find desired acl '$pattern' in '$file'" + exit 2 + fi + done +} + +check_acl_minimal () { + local file="$1" + local msg="${2:-''}" + local acls + acls=$(getfacl -c "${file}" | grep -v "::") + if [ -n "$acls" ] + then + echo "$msg" "Fail, '$file' unexpected getfacl result '$acls'" + exit 1 + fi +} + +test_modify_once () { + local file="$1" + local acl="$2" + local msg="${3:-''}" + # ensure that file is pristine + check_acl_minimal "$file" "$msg precondition:" + check_owner "$file" root "$msg precondition:" + check_group "$file" root "$msg precondition:" + if ! setfacl -m "$acl" "$file" + then + echo "$msg" "Fail, unable to call setfacl" + exit 2 + fi + check_acl_contains "$file" "$acl" "$msg: acl not set:" + check_owner "$file" root "$msg owner corrupted:" + check_group "$file" root "$msg group corrupted:" +} + + +trap "rm -rf testdir" EXIT +mkdir testdir || exit 1 + + +# user +touch testdir/f1 || exit 1 +mkdir testdir/d1 || exit 1 +# regular file +test_modify_once testdir/f1 "user:root:r" "$LINENO:" +# directory +test_modify_once testdir/d1 "user:root:r" "$LINENO:" +rm -rf testdir/f1 testdir/d1 + +#group +rm -rf testdir/f1 testdir/d1 +touch testdir/f1 || exit 1 +mkdir testdir/d1 || exit 1 +# regular file +test_modify_once testdir/f1 "group:root:r" "$LINENO:" +# directory +test_modify_once testdir/d1 "group:root:r" "$LINENO:" +rm -rf testdir/f1 testdir/d1 + +# multiple users +touch testdir/f1 || exit 1 +mkdir testdir/d1 || exit 1 +# regular file +test_modify_once testdir/f1 "user:root:r,group:root:r,user:bin:rw" "$LINENO:" +# directory +test_modify_once testdir/d1 "user:root:r,group:root:r,user:bin:rw" "$LINENO:" +rm -rf testdir/f1 testdir/d1 + + +# setfacl default acls +mkdir testdir/d1 || exit 1 +test_modify_once testdir/d1 "default:user:root:r,user:root:r" "$LINENO:" +rm -rf testdir/d1 + + +# multiple calls to setfacl -m on same file +touch testdir/f1 || exit 1 +mkdir testdir/d1 || exit 1 +check_owner testdir/f1 root "$LINENO: precondition:" +check_group testdir/f1 root "$LINENO: precondition:" +check_acl_minimal testdir/f1 "$LINENO: precondition:" + +acl1="user:root:r" +acl2="user:bin:rw" + +if ! setfacl -m "$acl1" testdir/f1 # first setfacl +then + echo "$LINENO:" "Fail, unable to call setfacl" + exit 2 +fi +check_acl_contains testdir/f1 "$acl1" "$LINENO: acl1 not set:" +check_owner testdir/f1 root "$LINENO: owner corrupted:" +check_group testdir/f1 root "$LINENO: group corrupted:" + +if ! setfacl -m "$acl2" testdir/f1 # second setfacl +then + echo "$LINENO:" "Fail, unable to call setfacl" + exit 2 +fi + +check_acl_contains testdir/f1 "$acl1" "$LINENO: acl1 not set:" +check_acl_contains testdir/f1 "$acl2" "$LINENO: acl2 not set:" +check_owner testdir/f1 root "$LINENO: owner corrupted:" +check_group testdir/f1 root "$LINENO: group corrupted:" +rm -rf testdir/f1 testdir/d1 + +# setfacl recursive +test_modify_recursive () { + local root_dir="$1" + local acl="$2" + local msg="${3:-''}" + + find "$root_dir" | while read -r file; do + check_owner "$file" root "$msg precondition:" + check_group "$file" root "$msg precondition:" + check_acl_minimal "$file" "$msg precondition:" + done + if ! setfacl -R -m "$acl" "$root_dir" + then + echo "$msg" "Fail, unable to call setfacl" + exit 2 + fi + find "$root_dir" | while read -r file; do + check_owner "$file" root "$msg owner corrupted:" + check_group "$file" root "$msg group corrupted:" + check_acl_contains "$file" "$acl" "$msg acl not set:" + done +} + +mkdir -p testdir/d1/d2 || exit 1 +touch testdir/d1/d2/f1 || exit 1 +test_modify_recursive testdir/d1 "user:root:r,group:root:r,user:bin:rw" "$LINENO:" +rm -rf testdir/d1 + +mkdir -p testdir/d1/d2 || exit 1 +mkdir -p testdir/d1/d3 || exit 1 +test_modify_recursive testdir/d1 "default:user:root:rwx,user:root:r,group:root:r,user:bin:rw" "$LINENO:" +rm -rf testdir/d1 + +#echo "Passed." +exit 0 diff --git a/test/test-chroot-symlink.c b/test/test-chroot-symlink.c new file mode 100644 index 0000000..469cb49 --- /dev/null +++ b/test/test-chroot-symlink.c @@ -0,0 +1,28 @@ +/* + * Test that stat'ing absolute/relative symlinks in a chroot environment works + * SPDX-License-Identifier: LGPL-2.1-only + * + */ +#define _GNU_SOURCE + +#include <unistd.h> +#include <sys/stat.h> +#include <stdio.h> + +int main(int argc, char *argv[]) { + struct stat buf; + + if (argc != 2) { + perror("args"); + return 2; + } + if (chroot(argv[1]) == -1) { + perror("chroot"); + return 1; + } + if (stat("symlink", &buf) == -1) { + perror("stat symlink"); + return 1; + } + return 0; +} diff --git a/test/test-chroot-symlink.sh b/test/test-chroot-symlink.sh new file mode 100755 index 0000000..91092c1 --- /dev/null +++ b/test/test-chroot-symlink.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Test that stat'ing absolute/relative symlinks in a chroot environment works +# SPDX-License-Identifier: LGPL-2.1-only +# + +set -e + +touch symlink_target +trap "rm -f symlink_target symlink" 0 + +# Absolute symlink +ln -s /symlink_target symlink +./test/test-chroot-symlink `pwd` +rm symlink + +# Relative symlink +ln -s symlink_target symlink +./test/test-chroot-symlink `pwd` diff --git a/test/test-fcntl.c b/test/test-fcntl.c new file mode 100644 index 0000000..b593d50 --- /dev/null +++ b/test/test-fcntl.c @@ -0,0 +1,58 @@ +/* fcntl-linux.h doesn't define F_GETPIPE_SZ and F_SETPIPE_SZ without + * this */ +#define _GNU_SOURCE + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <unistd.h> +#include <string.h> + +int test_pipe_sz() +{ +#if defined(F_GETPIPE_SZ) && defined(F_SETPIPE_SZ) + int pipefd[2]; + + if (pipe(pipefd) < 0) { + perror("pipe"); + return 1; + } + + const int orig_size = fcntl(pipefd[0], F_GETPIPE_SZ); + if (orig_size < 0) { + perror("F_GETPIPE_SZ"); + return 1; + } + + const int new_size = orig_size * 2; + + if (fcntl(pipefd[0], F_SETPIPE_SZ, new_size) < 0) { + perror("F_SETPIPE_SZ"); + return 1; + } + + const int final_size = fcntl(pipefd[0], F_GETPIPE_SZ); + if (final_size < 0) { + perror("Second F_GETPIPE_SZ"); + return 1; + } + + if (final_size < new_size) { + fprintf(stderr, "Unexpected final pipe size: %d\n", final_size); + return 1; + } +#else + printf("Host too old for F_GETPIPE_SZ and F_SETPIPE_SZ tests\n"); +#endif + return 0; +} + +int main() +{ + int result = 0; + result += test_pipe_sz(); + return result; +} diff --git a/test/test-fcntl.sh b/test/test-fcntl.sh new file mode 100755 index 0000000..7112620 --- /dev/null +++ b/test/test-fcntl.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# +# SPDX-License-Identifier: LGPL-2.1-only +# +./test/test-fcntl diff --git a/test/test-fstat.c b/test/test-fstat.c new file mode 100644 index 0000000..78f7013 --- /dev/null +++ b/test/test-fstat.c @@ -0,0 +1,29 @@ +/* + * Test that stat'ing a file descriptor of a symlink does not dereference the symlink + * SPDX-License-Identifier: LGPL-2.1-only + * + */ +#define _GNU_SOURCE + +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <stdio.h> + +int main(void) { + struct stat buf; + int fd = open("symlink", O_NOFOLLOW | O_PATH); + if (fd == -1) { + perror("open symlink"); + return 1; + } + if (fstatat(fd, "", &buf, AT_EMPTY_PATH) == -1) { + perror("stat symlink"); + return 1; + } + if (S_ISLNK(buf.st_mode) != 1) { + fprintf(stderr, "path is not a symlink\n"); + return 1; + } + return 0; +} diff --git a/test/test-fstat.sh b/test/test-fstat.sh new file mode 100755 index 0000000..88eab8b --- /dev/null +++ b/test/test-fstat.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# +# SPDX-License-Identifier: LGPL-2.1-only +# + +ln -s . symlink +trap "rm symlink" 0 +./test/test-fstat diff --git a/test/test-openat.c b/test/test-openat.c new file mode 100644 index 0000000..df6655a --- /dev/null +++ b/test/test-openat.c @@ -0,0 +1,58 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <unistd.h> +#include <string.h> + +char *path_of(int fd) { + ssize_t len; + char proc[PATH_MAX], real[PATH_MAX]; + snprintf(proc, sizeof(proc), "/proc/self/fd/%d", fd); + len = readlink(proc, real, sizeof(real)); + real[len] = '\0'; + return strdup(real); +} + +/* +* Test that recusing up the tree with openat(fd, "../") handles slashes +* correctly and doesn't end up opening the same directory instead of going up a +* level. +*/ +int main () { + int fd, dir_fd; + struct stat st; + ino_t ino; + dev_t dev; + char *path; + + fd = openat(AT_FDCWD, ".", O_DIRECTORY, 0); + fstat(fd, &st); + ino = st.st_ino; + dev = st.st_dev; + + while (1) { + path = path_of(fd); + //puts(path); + + dir_fd = openat(fd, "../", O_DIRECTORY, 0); + fstat(dir_fd, &st); + if (st.st_ino == ino && st.st_dev == dev) { + if (strcmp(path, "/") == 0) { + //puts("Reached top of tree"); + return 0; + } else { + //puts("Recursion failed!"); + return 1; + } + } + + free (path); + ino = st.st_ino; + dev = st.st_dev; + fd = dir_fd; + } + return 0; +} diff --git a/test/test-openat.sh b/test/test-openat.sh new file mode 100755 index 0000000..0455586 --- /dev/null +++ b/test/test-openat.sh @@ -0,0 +1,7 @@ +#! /bin/sh + +# Test with and without paths being ignored. The bug was with paths being ignored. + +./test/test-openat + +PSEUDO_IGNORE_PATHS=/ ./test/test-openat diff --git a/test/test-relative-from-root.sh b/test/test-relative-from-root.sh new file mode 100755 index 0000000..e2c230e --- /dev/null +++ b/test/test-relative-from-root.sh @@ -0,0 +1,14 @@ +#!/bin/bash +# pseudo had a bug that made it abort() when looking up a relative path from +# base "/", such as by openat(dirfd_of_root, "foo/bar") or when cwd is /. It +# tried to look up base+"/"+path = "//foo/bar", which is wrong. + +set -e + +touch f1 +relative_pwd=${PWD#/} + +cd / +cat "$relative_pwd/f1" + +rm "$relative_pwd/f1" diff --git a/test/test-rename-fstat.c b/test/test-rename-fstat.c new file mode 100644 index 0000000..fb47c05 --- /dev/null +++ b/test/test-rename-fstat.c @@ -0,0 +1,23 @@ +/* + * SPDX-License-Identifier: LGPL-2.1-only + * + * Test we can rename a file whilst holding an open fd which we fstat after renaming + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +int main() +{ + struct stat buf; + int err; + int fd = open("test-rename-fstat1", O_RDONLY); + err = rename("test-rename-fstat1", "test-rename-fstat1"); + if (err) + return err; + return fstat(fd, &buf); +} diff --git a/test/test-rename-fstat.sh b/test/test-rename-fstat.sh new file mode 100755 index 0000000..4ac89b8 --- /dev/null +++ b/test/test-rename-fstat.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# +# SPDX-License-Identifier: LGPL-2.1-only +# + +rm -f test-rename-fstat1 test-rename-fstat2 +touch test-rename-fstat1 +# Will abort if it fails +./test/test-rename-fstat +ecode=$? +rm -f test-rename-fstat1 test-rename-fstat2 +exit $ecode diff --git a/test/test-statx.c b/test/test-statx.c new file mode 100644 index 0000000..06d86af --- /dev/null +++ b/test/test-statx.c @@ -0,0 +1,20 @@ +/* + * Test that passing NULL to a parameter marked as nonnull works correctly + * SPDX-License-Identifier: LGPL-2.1-only + * + */ +#define _GNU_SOURCE + +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> + +// Passing a null pointer is the test scenario +#pragma GCC diagnostic ignored "-Wnonnull" + +int main(void) { + if (statx(0, NULL, 0, 0, NULL) != -1) { + return 1; + } + return 0; +} diff --git a/test/test-statx.sh b/test/test-statx.sh new file mode 100755 index 0000000..77d0302 --- /dev/null +++ b/test/test-statx.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# +# SPDX-License-Identifier: LGPL-2.1-only +# + +exec ./test/test-statx diff --git a/test/test-umask.sh b/test/test-umask.sh index e4e366b..e09fdbf 100755 --- a/test/test-umask.sh +++ b/test/test-umask.sh @@ -35,3 +35,4 @@ case $(mode b) in *) exit 1;; esac +rm a b |