diff options
author | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2017-08-26 15:55:42 +0000 |
---|---|---|
committer | Ingo Schwarze <schwarze@cvs.openbsd.org> | 2017-08-26 15:55:42 +0000 |
commit | c0d496ecd4f9c6a510d36bd307ae6121839defee (patch) | |
tree | 96fdec972168bf13aa659264dbe3cdbc47679814 /usr.bin/mandoc/mandocdb.c | |
parent | 760de62e46f173fd020aa2d129b7cbb098989b34 (diff) |
Do not fork and exec cmp(1); instead, simply fstat(2), mmap(2), and
compare the files directly, allowing a much stricter pledge(2), at
very little cost: merely 15 additional lines of very simple code.
Suggested by George Brown <321 dot george at gmail dot com> on misc@.
Diffstat (limited to 'usr.bin/mandoc/mandocdb.c')
-rw-r--r-- | usr.bin/mandoc/mandocdb.c | 90 |
1 files changed, 52 insertions, 38 deletions
diff --git a/usr.bin/mandoc/mandocdb.c b/usr.bin/mandoc/mandocdb.c index 35683d4d848..6528d9fb6ac 100644 --- a/usr.bin/mandoc/mandocdb.c +++ b/usr.bin/mandoc/mandocdb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mandocdb.c,v 1.203 2017/08/26 12:59:13 schwarze Exp $ */ +/* $OpenBSD: mandocdb.c,v 1.204 2017/08/26 15:55:41 schwarze Exp $ */ /* * Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv> * Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org> @@ -17,8 +17,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <sys/types.h> +#include <sys/mman.h> #include <sys/stat.h> -#include <sys/wait.h> #include <assert.h> #include <ctype.h> @@ -303,7 +303,7 @@ mandocdb(int argc, char *argv[]) size_t j, sz; int ch, i; - if (pledge("stdio rpath wpath cpath fattr flock proc exec", NULL) == -1) { + if (pledge("stdio rpath wpath cpath", NULL) == -1) { warn("pledge"); return (int)MANDOCLEVEL_SYSERR; } @@ -414,13 +414,6 @@ mandocdb(int argc, char *argv[]) * The existing database is usable. Process * all files specified on the command-line. */ - if (!nodb) { - if (pledge("stdio rpath wpath cpath fattr flock", NULL) == -1) { - warn("pledge"); - exitcode = (int)MANDOCLEVEL_SYSERR; - goto out; - } - } use_all = 1; for (i = 0; i < argc; i++) filescan(argv[i]); @@ -2079,9 +2072,10 @@ dbprune(struct dba *dba) static void dbwrite(struct dba *dba) { - char tfn[33]; - int status; - pid_t child; + struct stat sb1, sb2; + char tfn[33], *cp1, *cp2; + off_t i; + int fd1, fd2; /* * Do not write empty databases, and delete existing ones @@ -2120,39 +2114,59 @@ dbwrite(struct dba *dba) say("", "&%s", tfn); return; } - + cp1 = cp2 = NULL; + fd1 = fd2 = -1; (void)strlcat(tfn, "/" MANDOC_DB, sizeof(tfn)); if (dba_write(tfn, dba) == -1) { - exitcode = (int)MANDOCLEVEL_SYSERR; say(tfn, "&dba_write"); - goto out; + goto err; } - - switch (child = fork()) { - case -1: - exitcode = (int)MANDOCLEVEL_SYSERR; - say("", "&fork cmp"); - return; - case 0: - execlp("cmp", "cmp", "-s", tfn, MANDOC_DB, (char *)NULL); - say("", "&exec cmp"); - exit(0); - default: - break; + if ((fd1 = open(MANDOC_DB, O_RDONLY, 0)) == -1) { + say(MANDOC_DB, "&open"); + goto err; } - if (waitpid(child, &status, 0) == -1) { - exitcode = (int)MANDOCLEVEL_SYSERR; - say("", "&wait cmp"); - } else if (WIFSIGNALED(status)) { - exitcode = (int)MANDOCLEVEL_SYSERR; - say("", "cmp died from signal %d", WTERMSIG(status)); - } else if (WEXITSTATUS(status)) { - exitcode = (int)MANDOCLEVEL_SYSERR; - say(MANDOC_DB, - "Data changed, but cannot replace database"); + if ((fd2 = open(tfn, O_RDONLY, 0)) == -1) { + say(tfn, "&open"); + goto err; + } + if (fstat(fd1, &sb1) == -1) { + say(MANDOC_DB, "&fstat"); + goto err; } + if (fstat(fd2, &sb2) == -1) { + say(tfn, "&fstat"); + goto err; + } + if (sb1.st_size != sb2.st_size) + goto err; + if ((cp1 = mmap(NULL, sb1.st_size, PROT_READ, MAP_PRIVATE, + fd1, 0)) == NULL) { + say(MANDOC_DB, "&mmap"); + goto err; + } + if ((cp2 = mmap(NULL, sb2.st_size, PROT_READ, MAP_PRIVATE, + fd2, 0)) == NULL) { + say(tfn, "&mmap"); + goto err; + } + for (i = 0; i < sb1.st_size; i++) + if (cp1[i] != cp2[i]) + goto err; + goto out; + +err: + exitcode = (int)MANDOCLEVEL_SYSERR; + say(MANDOC_DB, "Data changed, but cannot replace database"); out: + if (cp1 != NULL) + munmap(cp1, sb1.st_size); + if (cp2 != NULL) + munmap(cp2, sb2.st_size); + if (fd1 != -1) + close(fd1); + if (fd2 != -1) + close(fd2); unlink(tfn); *strrchr(tfn, '/') = '\0'; rmdir(tfn); |