162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Landlock tests - Common user space base 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net> 662306a36Sopenharmony_ci * Copyright © 2019-2020 ANSSI 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define _GNU_SOURCE 1062306a36Sopenharmony_ci#include <errno.h> 1162306a36Sopenharmony_ci#include <fcntl.h> 1262306a36Sopenharmony_ci#include <linux/landlock.h> 1362306a36Sopenharmony_ci#include <string.h> 1462306a36Sopenharmony_ci#include <sys/prctl.h> 1562306a36Sopenharmony_ci#include <sys/socket.h> 1662306a36Sopenharmony_ci#include <sys/types.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "common.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#ifndef O_PATH 2162306a36Sopenharmony_ci#define O_PATH 010000000 2262306a36Sopenharmony_ci#endif 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciTEST(inconsistent_attr) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci const long page_size = sysconf(_SC_PAGESIZE); 2762306a36Sopenharmony_ci char *const buf = malloc(page_size + 1); 2862306a36Sopenharmony_ci struct landlock_ruleset_attr *const ruleset_attr = (void *)buf; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci ASSERT_NE(NULL, buf); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci /* Checks copy_from_user(). */ 3362306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 0, 0)); 3462306a36Sopenharmony_ci /* The size if less than sizeof(struct landlock_attr_enforce). */ 3562306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 3662306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 1, 0)); 3762306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 3862306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 7, 0)); 3962306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(NULL, 1, 0)); 4262306a36Sopenharmony_ci /* The size if less than sizeof(struct landlock_attr_enforce). */ 4362306a36Sopenharmony_ci ASSERT_EQ(EFAULT, errno); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset( 4662306a36Sopenharmony_ci NULL, sizeof(struct landlock_ruleset_attr), 0)); 4762306a36Sopenharmony_ci ASSERT_EQ(EFAULT, errno); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size + 1, 0)); 5062306a36Sopenharmony_ci ASSERT_EQ(E2BIG, errno); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* Checks minimal valid attribute size. */ 5362306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, 8, 0)); 5462306a36Sopenharmony_ci ASSERT_EQ(ENOMSG, errno); 5562306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset( 5662306a36Sopenharmony_ci ruleset_attr, 5762306a36Sopenharmony_ci sizeof(struct landlock_ruleset_attr), 0)); 5862306a36Sopenharmony_ci ASSERT_EQ(ENOMSG, errno); 5962306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size, 0)); 6062306a36Sopenharmony_ci ASSERT_EQ(ENOMSG, errno); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* Checks non-zero value. */ 6362306a36Sopenharmony_ci buf[page_size - 2] = '.'; 6462306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size, 0)); 6562306a36Sopenharmony_ci ASSERT_EQ(E2BIG, errno); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(ruleset_attr, page_size + 1, 0)); 6862306a36Sopenharmony_ci ASSERT_EQ(E2BIG, errno); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci free(buf); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciTEST(abi_version) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci const struct landlock_ruleset_attr ruleset_attr = { 7662306a36Sopenharmony_ci .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, 7762306a36Sopenharmony_ci }; 7862306a36Sopenharmony_ci ASSERT_EQ(3, landlock_create_ruleset(NULL, 0, 7962306a36Sopenharmony_ci LANDLOCK_CREATE_RULESET_VERSION)); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, 8262306a36Sopenharmony_ci LANDLOCK_CREATE_RULESET_VERSION)); 8362306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr), 8662306a36Sopenharmony_ci LANDLOCK_CREATE_RULESET_VERSION)); 8762306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci ASSERT_EQ(-1, 9062306a36Sopenharmony_ci landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 9162306a36Sopenharmony_ci LANDLOCK_CREATE_RULESET_VERSION)); 9262306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0, 9562306a36Sopenharmony_ci LANDLOCK_CREATE_RULESET_VERSION | 9662306a36Sopenharmony_ci 1 << 31)); 9762306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* Tests ordering of syscall argument checks. */ 10162306a36Sopenharmony_ciTEST(create_ruleset_checks_ordering) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci const int last_flag = LANDLOCK_CREATE_RULESET_VERSION; 10462306a36Sopenharmony_ci const int invalid_flag = last_flag << 1; 10562306a36Sopenharmony_ci int ruleset_fd; 10662306a36Sopenharmony_ci const struct landlock_ruleset_attr ruleset_attr = { 10762306a36Sopenharmony_ci .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, 10862306a36Sopenharmony_ci }; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Checks priority for invalid flags. */ 11162306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(NULL, 0, invalid_flag)); 11262306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, invalid_flag)); 11562306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(NULL, sizeof(ruleset_attr), 11862306a36Sopenharmony_ci invalid_flag)); 11962306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci ASSERT_EQ(-1, 12262306a36Sopenharmony_ci landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 12362306a36Sopenharmony_ci invalid_flag)); 12462306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* Checks too big ruleset_attr size. */ 12762306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, -1, 0)); 12862306a36Sopenharmony_ci ASSERT_EQ(E2BIG, errno); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* Checks too small ruleset_attr size. */ 13162306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, 0)); 13262306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 13362306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 1, 0)); 13462306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* Checks valid call. */ 13762306a36Sopenharmony_ci ruleset_fd = 13862306a36Sopenharmony_ci landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 13962306a36Sopenharmony_ci ASSERT_LE(0, ruleset_fd); 14062306a36Sopenharmony_ci ASSERT_EQ(0, close(ruleset_fd)); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* Tests ordering of syscall argument checks. */ 14462306a36Sopenharmony_ciTEST(add_rule_checks_ordering) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci const struct landlock_ruleset_attr ruleset_attr = { 14762306a36Sopenharmony_ci .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE, 14862306a36Sopenharmony_ci }; 14962306a36Sopenharmony_ci struct landlock_path_beneath_attr path_beneath_attr = { 15062306a36Sopenharmony_ci .allowed_access = LANDLOCK_ACCESS_FS_EXECUTE, 15162306a36Sopenharmony_ci .parent_fd = -1, 15262306a36Sopenharmony_ci }; 15362306a36Sopenharmony_ci const int ruleset_fd = 15462306a36Sopenharmony_ci landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci ASSERT_LE(0, ruleset_fd); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* Checks invalid flags. */ 15962306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 1)); 16062306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* Checks invalid ruleset FD. */ 16362306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_add_rule(-1, 0, NULL, 0)); 16462306a36Sopenharmony_ci ASSERT_EQ(EBADF, errno); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* Checks invalid rule type. */ 16762306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, 0, NULL, 0)); 16862306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* Checks invalid rule attr. */ 17162306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 17262306a36Sopenharmony_ci NULL, 0)); 17362306a36Sopenharmony_ci ASSERT_EQ(EFAULT, errno); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Checks invalid path_beneath.parent_fd. */ 17662306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 17762306a36Sopenharmony_ci &path_beneath_attr, 0)); 17862306a36Sopenharmony_ci ASSERT_EQ(EBADF, errno); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* Checks valid call. */ 18162306a36Sopenharmony_ci path_beneath_attr.parent_fd = 18262306a36Sopenharmony_ci open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC); 18362306a36Sopenharmony_ci ASSERT_LE(0, path_beneath_attr.parent_fd); 18462306a36Sopenharmony_ci ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 18562306a36Sopenharmony_ci &path_beneath_attr, 0)); 18662306a36Sopenharmony_ci ASSERT_EQ(0, close(path_beneath_attr.parent_fd)); 18762306a36Sopenharmony_ci ASSERT_EQ(0, close(ruleset_fd)); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* Tests ordering of syscall argument and permission checks. */ 19162306a36Sopenharmony_ciTEST(restrict_self_checks_ordering) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci const struct landlock_ruleset_attr ruleset_attr = { 19462306a36Sopenharmony_ci .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE, 19562306a36Sopenharmony_ci }; 19662306a36Sopenharmony_ci struct landlock_path_beneath_attr path_beneath_attr = { 19762306a36Sopenharmony_ci .allowed_access = LANDLOCK_ACCESS_FS_EXECUTE, 19862306a36Sopenharmony_ci .parent_fd = -1, 19962306a36Sopenharmony_ci }; 20062306a36Sopenharmony_ci const int ruleset_fd = 20162306a36Sopenharmony_ci landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci ASSERT_LE(0, ruleset_fd); 20462306a36Sopenharmony_ci path_beneath_attr.parent_fd = 20562306a36Sopenharmony_ci open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC); 20662306a36Sopenharmony_ci ASSERT_LE(0, path_beneath_attr.parent_fd); 20762306a36Sopenharmony_ci ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, 20862306a36Sopenharmony_ci &path_beneath_attr, 0)); 20962306a36Sopenharmony_ci ASSERT_EQ(0, close(path_beneath_attr.parent_fd)); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* Checks unprivileged enforcement without no_new_privs. */ 21262306a36Sopenharmony_ci drop_caps(_metadata); 21362306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_restrict_self(-1, -1)); 21462306a36Sopenharmony_ci ASSERT_EQ(EPERM, errno); 21562306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_restrict_self(-1, 0)); 21662306a36Sopenharmony_ci ASSERT_EQ(EPERM, errno); 21762306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_restrict_self(ruleset_fd, 0)); 21862306a36Sopenharmony_ci ASSERT_EQ(EPERM, errno); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* Checks invalid flags. */ 22362306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_restrict_self(-1, -1)); 22462306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* Checks invalid ruleset FD. */ 22762306a36Sopenharmony_ci ASSERT_EQ(-1, landlock_restrict_self(-1, 0)); 22862306a36Sopenharmony_ci ASSERT_EQ(EBADF, errno); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* Checks valid call. */ 23162306a36Sopenharmony_ci ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0)); 23262306a36Sopenharmony_ci ASSERT_EQ(0, close(ruleset_fd)); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ciTEST(ruleset_fd_io) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct landlock_ruleset_attr ruleset_attr = { 23862306a36Sopenharmony_ci .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, 23962306a36Sopenharmony_ci }; 24062306a36Sopenharmony_ci int ruleset_fd; 24162306a36Sopenharmony_ci char buf; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci drop_caps(_metadata); 24462306a36Sopenharmony_ci ruleset_fd = 24562306a36Sopenharmony_ci landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 24662306a36Sopenharmony_ci ASSERT_LE(0, ruleset_fd); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci ASSERT_EQ(-1, write(ruleset_fd, ".", 1)); 24962306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 25062306a36Sopenharmony_ci ASSERT_EQ(-1, read(ruleset_fd, &buf, 1)); 25162306a36Sopenharmony_ci ASSERT_EQ(EINVAL, errno); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci ASSERT_EQ(0, close(ruleset_fd)); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci/* Tests enforcement of a ruleset FD transferred through a UNIX socket. */ 25762306a36Sopenharmony_ciTEST(ruleset_fd_transfer) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct landlock_ruleset_attr ruleset_attr = { 26062306a36Sopenharmony_ci .handled_access_fs = LANDLOCK_ACCESS_FS_READ_DIR, 26162306a36Sopenharmony_ci }; 26262306a36Sopenharmony_ci struct landlock_path_beneath_attr path_beneath_attr = { 26362306a36Sopenharmony_ci .allowed_access = LANDLOCK_ACCESS_FS_READ_DIR, 26462306a36Sopenharmony_ci }; 26562306a36Sopenharmony_ci int ruleset_fd_tx, dir_fd; 26662306a36Sopenharmony_ci int socket_fds[2]; 26762306a36Sopenharmony_ci pid_t child; 26862306a36Sopenharmony_ci int status; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci drop_caps(_metadata); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Creates a test ruleset with a simple rule. */ 27362306a36Sopenharmony_ci ruleset_fd_tx = 27462306a36Sopenharmony_ci landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); 27562306a36Sopenharmony_ci ASSERT_LE(0, ruleset_fd_tx); 27662306a36Sopenharmony_ci path_beneath_attr.parent_fd = 27762306a36Sopenharmony_ci open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC); 27862306a36Sopenharmony_ci ASSERT_LE(0, path_beneath_attr.parent_fd); 27962306a36Sopenharmony_ci ASSERT_EQ(0, 28062306a36Sopenharmony_ci landlock_add_rule(ruleset_fd_tx, LANDLOCK_RULE_PATH_BENEATH, 28162306a36Sopenharmony_ci &path_beneath_attr, 0)); 28262306a36Sopenharmony_ci ASSERT_EQ(0, close(path_beneath_attr.parent_fd)); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Sends the ruleset FD over a socketpair and then close it. */ 28562306a36Sopenharmony_ci ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, 28662306a36Sopenharmony_ci socket_fds)); 28762306a36Sopenharmony_ci ASSERT_EQ(0, send_fd(socket_fds[0], ruleset_fd_tx)); 28862306a36Sopenharmony_ci ASSERT_EQ(0, close(socket_fds[0])); 28962306a36Sopenharmony_ci ASSERT_EQ(0, close(ruleset_fd_tx)); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci child = fork(); 29262306a36Sopenharmony_ci ASSERT_LE(0, child); 29362306a36Sopenharmony_ci if (child == 0) { 29462306a36Sopenharmony_ci const int ruleset_fd_rx = recv_fd(socket_fds[1]); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci ASSERT_LE(0, ruleset_fd_rx); 29762306a36Sopenharmony_ci ASSERT_EQ(0, close(socket_fds[1])); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* Enforces the received ruleset on the child. */ 30062306a36Sopenharmony_ci ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)); 30162306a36Sopenharmony_ci ASSERT_EQ(0, landlock_restrict_self(ruleset_fd_rx, 0)); 30262306a36Sopenharmony_ci ASSERT_EQ(0, close(ruleset_fd_rx)); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* Checks that the ruleset enforcement. */ 30562306a36Sopenharmony_ci ASSERT_EQ(-1, open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC)); 30662306a36Sopenharmony_ci ASSERT_EQ(EACCES, errno); 30762306a36Sopenharmony_ci dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC); 30862306a36Sopenharmony_ci ASSERT_LE(0, dir_fd); 30962306a36Sopenharmony_ci ASSERT_EQ(0, close(dir_fd)); 31062306a36Sopenharmony_ci _exit(_metadata->passed ? EXIT_SUCCESS : EXIT_FAILURE); 31162306a36Sopenharmony_ci return; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci ASSERT_EQ(0, close(socket_fds[1])); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* Checks that the parent is unrestricted. */ 31762306a36Sopenharmony_ci dir_fd = open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC); 31862306a36Sopenharmony_ci ASSERT_LE(0, dir_fd); 31962306a36Sopenharmony_ci ASSERT_EQ(0, close(dir_fd)); 32062306a36Sopenharmony_ci dir_fd = open("/tmp", O_RDONLY | O_DIRECTORY | O_CLOEXEC); 32162306a36Sopenharmony_ci ASSERT_LE(0, dir_fd); 32262306a36Sopenharmony_ci ASSERT_EQ(0, close(dir_fd)); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci ASSERT_EQ(child, waitpid(child, &status, 0)); 32562306a36Sopenharmony_ci ASSERT_EQ(1, WIFEXITED(status)); 32662306a36Sopenharmony_ci ASSERT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ciTEST_HARNESS_MAIN 330