1 /* $OpenBSD: syscalls.c,v 1.37 2024/09/03 04:59:03 anton Exp $ */ 2 3 /* 4 * Copyright (c) 2017-2019 Bob Beck <beck@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <stdio.h> 20 #include <unistd.h> 21 #include <dirent.h> 22 #include <fcntl.h> 23 #include <sys/mount.h> 24 25 #include "unveil.h" 26 27 /* all the things unless we override */ 28 const char *uv_flags = "rwxc"; 29 30 static void 31 do_unveil(void) 32 { 33 if (unveil(uv_dir1, uv_flags) == -1) 34 err(1, "%s:%d - unveil", __FILE__, __LINE__); 35 if (unveil(uv_file1, uv_flags) == -1) 36 err(1, "%s:%d - unveil", __FILE__, __LINE__); 37 } 38 39 static void 40 do_unveil2(void) 41 { 42 if (unveil(uv_dir1, uv_flags) == -1) 43 err(1, "%s:%d - unveil", __FILE__, __LINE__); 44 } 45 46 static int 47 test_openat(int do_uv) 48 { 49 int slashbefore; 50 int dirfd1before; 51 int dirfd2before; 52 int dirfd1after; 53 int dirfd2after; 54 UV_SHOULD_SUCCEED(((slashbefore = open("/", O_RDONLY | O_DIRECTORY)) == -1), "open"); 55 UV_SHOULD_SUCCEED(((dirfd1before = open(uv_dir1, O_RDONLY | O_DIRECTORY)) == -1), "open"); 56 UV_SHOULD_SUCCEED(((dirfd2before = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open"); 57 if (do_uv) { 58 printf("testing openat\n"); 59 do_unveil(); 60 } 61 UV_SHOULD_SUCCEED(((dirfd1after = open(uv_dir1, O_RDONLY | O_DIRECTORY)) == -1), "open"); 62 UV_SHOULD_ENOENT(((dirfd2after = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open"); 63 64 UV_SHOULD_ENOENT((openat(slashbefore, "etc/hosts", O_RDONLY) == -1), "openat"); 65 UV_SHOULD_SUCCEED((openat(slashbefore, uv_file1, O_RDWR) == -1), "openat"); 66 UV_SHOULD_ENOENT((openat(slashbefore, uv_file2, O_RDWR) == -1), "openat"); 67 68 UV_SHOULD_ENOENT((openat(dirfd1before, "/etc/hosts", O_RDONLY) == -1), "openat"); 69 UV_SHOULD_SUCCEED((openat(dirfd1before, "hooray", O_RDWR|O_CREAT, 0644) == -1), "openat"); 70 UV_SHOULD_SUCCEED((openat(dirfd1before, uv_file1, O_RDWR|O_CREAT, 0644) == -1), "openat"); 71 UV_SHOULD_ENOENT((openat(dirfd1before, uv_file2, O_RDWR|O_CREAT, 0644) == -1), "openat"); 72 73 UV_SHOULD_ENOENT((openat(dirfd2before, "/etc/hosts", O_RDONLY) == -1), "openat"); 74 UV_SHOULD_ENOENT((openat(dirfd2before, "hooray", O_RDWR|O_CREAT, 0644) == -1), "openat"); 75 UV_SHOULD_SUCCEED((openat(dirfd2before, uv_file1, O_RDWR|O_CREAT, 0644) == -1), "openat"); 76 UV_SHOULD_ENOENT((openat(dirfd2before, uv_file2, O_RDWR|O_CREAT, 0644) == -1), "openat"); 77 78 UV_SHOULD_ENOENT((openat(dirfd1after, "/etc/hosts", O_RDONLY) == -1), "openat"); 79 UV_SHOULD_SUCCEED((openat(dirfd1after, "hooray", O_RDWR|O_CREAT, 0644) == -1), "openat"); 80 UV_SHOULD_SUCCEED((openat(dirfd1after, uv_file1, O_RDWR|O_CREAT, 0644) == -1), "openat"); 81 UV_SHOULD_ENOENT((openat(dirfd1after, uv_file2, O_RDWR|O_CREAT, 0644) == -1), "openat"); 82 83 UV_SHOULD_SUCCEED(((dirfd2after = openat(dirfd1after, "subdir", O_RDONLY | O_DIRECTORY)) == -1), "openat"); 84 UV_SHOULD_SUCCEED((openat(dirfd2after, "../derp", O_RDWR|O_CREAT, 0644) == -1), "openat"); 85 UV_SHOULD_ENOENT((openat(dirfd2after, "../../derpyluvs", O_RDWR|O_CREAT, 0644) == -1), "openat"); 86 UV_SHOULD_ENOENT((openat(dirfd2after, "/etc/hosts", O_RDONLY) == -1), "openat"); 87 UV_SHOULD_SUCCEED((openat(dirfd2after, "hooray", O_RDWR|O_CREAT, 0644) == -1), "openat"); 88 UV_SHOULD_SUCCEED((openat(dirfd2after, uv_file1, O_RDWR|O_CREAT, 0644) == -1), "openat"); 89 UV_SHOULD_ENOENT((openat(dirfd2after, uv_file2, O_RDWR|O_CREAT, 0644) == -1), "openat"); 90 return 0; 91 } 92 93 94 95 static int 96 test_open(int do_uv) 97 { 98 char filename[256]; 99 int dirfd; 100 int dirfd2; 101 int dirfd3; 102 103 104 UV_SHOULD_SUCCEED(((dirfd = open("/", O_RDONLY | O_DIRECTORY)) == -1), "open"); 105 UV_SHOULD_SUCCEED(((dirfd2 = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open"); 106 if (do_uv) { 107 printf("testing open\n"); 108 do_unveil(); 109 if (unveil("/tmp/alpha", uv_flags) == -1) 110 err(1, "%s:%d - unveil", __FILE__, __LINE__); 111 if (unveil("/tmp/bravo", uv_flags) == -1) 112 err(1, "%s:%d - unveil", __FILE__, __LINE__); 113 if (unveil("/tmp/charlie", uv_flags) == -1) 114 err(1, "%s:%d - unveil", __FILE__, __LINE__); 115 if (unveil("/tmp/delta", uv_flags) == -1) 116 err(1, "%s:%d - unveil", __FILE__, __LINE__); 117 if (unveil("/tmp/echo", uv_flags) == -1) 118 err(1, "%s:%d - unveil", __FILE__, __LINE__); 119 if (unveil("/tmp/foxtrot", uv_flags) == -1) 120 err(1, "%s:%d - unveil", __FILE__, __LINE__); 121 if (unveil("/tmp/golf", uv_flags) == -1) 122 err(1, "%s:%d - unveil", __FILE__, __LINE__); 123 if (unveil("/tmp/hotel", uv_flags) == -1) 124 err(1, "%s:%d - unveil", __FILE__, __LINE__); 125 if (unveil("/tmp/india", uv_flags) == -1) 126 err(1, "%s:%d - unveil", __FILE__, __LINE__); 127 if (unveil("/tmp/juliet", uv_flags) == -1) 128 err(1, "%s:%d - unveil", __FILE__, __LINE__); 129 if (unveil("/tmp/kilo", uv_flags) == -1) 130 err(1, "%s:%d - unveil", __FILE__, __LINE__); 131 if (unveil("/tmp/lima", uv_flags) == -1) 132 err(1, "%s:%d - unveil", __FILE__, __LINE__); 133 if (unveil("/tmp/money", uv_flags) == -1) 134 err(1, "%s:%d - unveil", __FILE__, __LINE__); 135 if (unveil("/tmp/november", uv_flags) == -1) 136 err(1, "%s:%d - unveil", __FILE__, __LINE__); 137 if (unveil("/tmp/oscar", uv_flags) == -1) 138 err(1, "%s:%d - unveil", __FILE__, __LINE__); 139 if (unveil("/tmp/papa", uv_flags) == -1) 140 err(1, "%s:%d - unveil", __FILE__, __LINE__); 141 if (unveil("/tmp/quebec", uv_flags) == -1) 142 err(1, "%s:%d - unveil", __FILE__, __LINE__); 143 if (unveil("/tmp/romeo", uv_flags) == -1) 144 err(1, "%s:%d - unveil", __FILE__, __LINE__); 145 if (unveil("/tmp/sierra", uv_flags) == -1) 146 err(1, "%s:%d - unveil", __FILE__, __LINE__); 147 if (unveil("/tmp/tango", uv_flags) == -1) 148 err(1, "%s:%d - unveil", __FILE__, __LINE__); 149 if (unveil("/tmp/uniform", uv_flags) == -1) 150 err(1, "%s:%d - unveil", __FILE__, __LINE__); 151 if (unveil("/tmp/victor", uv_flags) == -1) 152 err(1, "%s:%d - unveil", __FILE__, __LINE__); 153 if (unveil("/tmp/whiskey", uv_flags) == -1) 154 err(1, "%s:%d - unveil", __FILE__, __LINE__); 155 if (unveil("/tmp/xray", uv_flags) == -1) 156 err(1, "%s:%d - unveil", __FILE__, __LINE__); 157 if (unveil("/tmp/yankee", uv_flags) == -1) 158 err(1, "%s:%d - unveil", __FILE__, __LINE__); 159 if (unveil("/tmp/zulu", uv_flags) == -1) 160 err(1, "%s:%d - unveil", __FILE__, __LINE__); 161 } 162 UV_SHOULD_SUCCEED((pledge("unveil stdio rpath cpath wpath exec", NULL) == -1), "pledge"); 163 164 UV_SHOULD_ENOENT((open(uv_file2, O_RDWR) == -1), "open"); 165 UV_SHOULD_ENOENT(((dirfd3= open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open"); 166 167 UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open"); 168 if (!do_uv) { 169 /* Unlink the unveiled file and make it again */ 170 UV_SHOULD_SUCCEED((unlink(uv_file1) == -1), "unlink"); 171 UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR|O_CREAT, 0644) == -1), "open"); 172 } 173 sleep(1); 174 UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open"); 175 UV_SHOULD_ENOENT((open(uv_file2, O_RDWR) == -1), "open"); 176 (void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir1, "newfile"); 177 UV_SHOULD_SUCCEED((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open"); 178 (void) snprintf(filename, sizeof(filename), "/%s/%s", uv_dir1, "doubleslash"); 179 UV_SHOULD_SUCCEED((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open"); 180 (void) snprintf(filename, sizeof(filename), "/%s//%s", uv_dir1, "doubleslash2"); 181 UV_SHOULD_SUCCEED((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open"); 182 183 (void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir2, "newfile"); 184 UV_SHOULD_ENOENT((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open"); 185 186 if (do_uv) { 187 printf("testing flag escalation\n"); 188 if (unveil(uv_file1, "x") == -1) 189 err(1, "%s:%d - unveil", __FILE__, __LINE__); 190 if (unveil(uv_file1, "rx") == -1) 191 if (errno != EPERM) 192 err(1, "%s:%d - unveil", __FILE__, 193 __LINE__); 194 } 195 return 0; 196 } 197 198 static int 199 test_opendir(int do_uv) 200 { 201 char filename[256]; 202 if (do_uv) { 203 printf("testing opendir\n"); 204 do_unveil(); 205 } 206 UV_SHOULD_SUCCEED((opendir(uv_dir1) == NULL), "opendir"); 207 UV_SHOULD_ENOENT((opendir(uv_dir2) == NULL), "opendir"); 208 (void) snprintf(filename, sizeof(filename), "/%s/.", uv_dir1); 209 UV_SHOULD_SUCCEED((opendir(filename) == NULL), "opendir"); 210 (void) snprintf(filename, sizeof(filename), "/%s/..", uv_dir1); 211 UV_SHOULD_ENOENT((opendir(filename) == NULL), "opendir"); 212 (void) snprintf(filename, sizeof(filename), "/%s/subdir", uv_dir1); 213 UV_SHOULD_SUCCEED((opendir(filename) == NULL), "opendir"); 214 (void) snprintf(filename, sizeof(filename), "/%s/subdir/../subdir", uv_dir1); 215 UV_SHOULD_SUCCEED((opendir(filename) == NULL), "opendir"); 216 (void) snprintf(filename, sizeof(filename), "/%s/../../%s/subdir", uv_dir1, uv_dir1); 217 UV_SHOULD_SUCCEED((opendir(filename) == NULL), "opendir"); 218 (void) snprintf(filename, sizeof(filename), "/%s/subdir", uv_dir2); 219 UV_SHOULD_ENOENT((opendir(filename) == NULL), "opendir"); 220 UV_SHOULD_ENOENT((opendir(filename) == NULL), "opendir"); 221 (void) snprintf(filename, sizeof(filename), "%s/../..%s/subdir", uv_dir1, uv_dir2); 222 UV_SHOULD_ENOENT((opendir(filename) == NULL), "opendir"); 223 return 0; 224 } 225 226 static int 227 test_realpath(int do_uv) 228 { 229 char buf[PATH_MAX]; 230 if (do_uv) { 231 printf("testing realpath\n"); 232 do_unveil(); 233 } 234 UV_SHOULD_SUCCEED((realpath(uv_dir1, buf) == NULL), "realpath"); 235 UV_SHOULD_ENOENT((realpath(uv_dir2, buf) == NULL), "realpath"); 236 return 0; 237 } 238 239 static int 240 test_r(int do_uv) 241 { 242 if (do_uv) { 243 printf("testing \"r\"\n"); 244 if (unveil(uv_file1, "r") == -1) 245 err(1, "%s:%d - unveil", __FILE__, __LINE__); 246 if (unveil("/", "") == -1) 247 err(1, "%s:%d - unveil", __FILE__, __LINE__); 248 } 249 UV_SHOULD_SUCCEED((open(uv_file1, O_RDONLY) == -1), "open"); 250 UV_SHOULD_EACCES((open(uv_file1, O_RDWR) == -1), "open"); 251 return 0; 252 } 253 254 static int 255 test_rw(int do_uv) 256 { 257 if (do_uv) { 258 printf("testing \"rw\"\n"); 259 if (unveil(uv_file1, "rw") == -1) 260 err(1, "%s:%d - unveil", __FILE__, __LINE__); 261 if (unveil("/", "") == -1) 262 err(1, "%s:%d - unveil", __FILE__, __LINE__); 263 } 264 UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open"); 265 UV_SHOULD_SUCCEED((open(uv_file1, O_RDONLY) == -1), "open"); 266 return 0; 267 } 268 269 static int 270 test_x(int do_uv) 271 { 272 struct stat sb; 273 if (do_uv) { 274 printf("testing \"x\"\n"); 275 if (unveil(uv_file1, "x") == -1) 276 err(1, "%s:%d - unveil", __FILE__, __LINE__); 277 if (unveil("/", "") == -1) 278 err(1, "%s:%d - unveil", __FILE__, __LINE__); 279 } 280 UV_SHOULD_EACCES((lstat(uv_file1, &sb) == -1), "lstat"); 281 UV_SHOULD_EACCES((open(uv_file1, O_RDONLY) == -1), "open"); 282 UV_SHOULD_EACCES((open(uv_file1, O_RDONLY) == -1), "open"); 283 UV_SHOULD_ENOENT((open(uv_file2, O_RDWR) == -1), "open"); 284 return 0; 285 } 286 287 static int 288 test_noflags(int do_uv) 289 { 290 char filename[256]; 291 292 if (do_uv) { 293 printf("testing clearing flags\n"); 294 do_unveil(); 295 } 296 297 UV_SHOULD_SUCCEED((pledge("unveil stdio rpath cpath wpath exec", NULL) == -1), "pledge"); 298 UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open"); 299 if (do_uv) { 300 if (unveil(uv_dir1, "") == -1) 301 err(1, "%s:%d - unveil", __FILE__, __LINE__); 302 } 303 (void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir1, "noflagsiamboned"); 304 UV_SHOULD_ENOENT((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open"); 305 UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open"); 306 return 0; 307 } 308 309 310 static int 311 test_drounveil(int do_uv) 312 { 313 if (do_uv) { 314 printf("(testing unveil after pledge)\n"); 315 do_unveil(); 316 } 317 318 UV_SHOULD_SUCCEED((pledge("unveil stdio rpath cpath wpath exec", NULL) == -1), "pledge"); 319 320 if (do_uv) { 321 do_unveil(); 322 } 323 UV_SHOULD_SUCCEED((pledge("stdio rpath cpath wpath", NULL) == -1), "pledge"); 324 325 UV_SHOULD_ENOENT((open(uv_file2, O_RDWR) == -1), "open"); 326 UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR) == -1), "open"); 327 return 0; 328 } 329 330 static int 331 test_unlink(int do_uv) 332 { 333 char filename1[256]; 334 char filename2[256]; 335 char filename3[] = "/tmp/nukeme.XXXXXX"; 336 int fd; 337 338 (void) snprintf(filename1, sizeof(filename1), "%s/%s", uv_dir1, 339 "nukeme"); 340 (void) snprintf(filename2, sizeof(filename2), "%s/%s", uv_dir2, 341 "nukeme"); 342 UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open"); 343 UV_SHOULD_SUCCEED((open(filename2, O_RDWR|O_CREAT, 0644) == -1), "open"); 344 if ((fd = mkstemp(filename3)) == -1) 345 err(1, "%s:%d - mkstemp", __FILE__, __LINE__); 346 if (do_uv) { 347 printf("testing unlink\n"); 348 do_unveil(); 349 if (unveil(filename3, "rw") == -1) 350 err(1, "%s:%d - unveil", __FILE__, __LINE__); 351 } 352 353 UV_SHOULD_SUCCEED((pledge("unveil stdio fattr rpath cpath wpath", NULL) == -1), 354 "pledge"); 355 UV_SHOULD_SUCCEED((unlink(filename1) == -1), "unlink"); 356 UV_SHOULD_ENOENT((unlink(filename2) == -1), "unlink"); 357 UV_SHOULD_EACCES((unlink(filename3) == -1), "unlink"); 358 return 0; 359 } 360 361 static int 362 test_link(int do_uv) 363 { 364 char filename[256]; 365 char filename2[256]; 366 367 if (do_uv) { 368 printf("testing link\n"); 369 do_unveil(); 370 } 371 372 UV_SHOULD_SUCCEED((pledge("unveil stdio fattr rpath cpath wpath", NULL) == -1), 373 "pledge"); 374 (void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir1, 375 "linkuv1"); 376 (void) snprintf(filename2, sizeof(filename2), "%s/%s", uv_dir2, 377 "linkuv2"); 378 unlink(filename); 379 unlink(filename2); 380 UV_SHOULD_SUCCEED((link(uv_file1, filename) == -1), "link"); 381 unlink(filename); 382 UV_SHOULD_ENOENT((link(uv_file2, filename) == -1), "link"); 383 UV_SHOULD_ENOENT((link(uv_file1, filename2) == -1), "link"); 384 if (do_uv) { 385 printf("testing link without O_CREAT\n"); 386 if (unveil(filename, "rw") == -1) 387 err(1, "%s:%d - unveil", __FILE__, __LINE__); 388 389 } 390 UV_SHOULD_EACCES((link(uv_file1, filename) == -1), "link"); 391 unlink(filename); 392 393 return 0; 394 } 395 396 397 static int 398 test_chdir(int do_uv) 399 { 400 if (do_uv) { 401 printf("testing chdir\n"); 402 do_unveil2(); 403 } 404 405 UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge"); 406 UV_SHOULD_ENOENT((chdir(uv_dir2) == -1), "chdir"); 407 UV_SHOULD_SUCCEED((chdir(uv_dir1) == -1), "chdir"); 408 UV_SHOULD_ENOENT((chdir(uv_dir2) == -1), "chdir"); 409 410 return 0; 411 } 412 413 static int 414 test_parent_dir(int do_uv) 415 { 416 char filename[255]; 417 if (do_uv) { 418 printf("testing parent dir\n"); 419 do_unveil2(); 420 } else { 421 (void) snprintf(filename, sizeof(filename), "/%s/doof", uv_dir1); 422 UV_SHOULD_SUCCEED((mkdir(filename, 0777) == -1), "mkdir"); 423 (void) snprintf(filename, sizeof(filename), "/%s/doof/subdir2", uv_dir1); 424 UV_SHOULD_SUCCEED((mkdir(filename, 0777) == -1), "mkdir"); 425 (void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1", uv_dir1); 426 UV_SHOULD_SUCCEED((mkdir(filename, 0777) == -1), "mkdir"); 427 (void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1/poop", uv_dir1); 428 UV_SHOULD_SUCCEED((open(filename, O_RDWR|O_CREAT, 0644) == -1), "open"); 429 (void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1/link", uv_dir1); 430 UV_SHOULD_SUCCEED((symlink("../subdir1/poop", filename) == -1), "symlink"); 431 } 432 sleep(1); 433 (void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1/link", uv_dir1); 434 UV_SHOULD_SUCCEED((access(filename, R_OK) == -1), "access"); 435 (void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1/poop", uv_dir1); 436 UV_SHOULD_SUCCEED((access(filename, R_OK) == -1), "access"); 437 UV_SHOULD_SUCCEED((chdir(uv_dir1) == -1), "chdir"); 438 (void) snprintf(filename, sizeof(filename), "/%s/doof/subdir1", uv_dir1); 439 UV_SHOULD_SUCCEED((chdir(filename) == -1), "chdir"); 440 UV_SHOULD_SUCCEED((access("poop", R_OK) == -1), "access"); 441 UV_SHOULD_SUCCEED((chdir("../subdir2") == -1), "chdir"); 442 UV_SHOULD_SUCCEED((chdir("../subdir1") == -1), "chdir"); 443 UV_SHOULD_SUCCEED((chdir(filename) == -1), "chdir"); 444 UV_SHOULD_SUCCEED((chdir("../../doof/subdir2") == -1), "chdir"); 445 UV_SHOULD_SUCCEED((chdir("../../doof/subdir1") == -1), "chdir"); 446 UV_SHOULD_SUCCEED((chdir("../../doof/subdir2") == -1), "chdir"); 447 UV_SHOULD_SUCCEED((chdir("../../doof/subdir1") == -1), "chdir"); 448 UV_SHOULD_SUCCEED((access("poop", R_OK) == -1), "access"); 449 UV_SHOULD_SUCCEED((access("../subdir1/poop", R_OK) == -1), "access"); 450 UV_SHOULD_ENOENT((chdir("../../..") == -1), "chdir"); 451 UV_SHOULD_ENOENT((chdir(uv_dir2) == -1), "chdir"); 452 return(0); 453 } 454 455 static int 456 test_rename(int do_uv) 457 { 458 char filename1[256]; 459 char filename2[256]; 460 char rfilename1[256]; 461 char rfilename2[256]; 462 int dirfd1, dirfd2; 463 464 if ((dirfd1 = open(uv_dir1, O_RDONLY | O_DIRECTORY)) == -1) 465 err(1, "%s:%d - open of dir1", __FILE__, __LINE__); 466 if ((dirfd2 = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1) 467 err(1, "%s:%d - open of dir2", __FILE__, __LINE__); 468 (void) snprintf(filename1, sizeof(filename1), "%s/%s", uv_dir1, 469 "file1"); 470 UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open"); 471 (void) snprintf(filename2, sizeof(filename2), "%s/%s", uv_dir2, 472 "file2"); 473 UV_SHOULD_SUCCEED((open(filename2, O_RDWR|O_CREAT, 0644) == -1), "open"); 474 (void) snprintf(rfilename1, sizeof(rfilename1), "%s/%s", uv_dir1, 475 "rfile1"); 476 (void) snprintf(rfilename2, sizeof(rfilename2), "%s/%s", uv_dir2, 477 "rfile2"); 478 if (do_uv) { 479 printf("testing rename\n"); 480 do_unveil(); 481 } 482 483 UV_SHOULD_SUCCEED((pledge("stdio fattr rpath wpath cpath", NULL) == -1), 484 "pledge"); 485 UV_SHOULD_SUCCEED((rename(filename1, rfilename1) == -1), "rename"); 486 UV_SHOULD_ENOENT((rename(filename2, rfilename2) == -1), "rename"); 487 UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open"); 488 UV_SHOULD_ENOENT((rename(filename1, rfilename2) == -1), "rename"); 489 UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open"); 490 UV_SHOULD_ENOENT((rename(filename1, uv_file2) == -1), "rename"); 491 UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open"); 492 UV_SHOULD_ENOENT((renameat(dirfd1, "file1", dirfd2, "rfile2") == -1), 493 "renameat"); 494 UV_SHOULD_SUCCEED((open(filename1, O_RDWR|O_CREAT, 0644) == -1), "open"); 495 UV_SHOULD_ENOENT((renameat(dirfd1, "file1", dirfd2, rfilename2) == -1), 496 "renameat"); 497 498 return (0); 499 } 500 501 502 static int 503 test_access(int do_uv) 504 { 505 if (do_uv) { 506 printf("testing access\n"); 507 do_unveil(); 508 } 509 510 UV_SHOULD_SUCCEED((access(uv_file1, R_OK) == -1), "access"); 511 UV_SHOULD_ENOENT((access(uv_file2, R_OK) == -1), "access"); 512 UV_SHOULD_ENOENT((access("/etc/passwd", R_OK) == -1), "access"); 513 UV_SHOULD_SUCCEED((access(uv_dir1, R_OK) == -1), "access"); 514 UV_SHOULD_ENOENT((access(uv_dir2, R_OK) == -1), "access"); 515 UV_SHOULD_ENOENT((access("/", R_OK) == -1), "access"); 516 UV_SHOULD_ENOENT((access("/home", F_OK) == -1), "access"); 517 518 UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge"); 519 UV_SHOULD_SUCCEED((access(uv_file1, R_OK) == -1), "access"); 520 UV_SHOULD_ENOENT((access(uv_file2, R_OK) == -1), "access"); 521 UV_SHOULD_SUCCEED((access(uv_dir1, R_OK) == -1), "access"); 522 UV_SHOULD_ENOENT((access(uv_dir2, R_OK) == -1), "access"); 523 UV_SHOULD_ENOENT((access("/", R_OK) == -1), "access"); 524 UV_SHOULD_ENOENT((access("/home", F_OK) == -1), "access"); 525 526 return 0; 527 } 528 529 static int 530 test_chflags(int do_uv) 531 { 532 if (do_uv) { 533 printf("testing chflags\n"); 534 do_unveil(); 535 } 536 537 UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge"); 538 UV_SHOULD_SUCCEED((chflags(uv_file1, UF_NODUMP) == -1), "chflags"); 539 UV_SHOULD_ENOENT((chflags(uv_file2, UF_NODUMP) == -1), "chflags"); 540 541 return 0; 542 } 543 544 static int 545 test_stat(int do_uv) 546 { 547 if (do_uv) { 548 printf("testing stat\n"); 549 do_unveil(); 550 } 551 struct stat sb; 552 553 UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge"); 554 UV_SHOULD_SUCCEED((stat(uv_file1, &sb) == -1), "stat"); 555 UV_SHOULD_ENOENT((stat(uv_file2, &sb) == -1), "stat"); 556 UV_SHOULD_SUCCEED((stat(uv_dir1, &sb) == -1), "stat"); 557 UV_SHOULD_ENOENT((stat(uv_dir2, &sb) == -1), "stat"); 558 UV_SHOULD_ENOENT((stat("/", &sb) == -1), "stat"); 559 560 return 0; 561 } 562 563 static int 564 test_stat2(int do_uv) 565 { 566 if (do_uv) { 567 printf("testing stat components to nonexistent \"rw\"\n"); 568 if (unveil("/usr/share/man/nonexistent", "rw") == -1) 569 err(1, "%s:%d - unveil", __FILE__, __LINE__); 570 } 571 struct stat sb; 572 573 UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge"); 574 UV_SHOULD_ENOENT((stat("/", &sb) == -1), "stat"); 575 UV_SHOULD_ENOENT((stat("/usr", &sb) == -1), "stat"); 576 UV_SHOULD_ENOENT((stat("/usr/share", &sb) == -1), "stat"); 577 UV_SHOULD_ENOENT((stat("/usr/share/man", &sb) == -1), "stat"); 578 UV_SHOULD_ENOENT((stat("/usr/share/man/nonexistent", &sb) == -1), "stat"); 579 return 0; 580 } 581 582 static int 583 test_statfs(int do_uv) 584 { 585 if (do_uv) { 586 printf("testing statfs\n"); 587 do_unveil(); 588 } 589 struct statfs sb; 590 591 592 UV_SHOULD_SUCCEED((statfs("/home", &sb) == -1), "statfs"); 593 UV_SHOULD_SUCCEED((statfs("/", &sb) == -1), "statfs"); 594 UV_SHOULD_SUCCEED((statfs(uv_file1, &sb) == -1), "statfs"); 595 UV_SHOULD_SUCCEED((statfs(uv_file2, &sb) == -1), "statfs"); 596 UV_SHOULD_SUCCEED((statfs(uv_dir1, &sb) == -1), "statfs"); 597 UV_SHOULD_SUCCEED((statfs(uv_dir2, &sb) == -1), "statfs"); 598 UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge"); 599 UV_SHOULD_SUCCEED((statfs(uv_file1, &sb) == -1), "statfs"); 600 UV_SHOULD_SUCCEED((statfs(uv_file2, &sb) == -1), "statfs"); 601 UV_SHOULD_SUCCEED((statfs(uv_dir1, &sb) == -1), "statfs"); 602 UV_SHOULD_SUCCEED((statfs(uv_dir2, &sb) == -1), "statfs"); 603 604 return 0; 605 } 606 607 static int 608 test_symlink(int do_uv) 609 { 610 char filename[256]; 611 char filename2[256]; 612 char buf[256]; 613 struct stat sb; 614 615 if (do_uv) { 616 printf("testing symlink and lstat and readlink\n"); 617 do_unveil(); 618 } 619 620 UV_SHOULD_SUCCEED((pledge("unveil stdio fattr rpath cpath wpath", NULL) == -1), 621 "pledge"); 622 (void) snprintf(filename, sizeof(filename), "%s/%s", uv_dir1, 623 "slinkuv1"); 624 (void) snprintf(filename2, sizeof(filename2), "%s/%s", uv_dir2, 625 "slinkuv2"); 626 unlink(filename); 627 unlink(filename2); 628 UV_SHOULD_SUCCEED((symlink(uv_file1, filename) == -1), "symlink"); 629 UV_SHOULD_SUCCEED((lstat(filename, &sb) == -1), "lstat"); 630 UV_SHOULD_SUCCEED((lstat(uv_file1, &sb) == -1), "lstat"); 631 UV_SHOULD_SUCCEED((readlink(filename, buf, sizeof(buf)) == -1), "readlink"); 632 unlink(filename); 633 UV_SHOULD_SUCCEED((symlink(uv_file2, filename) == -1), "symlink"); 634 UV_SHOULD_SUCCEED((lstat(filename, &sb) == -1), "lstat"); 635 UV_SHOULD_SUCCEED((readlink(filename, buf, sizeof(buf)) == -1), "readlink"); 636 UV_SHOULD_ENOENT((lstat(uv_file2, &sb) == -1), "lstat"); 637 UV_SHOULD_ENOENT((symlink(uv_file1, filename2) == -1), "symlink"); 638 UV_SHOULD_ENOENT((readlink(filename2, buf, sizeof(buf)) == -1), "readlink"); 639 unlink(filename); 640 641 if (do_uv) { 642 printf("testing symlink with \"rw\"\n"); 643 if (unveil(filename, "rw") == -1) 644 err(1, "%s:%d - unveil", __FILE__, __LINE__); 645 } 646 UV_SHOULD_EACCES((symlink(uv_file1, filename) == -1), "symlink"); 647 648 return 0; 649 } 650 651 static int 652 test_chmod(int do_uv) 653 { 654 if (do_uv) { 655 printf("testing chmod\n"); 656 do_unveil(); 657 } 658 UV_SHOULD_SUCCEED((pledge("stdio fattr rpath unveil", NULL) == -1), "pledge"); 659 UV_SHOULD_SUCCEED((chmod(uv_file1, S_IRWXU) == -1), "chmod"); 660 UV_SHOULD_ENOENT((chmod(uv_file2, S_IRWXU) == -1), "chmod"); 661 UV_SHOULD_SUCCEED((chmod(uv_dir1, S_IRWXU) == -1), "chmod"); 662 UV_SHOULD_ENOENT((chmod(uv_dir2, S_IRWXU) == -1), "chmod"); 663 if (do_uv) { 664 printf("testing chmod should fail for read\n"); 665 if (unveil(uv_file1, "r") == -1) 666 err(1, "%s:%d - unveil", __FILE__, __LINE__); 667 } 668 UV_SHOULD_EACCES((chmod(uv_file1, S_IRWXU) == -1), "chmod"); 669 return 0; 670 } 671 672 673 static int 674 test_fork_body(int do_uv) 675 { 676 UV_SHOULD_SUCCEED((open(uv_file1, O_RDWR|O_CREAT, 0644) == -1), "open after fork"); 677 UV_SHOULD_SUCCEED((opendir(uv_dir1) == NULL), "opendir after fork"); 678 UV_SHOULD_ENOENT((opendir(uv_dir2) == NULL), "opendir after fork"); 679 UV_SHOULD_ENOENT((open(uv_file2, O_RDWR|O_CREAT, 0644) == -1), "open after fork"); 680 return 0; 681 } 682 683 static int 684 test_fork(int do_uv) 685 { 686 printf("testing fork inhertiance\n"); 687 do_unveil(); 688 return runcompare_internal(test_fork_body, 0); 689 } 690 691 static int 692 test_exec(int do_uv) 693 { 694 char *argv[] = {"/usr/bin/true", NULL}; 695 extern char **environ; 696 if (do_uv) { 697 printf("testing execve with \"x\"\n"); 698 if (unveil("/usr/bin/true", "x") == -1) 699 err(1, "%s:%d - unveil", __FILE__, __LINE__); 700 /* dynamic linking requires this */ 701 if (unveil("/usr/lib", "r") == -1) 702 err(1, "%s:%d - unveil", __FILE__, __LINE__); 703 if (unveil("/usr/libexec/ld.so", "r") == -1) 704 err(1, "%s:%d - unveil", __FILE__, __LINE__); 705 } 706 UV_SHOULD_SUCCEED((pledge("unveil stdio fattr exec", NULL) == -1), "pledge"); 707 UV_SHOULD_SUCCEED((execve(argv[0], argv, environ) == -1), "execve"); 708 return 0; 709 } 710 711 static int 712 test_exec2(int do_uv) 713 { 714 char *argv[] = {"/usr/bin/true", NULL}; 715 extern char **environ; 716 if (do_uv) { 717 printf("testing execve with \"rw\"\n"); 718 if (unveil("/usr/bin/true", "rw") == -1) 719 err(1, "%s:%d - unveil", __FILE__, __LINE__); 720 /* dynamic linking requires this */ 721 if (unveil("/usr/lib", "r") == -1) 722 err(1, "%s:%d - unveil", __FILE__, __LINE__); 723 if (unveil("/usr/libexec/ld.so", "r") == -1) 724 err(1, "%s:%d - unveil", __FILE__, __LINE__); 725 } 726 UV_SHOULD_SUCCEED((pledge("unveil stdio fattr exec", NULL) == -1), "pledge"); 727 UV_SHOULD_EACCES((execve(argv[0], argv, environ) == -1), "execve"); 728 return 0; 729 } 730 731 static int 732 test_slash(int do_uv) 733 { 734 extern char **environ; 735 if (do_uv) { 736 printf("testing unveil(\"/\")\n"); 737 if (unveil("/bin/sh", "x") == -1) 738 err(1, "%s:%d - unveil", __FILE__, __LINE__); 739 if (unveil("/", "r") == -1) 740 err(1, "%s:%d - unveil", __FILE__, __LINE__); 741 } 742 return 0; 743 } 744 745 static int 746 test_dot(int do_uv) 747 { 748 extern char **environ; 749 if (do_uv) { 750 printf("testing dot(\".\")\n"); 751 if (unveil(".", "rwxc") == -1) 752 err(1, "%s:%d - unveil", __FILE__, __LINE__); 753 if ((unlink(".") == -1) && errno != EPERM) 754 err(1, "%s:%d - unlink", __FILE__, __LINE__); 755 printf("testing dot flags(\".\")\n"); 756 if (unveil(".", "r") == -1) 757 err(1, "%s:%d - unveil", __FILE__, __LINE__); 758 if ((unlink(".") == -1) && errno != EACCES) 759 warn("%s:%d - unlink", __FILE__, __LINE__); 760 } 761 return 0; 762 } 763 764 static int 765 test_bypassunveil(int do_uv) 766 { 767 if (do_uv) { 768 printf("testing BYPASSUNVEIL\n"); 769 do_unveil2(); 770 } 771 char filename3[] = "/tmp/nukeme.XXXXXX"; 772 773 UV_SHOULD_SUCCEED((pledge("stdio tmppath", NULL) == -1), "pledge"); 774 UV_SHOULD_SUCCEED((mkstemp(filename3) == -1), "mkstemp"); 775 776 return 0; 777 } 778 779 780 static int 781 test_dotdotup(int do_uv) 782 { 783 UV_SHOULD_SUCCEED((open("/tmp/hello", O_RDWR|O_CREAT, 0644) == -1), "open"); 784 if (do_uv) { 785 printf("testing dotdotup\n"); 786 do_unveil2(); 787 } 788 if ((chdir(uv_dir1) == -1)) { 789 err(1, "chdir"); 790 } 791 UV_SHOULD_SUCCEED((open("./derp", O_RDWR|O_CREAT, 0644) == -1), "open"); 792 UV_SHOULD_SUCCEED((open("derp", O_RDWR|O_CREAT, 0644) == -1), "open"); 793 UV_SHOULD_ENOENT((open("../hello", O_RDWR|O_CREAT, 0644) == -1), "open"); 794 UV_SHOULD_ENOENT((open(".././hello", O_RDWR|O_CREAT, 0644) == -1), "open"); 795 return 0; 796 } 797 798 static int 799 test_kn(int do_uv) 800 { 801 if (do_uv) { 802 printf("testing read only with one writeable file\n"); 803 if (unveil("/", "r") == -1) 804 err(1, "%s:%d - unveil", __FILE__, __LINE__); 805 if (unveil("/dev/null", "rw") == -1) 806 err(1, "%s:%d - unveil", __FILE__, __LINE__); 807 } 808 UV_SHOULD_SUCCEED((open("/dev/null", O_RDWR) == -1), "open"); 809 UV_SHOULD_SUCCEED((open("/dev/zero", O_RDONLY) == -1), "open"); 810 UV_SHOULD_EACCES((open("/dev/zero", O_RDWR) == -1), "open"); 811 return 0; 812 } 813 814 815 static int 816 test_pathdiscover(int do_uv) 817 { 818 struct stat sb; 819 if (do_uv) { 820 printf("testing path discovery\n"); 821 if (unveil("/usr/share/man", "rx") == -1) 822 err(1, "%s:%d - unveil", __FILE__, __LINE__); 823 } 824 UV_SHOULD_SUCCEED((lstat("/usr/share/man", &sb) == -1), "lstat"); 825 UV_SHOULD_SUCCEED((lstat("/usr/share/man/../../share/man", &sb) == -1), "lstat"); 826 /* XXX XXX XXX This should fail */ 827 UV_SHOULD_SUCCEED((lstat("/usr/share/man/../../local/../share/man", &sb) == -1), "lstat"); 828 return 0; 829 } 830 831 static int 832 test_fchdir(int do_uv) 833 { 834 int fd2, fd; 835 836 UV_SHOULD_SUCCEED(((fd2 = open(uv_dir2, O_RDONLY | O_DIRECTORY)) == -1), "open"); 837 838 if (do_uv) { 839 printf("testing fchdir\n"); 840 do_unveil2(); 841 } 842 843 UV_SHOULD_SUCCEED((pledge("stdio fattr rpath", NULL) == -1), "pledge"); 844 UV_SHOULD_SUCCEED((chdir(uv_dir1) == -1), "chdir"); 845 UV_SHOULD_SUCCEED((fchdir(fd2) == -1), "fchdir"); 846 UV_SHOULD_ENOENT((fd = (open("subdir", O_RDONLY | O_DIRECTORY)) == -1), "open"); 847 848 return 0; 849 } 850 851 static int 852 test_fork_locked(int do_uv) 853 { 854 int status; 855 pid_t pid; 856 857 if (do_uv) { 858 printf("testing unveil locked fork\n"); 859 unveil(NULL, NULL); 860 } 861 862 pid = fork(); 863 if (pid == 0) { 864 UV_SHOULD_EPERM((unveil("/", "rwx") == -1), "unveil"); 865 exit(0); 866 } 867 868 status = 0; 869 waitpid(pid, &status, 0); 870 if (WIFSIGNALED(status)) 871 errx(1, "child exited with signal %d", WTERMSIG(status)); 872 if (WEXITSTATUS(status) == 0) 873 return 0; 874 else 875 return 1; 876 } 877 878 static int 879 test_intermediate_node(int do_uv) 880 { 881 struct stat st; 882 883 if (do_uv) { 884 printf("testing unveil on intermediate node\n"); 885 UV_SHOULD_SUCCEED((unveil("/", "r") == -1), "unveil"); 886 UV_SHOULD_SUCCEED((unveil("/usr/bin/id", "rx") == -1), 887 "unveil"); 888 UV_SHOULD_SUCCEED((unveil(NULL, NULL) == -1), "unveil"); 889 } 890 891 UV_SHOULD_SUCCEED((stat("/usr/bin", &st) == -1), "stat"); 892 return 0; 893 } 894 895 static int 896 test_noaccess_node(int do_uv) 897 { 898 struct stat st; 899 900 if (do_uv) { 901 printf("testing unveil on noaccess node\n"); 902 UV_SHOULD_SUCCEED((unveil("/", "r") == -1), "unveil"); 903 UV_SHOULD_SUCCEED((unveil("/usr/bin/id", "rx") == -1), 904 "unveil"); 905 UV_SHOULD_SUCCEED((unveil("/usr/bin", "") == -1), "unveil"); 906 UV_SHOULD_SUCCEED((unveil(NULL, NULL) == -1), "unveil"); 907 } 908 909 UV_SHOULD_ENOENT((stat("/usr/bin", &st) == -1), "stat"); 910 return 0; 911 } 912 913 int 914 main(int argc, char *argv[]) 915 { 916 int failures = 0; 917 918 test_setup(); 919 920 failures += runcompare(test_open); 921 failures += runcompare(test_openat); 922 failures += runcompare(test_opendir); 923 failures += runcompare(test_noflags); 924 failures += runcompare(test_drounveil); 925 failures += runcompare(test_r); 926 failures += runcompare(test_rw); 927 failures += runcompare(test_x); 928 failures += runcompare(test_unlink); 929 failures += runcompare(test_link); 930 failures += runcompare(test_chdir); 931 failures += runcompare(test_rename); 932 failures += runcompare(test_access); 933 failures += runcompare(test_chflags); 934 failures += runcompare(test_stat); 935 failures += runcompare(test_stat2); 936 failures += runcompare(test_statfs); 937 failures += runcompare(test_symlink); 938 failures += runcompare(test_chmod); 939 failures += runcompare(test_exec); 940 failures += runcompare(test_exec2); 941 failures += runcompare(test_realpath); 942 failures += runcompare(test_parent_dir); 943 failures += runcompare(test_slash); 944 failures += runcompare(test_dot); 945 failures += runcompare(test_bypassunveil); 946 failures += runcompare_internal(test_fork, 0); 947 failures += runcompare(test_dotdotup); 948 failures += runcompare(test_kn); 949 failures += runcompare(test_pathdiscover); 950 failures += runcompare(test_fchdir); 951 failures += runcompare(test_fork_locked); 952 failures += runcompare(test_intermediate_node); 953 failures += runcompare(test_noaccess_node); 954 exit(failures); 955 } 956