diff options
| -rw-r--r-- | util/libreboot-utils/include/common.h | 15 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/command.c | 15 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/file.c | 14 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/io.c | 4 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/mkhtemp.c | 37 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/state.c | 13 | ||||
| -rw-r--r-- | util/libreboot-utils/lib/string.c | 382 | ||||
| -rw-r--r-- | util/libreboot-utils/lottery.c | 6 | ||||
| -rw-r--r-- | util/libreboot-utils/mkhtemp.c | 11 |
9 files changed, 346 insertions, 151 deletions
diff --git a/util/libreboot-utils/include/common.h b/util/libreboot-utils/include/common.h index 0ccc02aa..8276d6da 100644 --- a/util/libreboot-utils/include/common.h +++ b/util/libreboot-utils/include/common.h @@ -372,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 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 f35d9749..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), @@ -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; 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 bba8a7ca..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,15 +130,12 @@ new_tmp_common(int *fd, char **path, int type, else templatestr = "tmp.XXXXXXXXXX"; - if (slen(templatestr, maxlen, &templatestr_len) < 0) - goto err; - /* may as well calculate in advance */ - destlen = dirlen + 1 + templatestr_len; + destlen = slen(tmpdir, maxlen, &dirlen) + 1 + + slen(templatestr, maxlen, &templatestr_len); /* full path: */ - if (scatn(3, (const char *[]) { tmpdir, "/", templatestr }, - maxlen, &dest) < 0) - goto err; + dest = scatn(3, (const char *[]) { tmpdir, "/", templatestr }, + maxlen, &dest); fname = dest + dirlen + 1; @@ -312,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); @@ -550,24 +543,22 @@ 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, &template_len) < 0) || - if_err(template_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 + template_len; /* count X */ + /* count X */ + for (end = template + slen(template, max_len, &template_len); end > template && *--end == 'X'; xc++); + 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 + template_len - fname_len, + if (if_err(vcmp(fname, template + template_len - fname_len, fname_len) != 0, EINVAL)) return -1; diff --git a/util/libreboot-utils/lib/state.c b/util/libreboot-utils/lib/state.c index bcf2ccbc..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; @@ -113,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); @@ -128,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 39b31cb0..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,103 +119,224 @@ 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; - if (dest == NULL || - slen(s, n, &size) < 0) { - if (dest != NULL) - *dest = NULL; - return -1; + out = smalloc(dest, max); + + for ( ; ((uintptr_t)(s + i) % sizeof(size_t)) != 0; i++) { + + if (if_err(i >= max, EOVERFLOW)) + goto err; + + 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 */ -int +char * scatn(ssize_t sc, const char **sv, size_t max, char **rval) { @@ -194,61 +356,73 @@ scatn(ssize_t sc, const char **sv, if (if_err(sv[i] == NULL, EFAULT)) goto err; else if (i == 0) { - if (sdup(sv[0], max, &final) < 0) - goto err; + (void) sdup(sv[0], max, &final); continue; } rtmp = NULL; - if (scat(final, sv[i], max, &rtmp) < 0) - goto err; + scat(final, sv[i], max, &rtmp); free_and_set_null(&final); final = rtmp; rtmp = NULL; } + errno = saved_errno; *rval = final; - return 0; + return *rval; err: 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 (if_err(dest == NULL || *dest != NULL, EFAULT) || - 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) @@ -256,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); @@ -276,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, @@ -390,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 fd39c68c..7370de1b 100644 --- a/util/libreboot-utils/lottery.c +++ b/util/libreboot-utils/lottery.c @@ -18,7 +18,7 @@ main(int argc, char **argv) { int same = 0; char *buf; - size_t size = 8589934592; + size_t size = BUFSIZ; (void) argc, (void) argv; (void) errhook(exit_cleanup); @@ -28,7 +28,7 @@ main(int argc, char **argv) xpledgex("stdio", NULL); buf = rmalloc(size); - if (!memcmp(buf, buf + (size >> 1), size >> 1)) + if (!vcmp(buf, buf + (size >> 1), size >> 1)) same = 1; if (argc < 2) /* no spew */ @@ -36,7 +36,7 @@ main(int argc, char **argv) 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 de86a2bf..f4c2b646 100644 --- a/util/libreboot-utils/mkhtemp.c +++ b/util/libreboot-utils/mkhtemp.c @@ -95,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 */ @@ -132,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); |
