162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci#include <errno.h> 362306a36Sopenharmony_ci#include <fcntl.h> 462306a36Sopenharmony_ci#include <stdio.h> 562306a36Sopenharmony_ci#include <string.h> 662306a36Sopenharmony_ci#include <unistd.h> 762306a36Sopenharmony_ci#include <sys/socket.h> 862306a36Sopenharmony_ci#include <sys/stat.h> 962306a36Sopenharmony_ci#include <sys/sysmacros.h> 1062306a36Sopenharmony_ci#include <sys/types.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "../kselftest_harness.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* Remove a file, ignoring the result if it didn't exist. */ 1562306a36Sopenharmony_civoid rm(struct __test_metadata *_metadata, const char *pathname, 1662306a36Sopenharmony_ci int is_dir) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci int rc; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci if (is_dir) 2162306a36Sopenharmony_ci rc = rmdir(pathname); 2262306a36Sopenharmony_ci else 2362306a36Sopenharmony_ci rc = unlink(pathname); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci if (rc < 0) { 2662306a36Sopenharmony_ci ASSERT_EQ(errno, ENOENT) { 2762306a36Sopenharmony_ci TH_LOG("Not ENOENT: %s", pathname); 2862306a36Sopenharmony_ci } 2962306a36Sopenharmony_ci } else { 3062306a36Sopenharmony_ci ASSERT_EQ(rc, 0) { 3162306a36Sopenharmony_ci TH_LOG("Failed to remove: %s", pathname); 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ciFIXTURE(file) { 3762306a36Sopenharmony_ci char *pathname; 3862306a36Sopenharmony_ci int is_dir; 3962306a36Sopenharmony_ci}; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciFIXTURE_VARIANT(file) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci const char *name; 4462306a36Sopenharmony_ci int expected; 4562306a36Sopenharmony_ci int is_dir; 4662306a36Sopenharmony_ci void (*setup)(struct __test_metadata *_metadata, 4762306a36Sopenharmony_ci FIXTURE_DATA(file) *self, 4862306a36Sopenharmony_ci const FIXTURE_VARIANT(file) *variant); 4962306a36Sopenharmony_ci int major, minor, mode; /* for mknod() */ 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_civoid setup_link(struct __test_metadata *_metadata, 5362306a36Sopenharmony_ci FIXTURE_DATA(file) *self, 5462306a36Sopenharmony_ci const FIXTURE_VARIANT(file) *variant) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci const char * const paths[] = { 5762306a36Sopenharmony_ci "/bin/true", 5862306a36Sopenharmony_ci "/usr/bin/true", 5962306a36Sopenharmony_ci }; 6062306a36Sopenharmony_ci int i; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(paths); i++) { 6362306a36Sopenharmony_ci if (access(paths[i], X_OK) == 0) { 6462306a36Sopenharmony_ci ASSERT_EQ(symlink(paths[i], self->pathname), 0); 6562306a36Sopenharmony_ci return; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci ASSERT_EQ(1, 0) { 6962306a36Sopenharmony_ci TH_LOG("Could not find viable 'true' binary"); 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(file, S_IFLNK) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci .name = "S_IFLNK", 7662306a36Sopenharmony_ci .expected = ELOOP, 7762306a36Sopenharmony_ci .setup = setup_link, 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_civoid setup_dir(struct __test_metadata *_metadata, 8162306a36Sopenharmony_ci FIXTURE_DATA(file) *self, 8262306a36Sopenharmony_ci const FIXTURE_VARIANT(file) *variant) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci ASSERT_EQ(mkdir(self->pathname, 0755), 0); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(file, S_IFDIR) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci .name = "S_IFDIR", 9062306a36Sopenharmony_ci .is_dir = 1, 9162306a36Sopenharmony_ci .expected = EACCES, 9262306a36Sopenharmony_ci .setup = setup_dir, 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_civoid setup_node(struct __test_metadata *_metadata, 9662306a36Sopenharmony_ci FIXTURE_DATA(file) *self, 9762306a36Sopenharmony_ci const FIXTURE_VARIANT(file) *variant) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci dev_t dev; 10062306a36Sopenharmony_ci int rc; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci dev = makedev(variant->major, variant->minor); 10362306a36Sopenharmony_ci rc = mknod(self->pathname, 0755 | variant->mode, dev); 10462306a36Sopenharmony_ci ASSERT_EQ(rc, 0) { 10562306a36Sopenharmony_ci if (errno == EPERM) 10662306a36Sopenharmony_ci SKIP(return, "Please run as root; cannot mknod(%s)", 10762306a36Sopenharmony_ci variant->name); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(file, S_IFBLK) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci .name = "S_IFBLK", 11462306a36Sopenharmony_ci .expected = EACCES, 11562306a36Sopenharmony_ci .setup = setup_node, 11662306a36Sopenharmony_ci /* /dev/loop0 */ 11762306a36Sopenharmony_ci .major = 7, 11862306a36Sopenharmony_ci .minor = 0, 11962306a36Sopenharmony_ci .mode = S_IFBLK, 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(file, S_IFCHR) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci .name = "S_IFCHR", 12562306a36Sopenharmony_ci .expected = EACCES, 12662306a36Sopenharmony_ci .setup = setup_node, 12762306a36Sopenharmony_ci /* /dev/zero */ 12862306a36Sopenharmony_ci .major = 1, 12962306a36Sopenharmony_ci .minor = 5, 13062306a36Sopenharmony_ci .mode = S_IFCHR, 13162306a36Sopenharmony_ci}; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_civoid setup_fifo(struct __test_metadata *_metadata, 13462306a36Sopenharmony_ci FIXTURE_DATA(file) *self, 13562306a36Sopenharmony_ci const FIXTURE_VARIANT(file) *variant) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci ASSERT_EQ(mkfifo(self->pathname, 0755), 0); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ciFIXTURE_VARIANT_ADD(file, S_IFIFO) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci .name = "S_IFIFO", 14362306a36Sopenharmony_ci .expected = EACCES, 14462306a36Sopenharmony_ci .setup = setup_fifo, 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ciFIXTURE_SETUP(file) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci ASSERT_GT(asprintf(&self->pathname, "%s.test", variant->name), 6); 15062306a36Sopenharmony_ci self->is_dir = variant->is_dir; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci rm(_metadata, self->pathname, variant->is_dir); 15362306a36Sopenharmony_ci variant->setup(_metadata, self, variant); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ciFIXTURE_TEARDOWN(file) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci rm(_metadata, self->pathname, self->is_dir); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ciTEST_F(file, exec_errno) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci char * const argv[2] = { (char * const)self->pathname, NULL }; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci EXPECT_LT(execv(argv[0], argv), 0); 16662306a36Sopenharmony_ci EXPECT_EQ(errno, variant->expected); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* S_IFSOCK */ 17062306a36Sopenharmony_ciFIXTURE(sock) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci int fd; 17362306a36Sopenharmony_ci}; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ciFIXTURE_SETUP(sock) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci self->fd = socket(AF_INET, SOCK_STREAM, 0); 17862306a36Sopenharmony_ci ASSERT_GE(self->fd, 0); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ciFIXTURE_TEARDOWN(sock) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci if (self->fd >= 0) 18462306a36Sopenharmony_ci ASSERT_EQ(close(self->fd), 0); 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ciTEST_F(sock, exec_errno) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci char * const argv[2] = { " magic socket ", NULL }; 19062306a36Sopenharmony_ci char * const envp[1] = { NULL }; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci EXPECT_LT(fexecve(self->fd, argv, envp), 0); 19362306a36Sopenharmony_ci EXPECT_EQ(errno, EACCES); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ciTEST_HARNESS_MAIN 197