diff options
Diffstat (limited to 'util')
| -rw-r--r-- | util/libreboot-utils/include/common.h | 25 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/command.c | 15 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/file.c | 131 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/io.c | 4 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/mkhtemp.c | 58 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/num.c | 21 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/rand.c | 3 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/state.c | 17 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/string.c | 435 | ||||
| -rw-r--r-- | util/libreboot-utils/lottery.c | 12 | ||||
| -rw-r--r-- | util/libreboot-utils/mkhtemp.c | 14 | ||||
| -rw-r--r-- | util/libreboot-utils/nvmutil.c | 22 |
12 files changed, 540 insertions, 217 deletions
diff --git a/util/libreboot-utils/include/common.h b/util/libreboot-utils/include/common.h index 4b736808..8276d6da 100644 --- a/util/libreboot-utils/include/common.h +++ b/util/libreboot-utils/include/common.h @@ -301,8 +301,6 @@ struct xstate { struct macaddr mac; struct xfile f; - char *argv0; - size_t i; /* index to cmd[] for current command */ int no_cmd; @@ -374,21 +372,26 @@ void write_mac_part(size_t partnum); /* string functions */ +size_t page_remain(const void *p); +long pagesize(void); int xunveilx(const char *path, const char *permissions); int xpledgex(const char *promises, const char *execpromises); char *smalloc(char **buf, size_t size); void *vmalloc(void **buf, size_t size); -int slen(const char *scmp, size_t maxlen, +size_t slen(const char *scmp, size_t maxlen, size_t *rval); +int vcmp(const void *s1, const void *s2, size_t n); int scmp(const char *a, const char *b, size_t maxlen, int *rval); -int sdup(const char *s, +int ccmp(const char *a, const char *b, size_t i, + int *rval); +char *sdup(const char *s, size_t n, char **dest); -int scatn(ssize_t sc, const char **sv, +char *scatn(ssize_t sc, const char **sv, size_t max, char **rval); -int scat(const char *s1, const char *s2, +char *scat(const char *s1, const char *s2, size_t n, char **dest); -int dcat(const char *s, size_t n, +void dcat(const char *s, size_t n, size_t off, char **dest1, char **dest2); /* numerical functions @@ -484,6 +487,14 @@ ssize_t rw_over_nrw(ssize_t r, size_t nrw); off_t lseek_on_eintr(int fd, off_t off, int whence, int loop_eagain, int loop_eintr); int try_err(int loop_err, int errval); +ssize_t read_on_eintr(int fd, + void *buf, size_t count); +ssize_t write_on_eintr(int fd, + void *buf, size_t count); +ssize_t pread_on_eintr(int fd, + void *buf, size_t count, off_t off); +ssize_t pwrite_on_eintr(int fd, + void *buf, size_t count, off_t off); /* Error handling and cleanup */ diff --git a/util/libreboot-utils/lib/command.c b/util/libreboot-utils/lib/command.c index a1e46e5f..3ee75628 100644 --- a/util/libreboot-utils/lib/command.c +++ b/util/libreboot-utils/lib/command.c @@ -57,10 +57,7 @@ sanitize_command_index(size_t c) err_exit(EINVAL, "cmd index %lu: empty str", (size_t)c); - if (slen(cmd->str, MAX_CMD_LEN +1, &rval) < 0) - err_exit(errno, "Could not get command length"); - - if (rval > MAX_CMD_LEN) { + if (slen(cmd->str, MAX_CMD_LEN +1, &rval) > MAX_CMD_LEN) { err_exit(EINVAL, "cmd index %lu: str too long: %s", (size_t)c, cmd->str); } @@ -109,10 +106,7 @@ set_cmd(int argc, char *argv[]) cmd = x->cmd[c].str; - if (scmp(argv[2], cmd, MAX_CMD_LEN, &rval) < 0) - err_exit(EINVAL, - "could not compare command strings"); - if (rval != 0) + if (scmp(argv[2], cmd, MAX_CMD_LEN, &rval)) continue; /* not the right command */ /* valid command found */ @@ -239,10 +233,7 @@ parse_mac_string(void) size_t rval; - if (slen(x->mac.str, 18, &rval) < 0) - err_exit(EINVAL, "Could not determine MAC length"); - - if (rval != 17) + if (slen(x->mac.str, 18, &rval) != 17) err_exit(EINVAL, "MAC address is the wrong length"); memset(mac->mac_buf, 0, sizeof(mac->mac_buf)); diff --git a/util/libreboot-utils/lib/file.c b/util/libreboot-utils/lib/file.c index 48eb37ed..b9d31ad7 100644 --- a/util/libreboot-utils/lib/file.c +++ b/util/libreboot-utils/lib/file.c @@ -88,10 +88,7 @@ fsync_dir(const char *path) maxlen = 4096; #endif - if (if_err(path == NULL, EFAULT) || - if_err_sys(slen(path, maxlen, &pathlen) < 0) || - if_err(pathlen >= maxlen || pathlen < 0, EMSGSIZE) || - if_err(pathlen == 0, EINVAL)) + if (if_err(slen(path, maxlen, &pathlen) == 0, EINVAL)) goto err_fsync_dir; memcpy(smalloc(&dirbuf, pathlen + 1), @@ -323,15 +320,15 @@ try_rw_again: real_pread_pwrite: #endif if (rw_type == IO_WRITE) - r = write(fd, mem, nrw); + r = write_on_eintr(fd, mem, nrw); else if (rw_type == IO_READ) - r = read(fd, mem, nrw); + r = read_on_eintr(fd, mem, nrw); #if defined(REAL_POS_IO) && \ REAL_POS_IO > 0 else if (rw_type == IO_PWRITE) - r = pwrite(fd, mem, nrw, off); + r = pwrite_on_eintr(fd, mem, nrw, off); else if (rw_type == IO_PREAD) - r = pread(fd, mem, nrw, off); + r = pread_on_eintr(fd, mem, nrw, off); #endif if (r == -1 && (errno == try_err(loop_eintr, EINTR) @@ -386,9 +383,9 @@ real_pread_pwrite: } if (rw_type == IO_PREAD) - r = read(fd, mem, nrw); + r = read_on_eintr(fd, mem, nrw); else if (rw_type == IO_PWRITE) - r = write(fd, mem, nrw); + r = write_on_eintr(fd, mem, nrw); if (rw_over_nrw(r, nrw) == -1) break; @@ -841,11 +838,12 @@ fs_dirname_basename(const char *path, size_t maxlen = 4096; #endif - if (path == NULL || dir == NULL || base == NULL || - if_err_sys(slen(path, maxlen, &len) < 0)) + if (if_err(path == NULL || dir == NULL || base == NULL, EFAULT)) return -1; - memcpy(smalloc(&buf, len + 1), path, len + 1); + slen(path, maxlen, &len); + memcpy(smalloc(&buf, len + 1), + path, len + 1); /* strip trailing slashes */ while (len > 1 && buf[len - 1] == '/') @@ -865,7 +863,7 @@ fs_dirname_basename(const char *path, } } else if (allow_relative) { - *dir = strdup("."); + sdup(".", maxlen, dir); *base = buf; } else { errno = EINVAL; @@ -955,13 +953,118 @@ retry: return rval; } +ssize_t +read_on_eintr(int fd, + void *buf, size_t count) +{ + int saved_errno = errno; + int rval; + + if (if_err(buf == NULL, EFAULT) || + if_err(fd < 0, EBADF) || + if_err(count == 0, EINVAL)) + goto err; + +retry: + errno = 0; + + if ((rval = read(fd, buf, count)) == -1 && ( + errno == EINTR || + errno == EAGAIN || + errno == EWOULDBLOCK || + errno == ETXTBSY)) + goto retry; + + errno = saved_errno; + return rval; +err: + return set_errno(saved_errno, EIO); +} + +ssize_t +pread_on_eintr(int fd, + void *buf, size_t count, + off_t off) +{ + int saved_errno = errno; + int rval; + + if (if_err(buf == NULL, EFAULT) || + if_err(fd < 0, EBADF) || + if_err(off < 0, EFAULT) || + if_err(count == 0, EINVAL)) + goto err; + +retry: + errno = 0; + + if ((rval = pread(fd, buf, count, off)) == -1 && ( + errno == EINTR || + errno == EAGAIN || + errno == EWOULDBLOCK || + errno == ETXTBSY)) + goto retry; + + errno = saved_errno; + return rval; +err: + return set_errno(saved_errno, EIO); +} +ssize_t +write_on_eintr(int fd, + void *buf, size_t count) +{ + int saved_errno = errno; + int rval; + if (if_err(buf == NULL, EFAULT) || + if_err(fd < 0, EBADF) || + if_err(count == 0, EINVAL)) + goto err; +retry: + errno = 0; + if ((rval = write(fd, buf, count)) == -1 && ( + errno == EINTR || + errno == EAGAIN || + errno == EWOULDBLOCK || + errno == ETXTBSY)) + goto retry; + errno = saved_errno; + return rval; +err: + return set_errno(saved_errno, EIO); +} +ssize_t +pwrite_on_eintr(int fd, + void *buf, size_t count, + off_t off) +{ + int saved_errno = errno; + int rval; + if (if_err(buf == NULL, EFAULT) || + if_err(fd < 0, EBADF) || + if_err(off < 0, EFAULT) || + if_err(count == 0, EINVAL)) + goto err; +retry: + errno = 0; + if ((rval = pwrite(fd, buf, count, off)) == -1 && ( + errno == EINTR || + errno == EAGAIN || + errno == EWOULDBLOCK || + errno == ETXTBSY)) + goto retry; + errno = saved_errno; + return rval; +err: + return set_errno(saved_errno, EIO); +} diff --git a/util/libreboot-utils/lib/io.c b/util/libreboot-utils/lib/io.c index eac6073e..4938cdc8 100644 --- a/util/libreboot-utils/lib/io.c +++ b/util/libreboot-utils/lib/io.c @@ -143,7 +143,7 @@ read_file(void) if (_r < 0) err_exit(errno, "%s: read failed (cmp)", f->tname); - if (memcmp(f->buf, f->bufcmp, f->gbe_file_size) != 0) + if (vcmp(f->buf, f->bufcmp, f->gbe_file_size) != 0) err_exit(errno, "%s: %s: read contents differ (pre-test)", f->fname, f->tname); } @@ -329,7 +329,7 @@ check_written_part(size_t p) f->rw_check_err_read[p] = f->io_err_gbe = 1; else if ((size_t)rval != gbe_rw_size) f->rw_check_partial_read[p] = f->io_err_gbe = 1; - else if (memcmp(mem_offset, f->pad, gbe_rw_size) != 0) + else if (vcmp(mem_offset, f->pad, gbe_rw_size) != 0) f->rw_check_bad_part[p] = f->io_err_gbe = 1; if (f->rw_check_err_read[p] || diff --git a/util/libreboot-utils/lib/mkhtemp.c b/util/libreboot-utils/lib/mkhtemp.c index 72942868..0560da47 100644 --- a/util/libreboot-utils/lib/mkhtemp.c +++ b/util/libreboot-utils/lib/mkhtemp.c @@ -120,8 +120,6 @@ new_tmp_common(int *fd, char **path, int type, if (tmpdir == NULL) goto err; - if (slen(tmpdir, maxlen, &dirlen) < 0) - goto err; if (*tmpdir == '\0') goto err; if (*tmpdir != '/') @@ -132,22 +130,12 @@ new_tmp_common(int *fd, char **path, int type, else templatestr = "tmp.XXXXXXXXXX"; - if (slen(templatestr, maxlen, &templatestr_len) < 0) - goto err; - - /* sizeof adds an extra byte, useful - * because we also want '.' or '/' - */ - destlen = dirlen + 1 + templatestr_len; - if (destlen > maxlen - 1) { - errno = EOVERFLOW; - goto err; - } - - memcpy(smalloc(&dest, destlen + 1), tmpdir, dirlen); - *(dest + dirlen) = '/'; - memcpy(dest + dirlen + 1, templatestr, templatestr_len); - *(dest + destlen) = '\0'; + /* may as well calculate in advance */ + destlen = slen(tmpdir, maxlen, &dirlen) + 1 + + slen(templatestr, maxlen, &templatestr_len); + /* full path: */ + dest = scatn(3, (const char *[]) { tmpdir, "/", templatestr }, + maxlen, &dest); fname = dest + dirlen + 1; @@ -319,12 +307,10 @@ same_dir(const char *a, const char *b) /* optimisation: if both dirs are the same, we don't need - to check anything. sehr schnell: + to check anything. sehr schnell! */ - if (scmp(a, b, maxlen, &rval_scmp) < 0) - goto err_same_dir; /* bonus: scmp checks null for us */ - if (rval_scmp == 0) + if (!scmp(a, b, maxlen, &rval_scmp)) goto success_same_dir; fd_a = fs_open(a, O_RDONLY | O_DIRECTORY | O_NOFOLLOW); @@ -533,7 +519,7 @@ mkhtemp(int *fd, struct stat *st_dir_initial, int type) { - size_t len = 0; + size_t template_len = 0; size_t xc = 0; size_t fname_len = 0; @@ -557,30 +543,28 @@ mkhtemp(int *fd, if (if_err(fd == NULL || template == NULL || fname == NULL || st_dir_initial == NULL, EFAULT) || if_err(*fd >= 0, EEXIST) || - if_err(dirfd < 0, EBADF) - || - if_err_sys(slen(template, max_len, &len) < 0) || - if_err(len >= max_len, EMSGSIZE) - || - if_err_sys(slen(fname, max_len, &fname_len) < 0) || - if_err(fname == NULL, EINVAL) || - if_err(strrchr(fname, '/') != NULL, EINVAL)) + if_err(dirfd < 0, EBADF)) return -1; - for (end = template + len; /* count X */ + /* count X */ + for (end = template + slen(template, max_len, &template_len); end > template && *--end == 'X'; xc++); - if (if_err(xc < 3 || xc > len, EINVAL) || - if_err(fname_len > len, EOVERFLOW)) + fname_len = slen(fname, max_len, &fname_len); + if (if_err(strrchr(fname, '/') != NULL, EINVAL)) + return -1; + + if (if_err(xc < 3 || xc > template_len, EINVAL) || + if_err(fname_len > template_len, EOVERFLOW)) return -1; - if (if_err(memcmp(fname, template + len - fname_len, + if (if_err(vcmp(fname, template + template_len - fname_len, fname_len) != 0, EINVAL)) return -1; /* fname_copy = templatestr region only; p points to trailing XXXXXX */ memcpy(smalloc(&fname_copy, fname_len + 1), - template + len - fname_len, + template + template_len - fname_len, fname_len + 1); p = fname_copy + fname_len - xc; @@ -596,7 +580,7 @@ mkhtemp(int *fd, goto err; /* success: copy final name back */ - memcpy(template + len - fname_len, + memcpy(template + template_len - fname_len, fname_copy, fname_len); errno = saved_errno; diff --git a/util/libreboot-utils/lib/num.c b/util/libreboot-utils/lib/num.c index e4d0ce6b..e13a8853 100644 --- a/util/libreboot-utils/lib/num.c +++ b/util/libreboot-utils/lib/num.c @@ -50,6 +50,22 @@ hextonum(char ch_s) } /* basically hexdump -C */ +/* + TODO: optimise this + write a full util for hexdump + how to optimise: + don't call print tens of thousands of times! + convert the numbers manually, and cache everything + in a BUFSIZ sized buffer, with everything properly + aligned. i worked out that i could fit 79 rows + in a 8KB buffer (1264 bytes of numbers represented + as strings in hex) + this depends on the OS, and would be calculated at + runtime. + then: + don't use printf. just write it to stdout (basically + a simple cat implementation) +*/ void spew_hex(const void *data, size_t len) { @@ -64,7 +80,10 @@ spew_hex(const void *data, size_t len) for (i = 0; i < len; i += 16) { - printf("%08zx ", i); + if (len <= 4294967296) /* below 4GB */ + printf("%08zx ", i); + else + printf("%0*zx ", sizeof(size_t) * 2, i); for (j = 0; j < 16; j++) { diff --git a/util/libreboot-utils/lib/rand.c b/util/libreboot-utils/lib/rand.c index 2aa0de3a..9da8d9eb 100644 --- a/util/libreboot-utils/lib/rand.c +++ b/util/libreboot-utils/lib/rand.c @@ -150,7 +150,8 @@ rset(void *buf, size_t n) int fd = -1; open_on_eintr("/dev/urandom", &fd, O_RDONLY, 0400, NULL); retry_rand: - if ((rc = read(fd, (unsigned char *)buf + off, n - off)) < 0) { + if ((rc = read_on_eintr(fd, + (unsigned char *)buf + off, n - off)) < 0) { #elif defined(__linux__) retry_rand: if ((rc = (ssize_t)syscall(SYS_getrandom, diff --git a/util/libreboot-utils/lib/state.c b/util/libreboot-utils/lib/state.c index a3cd5b1f..f0be5656 100644 --- a/util/libreboot-utils/lib/state.c +++ b/util/libreboot-utils/lib/state.c @@ -22,6 +22,12 @@ struct xstate * xstart(int argc, char *argv[]) { +#if defined(PATH_LEN) && \ + ((PATH_LEN) >= 256) + static size_t maxlen = PATH_LEN; +#else + static size_t maxlen = 4096; +#endif static int first_run = 1; static char *dir = NULL; static char *base = NULL; @@ -77,9 +83,6 @@ xstart(int argc, char *argv[]) /* .f */ {0}, - /* .argv0 (for our getprogname implementation) */ - NULL, - /* ->i (index to cmd[]) */ 0, @@ -103,7 +106,6 @@ xstart(int argc, char *argv[]) us.f.buf = us.f.real_buf; - us.argv0 = argv[0]; us.f.fname = argv[1]; us.f.tmp_fd = -1; @@ -117,8 +119,7 @@ xstart(int argc, char *argv[]) err_exit(errno, "xstart: don't know CWD of %s", us.f.fname); - if ((us.f.base = strdup(base)) == NULL) - err_exit(errno, "strdup base"); + sdup(base, maxlen, &us.f.base); us.f.dirfd = fs_open(dir, O_RDONLY | O_DIRECTORY); @@ -132,9 +133,7 @@ xstart(int argc, char *argv[]) &tmpdir, &tmpbase_local, 0) < 0) err_exit(errno, "tmp basename"); - us.f.tmpbase = strdup(tmpbase_local); - if (us.f.tmpbase == NULL) - err_exit(errno, "strdup tmpbase"); + sdup(tmpbase_local, maxlen, &us.f.tmpbase); free_and_set_null(&tmpdir); diff --git a/util/libreboot-utils/lib/string.c b/util/libreboot-utils/lib/string.c index c3cf4519..c083bd6d 100644 --- a/util/libreboot-utils/lib/string.c +++ b/util/libreboot-utils/lib/string.c @@ -19,6 +19,47 @@ #include "../include/common.h" +/* for null detection inside + * word-optimised string functions + */ +#define ff ((size_t)-1 / 0xFF) +#define high ((ff) * 0x80) +/* NOTE: + * do not assume that a match means + * both words have null at the same + * location. see how this is handled + * e.g. in scmp. + */ +#define zeroes(x) (((x) - (ff)) & ~(x) & (high)) + +size_t +page_remain(const void *p) +{ + /* calling sysconf repeatedly + * is folly. cache it (static) + */ + static size_t pagesz = 0; + if (!pagesz) + pagesz = (size_t)pagesize(); + + return pagesz - ((uintptr_t)p & (pagesz - 1)); +} + +long +pagesize(void) +{ + static long rval = 0; + static int set = 0; + + if (!set) { + if ((rval = sysconf(_SC_PAGESIZE)) < 0) + err_exit(errno, "could not determine page size"); + set = 1; + } + + return rval; +} + void free_and_set_null(char **buf) { @@ -78,180 +119,310 @@ vmalloc(void **buf, size_t size) return *buf = rval; } -/* strict strcmp */ +/* strict word-based strcmp */ int scmp(const char *a, const char *b, size_t maxlen, int *rval) { - size_t ch; - unsigned char ac; - unsigned char bc; + size_t i = 0; + size_t j; + size_t wa; + size_t wb; + int saved_errno = errno; - if (a == NULL || - b == NULL || - rval == NULL) { - errno = EFAULT; + if (if_err(a == NULL || b == NULL || rval == NULL, EFAULT)) goto err; + + for ( ; ((uintptr_t)(a + i) % sizeof(size_t)) != 0; i++) { + + if (if_err(i >= maxlen, EOVERFLOW)) + goto err; + else if (!ccmp(a, b, i, rval)) + goto out; } - for (ch = 0; ch < maxlen; ch++) { + for ( ; i + sizeof(size_t) <= maxlen; + i += sizeof(size_t)) { - ac = (unsigned char)a[ch]; - bc = (unsigned char)b[ch]; + /* prevent crossing page boundary on word check */ + if (page_remain(a + i) < sizeof(size_t) || + page_remain(b + i) < sizeof(size_t)) + break; - if (ac != bc) { - *rval = ac - bc; - return 0; - } + memcpy(&wa, a + i, sizeof(size_t)); + memcpy(&wb, b + i, sizeof(size_t)); - if (ac == '\0') { - *rval = 0; - return 0; - } + if (wa != wb) + for (j = 0; j < sizeof(size_t); j++) + if (!ccmp(a, b, i + j, rval)) + goto out; + + if (!zeroes(wa)) + continue; + + *rval = 0; + goto out; } + for ( ; i < maxlen; i++) + if (!ccmp(a, b, i, rval)) + goto out; + err: - errno = EFAULT; + (void) set_errno(saved_errno, EFAULT); if (rval != NULL) *rval = -1; + + err_exit(errno, "scmp"); return -1; +out: + errno = saved_errno; + return *rval; } -/* strict strlen */ -int +int ccmp(const char *a, const char *b, + size_t i, int *rval) +{ + unsigned char ac; + unsigned char bc; + + if (if_err(a == NULL || b == NULL || rval == NULL, EFAULT)) + err_exit(errno, "ccmp"); + + ac = (unsigned char)a[i]; + bc = (unsigned char)b[i]; + + if (ac != bc) { + *rval = ac - bc; + return 0; + } else if (ac == '\0') { + *rval = 0; + return 0; + } + + return 1; +} + +/* strict word-based strlen */ +size_t slen(const char *s, size_t maxlen, size_t *rval) { - size_t ch; + int saved_errno = errno; + size_t i = 0; + size_t w; + size_t j; - if (s == NULL || - rval == NULL) { - errno = EFAULT; + if (if_err(s == NULL || rval == NULL, EFAULT)) goto err; + + for ( ; ((uintptr_t)(s + i) % sizeof(size_t)) != 0; i++) { + + if (i >= maxlen) + goto err; + if (s[i] == '\0') { + *rval = i; + goto out; + } } - for (ch = 0; - ch < maxlen && s[ch] != '\0'; - ch++); + for ( ; i + sizeof(size_t) <= maxlen; + i += sizeof(size_t)) { - if (ch == maxlen) { - /* unterminated */ - errno = EFAULT; - goto err; + memcpy(&w, s + i, sizeof(size_t)); + if (!zeroes(w)) + continue; + + for (j = 0; j < sizeof(size_t); j++) { + if (s[i + j] == '\0') { + *rval = i + j; + goto out; + } + } + } + + for ( ; i < maxlen; i++) { + if (s[i] == '\0') { + *rval = i; + goto out; + } } - *rval = ch; - return 0; err: + (void) set_errno(saved_errno, EFAULT); if (rval != NULL) *rval = 0; - return -1; + + err_exit(errno, "slen"); /* abort */ + return 0; /* gcc15 is happy */ +out: + errno = saved_errno; + return *rval; } -/* strict strdup */ -int +/* strict word-based strdup */ +char * sdup(const char *s, - size_t n, char **dest) + size_t max, char **dest) { - size_t size; - char *rval = NULL; + size_t j; + size_t w; + size_t i = 0; + char *out = NULL; + int saved_errno = errno; + + if (if_err(dest == NULL || *dest != NULL || s == NULL, EFAULT)) + goto err; + + out = smalloc(dest, max); + + for ( ; ((uintptr_t)(s + i) % sizeof(size_t)) != 0; i++) { + + if (if_err(i >= max, EOVERFLOW)) + goto err; - if (dest == NULL || - slen(s, n, &size) < 0) { - if (dest != NULL) - *dest = NULL; - return -1; + out[i] = s[i]; + if (s[i] == '\0') { + *dest = out; + goto out; + } } - memcpy(smalloc(&rval, size + 1), s, size); - *(rval + size) = '\0'; + for ( ; i + sizeof(size_t) <= max; i += sizeof(size_t)) { - *dest = rval; - return 0; + if (page_remain(s + i) < sizeof(size_t)) + break; + + memcpy(&w, s + i, sizeof(size_t)); + if (!zeroes(w)) { + memcpy(out + i, &w, sizeof(size_t)); + continue; + } + + for (j = 0; j < sizeof(size_t); j++) { + + out[i + j] = s[i + j]; + if (s[i + j] == '\0') { + *dest = out; + goto out; + } + } + } + + for ( ; i < max; i++) { + + out[i] = s[i]; + if (s[i] == '\0') { + *dest = out; + goto out; + } + } + +err: + free_and_set_null(&out); + if (dest != NULL) + *dest = NULL; + + (void) set_errno(saved_errno, EFAULT); + err_exit(errno, "sdup"); + + return NULL; +out: + errno = saved_errno; + return *dest; } /* concatenate N number of strings */ -/* slen already checks null/termination */ -int +char * scatn(ssize_t sc, const char **sv, size_t max, char **rval) { - ssize_t i = 0; - - size_t ts = 0; - size_t *size = NULL; - - char *ct = NULL; int saved_errno = errno; - - if (if_err(sc <= 0, EINVAL) || - if_err(sc > SIZE_MAX / sizeof(size_t), EOVERFLOW) || - if_err(sv == NULL, EINVAL)) + char *final = NULL; + char *rcur = NULL; + char *rtmp = NULL; + size_t i; + + if (if_err(sc < 2, EINVAL) || + if_err(sv == NULL, EFAULT) || + if_err(rval == NULL || *rval != NULL, EFAULT)) goto err; - vmalloc((void **)&size, sizeof(size_t) * sc); + for (i = 0; i < sc; i++) { - for (i = 0; i < sc; i++, ts += size[i]) - if (if_err(sv[i] == NULL, EINVAL) || - slen(sv[i], max, &size[i]) < 0 || - if_err(size[i] > max - 1, EOVERFLOW) || - if_err((size[i] + ts) < ts, EOVERFLOW)) + if (if_err(sv[i] == NULL, EFAULT)) goto err; + else if (i == 0) { + (void) sdup(sv[0], max, &final); + continue; + } - if (if_err(ts > SIZE_MAX - 1, EOVERFLOW) || - if_err(ts > max - 1, EOVERFLOW)) - goto err; - - smalloc(&ct, ts + 1); - for (ts = i = 0; i < sc; i++, ts += size[i]) - memcpy(ct + ts, sv[i], size[i]); + rtmp = NULL; + scat(final, sv[i], max, &rtmp); - *(ct + ts) = '\0'; - *rval = ct; + free_and_set_null(&final); + final = rtmp; + rtmp = NULL; + } errno = saved_errno; - return 0; + *rval = final; + return *rval; err: - free_and_set_null(&ct); - free_and_set_null((char **)&size); + free_and_set_null(&rcur); + free_and_set_null(&rtmp); + free_and_set_null(&final); - return set_errno(saved_errno, EFAULT); + (void) set_errno(saved_errno, EFAULT); + + err_exit(errno, "scatn"); + return NULL; } /* strict strcat */ -int +char * scat(const char *s1, const char *s2, size_t n, char **dest) { size_t size1; size_t size2; char *rval = NULL; + int saved_errno = errno; - if (dest == NULL || - slen(s1, n, &size1) < 0 || - slen(s2, n, &size2) < 0 || - if_err(size1 > SIZE_MAX - size2 - 1, EOVERFLOW)) { + if (if_err(dest == NULL || *dest != NULL, EFAULT)) + goto err; - if (dest != NULL) - *dest = NULL; - return -1; - } + slen(s1, n, &size1); + slen(s2, n, &size2); - memcpy(smalloc(&rval, size1 + size2 + 1), - s1, size1); + if (if_err(size1 + > SIZE_MAX - size2 - 1, EOVERFLOW)) + goto err; + + smalloc(&rval, size1 + size2 + 1); + + memcpy(rval, s1, size1); memcpy(rval + size1, s2, size2); *(rval + size1 + size2) = '\0'; *dest = rval; - return 0; + errno = saved_errno; + return *dest; +err: + (void) set_errno(saved_errno, EINVAL); + if (dest != NULL) + *dest = NULL; + err_exit(errno, "scat"); + + return NULL; } /* strict split/de-cat - off is where 2nd buffer will start from */ -int +void dcat(const char *s, size_t n, size_t off, char **dest1, char **dest2) @@ -259,14 +430,14 @@ dcat(const char *s, size_t n, size_t size; char *rval1 = NULL; char *rval2 = NULL; + int saved_errno = errno; - if (dest1 == NULL || dest2 == NULL || - slen(s, n, &size) < 0 || - if_err(size == SIZE_MAX, EOVERFLOW) || - if_err(off >= size, EOVERFLOW)) { + if (if_err(dest1 == NULL || dest2 == NULL, EFAULT)) + goto err; + if (if_err(slen(s, n, &size) >= SIZE_MAX - 1, EOVERFLOW) || + if_err(off >= size, EOVERFLOW)) goto err; - } memcpy(smalloc(&rval1, off + 1), s, off); @@ -279,20 +450,55 @@ dcat(const char *s, size_t n, *dest1 = rval1; *dest2 = rval2; - return 0; + errno = saved_errno; + return; err: - if (rval1 != NULL) - free(rval1); - if (rval2 != NULL) - free(rval2); + *dest1 = *dest2 = NULL; - if (dest1 != NULL) - *dest1 = NULL; - if (dest2 != NULL) - *dest2 = NULL; + free_and_set_null(&rval1); + free_and_set_null(&rval2); - return -1; + (void) set_errno(saved_errno, EINVAL); + err_exit(errno, "dcat"); +} + +/* because no libc reimagination is complete + * without a reimplementation of memcmp. and + * no safe one is complete without null checks. + */ +int +vcmp(const void *s1, const void *s2, size_t n) +{ + int saved_errno = errno; + size_t i = 0; + size_t a; + size_t b; + + const unsigned char *x; + const unsigned char *y; + + if (if_err(s1 == NULL || s2 == NULL, EFAULT)) + err_exit(EFAULT, "vcmp: null input"); + + x = s1; + y = s2; + + for ( ; i + sizeof(size_t) <= n; i += sizeof(size_t)) { + + memcpy(&a, x + i, sizeof(size_t)); + memcpy(&b, y + i, sizeof(size_t)); + + if (a != b) + break; + } + + for ( ; i < n; i++) + if (x[i] != y[i]) + return (int)x[i] - (int)y[i]; + + errno = saved_errno; + return 0; } /* on functions that return with errno, @@ -324,17 +530,13 @@ err_exit(int nvm_errval, const char *msg, ...) if (!errno) saved_errno = errno = ECANCELED; - if ((p = lbgetprogname()) != NULL) - fprintf(stderr, "%s: ", p); + fprintf(stderr, "%s: ", lbgetprogname()); va_start(args, msg); vfprintf(stderr, msg, args); va_end(args); - if (p != NULL) - fprintf(stderr, ": %s\n", strerror(errno)); - else - fprintf(stderr, "%s\n", strerror(errno)); + fprintf(stderr, ": %s\n", strerror(errno)); exit(EXIT_FAILURE); } @@ -397,8 +599,9 @@ lbsetprogname(char *argv0) static int set = 0; if (!set) { - if (argv0 == NULL || sdup(argv0, 4096, &progname) < 0) + if (argv0 == NULL) return "libreboot-utils"; + (void) sdup(argv0, 4096, &progname); set = 1; } diff --git a/util/libreboot-utils/lottery.c b/util/libreboot-utils/lottery.c index 48565c87..7370de1b 100644 --- a/util/libreboot-utils/lottery.c +++ b/util/libreboot-utils/lottery.c @@ -18,25 +18,25 @@ main(int argc, char **argv) { int same = 0; char *buf; + size_t size = BUFSIZ; (void) argc, (void) argv; (void) errhook(exit_cleanup); - if (lbsetprogname(argv[0]) == NULL) - err_exit(errno, "could not set progname"); + (void) lbsetprogname(argv[0]); /* https://man.openbsd.org/pledge.2 */ xpledgex("stdio", NULL); - buf = rmalloc(BUFSIZ); - if (!memcmp(buf, buf + (BUFSIZ >> 1), BUFSIZ >> 1)) + buf = rmalloc(size); + if (!vcmp(buf, buf + (size >> 1), size >> 1)) same = 1; if (argc < 2) /* no spew */ - spew_hex(buf, BUFSIZ); + spew_hex(buf, size); free_and_set_null(&buf); fprintf(stderr, "\n%s\n", same ? "You win!" : "You lose!"); - return same ^ 1; + return same ? EXIT_SUCCESS : EXIT_FAILURE; } static void diff --git a/util/libreboot-utils/mkhtemp.c b/util/libreboot-utils/mkhtemp.c index 04ce1993..f4c2b646 100644 --- a/util/libreboot-utils/mkhtemp.c +++ b/util/libreboot-utils/mkhtemp.c @@ -62,8 +62,7 @@ main(int argc, char *argv[]) int type = MKHTEMP_FILE; (void) errhook(exit_cleanup); - if (lbsetprogname(argv[0]) == NULL) - err_exit(errno, "could not set progname"); + (void) lbsetprogname(argv[0]); /* https://man.openbsd.org/pledge.2 */ xpledgex("stdio flock rpath wpath cpath", NULL); @@ -96,11 +95,7 @@ main(int argc, char *argv[]) /* custom template e.g. foo.XXXXXXXXXXXXXXXXXXXXX */ if (template != NULL) { - if (slen(template, maxlen, &tlen) < 0) - err_exit(EINVAL, - "invalid template"); - - for (p = template + tlen; + for (p = template + slen(template, maxlen, &tlen); p > template && *--p == 'X'; xc++); if (xc < 3) /* the gnu mktemp errs on less than 3 */ @@ -133,8 +128,9 @@ main(int argc, char *argv[]) err_exit(EFAULT, "bad string initialisation"); if (*s == '\0') err_exit(EFAULT, "empty string initialisation"); - if (slen(s, maxlen, &len) < 0) - err_exit(EFAULT, "unterminated string initialisiert"); + + slen(s, maxlen, &len); /* Nullterminierung prüfen */ + /* for good measure */ printf("%s\n", s); diff --git a/util/libreboot-utils/nvmutil.c b/util/libreboot-utils/nvmutil.c index 49d81a01..ec41371f 100644 --- a/util/libreboot-utils/nvmutil.c +++ b/util/libreboot-utils/nvmutil.c @@ -33,8 +33,7 @@ main(int argc, char *argv[]) size_t c; (void) errhook(exit_cleanup); - if (lbsetprogname(argv[0]) == NULL) - err_exit(errno, "could not set progname"); + (void) lbsetprogname(argv[0]); /* https://man.openbsd.org/pledge.2 */ /* https://man.openbsd.org/unveil.2 */ @@ -96,5 +95,22 @@ main(int argc, char *argv[]) static void exit_cleanup(void) { - return; + struct xstate *x; + struct xfile *f; + + x = xstatus(); + if (x == NULL) + return; + + f = &x->f; + + /* close fds if still open */ + close_on_eintr(&f->tmp_fd); + close_on_eintr(&f->gbe_fd); + + /* unlink tmpfile if it exists */ + if (f->tname != NULL) { + (void) unlink(f->tname); + free_and_set_null(&f->tname); + } } |
