non-regular.c (3647B)
1// SPDX-License-Identifier: GPL-2.0+ 2#include <errno.h> 3#include <fcntl.h> 4#include <stdio.h> 5#include <string.h> 6#include <unistd.h> 7#include <sys/socket.h> 8#include <sys/stat.h> 9#include <sys/sysmacros.h> 10#include <sys/types.h> 11 12#include "../kselftest_harness.h" 13 14/* Remove a file, ignoring the result if it didn't exist. */ 15void rm(struct __test_metadata *_metadata, const char *pathname, 16 int is_dir) 17{ 18 int rc; 19 20 if (is_dir) 21 rc = rmdir(pathname); 22 else 23 rc = unlink(pathname); 24 25 if (rc < 0) { 26 ASSERT_EQ(errno, ENOENT) { 27 TH_LOG("Not ENOENT: %s", pathname); 28 } 29 } else { 30 ASSERT_EQ(rc, 0) { 31 TH_LOG("Failed to remove: %s", pathname); 32 } 33 } 34} 35 36FIXTURE(file) { 37 char *pathname; 38 int is_dir; 39}; 40 41FIXTURE_VARIANT(file) 42{ 43 const char *name; 44 int expected; 45 int is_dir; 46 void (*setup)(struct __test_metadata *_metadata, 47 FIXTURE_DATA(file) *self, 48 const FIXTURE_VARIANT(file) *variant); 49 int major, minor, mode; /* for mknod() */ 50}; 51 52void setup_link(struct __test_metadata *_metadata, 53 FIXTURE_DATA(file) *self, 54 const FIXTURE_VARIANT(file) *variant) 55{ 56 const char * const paths[] = { 57 "/bin/true", 58 "/usr/bin/true", 59 }; 60 int i; 61 62 for (i = 0; i < ARRAY_SIZE(paths); i++) { 63 if (access(paths[i], X_OK) == 0) { 64 ASSERT_EQ(symlink(paths[i], self->pathname), 0); 65 return; 66 } 67 } 68 ASSERT_EQ(1, 0) { 69 TH_LOG("Could not find viable 'true' binary"); 70 } 71} 72 73FIXTURE_VARIANT_ADD(file, S_IFLNK) 74{ 75 .name = "S_IFLNK", 76 .expected = ELOOP, 77 .setup = setup_link, 78}; 79 80void setup_dir(struct __test_metadata *_metadata, 81 FIXTURE_DATA(file) *self, 82 const FIXTURE_VARIANT(file) *variant) 83{ 84 ASSERT_EQ(mkdir(self->pathname, 0755), 0); 85} 86 87FIXTURE_VARIANT_ADD(file, S_IFDIR) 88{ 89 .name = "S_IFDIR", 90 .is_dir = 1, 91 .expected = EACCES, 92 .setup = setup_dir, 93}; 94 95void setup_node(struct __test_metadata *_metadata, 96 FIXTURE_DATA(file) *self, 97 const FIXTURE_VARIANT(file) *variant) 98{ 99 dev_t dev; 100 int rc; 101 102 dev = makedev(variant->major, variant->minor); 103 rc = mknod(self->pathname, 0755 | variant->mode, dev); 104 ASSERT_EQ(rc, 0) { 105 if (errno == EPERM) 106 SKIP(return, "Please run as root; cannot mknod(%s)", 107 variant->name); 108 } 109} 110 111FIXTURE_VARIANT_ADD(file, S_IFBLK) 112{ 113 .name = "S_IFBLK", 114 .expected = EACCES, 115 .setup = setup_node, 116 /* /dev/loop0 */ 117 .major = 7, 118 .minor = 0, 119 .mode = S_IFBLK, 120}; 121 122FIXTURE_VARIANT_ADD(file, S_IFCHR) 123{ 124 .name = "S_IFCHR", 125 .expected = EACCES, 126 .setup = setup_node, 127 /* /dev/zero */ 128 .major = 1, 129 .minor = 5, 130 .mode = S_IFCHR, 131}; 132 133void setup_fifo(struct __test_metadata *_metadata, 134 FIXTURE_DATA(file) *self, 135 const FIXTURE_VARIANT(file) *variant) 136{ 137 ASSERT_EQ(mkfifo(self->pathname, 0755), 0); 138} 139 140FIXTURE_VARIANT_ADD(file, S_IFIFO) 141{ 142 .name = "S_IFIFO", 143 .expected = EACCES, 144 .setup = setup_fifo, 145}; 146 147FIXTURE_SETUP(file) 148{ 149 ASSERT_GT(asprintf(&self->pathname, "%s.test", variant->name), 6); 150 self->is_dir = variant->is_dir; 151 152 rm(_metadata, self->pathname, variant->is_dir); 153 variant->setup(_metadata, self, variant); 154} 155 156FIXTURE_TEARDOWN(file) 157{ 158 rm(_metadata, self->pathname, self->is_dir); 159} 160 161TEST_F(file, exec_errno) 162{ 163 char * const argv[2] = { (char * const)self->pathname, NULL }; 164 165 EXPECT_LT(execv(argv[0], argv), 0); 166 EXPECT_EQ(errno, variant->expected); 167} 168 169/* S_IFSOCK */ 170FIXTURE(sock) 171{ 172 int fd; 173}; 174 175FIXTURE_SETUP(sock) 176{ 177 self->fd = socket(AF_INET, SOCK_STREAM, 0); 178 ASSERT_GE(self->fd, 0); 179} 180 181FIXTURE_TEARDOWN(sock) 182{ 183 if (self->fd >= 0) 184 ASSERT_EQ(close(self->fd), 0); 185} 186 187TEST_F(sock, exec_errno) 188{ 189 char * const argv[2] = { " magic socket ", NULL }; 190 char * const envp[1] = { NULL }; 191 192 EXPECT_LT(fexecve(self->fd, argv, envp), 0); 193 EXPECT_EQ(errno, EACCES); 194} 195 196TEST_HARNESS_MAIN