diff options
Diffstat (limited to 'util')
| -rw-r--r-- | util/libreboot-utils/include/common.h | 12 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/command.c | 4 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/file.c | 8 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/mkhtemp.c | 20 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/num.c | 2 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/state.c | 26 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/string.c | 158 | ||||
| -rw-r--r-- | util/libreboot-utils/mkhtemp.c | 54 | ||||
| -rw-r--r-- | util/libreboot-utils/nvmutil.c | 14 |
9 files changed, 201 insertions, 97 deletions
diff --git a/util/libreboot-utils/include/common.h b/util/libreboot-utils/include/common.h index 196f2810..97bbdf0c 100644 --- a/util/libreboot-utils/include/common.h +++ b/util/libreboot-utils/include/common.h @@ -384,7 +384,13 @@ int slen(const char *scmp, size_t maxlen, size_t *rval); int scmp(const char *a, const char *b, size_t maxlen, int *rval); - +int sdup(const char *s, + size_t n, char **dest); +int scat(const char *s1, const char *s2, + size_t n, char **dest); +int dcat(const char *s, size_t n, + size_t off, char **dest1, + char **dest2); /* numerical functions */ @@ -494,11 +500,13 @@ int try_err(int loop_err, int errval); */ void usage(void); -void err_no_cleanup(int nvm_errval, const char *msg, ...); +void err_no_cleanup(int stfu, int nvm_errval, const char *msg, ...); void b0rk(int nvm_errval, const char *msg, ...); int exit_cleanup(void); const char *getnvmprogname(void); +void err_mkhtemp(int stfu, int errval, const char *msg, ...); + /* libc hardening */ diff --git a/util/libreboot-utils/lib/command.c b/util/libreboot-utils/lib/command.c index 6d0e8856..c7048a23 100644 --- a/util/libreboot-utils/lib/command.c +++ b/util/libreboot-utils/lib/command.c @@ -110,7 +110,7 @@ set_cmd(int argc, char *argv[]) cmd = x->cmd[c].str; if (scmp(argv[2], cmd, MAX_CMD_LEN, &rval) < 0) - err_no_cleanup(EINVAL, + err_no_cleanup(0, EINVAL, "could not compare command strings"); if (rval != 0) continue; /* not the right command */ @@ -123,7 +123,7 @@ set_cmd(int argc, char *argv[]) return; } - err_no_cleanup(EINVAL, + err_no_cleanup(0, EINVAL, "Too few args on command '%s'", cmd); } diff --git a/util/libreboot-utils/lib/file.c b/util/libreboot-utils/lib/file.c index 46d5e016..552618d6 100644 --- a/util/libreboot-utils/lib/file.c +++ b/util/libreboot-utils/lib/file.c @@ -96,16 +96,16 @@ void xopen(int *fd_ptr, const char *path, int flags, struct stat *st) { if ((*fd_ptr = open(path, flags)) < 0) - err_no_cleanup(errno, "%s", path); + err_no_cleanup(0, errno, "%s", path); if (fstat(*fd_ptr, st) < 0) - err_no_cleanup(errno, "%s: stat", path); + err_no_cleanup(0, errno, "%s: stat", path); if (!S_ISREG(st->st_mode)) - err_no_cleanup(errno, "%s: not a regular file", path); + err_no_cleanup(0, errno, "%s: not a regular file", path); if (lseek_on_eintr(*fd_ptr, 0, SEEK_CUR, 1, 1) == (off_t)-1) - err_no_cleanup(errno, "%s: file not seekable", path); + err_no_cleanup(0, errno, "%s: file not seekable", path); } /* fsync() the directory of a file, diff --git a/util/libreboot-utils/lib/mkhtemp.c b/util/libreboot-utils/lib/mkhtemp.c index 6b4898fd..2fb2f01a 100644 --- a/util/libreboot-utils/lib/mkhtemp.c +++ b/util/libreboot-utils/lib/mkhtemp.c @@ -79,8 +79,8 @@ new_tmp_common(int *fd, char **path, int type, #endif struct stat st; - const char *suffix; - size_t suffix_len; + const char *templatestr; + size_t templatestr_len; size_t dirlen; size_t destlen; @@ -144,17 +144,17 @@ new_tmp_common(int *fd, char **path, int type, goto err; if (template != NULL) - suffix = template; + templatestr = template; else - suffix = "tmp.XXXXXXXXXX"; + templatestr = "tmp.XXXXXXXXXX"; - if (slen(suffix, maxlen, &suffix_len) < 0) + if (slen(templatestr, maxlen, &templatestr_len) < 0) goto err; /* sizeof adds an extra byte, useful * because we also want '.' or '/' */ - destlen = dirlen + 1 + suffix_len; + destlen = dirlen + 1 + templatestr_len; if (destlen > maxlen - 1) { errno = EOVERFLOW; goto err; @@ -168,7 +168,7 @@ new_tmp_common(int *fd, char **path, int type, memcpy(dest, tmpdir, dirlen); *(dest + dirlen) = '/'; - memcpy(dest + dirlen + 1, suffix, suffix_len); + memcpy(dest + dirlen + 1, templatestr, templatestr_len); *(dest + destlen) = '\0'; fname = dest + dirlen + 1; @@ -603,7 +603,7 @@ mkhtemp(int *fd, if_err_sys(slen(template, max_len, &len) < 0) || if_err(len >= max_len, EMSGSIZE) || - if_err_sys(slen(fname, max_len, &fname_len)) || + if_err_sys(slen(fname, max_len, &fname_len) < 0) || if_err(fname == NULL, EINVAL) || if_err(strrchr(fname, '/') != NULL, EINVAL)) return -1; @@ -611,7 +611,7 @@ mkhtemp(int *fd, for (end = template + len; /* count X */ end > template && *--end == 'X'; xc++); - if (if_err(xc < 6 || xc > len, EINVAL) || + if (if_err(xc < 3 || xc > len, EINVAL) || if_err(fname_len > len, EOVERFLOW)) return -1; @@ -622,7 +622,7 @@ mkhtemp(int *fd, if((fname_copy = malloc(fname_len + 1)) == NULL) goto err; - /* fname_copy = suffix region only; p points to trailing XXXXXX */ + /* fname_copy = templatestr region only; p points to trailing XXXXXX */ memcpy(fname_copy, template + len - fname_len, fname_len + 1); diff --git a/util/libreboot-utils/lib/num.c b/util/libreboot-utils/lib/num.c index 43efba71..0b76e257 100644 --- a/util/libreboot-utils/lib/num.c +++ b/util/libreboot-utils/lib/num.c @@ -436,6 +436,6 @@ void check_bin(size_t a, const char *a_name) { if (a > 1) - err_no_cleanup(EINVAL, "%s must be 0 or 1, but is %lu", + err_no_cleanup(0, EINVAL, "%s must be 0 or 1, but is %lu", a_name, (size_t)a); } diff --git a/util/libreboot-utils/lib/state.c b/util/libreboot-utils/lib/state.c index 4ef7163f..42d060b7 100644 --- a/util/libreboot-utils/lib/state.c +++ b/util/libreboot-utils/lib/state.c @@ -98,9 +98,9 @@ xstart(int argc, char *argv[]) return &us; if (argc < 3) - err_no_cleanup(EINVAL, "xstart: Too few arguments"); + err_no_cleanup(0, EINVAL, "xstart: Too few arguments"); if (argv == NULL) - err_no_cleanup(EINVAL, "xstart: NULL argv"); + err_no_cleanup(0, EINVAL, "xstart: NULL argv"); first_run = 0; @@ -113,41 +113,41 @@ xstart(int argc, char *argv[]) us.f.tname = NULL; if ((realdir = realpath(us.f.fname, NULL)) == NULL) - err_no_cleanup(errno, "xstart: can't get realpath of %s", + err_no_cleanup(0, errno, "xstart: can't get realpath of %s", us.f.fname); if (fs_dirname_basename(realdir, &dir, &base, 0) < 0) - err_no_cleanup(errno, "xstart: don't know CWD of %s", + err_no_cleanup(0, errno, "xstart: don't know CWD of %s", us.f.fname); if ((us.f.base = strdup(base)) == NULL) - err_no_cleanup(errno, "strdup base"); + err_no_cleanup(0, errno, "strdup base"); us.f.dirfd = fs_open(dir, O_RDONLY | O_DIRECTORY); if (us.f.dirfd < 0) - err_no_cleanup(errno, "%s: open dir", dir); + err_no_cleanup(0, errno, "%s: open dir", dir); if (new_tmpfile(&us.f.tmp_fd, &us.f.tname, dir, ".gbe.XXXXXXXXXX") < 0) - err_no_cleanup(errno, "%s", us.f.tname); + err_no_cleanup(0, errno, "%s", us.f.tname); if (fs_dirname_basename(us.f.tname, &tmpdir, &tmpbase_local, 0) < 0) - err_no_cleanup(errno, "tmp basename"); + err_no_cleanup(0, errno, "tmp basename"); us.f.tmpbase = strdup(tmpbase_local); if (us.f.tmpbase == NULL) - err_no_cleanup(errno, "strdup tmpbase"); + err_no_cleanup(0, errno, "strdup tmpbase"); free_if_null(&tmpdir); if (us.f.tname == NULL) - err_no_cleanup(errno, "x->f.tname null"); + err_no_cleanup(0, errno, "x->f.tname null"); if (*us.f.tname == '\0') - err_no_cleanup(errno, "x->f.tname empty"); + err_no_cleanup(0, errno, "x->f.tname empty"); if (fstat(us.f.tmp_fd, &us.f.tmp_st) < 0) - err_no_cleanup(errno, "%s: stat", us.f.tname); + err_no_cleanup(0, errno, "%s: stat", us.f.tname); memset(us.f.real_buf, 0, sizeof(us.f.real_buf)); memset(us.f.bufcmp, 0, sizeof(us.f.bufcmp)); @@ -164,7 +164,7 @@ xstatus(void) struct xstate *x = xstart(0, NULL); if (x == NULL) - err_no_cleanup(EACCES, "NULL pointer to xstate"); + err_no_cleanup(0, EACCES, "NULL pointer to xstate"); return x; } diff --git a/util/libreboot-utils/lib/string.c b/util/libreboot-utils/lib/string.c index 2f2be5f3..0329c6c3 100644 --- a/util/libreboot-utils/lib/string.c +++ b/util/libreboot-utils/lib/string.c @@ -14,25 +14,12 @@ #include <string.h> #include <stdlib.h> #include <unistd.h> +#include <limits.h> +#include <stdint.h> #include "../include/common.h" -/* scmp() - strict string comparison - * - * strict string comparison - * similar to strncmp, but null and - * unterminated inputs do not produce - * a return value; on error, errno is - * set and -1 is returned. - * - * the real return value is stored in - * the 4th argument by pointer. - * - * the value at rval pointer is set, - * only upon success. callers should - * check the return value accordingly. - */ - +/* strict strcmp */ int scmp(const char *a, const char *b, @@ -46,9 +33,8 @@ scmp(const char *a, if (a == NULL || b == NULL || rval == NULL) { - errno = EFAULT; - return -1; + goto err; } for (ch = 0; ch < maxlen; ch++) { @@ -67,27 +53,14 @@ scmp(const char *a, } } - /* block unterminated strings */ +err: errno = EFAULT; + if (rval != NULL) + *rval = -1; return -1; } -/* slen() - strict strict length - * - * strict string length calculation - * similar to strnlen, but null and - * unterminated inputs do not produce - * a return value; on error, errno is - * set and -1 is returned. - * - * the real return value is stored in - * the 3rd argument by pointer. - * - * the value at rval pointer is set, - * only upon success. callers should - * check the return value accordingly. - */ - +/* strict strlen */ int slen(const char *s, size_t maxlen, @@ -97,9 +70,8 @@ slen(const char *s, if (s == NULL || rval == NULL) { - errno = EFAULT; - return -1; + goto err; } for (ch = 0; @@ -109,17 +81,120 @@ slen(const char *s, if (ch == maxlen) { /* unterminated */ errno = EFAULT; - return -1; + goto err; } *rval = ch; return 0; +err: + if (rval != NULL) + *rval = 0; + return -1; +} + +/* strict strdup */ +int +sdup(const char *s, + size_t n, char **dest) +{ + size_t size; + char *rval; + + if (dest == NULL || + slen(s, n, &size) < 0 || + if_err(size == SIZE_MAX, EOVERFLOW) || + (rval = malloc(size + 1)) == NULL) { + + if (dest != NULL) + *dest = NULL; + return -1; + } + + memcpy(rval, s, size); + *(rval + size) = '\0'; + + *dest = rval; + return 0; +} + +/* strict strcat */ +int +scat(const char *s1, const char *s2, + size_t n, char **dest) +{ + size_t size1; + size_t size2; + char *rval; + + if (dest == NULL || + slen(s1, n, &size1) < 0 || + slen(s2, n, &size2) < 0 || + if_err(size1 > SIZE_MAX - size2 - 1, EOVERFLOW) || + (rval = malloc(size1 + size2 + 1)) == NULL) { + + if (dest != NULL) + *dest = NULL; + return -1; + } + + memcpy(rval, s1, size1); + memcpy(rval + size1, s2, size2); + *(rval + size1 + size2) = '\0'; + + *dest = rval; + return 0; +} + +/* strict split/de-cat - off is where + 2nd buffer will start from */ +int +dcat(const char *s, size_t n, + size_t off, char **dest1, + char **dest2) +{ + size_t size; + char *rval1 = NULL; + char *rval2 = NULL; + + if (dest1 == NULL || dest2 == NULL || + slen(s, n, &size) < 0 || + if_err(size == SIZE_MAX, EOVERFLOW) || + if_err(off >= size, EOVERFLOW) || + (rval1 = malloc(off + 1)) == NULL || + (rval2 = malloc(size - off + 1)) == NULL) { + + goto err; + } + + memcpy(rval1, s, off); + *(rval1 + off) = '\0'; + + memcpy(rval2, s + off, size - off); + *(rval2 + size - off) = '\0'; + + *dest1 = rval1; + *dest2 = rval2; + + return 0; + +err: + if (rval1 != NULL) + free(rval1); + if (rval2 != NULL) + free(rval2); + + if (dest1 != NULL) + *dest1 = NULL; + if (dest2 != NULL) + *dest2 = NULL; + + return -1; } /* the one for nvmutil state is in state.c */ /* this one just exits */ void -err_no_cleanup(int nvm_errval, const char *msg, ...) +err_no_cleanup(int stfu, int nvm_errval, const char *msg, ...) { va_list args; int saved_errno = errno; @@ -141,7 +216,10 @@ err_no_cleanup(int nvm_errval, const char *msg, ...) vfprintf(stderr, msg, args); va_end(args); - fprintf(stderr, ": %s\n", strerror(errno)); + if (p != NULL) + fprintf(stderr, ": %s\n", strerror(errno)); + else + fprintf(stderr, "%s\n", strerror(errno)); exit(EXIT_FAILURE); } diff --git a/util/libreboot-utils/mkhtemp.c b/util/libreboot-utils/mkhtemp.c index 4408f763..261227cb 100644 --- a/util/libreboot-utils/mkhtemp.c +++ b/util/libreboot-utils/mkhtemp.c @@ -10,6 +10,10 @@ * generally provides much higher strictness than previous * implementations such as mktemp, mkstemp or even mkdtemp. * + * It uses several modern features by default, e.g. openat2 + * and O_TMPFILE on Linux, with additional hardening; BSD + * projects only have openat so the code uses that there. + * * Many programs rely on mktemp, and they use TMPDIR in a way * that is quite insecure. Mkhtemp intends to change that, * quite dramatically, with: userspace sandbox (and use OS @@ -87,9 +91,10 @@ main(int argc, char *argv[]) int fd = -1; int type = MKHTEMP_FILE; + int stfu = 0; /* -q option */ if (lbgetprogname(argv[0]) == NULL) - err_no_cleanup(errno, "could not set progname"); + err_no_cleanup(stfu, errno, "could not set progname"); /* https://man.openbsd.org/pledge.2 */ #if defined(__OpenBSD__) && defined(OpenBSD) @@ -100,7 +105,7 @@ main(int argc, char *argv[]) #endif while ((c = - getopt(argc, argv, "dp:")) != -1) { + getopt(argc, argv, "qdp:")) != -1) { switch (c) { case 'd': @@ -111,6 +116,11 @@ main(int argc, char *argv[]) tmpdir = optarg; break; + case 'q': /* don't print errors */ + /* (exit status unchanged) */ + stfu = 1; + break; + default: goto err_usage; } @@ -119,21 +129,20 @@ main(int argc, char *argv[]) if (optind < argc) template = argv[optind]; if (optind + 1 < argc) - err_no_cleanup(EINVAL, - "usage: mkhtemp [-d] [-p dir] [template]\n"); + goto err_usage; /* custom template e.g. foo.XXXXXXXXXXXXXXXXXXXXX */ if (template != NULL) { if (slen(template, maxlen, &tlen) < 0) - err_no_cleanup(EINVAL, + err_no_cleanup(stfu, EINVAL, "invalid template"); for (p = template + tlen; p > template && *--p == 'X'; xc++); - if (xc < 6) - err_no_cleanup(EINVAL, - "template must end in at least 6 X"); + if (xc < 3) /* the gnu mktemp errs on less than 3 */ + err_no_cleanup(stfu, EINVAL, + "template must have 3 X or more on end (12+ advised"); } /* user supplied -p PATH - WARNING: @@ -146,38 +155,35 @@ main(int argc, char *argv[]) if (tmpdir != NULL) { rp = realpath(tmpdir, resolved); if (rp == NULL) - err_no_cleanup(errno, - "%s", tmpdir); + err_no_cleanup(stfu, errno, "%s", tmpdir); tmpdir = resolved; } if (new_tmp_common(&fd, &s, type, tmpdir, template) < 0) - err_no_cleanup(errno, "%s", s); + err_no_cleanup(stfu, errno, "%s", s); #if defined(__OpenBSD__) && defined(OpenBSD) #if (OpenBSD) >= 509 if (pledge("stdio", NULL) == -1) - err_no_cleanup(errno, "pledge, exit"); + err_no_cleanup(stfu, errno, "pledge, exit"); #endif #endif if (s == NULL) - err_no_cleanup(EFAULT, "bad string initialisation"); - + err_no_cleanup(stfu, EFAULT, "bad string initialisation"); if (*s == '\0') - err_no_cleanup(EFAULT, "empty string initialisation"); - + err_no_cleanup(stfu, EFAULT, "empty string initialisation"); if (slen(s, maxlen, &len) < 0) - err_no_cleanup(EFAULT, "unterminated string initialisation"); + err_no_cleanup(stfu, EFAULT, "unterminated string initialisiert"); printf("%s\n", s); return EXIT_SUCCESS; err_usage: - err_no_cleanup(EINVAL, + err_no_cleanup(stfu, EINVAL, "usage: %s [-d] [-p dir] [template]\n", getnvmprogname()); }/* @@ -191,3 +197,15 @@ err_usage: */ + + + + + + + + + + + + diff --git a/util/libreboot-utils/nvmutil.c b/util/libreboot-utils/nvmutil.c index d9b91349..e02f60af 100644 --- a/util/libreboot-utils/nvmutil.c +++ b/util/libreboot-utils/nvmutil.c @@ -36,34 +36,34 @@ main(int argc, char *argv[]) size_t c; if (lbgetprogname(argv[0]) == NULL) - err_no_cleanup(errno, "could not set progname"); + err_no_cleanup(0, errno, "could not set progname"); /* https://man.openbsd.org/pledge.2 https://man.openbsd.org/unveil.2 */ #if defined(__OpenBSD__) && defined(OpenBSD) #if (OpenBSD) >= 604 if (pledge("stdio flock rpath wpath cpath unveil", NULL) == -1) - err_no_cleanup(errno, "pledge plus unveil, main"); + err_no_cleanup(0, errno, "pledge plus unveil, main"); if (unveil("/dev/null", "r") == -1) - err_no_cleanup(errno, "unveil r: /dev/null"); + err_no_cleanup(0, errno, "unveil r: /dev/null"); #elif (OpenBSD) >= 509 if (pledge("stdio flock rpath wpath cpath", NULL) == -1) - err_no_cleanup(errno, "pledge, main"); + err_no_cleanup(0, errno, "pledge, main"); #endif #endif #ifndef S_ISREG - err_no_cleanup(ECANCELED, + err_no_cleanup(0, ECANCELED, "Can't determine file types (S_ISREG undefined)"); #endif #if ((CHAR_BIT) != 8) - err_no_cleanup(ECANCELED, "Unsupported char size"); + err_no_cleanup(0, ECANCELED, "Unsupported char size"); #endif x = xstart(argc, argv); if (x == NULL) - err_no_cleanup(ECANCELED, "NULL state on init"); + err_no_cleanup(0, ECANCELED, "NULL state on init"); /* parse user command */ /* TODO: CHECK ACCESSES VIA xstatus() */ |
