Serenity Operating System
at portability 326 lines 11 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/Assertions.h> 28#include <AK/Types.h> 29#include <fcntl.h> 30#include <stdio.h> 31#include <string.h> 32#include <sys/mman.h> 33#include <sys/stat.h> 34#include <sys/uio.h> 35#include <unistd.h> 36 37#define EXPECT_ERROR_2(err, syscall, arg1, arg2) \ 38 do { \ 39 rc = syscall(arg1, arg2); \ 40 if (rc >= 0 || errno != err) { \ 41 fprintf(stderr, __FILE__ ":%d: Expected " #err ": " #syscall "(%p, %p), got rc=%d, errno=%d\n", __LINE__, (const void*)(arg1), (const void*)arg2, rc, errno); \ 42 } \ 43 } while (0) 44 45#define EXPECT_ERROR_3(err, syscall, arg1, arg2, arg3) \ 46 do { \ 47 rc = syscall(arg1, arg2, arg3); \ 48 if (rc >= 0 || errno != err) { \ 49 fprintf(stderr, __FILE__ ":%d: Expected " #err ": " #syscall "(%p, %p, %p), got rc=%d, errno=%d\n", __LINE__, (const void*)(arg1), (const void*)(arg2), (const void*)(arg3), rc, errno); \ 50 } \ 51 } while (0) 52 53void test_read_from_directory() 54{ 55 char buffer[BUFSIZ]; 56 int fd = open("/", O_DIRECTORY | O_RDONLY); 57 ASSERT(fd >= 0); 58 int rc; 59 EXPECT_ERROR_3(EISDIR, read, fd, buffer, sizeof(buffer)); 60 rc = close(fd); 61 ASSERT(rc == 0); 62} 63 64void test_write_to_directory() 65{ 66 char str[] = "oh frick"; 67 int fd = open("/", O_DIRECTORY | O_RDONLY); 68 if (fd < 0) 69 perror("open"); 70 ASSERT(fd >= 0); 71 int rc; 72 EXPECT_ERROR_3(EBADF, write, fd, str, sizeof(str)); 73 rc = close(fd); 74 ASSERT(rc == 0); 75} 76 77void test_read_from_writeonly() 78{ 79 char buffer[BUFSIZ]; 80 int fd = open("/tmp/xxxx123", O_CREAT | O_WRONLY); 81 ASSERT(fd >= 0); 82 int rc; 83 EXPECT_ERROR_3(EBADF, read, fd, buffer, sizeof(buffer)); 84 rc = close(fd); 85 ASSERT(rc == 0); 86} 87 88void test_write_to_readonly() 89{ 90 char str[] = "hello"; 91 int fd = open("/tmp/abcd123", O_CREAT | O_RDONLY); 92 ASSERT(fd >= 0); 93 int rc; 94 EXPECT_ERROR_3(EBADF, write, fd, str, sizeof(str)); 95 rc = close(fd); 96 ASSERT(rc == 0); 97} 98 99void test_read_past_eof() 100{ 101 char buffer[BUFSIZ]; 102 int fd = open("/home/anon/myfile.txt", O_RDONLY); 103 if (fd < 0) 104 perror("open"); 105 ASSERT(fd >= 0); 106 int rc; 107 rc = lseek(fd, 9999, SEEK_SET); 108 if (rc < 0) 109 perror("lseek"); 110 rc = read(fd, buffer, sizeof(buffer)); 111 if (rc < 0) 112 perror("read"); 113 if (rc > 0) 114 fprintf(stderr, "read %d bytes past EOF\n", rc); 115 rc = close(fd); 116 ASSERT(rc == 0); 117} 118 119void test_ftruncate_readonly() 120{ 121 int fd = open("/tmp/trunctest", O_RDONLY | O_CREAT, 0666); 122 ASSERT(fd >= 0); 123 int rc; 124 EXPECT_ERROR_2(EBADF, ftruncate, fd, 0); 125 close(fd); 126} 127 128void test_ftruncate_negative() 129{ 130 int fd = open("/tmp/trunctest", O_RDWR | O_CREAT, 0666); 131 ASSERT(fd >= 0); 132 int rc; 133 EXPECT_ERROR_2(EINVAL, ftruncate, fd, -1); 134 close(fd); 135} 136 137void test_mmap_directory() 138{ 139 int fd = open("/tmp", O_RDONLY | O_DIRECTORY); 140 ASSERT(fd >= 0); 141 auto* ptr = mmap(nullptr, 4096, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); 142 if (ptr != MAP_FAILED) { 143 fprintf(stderr, "Boo! mmap() of a directory succeeded!\n"); 144 return; 145 } 146 if (errno != ENODEV) { 147 fprintf(stderr, "Boo! mmap() of a directory gave errno=%d instead of ENODEV!\n", errno); 148 return; 149 } 150 close(fd); 151} 152 153void test_tmpfs_read_past_end() 154{ 155 int fd = open("/tmp/x", O_RDWR | O_CREAT | O_TRUNC, 0600); 156 ASSERT(fd >= 0); 157 158 int rc = ftruncate(fd, 1); 159 ASSERT(rc == 0); 160 161 rc = lseek(fd, 4096, SEEK_SET); 162 ASSERT(rc == 4096); 163 164 char buffer[16]; 165 int nread = read(fd, buffer, sizeof(buffer)); 166 if (nread != 0) { 167 fprintf(stderr, "Expected 0-length read past end of file in /tmp\n"); 168 } 169 close(fd); 170} 171 172void test_procfs_read_past_end() 173{ 174 int fd = open("/proc/uptime", O_RDONLY); 175 ASSERT(fd >= 0); 176 177 int rc = lseek(fd, 4096, SEEK_SET); 178 ASSERT(rc == 4096); 179 180 char buffer[16]; 181 int nread = read(fd, buffer, sizeof(buffer)); 182 if (nread != 0) { 183 fprintf(stderr, "Expected 0-length read past end of file in /proc\n"); 184 } 185 close(fd); 186} 187 188void test_open_create_device() 189{ 190 int fd = open("/tmp/fakedevice", (O_RDWR | O_CREAT), (S_IFCHR | 0600)); 191 ASSERT(fd >= 0); 192 193 struct stat st; 194 if (fstat(fd, &st) < 0) { 195 perror("stat"); 196 ASSERT_NOT_REACHED(); 197 } 198 199 if (st.st_mode != 0100600) { 200 fprintf(stderr, "Expected mode 0100600 after attempt to create a device node with open(O_CREAT), mode=%o\n", st.st_mode); 201 } 202 unlink("/tmp/fakedevice"); 203 close(fd); 204} 205 206void test_unlink_symlink() 207{ 208 int rc = symlink("/proc/2/foo", "/tmp/linky"); 209 if (rc < 0) { 210 perror("symlink"); 211 ASSERT_NOT_REACHED(); 212 } 213 214 char buffer[PATH_MAX]; 215 rc = readlink("/tmp/linky", buffer, sizeof(buffer)); 216 ASSERT(rc == strlen("/proc/2/foo") + 1); 217 218 rc = unlink("/tmp/linky"); 219 if (rc < 0) { 220 perror("unlink"); 221 fprintf(stderr, "Expected unlink() of a symlink into an unreadable directory to succeed!\n"); 222 } 223} 224 225void test_eoverflow() 226{ 227 int fd = open("/tmp/x", O_RDWR); 228 ASSERT(fd >= 0); 229 230 int rc = lseek(fd, INT32_MAX, SEEK_SET); 231 ASSERT(rc == INT32_MAX); 232 233 char buffer[16]; 234 rc = read(fd, buffer, sizeof(buffer)); 235 if (rc >= 0 || errno != EOVERFLOW) { 236 fprintf(stderr, "Expected EOVERFLOW when trying to read past INT32_MAX\n"); 237 } 238 rc = write(fd, buffer, sizeof(buffer)); 239 if (rc >= 0 || errno != EOVERFLOW) { 240 fprintf(stderr, "Expected EOVERFLOW when trying to write past INT32_MAX\n"); 241 } 242 close(fd); 243} 244 245void test_rmdir_while_inside_dir() 246{ 247 int rc = mkdir("/home/anon/testdir", 0700); 248 ASSERT(rc == 0); 249 250 rc = chdir("/home/anon/testdir"); 251 ASSERT(rc == 0); 252 253 rc = rmdir("/home/anon/testdir"); 254 ASSERT(rc == 0); 255 256 int fd = open("x", O_CREAT | O_RDWR, 0600); 257 if (fd >= 0 || errno != ENOENT) { 258 fprintf(stderr, "Expected ENOENT when trying to create a file inside a deleted directory. Got %d with errno=%d\n", fd, errno); 259 } 260 261 rc = chdir("/home/anon"); 262 ASSERT(rc == 0); 263} 264 265void test_writev() 266{ 267 int pipefds[2]; 268 pipe(pipefds); 269 270 iovec iov[2]; 271 iov[0].iov_base = const_cast<void*>((const void*)"Hello"); 272 iov[0].iov_len = 5; 273 iov[1].iov_base = const_cast<void*>((const void*)"Friends"); 274 iov[1].iov_len = 7; 275 int nwritten = writev(pipefds[1], iov, 2); 276 if (nwritten < 0) { 277 perror("writev"); 278 ASSERT_NOT_REACHED(); 279 } 280 if (nwritten != 12) { 281 fprintf(stderr, "Didn't write 12 bytes to pipe with writev\n"); 282 ASSERT_NOT_REACHED(); 283 } 284 285 char buffer[32]; 286 int nread = read(pipefds[0], buffer, sizeof(buffer)); 287 if (nread != 12 || memcmp(buffer, "HelloFriends", 12)) { 288 fprintf(stderr, "Didn't read the expected data from pipe after writev\n"); 289 ASSERT_NOT_REACHED(); 290 } 291 292 close(pipefds[0]); 293 close(pipefds[1]); 294} 295 296int main(int, char**) 297{ 298 int rc; 299 EXPECT_ERROR_2(ENOTDIR, open, "/dev/zero", (O_DIRECTORY | O_RDONLY)); 300 EXPECT_ERROR_2(EINVAL, open, "/dev/zero", (O_DIRECTORY | O_CREAT | O_RDWR)); 301 EXPECT_ERROR_2(EEXIST, open, "/dev/zero", (O_CREAT | O_EXCL | O_RDWR)); 302 EXPECT_ERROR_2(EINVAL, open, "/tmp/abcdef", (O_DIRECTORY | O_CREAT | O_RDWR)); 303 EXPECT_ERROR_2(EACCES, open, "/proc/all", (O_RDWR)); 304 EXPECT_ERROR_2(ENOENT, open, "/boof/baaf/nonexistent", (O_CREAT | O_RDWR)); 305 EXPECT_ERROR_2(EISDIR, open, "/tmp", (O_DIRECTORY | O_RDWR)); 306 307 test_read_from_directory(); 308 test_write_to_directory(); 309 test_read_from_writeonly(); 310 test_write_to_readonly(); 311 test_read_past_eof(); 312 test_ftruncate_readonly(); 313 test_ftruncate_negative(); 314 test_mmap_directory(); 315 test_tmpfs_read_past_end(); 316 test_procfs_read_past_end(); 317 test_open_create_device(); 318 test_unlink_symlink(); 319 test_eoverflow(); 320 test_rmdir_while_inside_dir(); 321 test_writev(); 322 323 EXPECT_ERROR_2(EPERM, link, "/", "/home/anon/lolroot"); 324 325 return 0; 326}