Index: usr.bin/bsdiff/bspatch/bspatch.c =================================================================== --- usr.bin/bsdiff/bspatch/bspatch.c +++ usr.bin/bsdiff/bspatch/bspatch.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,23 @@ #define O_BINARY 0 #endif +static char *newfile; +static int dirfd = -1; +static void +exit_cleanup(void) +{ + +#ifdef HAVE_CAPSICUM + if (dirfd != -1 && newfile != NULL) + if (unlinkat(dirfd, newfile, 0)) + warn("unlinkat"); +#else + if (newfile != NULL) + if (unlink(newfile)) + warn("unlink"); +#endif +} + static off_t offtin(u_char *buf) { off_t y; @@ -94,7 +112,8 @@ off_t lenread; off_t i; #ifdef HAVE_CAPSICUM - cap_rights_t rights_ro, rights_wr; + cap_rights_t rights_dir, rights_ro, rights_wr; + char *namebuf; #endif if (argc != 4) @@ -121,6 +140,14 @@ err(1, "open(%s)", argv[2]); #ifdef HAVE_CAPSICUM + /* open directory where we'll write newfile */ + namebuf = strdup(argv[2]); + if ((dirfd = open(dirname(namebuf), O_DIRECTORY)) < 0) + err(1, "open %s", namebuf); + free(namebuf); + newfile = basename(argv[2]); + atexit(exit_cleanup); + if (cap_enter() < 0) { /* Failed to sandbox, fatal if CAPABILITY_MODE enabled */ if (errno != ENOSYS) @@ -129,17 +156,20 @@ /* Capsicum Available */ cap_rights_init(&rights_ro, CAP_READ, CAP_FSTAT, CAP_SEEK); cap_rights_init(&rights_wr, CAP_WRITE); - + cap_rights_init(&rights_dir, CAP_UNLINKAT); if (cap_rights_limit(fileno(f), &rights_ro) < 0 || cap_rights_limit(fileno(cpf), &rights_ro) < 0 || cap_rights_limit(fileno(dpf), &rights_ro) < 0 || cap_rights_limit(fileno(epf), &rights_ro) < 0 || cap_rights_limit(oldfd, &rights_ro) < 0 || - cap_rights_limit(newfd, &rights_wr) < 0) + cap_rights_limit(newfd, &rights_wr) < 0 || + cap_rights_limit(dirfd, &rights_dir) < 0) err(1, "cap_rights_limit() failed, could not restrict" " capabilities"); } -#endif +#else + newfile = argv[2]; + atexit(exit_cleanup); #endif /* @@ -266,6 +296,8 @@ /* Write the new file */ if (write(newfd, new, newsize) != newsize || close(newfd) == -1) err(1, "%s", argv[2]); + /* Disable atexit cleanup */ + newfile = NULL; free(new); free(old);