Index: Makefile =================================================================== --- Makefile +++ Makefile @@ -27,12 +27,12 @@ BINDIR = $(PREFIX)/bin # The -O0 is to help with debugging coredumps. -CFLAGS += -O0 -g -W -Wall -Wextra -Wno-unused-parameter +CFLAGS += -O0 -g -W -Wall -Wextra -Wno-unused-parameter -DWITH_CASPER all: openrsync openrsync: $(ALLOBJS) - $(CC) -o $@ $(ALLOBJS) -lm + $(CC) -o $@ $(ALLOBJS) -lm -lcap_fileargs -lcasper afl: $(AFLS) Index: blocks.c =================================================================== --- blocks.c +++ blocks.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include Index: downloader.c =================================================================== --- downloader.c +++ downloader.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include Index: extern.h =================================================================== --- extern.h +++ extern.h @@ -17,6 +17,10 @@ #ifndef EXTERN_H #define EXTERN_H +#include +#include +#include + /* * This is the rsync protocol version that we support. */ @@ -272,7 +276,7 @@ int flist_del(struct sess *, int, const struct flist *, size_t); int flist_gen(struct sess *, size_t, char **, - struct flist **, size_t *); + struct flist **, size_t *, fileargs_t *); int flist_gen_local(struct sess *, const char *, struct flist **, size_t *); void flist_free(struct flist *, size_t); Index: flist.c =================================================================== --- flist.c +++ flist.c @@ -15,6 +15,8 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include +#include #include #include #include @@ -30,6 +32,9 @@ #include #include +#include +#include + #include "extern.h" /* @@ -523,8 +528,10 @@ return 1; } - pp = recallocarray(*fl, *max, - *max + FLIST_CHUNK_SIZE, sizeof(struct flist)); + pp = calloc(*max + FLIST_CHUNK_SIZE, sizeof(struct flist)); + memcpy(pp, *fl, (*sz) * sizeof(struct flist)); + free(*fl); + if (pp == NULL) { ERR(sess, "recallocarray"); return 0; @@ -802,10 +809,10 @@ */ static int flist_gen_dirent(struct sess *sess, char *root, struct flist **fl, size_t *sz, - size_t *max) + size_t *max, fileargs_t *fa) { char *cargv[2], *cp; - int rc = 0; + int rc = 0, fd; FTS *fts; FTSENT *ent; struct flist *f; @@ -820,7 +827,10 @@ * the non-recursive scan. */ - if (lstat(root, &st) == -1) { + if ((fd = fileargs_open(fa, root)) < 0) { + ERR(sess, "%s: fileargs_open", root); + return 0; + } else if (fstat(fd, &st) == -1) { ERR(sess, "%s: lstat", root); return 0; } else if (S_ISREG(st.st_mode)) { @@ -835,10 +845,6 @@ ERRX1(sess, "flist_append"); return 0; } - if (unveil(root, "r") == -1) { - ERR(sess, "%s: unveil", root); - return 0; - } return 1; } else if (S_ISLNK(st.st_mode)) { if (!sess->opts->preserve_links) { @@ -855,10 +861,6 @@ ERRX1(sess, "flist_append"); return 0; } - if (unveil(root, "r") == -1) { - ERR(sess, "%s: unveil", root); - return 0; - } return 1; } else if (!S_ISDIR(st.st_mode)) { WARNX(sess, "%s: skipping special", root); @@ -959,10 +961,6 @@ ERR(sess, "fts_read"); goto out; } - if (unveil(root, "r") == -1) { - ERR(sess, "%s: unveil", root); - goto out; - } LOG3(sess, "generated %zu filenames: %s", flsz, root); rc = 1; @@ -980,12 +978,12 @@ */ static int flist_gen_dirs(struct sess *sess, size_t argc, char **argv, struct flist **flp, - size_t *sz) + size_t *sz, fileargs_t *fa) { size_t i, max = 0; for (i = 0; i < argc; i++) - if (!flist_gen_dirent(sess, argv[i], flp, sz, &max)) + if (!flist_gen_dirent(sess, argv[i], flp, sz, &max, fa)) break; if (i == argc) { @@ -1008,11 +1006,12 @@ */ static int flist_gen_files(struct sess *sess, size_t argc, char **argv, - struct flist **flp, size_t *sz) + struct flist **flp, size_t *sz, fileargs_t *fa) { struct flist *fl = NULL, *f; size_t i, flsz = 0; struct stat st; + int fd; assert(argc); @@ -1024,8 +1023,13 @@ for (i = 0; i < argc; i++) { if ('\0' == argv[i][0]) continue; - if (lstat(argv[i], &st) == -1) { - ERR(sess, "%s: lstat", argv[i]); + + if ((fd = fileargs_open(fa, argv[i])) < 0) { + ERR(sess, "%s: fileargs_open", argv[i]); + goto out; + } + if (fstat(fd, &st) == -1) { + ERR(sess, "%s: fstat", argv[i]); goto out; } @@ -1054,12 +1058,6 @@ f = &fl[flsz++]; assert(f != NULL); - /* Add this file to our file-system worldview. */ - - if (unveil(argv[i], "r") == -1) { - ERR(sess, "%s: unveil", argv[i]); - goto out; - } if (!flist_append(sess, f, &st, argv[i])) { ERRX1(sess, "flist_append"); goto out; @@ -1087,21 +1085,15 @@ */ int flist_gen(struct sess *sess, size_t argc, char **argv, struct flist **flp, - size_t *sz) + size_t *sz, fileargs_t *fa) { int rc; assert(argc > 0); rc = sess->opts->recursive ? - flist_gen_dirs(sess, argc, argv, flp, sz) : - flist_gen_files(sess, argc, argv, flp, sz); - - /* After scanning, lock our file-system view. */ + flist_gen_dirs(sess, argc, argv, flp, sz, fa) : + flist_gen_files(sess, argc, argv, flp, sz, fa); - if (unveil(NULL, NULL) == -1) { - ERR(sess, "unveil"); - return 0; - } if (!rc) return 0; Index: hash.c =================================================================== --- hash.c +++ hash.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include Index: io.c =================================================================== --- io.c +++ io.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include Index: main.c =================================================================== --- main.c +++ main.c @@ -14,6 +14,8 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include +#include #include #include #include @@ -299,7 +301,8 @@ { struct opts opts; pid_t child; - int fds[2], c, st; + int fds[2], c, pd, kq, nev; + struct kevent ev, rev; struct fargs *fargs; struct option lopts[] = { { "port", required_argument, NULL, 3 }, @@ -334,12 +337,6 @@ { "no-verbose", no_argument, &opts.verbose, 0 }, { NULL, 0, NULL, 0 }}; - /* Global pledge. */ - - if (pledge("stdio unix rpath wpath cpath dpath inet fattr chown dns getpw proc exec unveil", - NULL) == -1) - err(EXIT_FAILURE, "pledge"); - memset(&opts, 0, sizeof(struct opts)); while ((c = getopt_long(argc, argv, "Dae:ghlnoprtv", lopts, NULL)) != -1) { @@ -423,8 +420,6 @@ */ if (opts.server) { - if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil", NULL) == -1) - err(EXIT_FAILURE, "pledge"); c = rsync_server(&opts, (size_t)argc, argv); return c ? EXIT_SUCCESS : EXIT_FAILURE; } @@ -450,49 +445,31 @@ if (fargs->remote) { assert(fargs->mode == FARGS_RECEIVER); - if (pledge("stdio unix rpath wpath cpath dpath inet fattr chown dns getpw unveil", - NULL) == -1) - err(EXIT_FAILURE, "pledge"); c = rsync_socket(&opts, fargs); fargs_free(fargs); return c ? EXIT_SUCCESS : EXIT_FAILURE; } - /* Drop the dns/inet possibility. */ - - if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw proc exec unveil", - NULL) == -1) - err(EXIT_FAILURE, "pledge"); - /* Create a bidirectional socket and start our child. */ if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds) == -1) err(EXIT_FAILURE, "socketpair"); - if ((child = fork()) == -1) { + if ((child = pdfork(&pd, 0)) == -1) { close(fds[0]); close(fds[1]); err(EXIT_FAILURE, "fork"); } - /* Drop the fork possibility. */ - - if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw exec unveil", NULL) == -1) - err(EXIT_FAILURE, "pledge"); - if (child == 0) { close(fds[0]); fds[0] = -1; - if (pledge("stdio exec", NULL) == -1) - err(EXIT_FAILURE, "pledge"); rsync_child(&opts, fds[1], fargs); /* NOTREACHED */ } close(fds[1]); fds[1] = -1; - if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil", NULL) == -1) - err(EXIT_FAILURE, "pledge"); c = rsync_client(&opts, fds[0], fargs); fargs_free(fargs); @@ -507,9 +484,19 @@ fds[0] = -1; } - if (waitpid(child, &st, 0) == -1) - err(EXIT_FAILURE, "waitpid"); - if (!(WIFEXITED(st) && WEXITSTATUS(st) == EXIT_SUCCESS)) + if ((kq = kqueue()) == -1) { + perror("kqueue"); + exit(EXIT_FAILURE); + } + EV_SET(&ev, pd, EVFILT_PROCDESC, EV_ADD|EV_ENABLE|EV_ONESHOT, + NOTE_EXIT, 0, 0); + + nev = kevent(kq, &ev, 1, &rev, 1, NULL); + if (nev == -1) + err(EXIT_FAILURE, "kevent"); + if ((rev.fflags & NOTE_EXIT) == 0) + err(EXIT_FAILURE, "Something other than NOTE_EXIT"); + if (!(WIFEXITED(rev.data) && WEXITSTATUS(rev.data) == EXIT_SUCCESS)) c = 0; if (fds[0] != -1) Index: mktemp.c =================================================================== --- mktemp.c +++ mktemp.c @@ -34,6 +34,14 @@ #include "extern.h" +#ifndef O_DSYNC +#define O_DSYNC 0 +#endif + +#ifndef O_RSYNC +#define O_RSYNC 0 +#endif + /* * The type of temporary files we can create. */ Index: receiver.c =================================================================== --- receiver.c +++ receiver.c @@ -16,6 +16,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include @@ -183,8 +184,42 @@ struct upload *ul = NULL; mode_t oumask; - if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil", NULL) == -1) { - ERR(sess, "pledge"); + /* + * Create the path for our destination directory, if we're not + * in dry-run mode (which would otherwise crash w/the pledge). + * This uses our current umask: we might set the permissions on + * this directory in post_dir(). + */ + + if (!sess->opts->dry_run) { + if ((tofree = strdup(root)) == NULL) { + ERR(sess, "strdup"); + goto out; + } else if (mkpath(sess, tofree) < 0) { + ERRX1(sess, "%s: mkpath2", root); + free(tofree); + goto out; + } + free(tofree); + } + + /* + * Disable umask() so we can set permissions fully. + * Then open the directory iff we're not in dry_run. + */ + + oumask = umask(0); + + if (!sess->opts->dry_run) { + dfd = open(root, O_RDONLY | O_DIRECTORY, 0); + if (dfd == -1) { + ERR(sess, "%s: open", root); + goto out; + } + } + + if (cap_enter() < 0 && errno != ENOSYS) { + ERRX(sess, "cap_enter"); goto out; } @@ -235,40 +270,6 @@ LOG2(sess, "%s: receiver destination", root); - /* - * Create the path for our destination directory, if we're not - * in dry-run mode (which would otherwise crash w/the pledge). - * This uses our current umask: we might set the permissions on - * this directory in post_dir(). - */ - - if (!sess->opts->dry_run) { - if ((tofree = strdup(root)) == NULL) { - ERR(sess, "strdup"); - goto out; - } else if (mkpath(sess, tofree) < 0) { - ERRX1(sess, "%s: mkpath", root); - free(tofree); - goto out; - } - free(tofree); - } - - /* - * Disable umask() so we can set permissions fully. - * Then open the directory iff we're not in dry_run. - */ - - oumask = umask(0); - - if (!sess->opts->dry_run) { - dfd = open(root, O_RDONLY | O_DIRECTORY, 0); - if (dfd == -1) { - ERR(sess, "%s: open", root); - goto out; - } - } - /* * Begin by conditionally getting all files we have currently * available in our destination. @@ -281,21 +282,6 @@ goto out; } - /* - * Make our entire view of the file-system be limited to what's - * in the root directory. - * This prevents us from accidentally (or "under the influence") - * writing into other parts of the file-system. - */ - - if (unveil(root, "rwc") == -1) { - ERR(sess, "%s: unveil", root); - goto out; - } else if (unveil(NULL, NULL) == -1) { - ERR(sess, "%s: unveil", root); - goto out; - } - /* If we have a local set, go for the deletion. */ if (!flist_del(sess, dfd, dfl, dflsz)) { Index: sender.c =================================================================== --- sender.c +++ sender.c @@ -14,11 +14,13 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include #include +#include #include #include #include @@ -408,8 +410,16 @@ size_t wbufpos = 0, wbufsz = 0, wbufmax = 0; ssize_t ssz; - if (pledge("stdio getpw rpath unveil", NULL) == -1) { - ERR(sess, "pledge"); + cap_rights_t rights; + fileargs_t* fa = fileargs_init(argc, argv, O_RDONLY|O_NONBLOCK, 0, + cap_rights_init(&rights, CAP_FSTAT, CAP_READ, CAP_EVENT, CAP_MMAP_R)); + if (fa == NULL) { + ERR(sess, "fileargs_init"); + return 0; + } + + if (cap_enter() < 0 && errno != ENOSYS) { + ERR(sess, "cap_enter"); return 0; } @@ -435,7 +445,7 @@ * This will also remove all invalid files. */ - if (!flist_gen(sess, argc, argv, &fl, &flsz)) { + if (!flist_gen(sess, argc, argv, &fl, &flsz, fa)) { ERRX1(sess, "flist_gen"); goto out; } @@ -691,8 +701,7 @@ * block of not being primed. */ - up.stat.fd = open(fl[up.cur->idx].path, - O_RDONLY|O_NONBLOCK, 0); + up.stat.fd = fileargs_open(fa, fl[up.cur->idx].path); if (up.stat.fd == -1) { ERR(sess, "%s: open", fl[up.cur->idx].path); goto out; Index: socket.c =================================================================== --- socket.c +++ socket.c @@ -14,6 +14,7 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include #include @@ -267,13 +268,6 @@ return 0; } - /* Drop the DNS pledge. */ - - if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw inet unveil", NULL) == -1) { - ERR(&sess, "pledge"); - goto out; - } - /* * Iterate over all addresses, trying to connect. * When we succeed, then continue using the connected socket. @@ -289,9 +283,8 @@ break; } - /* Drop the inet pledge. */ - if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil", NULL) == -1) { - ERR(&sess, "pledge"); + if (cap_enter() < 0 && errno != ENOSYS) { + ERRX(&sess, "cap_enter"); goto out; }