/*
* Copyright (c) 2024 Apple Computer, Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. The rights granted to you under the License
* may not be used to create, or enable the creation or redistribution of,
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
*
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/* compile: xcrun -sdk macosx.internal clang -ldarwintest -o resolve_beneath resolve_beneath.c -g -Weverything */
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/mount.h>
#include <sys/attr.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/xattr.h>
#include <sys/clonefile.h>
#include <darwintest.h>
#include <darwintest/utils.h>
static char template[MAXPATHLEN];
static char *testdir = NULL;
static int testdir_fd = -1, test_fd = -1;
#ifndef ENOTCAPABLE
#define ENOTCAPABLE 107
#endif
#ifndef O_RESOLVE_BENEATH
#define O_RESOLVE_BENEATH 0x1000
#endif
#ifndef AT_RESOLVE_BENEATH
#define AT_RESOLVE_BENEATH 0x2000
#endif
#ifndef XATTR_RESOLVE_BENEATH
#define XATTR_RESOLVE_BENEATH 0x0080
#endif
#ifndef CLONE_RESOLVE_BENEATH
#define CLONE_RESOLVE_BENEATH 0x0010
#endif
#ifndef RENAME_RESOLVE_BENEATH
#define RENAME_RESOLVE_BENEATH 0x0020
#endif
#ifndef FSOPT_RESOLVE_BENEATH
#define FSOPT_RESOLVE_BENEATH 0x1000
#endif
#define TEST_DIR "test_dir"
#define NESTED_DIR "test_dir/nested"
#define OUTSIDE_FILE "outside_file.txt"
#define INSIDE_FILE "test_dir/inside_file.txt"
#define NESTED_FILE "test_dir/nested/nested_file.txt"
#define SYMLINK "test_dir/symlink"
#define SYMLINK_TO_NESTED "test_dir/symlink_to_nested"
#define PARENT_SYMLINK "test_dir/parent_symlink"
#define CIRCULAR_SYMLINK "test_dir/circular_symlink"
#define SYMLINK_ABSOLUTE "test_dir/symlink_absolute"
#define SYMLINK_FROM "../outside_file.txt"
#define SYMLINK_TO_NESTED_FROM "nested/nested_file.txt"
#define PARENT_SYMLINK_FROM ".."
#define CIRCULAR_SYMLINK_FROM "circular_symlink"
T_GLOBAL_META(
T_META_NAMESPACE("xnu.vfs"),
T_META_RADAR_COMPONENT_NAME("xnu"),
T_META_RADAR_COMPONENT_VERSION("vfs"),
T_META_ASROOT(false),
T_META_CHECK_LEAKS(false));
static void
setup(const char *dirname)
{
int fd;
testdir_fd = test_fd = -1;
/* Create test root directory */
snprintf(template, sizeof(template), "%s/%s-XXXXXX", dt_tmpdir(), dirname);
T_ASSERT_POSIX_NOTNULL((testdir = mkdtemp(template)), "Creating test root directory");
T_ASSERT_POSIX_SUCCESS((testdir_fd = open(testdir, O_SEARCH, 0777)), "Opening test root directory %s", testdir);
/* Create test directories */
T_ASSERT_POSIX_SUCCESS(mkdirat(testdir_fd, TEST_DIR, 0777), "Creating %s/%s", testdir, TEST_DIR);
T_ASSERT_POSIX_SUCCESS((test_fd = openat(testdir_fd, TEST_DIR, O_SEARCH, 0777)), "Opening test directory %s/%s", testdir, TEST_DIR);
T_ASSERT_POSIX_SUCCESS(mkdirat(testdir_fd, NESTED_DIR, 0777), "Creating %s/%s", testdir, NESTED_DIR);
/* Create test files */
T_ASSERT_POSIX_SUCCESS((fd = openat(testdir_fd, OUTSIDE_FILE, O_CREAT | O_RDWR, 0777)), "Creating file %s/%s", testdir, OUTSIDE_FILE);
T_ASSERT_POSIX_SUCCESS(close(fd), "Closing %s", OUTSIDE_FILE);
T_ASSERT_POSIX_SUCCESS((fd = openat(testdir_fd, INSIDE_FILE, O_CREAT | O_RDWR, 0777)), "Creating file %s/%s", testdir, INSIDE_FILE);
T_ASSERT_POSIX_SUCCESS(close(fd), "Closing %s", INSIDE_FILE);
T_ASSERT_POSIX_SUCCESS((fd = openat(testdir_fd, NESTED_FILE, O_CREAT | O_RDWR, 0777)), "Creating file %s/%s", testdir, NESTED_FILE);
T_ASSERT_POSIX_SUCCESS(close(fd), "Closing %s", NESTED_FILE);
/* Create test symlinks */
T_ASSERT_POSIX_SUCCESS(symlinkat(SYMLINK_FROM, testdir_fd, SYMLINK), "Creating symlink %s/%s -> %s", testdir, SYMLINK, SYMLINK_FROM);
T_ASSERT_POSIX_SUCCESS(symlinkat(SYMLINK_TO_NESTED_FROM, testdir_fd, SYMLINK_TO_NESTED), "Creating symlink %s/%s -> %s", testdir, SYMLINK_TO_NESTED, SYMLINK_TO_NESTED_FROM);
T_ASSERT_POSIX_SUCCESS(symlinkat(PARENT_SYMLINK_FROM, testdir_fd, PARENT_SYMLINK), "Creating symlink %s/%s -> %s", testdir, PARENT_SYMLINK, PARENT_SYMLINK_FROM);
T_ASSERT_POSIX_SUCCESS(symlinkat(CIRCULAR_SYMLINK_FROM, testdir_fd, CIRCULAR_SYMLINK), "Creating symlink %s/%s -> %s", testdir, CIRCULAR_SYMLINK, CIRCULAR_SYMLINK_FROM);
T_ASSERT_POSIX_SUCCESS(symlinkat(testdir, testdir_fd, SYMLINK_ABSOLUTE), "Creating symlink %s/%s -> %s", testdir, SYMLINK_ABSOLUTE, testdir);
}
static void
cleanup(void)
{
if (test_fd != -1) {
close(test_fd);
}
if (testdir_fd != -1) {
unlinkat(testdir_fd, SYMLINK_ABSOLUTE, 0);
unlinkat(testdir_fd, CIRCULAR_SYMLINK, 0);
unlinkat(testdir_fd, PARENT_SYMLINK, 0);
unlinkat(testdir_fd, SYMLINK_TO_NESTED, 0);
unlinkat(testdir_fd, SYMLINK, 0);
unlinkat(testdir_fd, NESTED_FILE, 0);
unlinkat(testdir_fd, NESTED_DIR, AT_REMOVEDIR);
unlinkat(testdir_fd, INSIDE_FILE, 0);
unlinkat(testdir_fd, TEST_DIR, AT_REMOVEDIR);
unlinkat(testdir_fd, OUTSIDE_FILE, 0);
close(testdir_fd);
if (rmdir(testdir)) {
T_FAIL("Unable to remove the test directory (%s)", testdir);
}
}
}
T_DECL(resolve_beneath_open,
"test open()/openat() using the O_RESOLVE_BENEATH flag")
{
int fd, root_fd;
char path[MAXPATHLEN];
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_open");
T_ASSERT_POSIX_SUCCESS((root_fd = open("/", O_SEARCH, 0777)), "Opening the root directory");
T_SETUPEND;
T_LOG("Testing the openat() syscall using O_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS((fd = openat(test_fd, "inside_file.txt", O_RDONLY | O_RESOLVE_BENEATH, 0777)), "Test Case 1: File within the directory");
if (fd >= 0) {
close(fd);
}
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(openat(test_fd, "symlink", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(openat(test_fd, "../outside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS((fd = openat(test_fd, "nested/nested_file.txt", O_RDONLY | O_RESOLVE_BENEATH, 0777)), "Test Case 4: File within a nested directory");
if (fd >= 0) {
close(fd);
}
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS((fd = openat(test_fd, "symlink_to_nested", O_RDONLY | O_RESOLVE_BENEATH, 0777)), "Test Case 5: Symlink to a file within the same directory");
if (fd >= 0) {
close(fd);
}
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(openat(test_fd, "/etc/passwd", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
/* Test Case 7: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(openat(test_fd, "parent_symlink/outside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
/* Test Case 8: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(openat(test_fd, "circular_symlink", O_RDONLY | O_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
/* Test Case 9: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(openat(test_fd, "../test_dir/inside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
/* Test Case 10: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(openat(test_fd, "symlink_absolute/test_dir/inside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
/* Test Case 11: Absolute path relative to the root directory */
T_EXPECT_POSIX_FAILURE(openat(root_fd, "/etc/passwd", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 11: Absolute path relative to the root directory");
/* Test Case 12: Path can not escape outside of the root directory using dotdot */
T_EXPECT_POSIX_FAILURE((fd = openat(root_fd, "../private", O_RESOLVE_BENEATH)), ENOTCAPABLE, "Test Case 12: Path can not escape outside of the root directory using dotdot");
/* Changing current directory to the test directory */
T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
T_LOG("Testing the open() syscall using O_RESOLVE_BENEATH");
/* Test Case 13: Open a file within the directory */
T_EXPECT_POSIX_SUCCESS((fd = open("inside_file.txt", O_RDONLY | O_RESOLVE_BENEATH, 0777)), "Test Case 13: Open a file within the directory");
if (fd >= 0) {
close(fd);
}
/* Test Case 14: Attempt to open a file using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(open("symlink", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 14: Attempt to open a file using a symlink pointing outside");
/* Test Case 15: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(open("../outside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 15: Attempt to open a file using \"..\" to navigate outside");
/* Test Case 16: Open a file within a nested directory */
T_EXPECT_POSIX_SUCCESS((fd = open("nested/nested_file.txt", O_RDONLY | O_RESOLVE_BENEATH, 0777)), "Test Case 16: Open a file within a nested directory");
if (fd >= 0) {
close(fd);
}
/* Test Case 17: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS((fd = open("symlink_to_nested", O_RDONLY | O_RESOLVE_BENEATH, 0777)), "Test Case 17: Symlink to a file within the same directory");
if (fd >= 0) {
close(fd);
}
/* Test Case 18: Attempt to open a file using an absolute path */
T_EXPECT_POSIX_FAILURE(open("/etc/passwd", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 18: Attempt to open a file using an absolute path");
/* Test Case 19: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(open("parent_symlink/outside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 19: Valid symlink to parent directory");
/* Test Case 20: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(open("circular_symlink", O_RDONLY | O_RESOLVE_BENEATH), ELOOP, "Test Case 20: Circular symlink within directory");
/* Test Case 21: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(open("../test_dir/inside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 21: Path can not escape outside at any point of the resolution");
/* Test Case 22: Attempt to open a file using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(open("symlink_absolute/test_dir/inside_file.txt", O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 22: Attempt to open a file using a symlink pointing to absolute path");
/* Test Case 23: Path can not escape outside at any point of the resolution using absolute path */
snprintf(path, sizeof(path), "%s/%s", testdir, INSIDE_FILE);
T_EXPECT_POSIX_FAILURE(open(path, O_RDONLY | O_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 23: Path can not escape outside at any point of the resolution using absolute path");
T_EXPECT_POSIX_SUCCESS(close(root_fd), "Closing the root directory");
}
T_DECL(resolve_beneath_faccessat,
"test faccessat() using the AT_RESOLVE_BENEATH flag")
{
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_faccessat");
T_SETUPEND;
T_LOG("Testing the faccessat() syscall using AT_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(faccessat(test_fd, "inside_file.txt", R_OK, AT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(faccessat(test_fd, "symlink", R_OK, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(faccessat(test_fd, "../outside_file.txt", R_OK, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(faccessat(test_fd, "nested/nested_file.txt", R_OK, AT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(faccessat(test_fd, "symlink_to_nested", R_OK, AT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(faccessat(test_fd, "/etc/passwd", R_OK, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
/* Test Case 7: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(faccessat(test_fd, "parent_symlink/outside_file.txt", R_OK, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
/* Test Case 8: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(faccessat(test_fd, "circular_symlink", R_OK, AT_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
/* Test Case 9: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(faccessat(test_fd, "../test_dir/inside_file.txt", R_OK, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
/* Test Case 10: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(faccessat(test_fd, "symlink_absolute/test_dir/inside_file.txt", R_OK, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
}
T_DECL(resolve_beneath_fstatat,
"test fstatat() using the AT_RESOLVE_BENEATH flag")
{
struct stat buf;
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_fstatat");
T_SETUPEND;
T_LOG("Testing the fstatat() syscall using AT_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(fstatat(test_fd, "inside_file.txt", &buf, AT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(fstatat(test_fd, "symlink", &buf, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(fstatat(test_fd, "../outside_file.txt", &buf, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(fstatat(test_fd, "nested/nested_file.txt", &buf, AT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(fstatat(test_fd, "symlink_to_nested", &buf, AT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(fstatat(test_fd, "/etc/passwd", &buf, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
/* Test Case 7: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(fstatat(test_fd, "parent_symlink/outside_file.txt", &buf, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
/* Test Case 8: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(fstatat(test_fd, "circular_symlink", &buf, AT_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
/* Test Case 9: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(fstatat(test_fd, "../test_dir/inside_file.txt", &buf, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
/* Test Case 10: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(fstatat(test_fd, "symlink_absolute/test_dir/inside_file.txt", &buf, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
}
T_DECL(resolve_beneath_fchmodat,
"test fchmodat() using the AT_RESOLVE_BENEATH flag")
{
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_fchmodat");
T_SETUPEND;
T_LOG("Testing the fchmodat() syscall using AT_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(fchmodat(test_fd, "inside_file.txt", S_IRWXU, AT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(fchmodat(test_fd, "symlink", S_IRWXU, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(fchmodat(test_fd, "../outside_file.txt", S_IRWXU, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(fchmodat(test_fd, "nested/nested_file.txt", S_IRWXU, AT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(fchmodat(test_fd, "symlink_to_nested", S_IRWXU, AT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(fchmodat(test_fd, "/etc/passwd", S_IRWXU, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
/* Test Case 7: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(fchmodat(test_fd, "parent_symlink/outside_file.txt", S_IRWXU, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
/* Test Case 8: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(fchmodat(test_fd, "circular_symlink", S_IRWXU, AT_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
/* Test Case 9: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(fchmodat(test_fd, "../test_dir/inside_file.txt", S_IRWXU, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
/* Test Case 10: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(fchmodat(test_fd, "symlink_absolute/test_dir/inside_file.txt", S_IRWXU, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
}
T_DECL(resolve_beneath_fchownat,
"test fchownat() using the AT_RESOLVE_BENEATH flag")
{
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_fchownat");
T_SETUPEND;
T_LOG("Testing the fchownat() syscall using AT_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(fchownat(test_fd, "inside_file.txt", geteuid(), getgid(), AT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(fchownat(test_fd, "symlink", geteuid(), getgid(), AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(fchownat(test_fd, "../outside_file.txt", geteuid(), getgid(), AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(fchownat(test_fd, "nested/nested_file.txt", geteuid(), getgid(), AT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(fchownat(test_fd, "symlink_to_nested", geteuid(), getgid(), AT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(fchownat(test_fd, "/etc/passwd", geteuid(), getgid(), AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
/* Test Case 7: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(fchownat(test_fd, "parent_symlink/outside_file.txt", geteuid(), getgid(), AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
/* Test Case 8: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(fchownat(test_fd, "circular_symlink", geteuid(), getgid(), AT_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
/* Test Case 9: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(fchownat(test_fd, "../test_dir/inside_file.txt", geteuid(), getgid(), AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
/* Test Case 10: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(fchownat(test_fd, "symlink_absolute/test_dir/inside_file.txt", geteuid(), getgid(), AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
}
T_DECL(resolve_beneath_linkat,
"test linkat() using the AT_RESOLVE_BENEATH flag")
{
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_linkat");
T_SETUPEND;
T_LOG("Testing the linkat() syscall using AT_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(linkat(test_fd, "inside_file.txt", test_fd, "inside_file_2.txt", AT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
unlinkat(test_fd, "inside_file_2.txt", 0);
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(linkat(test_fd, "symlink/.", test_fd, "inside_file_2.txt", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(linkat(test_fd, "inside_file.txt", test_fd, "../outside_file.txt", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(linkat(test_fd, "nested/nested_file.txt", test_fd, "nested/nested_file_2.txt", AT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
unlinkat(test_fd, "nested/nested_file_2.txt", 0);
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(linkat(test_fd, "symlink_to_nested", test_fd, "nested/nested_file_2.txt", AT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
unlinkat(test_fd, "nested/nested_file_2.txt", 0);
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(linkat(test_fd, "/etc/passwd", test_fd, "inside_file_2.txt", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
}
T_DECL(resolve_beneath_unlinkat,
"test unlinkat() using the AT_RESOLVE_BENEATH flag")
{
int fd;
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_unlinkat");
T_SETUPEND;
T_LOG("Testing the unlinkat() syscall using AT_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(unlinkat(test_fd, "inside_file.txt", AT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
if ((fd = openat(testdir_fd, INSIDE_FILE, O_CREAT | O_RDWR, 0777)) < 0) {
T_FAIL("Unable to recreate %s", INSIDE_FILE);
}
close(fd);
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_SUCCESS(unlinkat(test_fd, "symlink", AT_RESOLVE_BENEATH), "Test Case 2: File using a symlink pointing outside");
if (symlinkat(SYMLINK_FROM, testdir_fd, SYMLINK) < 0) {
T_FAIL("Unable to recreate %s", INSIDE_FILE);
}
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(unlinkat(test_fd, "../outside_file.txt", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(unlinkat(test_fd, "nested/nested_file.txt", AT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
if ((fd = openat(testdir_fd, NESTED_FILE, O_CREAT | O_RDWR, 0777)) < 0) {
T_FAIL("Unable to recreate %s", NESTED_FILE);
}
close(fd);
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(unlinkat(test_fd, "symlink_to_nested", AT_RESOLVE_BENEATH), "Test Case 5: Symlink //to a file within the same directory");
if (symlinkat(SYMLINK_TO_NESTED_FROM, testdir_fd, SYMLINK_TO_NESTED) < 0) {
T_FAIL("Unable to recreate %s", SYMLINK_TO_NESTED);
}
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(unlinkat(test_fd, "/etc/passwd", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
/* Test Case 7: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(unlinkat(test_fd, "parent_symlink/outside_file.txt", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
/* Test Case 8: Circular symlink within directory */
T_EXPECT_POSIX_SUCCESS(unlinkat(test_fd, "circular_symlink", AT_RESOLVE_BENEATH), "Test Case 8: Circular symlink within directory");
if (symlinkat(CIRCULAR_SYMLINK_FROM, testdir_fd, CIRCULAR_SYMLINK) < 0) {
T_FAIL("Unable to recreate %s", CIRCULAR_SYMLINK);
}
/* Test Case 9: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(unlinkat(test_fd, "../test_dir/inside_file.txt", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
/* Test Case 10: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(unlinkat(test_fd, "symlink_absolute/test_dir/inside_file.txt", AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
}
T_DECL(resolve_beneath_utimensat,
"test utimensat() using the AT_RESOLVE_BENEATH flag")
{
static const struct timespec tptr[] = {
{ 0x12345678, 987654321 },
{ 0x15263748, 123456789 },
};
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_utimensat");
T_SETUPEND;
T_LOG("Testing the utimensat() syscall using AT_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(utimensat(test_fd, "inside_file.txt", tptr, AT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(utimensat(test_fd, "symlink", tptr, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(utimensat(test_fd, "../outside_file.txt", tptr, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(utimensat(test_fd, "nested/nested_file.txt", tptr, AT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(utimensat(test_fd, "symlink_to_nested", tptr, AT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(utimensat(test_fd, "/etc/passwd", tptr, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
/* Test Case 7: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(utimensat(test_fd, "parent_symlink/outside_file.txt", tptr, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
/* Test Case 8: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(utimensat(test_fd, "circular_symlink", tptr, AT_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
/* Test Case 9: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(utimensat(test_fd, "../test_dir/inside_file.txt", tptr, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
/* Test Case 10: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(utimensat(test_fd, "symlink_absolute/test_dir/inside_file.txt", tptr, AT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
}
T_DECL(resolve_beneath_getxattr,
"test getxattr()/fgetxattr() using the XATTR_RESOLVE_BENEATH flag")
{
char xattr_buff[100];
const char *xattr = "test1234";
size_t xattr_len = strlen(xattr);
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_getxattr");
/* Changing current directory to the test directory */
T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
/* Setting extended attributes */
T_ASSERT_POSIX_SUCCESS(setxattr("inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, 0), "Setting extended attributes to inside_file.txt");
T_ASSERT_POSIX_SUCCESS(setxattr("../outside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, 0), "Setting extended attributes to outside_file.txt");
T_ASSERT_POSIX_SUCCESS(setxattr("nested/nested_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, 0), "Setting extended attributes to nested_file.txt");
T_SETUPEND;
T_LOG("Testing the getxattr() syscall using XATTR_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(getxattr("inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), "Test Case 1: File within the directory");
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(getxattr("symlink", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(getxattr("../outside_file.txt", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(getxattr("nested/nested_file.txt", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(getxattr("symlink_to_nested", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(getxattr("/etc/passwd", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
/* Test Case 7: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(getxattr("parent_symlink/outside_file.txt", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
/* Test Case 8: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(getxattr("circular_symlink", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
/* Test Case 9: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(getxattr("../test_dir/inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
/* Test Case 10: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(getxattr("symlink_absolute/test_dir/inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
T_LOG("Testing the fgetxattr() syscall using XATTR_RESOLVE_BENEATH");
/* Test Case 11: Verifying that fgetxattr() fails with EINVAL */
T_EXPECT_POSIX_FAILURE(fgetxattr(test_fd, XATTR_RESOURCEFORK_NAME, xattr_buff, sizeof(xattr_buff), 0, XATTR_RESOLVE_BENEATH), EINVAL, "Test Case 11: Verifying that fgetxattr() fails with EINVAL");
}
T_DECL(resolve_beneath_setxattr,
"test setxattr()/fsetxattr() using the XATTR_RESOLVE_BENEATH flag")
{
const char *xattr = "test1234";
size_t xattr_len = strlen(xattr);
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_setxattr");
/* Changing current directory to the test directory */
T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
T_SETUPEND;
T_LOG("Testing the setxattr() syscall using XATTR_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(setxattr("inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), "Test Case 1: File within the directory");
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(setxattr("symlink", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(setxattr("../outside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(setxattr("nested/nested_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(setxattr("symlink_to_nested", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(setxattr("/etc/passwd", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
/* Test Case 7: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(setxattr("parent_symlink/outside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
/* Test Case 8: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(setxattr("circular_symlink", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
/* Test Case 9: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(setxattr("../test_dir/inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
/* Test Case 10: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(setxattr("symlink_absolute/test_dir/inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
T_LOG("Testing the fsetxattr() syscall using XATTR_RESOLVE_BENEATH");
/* Test Case 11: Verifying that fsetxattr() fails with EINVAL */
T_EXPECT_POSIX_FAILURE(fsetxattr(test_fd, XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, XATTR_RESOLVE_BENEATH), EINVAL, "Test Case 11: Verifying that fsetxattr() fails with EINVAL");
}
T_DECL(resolve_beneath_listxattr,
"test listxattr()/flistxattr() using the XATTR_RESOLVE_BENEATH flag")
{
char xattr_buff[100];
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_listxattr");
/* Changing current directory to the test directory */
T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
T_SETUPEND;
T_LOG("Testing the listxattr() syscall using XATTR_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(listxattr("inside_file.txt", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), "Test Case 1: File within the directory");
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(listxattr("symlink", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(listxattr("../outside_file.txt", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(listxattr("nested/nested_file.txt", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(listxattr("symlink_to_nested", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(listxattr("/etc/passwd", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
/* Test Case 7: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(listxattr("parent_symlink/outside_file.txt", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
/* Test Case 8: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(listxattr("circular_symlink", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
/* Test Case 9: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(listxattr("../test_dir/inside_file.txt", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
/* Test Case 10: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(listxattr("symlink_absolute/test_dir/inside_file.txt", xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
T_LOG("Testing the flistxattr() syscall using XATTR_RESOLVE_BENEATH");
/* Test Case 11: Verifying that flistxattr() fails with EINVAL */
T_EXPECT_POSIX_FAILURE(flistxattr(test_fd, xattr_buff, sizeof(xattr_buff), XATTR_RESOLVE_BENEATH), EINVAL, "Test Case 11: Verifying that flistxattr() fails with EINVAL");
}
T_DECL(resolve_beneath_removexattr,
"test removexattr()/fremovexattr() using the XATTR_RESOLVE_BENEATH flag")
{
const char *xattr = "test1234";
size_t xattr_len = strlen(xattr);
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_removexattr");
/* Changing current directory to the test directory */
T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
/* Setting extended attributes */
T_ASSERT_POSIX_SUCCESS(setxattr("inside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, 0), "Setting extended attributes to inside_file.txt");
T_ASSERT_POSIX_SUCCESS(setxattr("../outside_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, 0), "Setting extended attributes to outside_file.txt");
T_ASSERT_POSIX_SUCCESS(setxattr("nested/nested_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, 0), "Setting extended attributes to nested_file.txt");
T_SETUPEND;
T_LOG("Testing the removexattr() syscall using XATTR_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(removexattr("inside_file.txt", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), "Test Case 1: File within the directory");
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(removexattr("symlink", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(removexattr("../outside_file.txt", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(removexattr("nested/nested_file.txt", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
if (setxattr("nested/nested_file.txt", XATTR_RESOURCEFORK_NAME, xattr, xattr_len, 0, 0) < 0) {
T_FAIL("Unable to setxattr to nested_file.txt");
}
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(removexattr("symlink_to_nested", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(removexattr("/etc/passwd", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
/* Test Case 7: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(removexattr("parent_symlink/outside_file.txt", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
/* Test Case 8: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(removexattr("circular_symlink", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
/* Test Case 9: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(removexattr("../test_dir/inside_file.txt", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
/* Test Case 10: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(removexattr("symlink_absolute/test_dir/inside_file.txt", XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
T_LOG("Testing the fremovexattr() syscall using XATTR_RESOLVE_BENEATH");
/* Test Case 11: Verifying that fremovexattr() fails with EINVAL */
T_EXPECT_POSIX_FAILURE(fremovexattr(test_fd, XATTR_RESOURCEFORK_NAME, XATTR_RESOLVE_BENEATH), EINVAL, "Test Case 11: Verifying that fremovexattr() fails with EINVAL");
}
T_DECL(resolve_beneath_clonefile,
"test clonefile()/clonefileat()/fclonefileat() using the CLONE_RESOLVE_BENEATH flag")
{
int fd;
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_clonefile");
/* Changing current directory to the test directory */
T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
/* Open test file */
T_ASSERT_POSIX_SUCCESS((fd = open("inside_file.txt", O_RDWR, 0777)), "Opening %s", INSIDE_FILE);
T_SETUPEND;
T_LOG("Testing the clonefile() syscall using CLONE_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(clonefile("inside_file.txt", "inside_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 1: File within the directory");
unlink("inside_file_2.txt");
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(clonefile("symlink", "inside_file_2.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(clonefile("inside_file.txt", "../outside_file.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(clonefile("nested/nested_file.txt", "nested/nested_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
unlinkat(test_fd, "nested/nested_file_2.txt", 0);
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(clonefile("symlink_to_nested", "nested/nested_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
unlinkat(test_fd, "nested/nested_file_2.txt", 0);
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(clonefile("/etc/passwd", "inside_file_2.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
T_LOG("Testing the clonefileat() syscall using CLONE_RESOLVE_BENEATH");
/* Test Case 7: File within the directory */
T_EXPECT_POSIX_SUCCESS(clonefileat(test_fd, "inside_file.txt", test_fd, "inside_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 7: File within the directory");
unlinkat(test_fd, "inside_file_2.txt", 0);
/* Test Case 8: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(clonefileat(test_fd, "symlink", test_fd, "inside_file_2.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 8: File using a symlink pointing outside");
/* Test Case 9: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(clonefileat(test_fd, "inside_file.txt", test_fd, "../outside_file.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: File using \"..\" to navigate outside");
/* Test Case 10: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(clonefileat(test_fd, "nested/nested_file.txt", test_fd, "nested/nested_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 10: File within a nested directory");
unlinkat(test_fd, "nested/nested_file_2.txt", 0);
/* Test Case 11: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(clonefileat(test_fd, "symlink_to_nested", test_fd, "nested/nested_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 11: Symlink to a file within the same directory");
unlinkat(test_fd, "nested/nested_file_2.txt", 0);
/* Test Case 12: File using an absolute path */
T_EXPECT_POSIX_FAILURE(clonefileat(test_fd, "/etc/passwd", test_fd, "inside_file_2.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 12: File using an absolute path");
T_LOG("Testing the fclonefileat() syscall using CLONE_RESOLVE_BENEATH");
/* Test Case 13: File within the directory */
T_EXPECT_POSIX_SUCCESS(fclonefileat(fd, test_fd, "inside_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 13: File within the directory");
unlinkat(test_fd, "inside_file_2.txt", 0);
/* Test Case 14: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(fclonefileat(fd, test_fd, "symlink_absolute/test_dir/inside_file.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 14: File using a symlink pointing outside");
/* Test Case 15: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(fclonefileat(fd, test_fd, "../outside_file.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 15: File using \"..\" to navigate outside");
/* Test Case 16: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(fclonefileat(fd, test_fd, "nested/nested_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 16: File within a nested directory");
unlinkat(test_fd, "nested/nested_file_2.txt", 0);
/* Test Case 17: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(fclonefileat(fd, test_fd, "nested/nested_file_2.txt", CLONE_RESOLVE_BENEATH), "Test Case 17: Symlink to a file within the same directory");
unlinkat(test_fd, "nested/nested_file_2.txt", 0);
/* Test Case 18: File using an absolute path */
T_EXPECT_POSIX_FAILURE(fclonefileat(fd, test_fd, "/etc/inside_file_2.txt", CLONE_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 18: File using an absolute path");
T_EXPECT_POSIX_SUCCESS(close(fd), "Closing %s", INSIDE_FILE);
}
T_DECL(resolve_beneath_renamex_np,
"test renamex_np()/renameatx_np() using the RENAME_RESOLVE_BENEATH flag")
{
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_renamex_np");
/* Changing current directory to the test directory */
T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
T_SETUPEND;
T_LOG("Testing the renamex_np() syscall using RENAME_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(renamex_np("inside_file.txt", "inside_file_2.txt", RENAME_RESOLVE_BENEATH), "Test Case 1: File within the directory");
if (renamex_np("inside_file_2.txt", "inside_file.txt", 0)) {
T_FAIL("Unable to rename inside_file_2.txt to inside_file.txt");
}
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(renamex_np("symlink/.", "inside_file_2.txt", RENAME_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(renamex_np("inside_file.txt", "../outside_file.txt", RENAME_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(renamex_np("nested/nested_file.txt", "nested/nested_file_2.txt", RENAME_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
if (renamex_np("nested/nested_file_2.txt", "nested/nested_file.txt", 0)) {
T_FAIL("Unable to rename nested/nested_file_2.txt to nested/nested_file.txt");
}
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(renamex_np("symlink_to_nested", "nested/nested_file_2.txt", RENAME_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
if (renamex_np("nested/nested_file_2.txt", "symlink_to_nested", 0)) {
T_FAIL("Unable to rename nested/nested_file_2.txt to symlink_to_nested");
}
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(renamex_np("/etc/passwd", "inside_file_2.txt", RENAME_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
T_LOG("Testing the renameatx_np() syscall using RENAME_RESOLVE_BENEATH");
/* Test Case 7: File within the directory */
T_EXPECT_POSIX_SUCCESS(renameatx_np(test_fd, "inside_file.txt", test_fd, "inside_file_2.txt", RENAME_RESOLVE_BENEATH), "Test Case 7: File within the directory");
if (renamex_np("inside_file_2.txt", "inside_file.txt", 0)) {
T_FAIL("Unable to rename inside_file_2.txt to inside_file.txt");
}
/* Test Case 8: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(renameatx_np(test_fd, "symlink/.", test_fd, "inside_file_2.txt", RENAME_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 8: File using a symlink pointing outside");
/* Test Case 9: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(renameatx_np(test_fd, "inside_file.txt", test_fd, "../outside_file.txt", RENAME_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: File using \"..\" to navigate outside");
/* Test Case 10: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(renameatx_np(test_fd, "nested/nested_file.txt", test_fd, "nested/nested_file_2.txt", RENAME_RESOLVE_BENEATH), "Test Case 10: File within a nested directory");
if (renamex_np("nested/nested_file_2.txt", "nested/nested_file.txt", 0)) {
T_FAIL("Unable to rename nested/nested_file_2.txt to nested/nested_file.txt");
}
/* Test Case 11: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(renameatx_np(test_fd, "symlink_to_nested", test_fd, "nested/nested_file_2.txt", RENAME_RESOLVE_BENEATH), "Test Case 11: Symlink to a file within the same directory");
if (renamex_np("nested/nested_file_2.txt", "symlink_to_nested", 0)) {
T_FAIL("Unable to rename nested/nested_file_2.txt to symlink_to_nested");
}
/* Test Case 12: File using an absolute path */
T_EXPECT_POSIX_FAILURE(renameatx_np(test_fd, "/etc/passwd", test_fd, "inside_file_2.txt", RENAME_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 12: File using an absolute path");
}
T_DECL(resolve_beneath_getattrlist,
"test getattrlist()/fgetattrlist()/getattrlistat() using the FSOPT_RESOLVE_BENEATH flag")
{
int fd;
struct myattrbuf {
uint32_t length;
attribute_set_t returned_attrs;
vol_attributes_attr_t vol_attributes;
attrreference_t fstypename_ref;
uint32_t fssubtype;
char fstypename[MFSTYPENAMELEN];
} attrbuf;
struct attrlist attrs = {
.bitmapcount = ATTR_BIT_MAP_COUNT,
.commonattr = ATTR_CMN_RETURNED_ATTRS,
/*
* Request ATTR_VOL_ATTRIBUTES to ensure that
* ATTR_VOL_FSTYPENAME and ATTR_VOL_FSSUBTYPE
* are packed into the buffer *after*.
*/
.volattr = ATTR_VOL_INFO | ATTR_VOL_ATTRIBUTES |
ATTR_VOL_FSTYPENAME | ATTR_VOL_FSSUBTYPE,
};
T_SETUPBEGIN;
T_ATEND(cleanup);
setup("resolve_beneath_getattrlist");
/* Changing current directory to the test directory */
T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
/* Open test file */
T_ASSERT_POSIX_SUCCESS((fd = open("inside_file.txt", O_RDWR, 0777)), "Opening %s", INSIDE_FILE);
T_SETUPEND;
T_LOG("Testing the getattrlist() syscall using FSOPT_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(getattrlist("inside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(getattrlist("symlink", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(getattrlist("../outside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(getattrlist("nested/nested_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(getattrlist("symlink_to_nested", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(getattrlist("/etc/passwd", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
/* Test Case 7: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(getattrlist("parent_symlink/outside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
/* Test Case 8: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(getattrlist("circular_symlink", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
/* Test Case 9: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(getattrlist("../test_dir/inside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
/* Test Case 10: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(getattrlist("symlink_absolute/test_dir/inside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
T_LOG("Testing the fgetattrlist() syscall using FSOPT_RESOLVE_BENEATH");
/* Test Case 11: fgetattrlist() syscall using FSOPT_RESOLVE_BENEATH */
T_EXPECT_POSIX_SUCCESS(fgetattrlist(fd, &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), "Test Case 11: fgetattrlist() syscall using FSOPT_RESOLVE_BENEATH");
T_LOG("Testing the getattrlistat() syscall using FSOPT_RESOLVE_BENEATH");
/* Test Case 12: File within the directory */
T_EXPECT_POSIX_SUCCESS(getattrlistat(test_fd, "inside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), "Test Case 12: File within the directory");
/* Test Case 13: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(getattrlistat(test_fd, "symlink", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 13: File using a symlink pointing outside");
/* Test Case 14: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(getattrlistat(test_fd, "../outside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 14: File using \"..\" to navigate outside");
/* Test Case 15: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(getattrlistat(test_fd, "nested/nested_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), "Test Case 15: File within a nested directory");
/* Test Case 16: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(getattrlistat(test_fd, "symlink_to_nested", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), "Test Case 16: Symlink to a file within the same directory");
/* Test Case 17: File using an absolute path */
T_EXPECT_POSIX_FAILURE(getattrlistat(test_fd, "/etc/passwd", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 17: File using an absolute path");
/* Test Case 18: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(getattrlistat(test_fd, "parent_symlink/outside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 18: Valid symlink to parent directory");
/* Test Case 19: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(getattrlistat(test_fd, "circular_symlink", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ELOOP, "Test Case 19: Circular symlink within directory");
/* Test Case 20: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(getattrlistat(test_fd, "../test_dir/inside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 20: Path can not escape outside at any point of the resolution");
/* Test Case 21: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(getattrlistat(test_fd, "symlink_absolute/test_dir/inside_file.txt", &attrs, &attrbuf, sizeof(attrbuf), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 21: File using a symlink pointing to absolute path");
T_EXPECT_POSIX_SUCCESS(close(fd), "Closing %s", INSIDE_FILE);
}
T_DECL(resolve_beneath_setattrlist,
"test setattrlist()/fsetattrlist()/setattrlistat() using the FSOPT_RESOLVE_BENEATH flag")
{
int fd;
int flags;
struct attrlist attrlist;
T_SETUPBEGIN;
flags = 0;
memset(&attrlist, 0, sizeof(attrlist));
attrlist.bitmapcount = ATTR_BIT_MAP_COUNT;
attrlist.commonattr = ATTR_CMN_FLAGS;
T_ATEND(cleanup);
setup("resolve_beneath_setattrlist");
/* Changing current directory to the test directory */
T_ASSERT_POSIX_SUCCESS(fchdir(test_fd), "Changing directory to %s/%s", testdir, TEST_DIR);
/* Open test file */
T_ASSERT_POSIX_SUCCESS((fd = open("inside_file.txt", O_RDWR, 0777)), "Opening %s", INSIDE_FILE);
T_SETUPEND;
T_LOG("Testing the setattrlist() syscall using FSOPT_RESOLVE_BENEATH");
/* Test Case 1: File within the directory */
T_EXPECT_POSIX_SUCCESS(setattrlist("inside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), "Test Case 1: File within the directory");
/* Test Case 2: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(setattrlist("symlink", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 2: File using a symlink pointing outside");
/* Test Case 3: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(setattrlist("../outside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 3: File using \"..\" to navigate outside");
/* Test Case 4: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(setattrlist("nested/nested_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), "Test Case 4: File within a nested directory");
/* Test Case 5: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(setattrlist("symlink_to_nested", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), "Test Case 5: Symlink to a file within the same directory");
/* Test Case 6: File using an absolute path */
T_EXPECT_POSIX_FAILURE(setattrlist("/etc/passwd", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 6: File using an absolute path");
/* Test Case 7: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(setattrlist("parent_symlink/outside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 7: Valid symlink to parent directory");
/* Test Case 8: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(setattrlist("circular_symlink", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ELOOP, "Test Case 8: Circular symlink within directory");
/* Test Case 9: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(setattrlist("../test_dir/inside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 9: Path can not escape outside at any point of the resolution");
/* Test Case 10: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(setattrlist("symlink_absolute/test_dir/inside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 10: File using a symlink pointing to absolute path");
T_LOG("Testing the fsetattrlist() syscall using FSOPT_RESOLVE_BENEATH");
/* Test Case 11: fsetattrlist() syscall using FSOPT_RESOLVE_BENEATH */
T_EXPECT_POSIX_SUCCESS(fsetattrlist(fd, &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), "Test Case 11: fsetattrlist() syscall using FSOPT_RESOLVE_BENEATH");
T_LOG("Testing the setattrlistat() syscall using FSOPT_RESOLVE_BENEATH");
/* Test Case 12: File within the directory */
T_EXPECT_POSIX_SUCCESS(setattrlistat(test_fd, "inside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), "Test Case 12: File within the directory");
/* Test Case 13: File using a symlink pointing outside */
T_EXPECT_POSIX_FAILURE(setattrlistat(test_fd, "symlink", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 13: File using a symlink pointing outside");
/* Test Case 14: Attempt to open a file using ".." to navigate outside */
T_EXPECT_POSIX_FAILURE(setattrlistat(test_fd, "../outside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 14: File using \"..\" to navigate outside");
/* Test Case 15: File within a nested directory */
T_EXPECT_POSIX_SUCCESS(setattrlistat(test_fd, "nested/nested_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), "Test Case 15: File within a nested directory");
/* Test Case 16: Symlink to a file in a nested directory */
T_EXPECT_POSIX_SUCCESS(setattrlistat(test_fd, "symlink_to_nested", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), "Test Case 16: Symlink to a file within the same directory");
/* Test Case 17: File using an absolute path */
T_EXPECT_POSIX_FAILURE(setattrlistat(test_fd, "/etc/passwd", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 17: File using an absolute path");
/* Test Case 18: Valid symlink to parent directory */
T_EXPECT_POSIX_FAILURE(setattrlistat(test_fd, "parent_symlink/outside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 18: Valid symlink to parent directory");
/* Test Case 19: Circular symlink within directory */
T_EXPECT_POSIX_FAILURE(setattrlistat(test_fd, "circular_symlink", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ELOOP, "Test Case 19: Circular symlink within directory");
/* Test Case 20: Path can not escape outside at any point of the resolution */
T_EXPECT_POSIX_FAILURE(setattrlistat(test_fd, "../test_dir/inside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 20: Path can not escape outside at any point of the resolution");
/* Test Case 21: File using a symlink pointing to absolute path */
T_EXPECT_POSIX_FAILURE(setattrlistat(test_fd, "symlink_absolute/test_dir/inside_file.txt", &attrlist, &flags, sizeof(flags), FSOPT_RESOLVE_BENEATH), ENOTCAPABLE, "Test Case 21: File using a symlink pointing to absolute path");
T_EXPECT_POSIX_SUCCESS(close(fd), "Closing %s", INSIDE_FILE);
}