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. */ 15 void 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 36 FIXTURE(file) { 37 char *pathname; 38 int is_dir; 39 }; 40 41 FIXTURE_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 52 void 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 73 FIXTURE_VARIANT_ADD(file, S_IFLNK) 74 { 75 .name = "S_IFLNK", 76 .expected = ELOOP, 77 .setup = setup_link, 78 }; 79 80 void 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 87 FIXTURE_VARIANT_ADD(file, S_IFDIR) 88 { 89 .name = "S_IFDIR", 90 .is_dir = 1, 91 .expected = EACCES, 92 .setup = setup_dir, 93 }; 94 95 void 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 111 FIXTURE_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 122 FIXTURE_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 133 void 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 140 FIXTURE_VARIANT_ADD(file, S_IFIFO) 141 { 142 .name = "S_IFIFO", 143 .expected = EACCES, 144 .setup = setup_fifo, 145 }; 146 147 FIXTURE_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 156 FIXTURE_TEARDOWN(file) 157 { 158 rm(_metadata, self->pathname, self->is_dir); 159 } 160 161 TEST_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 */ 170 FIXTURE(sock) 171 { 172 int fd; 173 }; 174 175 FIXTURE_SETUP(sock) 176 { 177 self->fd = socket(AF_INET, SOCK_STREAM, 0); 178 ASSERT_GE(self->fd, 0); 179 } 180 181 FIXTURE_TEARDOWN(sock) 182 { 183 if (self->fd >= 0) 184 ASSERT_EQ(close(self->fd), 0); 185 } 186 187 TEST_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 196 TEST_HARNESS_MAIN 197