diff --git a/lib/libsecureboot/h/libsecureboot.h b/lib/libsecureboot/h/libsecureboot.h index 581b72b411d2..33f98bca0479 100644 --- a/lib/libsecureboot/h/libsecureboot.h +++ b/lib/libsecureboot/h/libsecureboot.h @@ -78,10 +78,11 @@ unsigned char *verify_sig(const char *, int); unsigned char *verify_asc(const char *, int); /* OpenPGP */ void ve_pcr_init(void); -void ve_pcr_update(unsigned char *, size_t); +void ve_pcr_update(const char *, unsigned char *, size_t); ssize_t ve_pcr_get(unsigned char *, size_t); int ve_pcr_updating_get(void); void ve_pcr_updating_set(int); +char * ve_pcr_hashed_get(int); /* flags for verify_{asc,sig,signed} */ #define VEF_VERBOSE 1 diff --git a/lib/libsecureboot/vectx.c b/lib/libsecureboot/vectx.c index 908e24fb554c..433df00f244c 100644 --- a/lib/libsecureboot/vectx.c +++ b/lib/libsecureboot/vectx.c @@ -104,8 +104,8 @@ vectx_open(int fd, const char *path, off_t off, struct stat *stp, rc = verify_prep(fd, path, off, stp, __func__); DEBUG_PRINTF(2, - ("vectx_open: caller=%s,name='%s',prep_rc=%d\n", - caller,path, rc)); + ("vectx_open: caller=%s,fd=%d,name='%s',prep_rc=%d\n", + caller, fd, path, rc)); switch (rc) { case VE_FINGERPRINT_NONE: @@ -316,6 +316,9 @@ vectx_lseek(struct vectx *ctx, off_t off, int whence) * We have finished reading file, compare the hash with what * we wanted. * + * Be sure to call this before closing the file, since we may + * need to seek to the end to ensure hashing is complete. + * * @param[in] pctx * pointer to ctx * @@ -337,20 +340,25 @@ vectx_close(struct vectx *ctx, int severity, const char *caller) */ ve_pcr_updating_set((severity == VE_MUST)); #endif + /* make sure we have hashed it all */ + vectx_lseek(ctx, 0, SEEK_END); rc = ve_check_hash(&ctx->vec_ctx, ctx->vec_md, ctx->vec_path, ctx->vec_want, ctx->vec_hashsz); } DEBUG_PRINTF(2, ("vectx_close: caller=%s,name='%s',rc=%d,severity=%d\n", caller,ctx->vec_path, rc, severity)); - if (severity > VE_WANT || rc == VE_FINGERPRINT_WRONG) + if (rc == VE_FINGERPRINT_WRONG) { + printf("Unverified: %s\n", ve_error_get()); +#if !defined(UNIT_TEST) && !defined(DEBUG_VECTX) + /* we are generally called with VE_MUST */ + if (severity > VE_WANT) + panic("cannot continue"); +#endif + } else if (severity > VE_WANT) { printf("%serified %s\n", (rc <= 0) ? "Unv" : "V", ctx->vec_path); -#if !defined(UNIT_TEST) && !defined(DEBUG_VECTX) - /* we are generally called with VE_MUST */ - if (severity > VE_WANT && rc == VE_FINGERPRINT_WRONG) - panic("cannot continue"); -#endif + } free(ctx); return ((rc < 0) ? rc : 0); } diff --git a/lib/libsecureboot/veopen.c b/lib/libsecureboot/veopen.c index 6ecf85c44af1..da6291504c4c 100644 --- a/lib/libsecureboot/veopen.c +++ b/lib/libsecureboot/veopen.c @@ -86,9 +86,11 @@ fingerprint_info_add(const char *filename, const char *prefix, } nfip->fi_prefix = strdup(filename); cp = strrchr(nfip->fi_prefix, '/'); - if (cp) + if (cp == nfip->fi_prefix) { + cp[1] = '\0'; + } else if (cp) { *cp = '\0'; - else { + } else { free(nfip->fi_prefix); free(nfip); return; @@ -96,7 +98,7 @@ fingerprint_info_add(const char *filename, const char *prefix, } /* collapse any trailing ..[/] */ n = 0; - while ((cp = strrchr(nfip->fi_prefix, '/')) != NULL) { + while ((cp = strrchr(nfip->fi_prefix, '/')) > nfip->fi_prefix) { if (cp[1] == '\0') { /* trailing "/" */ *cp = '\0'; continue; diff --git a/lib/libsecureboot/vepcr.c b/lib/libsecureboot/vepcr.c index a97cb7245832..88128647b086 100644 --- a/lib/libsecureboot/vepcr.c +++ b/lib/libsecureboot/vepcr.c @@ -25,6 +25,7 @@ #include __FBSDID("$FreeBSD$"); +#include #include "libsecureboot-priv.h" /* @@ -43,7 +44,16 @@ __FBSDID("$FreeBSD$"); static const br_hash_class *pcr_md = NULL; static br_hash_compat_context pcr_ctx; static size_t pcr_hlen = 0; -static int pcr_updating; +static int pcr_updating = -1; + +struct hashed_info { + const char *hi_path; + const char *hi_basename; + STAILQ_ENTRY(hashed_info) entries; +}; + +static STAILQ_HEAD(, hashed_info) hi_list; + /** * @brief initialize pcr context @@ -54,10 +64,13 @@ static int pcr_updating; void ve_pcr_init(void) { - pcr_updating = 0; - pcr_hlen = br_sha256_SIZE; - pcr_md = &br_sha256_vtable; - pcr_md->init(&pcr_ctx.vtable); + if (pcr_updating < 0) { + pcr_updating = 0; + pcr_hlen = br_sha256_SIZE; + pcr_md = &br_sha256_vtable; + pcr_md->init(&pcr_ctx.vtable); + STAILQ_INIT(&hi_list); + } } /** @@ -82,10 +95,28 @@ ve_pcr_updating_set(int updating) * @brief update pcr context */ void -ve_pcr_update(unsigned char *data, size_t dlen) +ve_pcr_update(const char *path, unsigned char *data, size_t dlen) { - if (pcr_updating != 0 && pcr_md != NULL) + struct hashed_info *hip; + + if (pcr_updating > 0 && pcr_md != NULL) { pcr_md->update(&pcr_ctx.vtable, data, dlen); + /* if mallocs fail, measured boot will likely fail too */ + if ((hip = malloc(sizeof(struct hashed_info)))) { + hip->hi_path = strdup(path); + if (!hip->hi_path) { + free(hip); + return; + } + hip->hi_basename = strrchr(hip->hi_path, '/'); + if (hip->hi_basename) { + hip->hi_basename++; + } else { + hip->hi_basename = hip->hi_path; + } + STAILQ_INSERT_TAIL(&hi_list, hip, entries); + } + } } /** @@ -102,3 +133,37 @@ ve_pcr_get(unsigned char *buf, size_t sz) return (pcr_hlen); } +/** + * @brief get list of paths in prc + */ +char * +ve_pcr_hashed_get(int flags) +{ + const char *cp; + char *hinfo; + struct hashed_info *hip; + size_t nbytes; + size_t x; + int n; + + n = 0; + nbytes = x = 0; + hinfo = NULL; + STAILQ_FOREACH(hip, &hi_list, entries) { + nbytes += 1 + strlen(flags ? hip->hi_basename : hip->hi_path); + } + if (nbytes > 1) { + hinfo = malloc(nbytes + 2); + if (hinfo) { + STAILQ_FOREACH(hip, &hi_list, entries) { + cp = flags ? hip->hi_basename : hip->hi_path; + n = snprintf(&hinfo[x], nbytes - x, "%s,", cp); + x += n; + } + if (x > 0) { + hinfo[x-1] = '\0'; + } + } + } + return hinfo; +} diff --git a/lib/libsecureboot/verify_file.c b/lib/libsecureboot/verify_file.c index eee749667759..20fc0ae4ae78 100644 --- a/lib/libsecureboot/verify_file.c +++ b/lib/libsecureboot/verify_file.c @@ -117,10 +117,12 @@ is_verified(struct stat *stp) { struct verify_status *vsp; - for (vsp = verified_files; vsp != NULL; vsp = vsp->vs_next) { - if (stp->st_dev == vsp->vs_dev && - stp->st_ino == vsp->vs_ino) - return (vsp->vs_status); + if (stp->st_ino > 0) { + for (vsp = verified_files; vsp != NULL; vsp = vsp->vs_next) { + if (stp->st_dev == vsp->vs_dev && + stp->st_ino == vsp->vs_ino) + return (vsp->vs_status); + } } return (VE_NOT_CHECKED); } @@ -367,10 +369,11 @@ verify_prep(int fd, const char *filename, off_t off, struct stat *stp, return (0); } DEBUG_PRINTF(2, - ("caller=%s,fd=%d,name='%s',off=%lld,dev=%lld,ino=%lld\n", + ("verify_prep: caller=%s,fd=%d,name='%s',off=%lld,dev=%lld,ino=%lld\n", caller, fd, filename, (long long)off, (long long)stp->st_dev, (long long)stp->st_ino)); rc = is_verified(stp); + DEBUG_PRINTF(4,("verify_prep: is_verified()->%d\n", rc)); if (rc == VE_NOT_CHECKED) { rc = find_manifest(filename); } else { @@ -458,7 +461,6 @@ verify_file(int fd, const char *filename, off_t off, int severity, #endif } if (severity < VE_MUST) { /* not a kernel or module */ - if ((cp = strrchr(filename, '/'))) { cp++; if (strncmp(cp, "loader.ve.", 10) == 0) { @@ -511,6 +513,7 @@ verify_pcr_export(void) #ifdef VE_PCR_SUPPORT char hexbuf[br_sha256_SIZE * 2 + 2]; unsigned char hbuf[br_sha256_SIZE]; + char *hinfo; char *hex; ssize_t hlen; @@ -520,6 +523,17 @@ verify_pcr_export(void) if (hex) { hex[hlen*2] = '\0'; /* clobber newline */ setenv("loader.ve.pcr", hex, 1); + DEBUG_PRINTF(1, + ("%s: setenv(loader.ve.pcr, %s\n", __func__, + hex)); + hinfo = ve_pcr_hashed_get(1); + if (hinfo) { + setenv("loader.ve.hashed", hinfo, 1); + DEBUG_PRINTF(1, + ("%s: setenv(loader.ve.hashed, %s\n", + __func__, hinfo)); + free(hinfo); + } } } #endif diff --git a/lib/libsecureboot/vets.c b/lib/libsecureboot/vets.c index 7d974fc54115..3a82592ea699 100644 --- a/lib/libsecureboot/vets.c +++ b/lib/libsecureboot/vets.c @@ -44,6 +44,10 @@ __FBSDID("$FreeBSD$"); #endif #define SECONDS_PER_DAY 86400 +#define SECONDS_PER_YEAR 365 * SECONDS_PER_DAY +#ifndef VE_UTC_MAX_JUMP +# define VE_UTC_MAX_JUMP 20 * SECONDS_PER_YEAR +#endif #define X509_DAYS_TO_UTC0 719528 int DebugVe = 0; @@ -113,12 +117,14 @@ static time_t ve_utc = 0; * set ve_utc used for certificate verification * * @param[in] utc - * time - ignored unless greater than current value. + * time - ignored unless greater than current value + * and not a leap of 20 years or more. */ void ve_utc_set(time_t utc) { - if (utc > ve_utc) { + if (utc > ve_utc && + (ve_utc == 0 || (utc - ve_utc) < VE_UTC_MAX_JUMP)) { DEBUG_PRINTF(2, ("Set ve_utc=%jd\n", (intmax_t)utc)); ve_utc = utc; } @@ -346,10 +352,10 @@ ve_trust_init(void) if (once >= 0) return (once); once = 0; /* to be sure */ - ve_utc_set(time(NULL)); #ifdef BUILD_UTC - ve_utc_set(BUILD_UTC); /* just in case */ + ve_utc_set(BUILD_UTC); /* ensure sanity */ #endif + ve_utc_set(time(NULL)); ve_error_set(NULL); /* make sure it is empty */ #ifdef VE_PCR_SUPPORT ve_pcr_init(); @@ -903,7 +909,7 @@ ve_check_hash(br_hash_compat_context *ctx, const br_hash_class *md, md->out(&ctx->vtable, hbuf); #ifdef VE_PCR_SUPPORT - ve_pcr_update(hbuf, hlen); + ve_pcr_update(path, hbuf, hlen); #endif hex = hexdigest(hexbuf, sizeof(hexbuf), hbuf, hlen); if (!hex) diff --git a/stand/common/install.c b/stand/common/install.c index 0ba73e491b68..032006ec4fd3 100644 --- a/stand/common/install.c +++ b/stand/common/install.c @@ -210,6 +210,13 @@ install(char *pkgname) if (currdev != NULL && strcmp(currdev, "pxe0:") == 0) { devname = "pxe0"; proto = NULL; +#ifdef HOSTPROG + } else if (currdev != NULL && strcmp(currdev, "host0:") == 0) { + extern struct fs_ops host_fsops; + + devname = "host0"; + proto = &host_fsops; +#endif } else { devname = "disk1"; proto = &dosfs_fsops; @@ -237,6 +244,10 @@ install(char *pkgname) setenv("serverip", inet_ntoa(servip), 1); + if (proto == &tftp_fsops) { + tftpip.s_addr = servip.s_addr; + } + *pkgname = '/'; } else pkgname = s; diff --git a/stand/libsa/pkgfs.c b/stand/libsa/pkgfs.c index e78ba3302e1f..df87a7035153 100644 --- a/stand/libsa/pkgfs.c +++ b/stand/libsa/pkgfs.c @@ -46,6 +46,7 @@ static int pkg_read(struct open_file *, void *, size_t, size_t *); static off_t pkg_seek(struct open_file *, off_t, int); static int pkg_stat(struct open_file *, struct stat *); static int pkg_readdir(struct open_file *, struct dirent *); +static off_t pkg_atol(const char *, unsigned); struct fs_ops pkgfs_fsops = { "pkg", @@ -59,7 +60,7 @@ struct fs_ops pkgfs_fsops = { }; #define PKG_BUFSIZE 512 -#define PKG_MAXCACHESZ 4096 +#define PKG_MAXCACHESZ 16384 #define PKG_FILEEXT ".tgz" @@ -334,6 +335,7 @@ pkg_seek(struct open_file *f, off_t ofs, int whence) char buf[512]; struct tarfile *tf; off_t delta; + off_t nofs; size_t sz, res; int error; @@ -359,6 +361,14 @@ pkg_seek(struct open_file *f, off_t ofs, int whence) } if (delta < 0) { + /* seeking backwards - ok if within cache */ + if (tf->tf_cachesz > 0 && tf->tf_fp <= tf->tf_cachesz) { + nofs = tf->tf_fp + delta; + if (nofs >= 0) { + tf->tf_fp = nofs; + return (tf->tf_fp); + } + } DBG(("%s: negative file seek (%jd)\n", __func__, (intmax_t)delta)); errno = ESPIPE; @@ -388,8 +398,15 @@ pkg_stat(struct open_file *f, struct stat *sb) return (EBADF); memset(sb, 0, sizeof(*sb)); sb->st_mode = get_mode(tf); + if ((sb->st_mode & S_IFMT) == 0) { + /* tar file bug - assume regular file */ + sb->st_mode |= S_IFREG; + } sb->st_size = tf->tf_size; sb->st_blocks = (tf->tf_size + 511) / 512; + sb->st_mtime = pkg_atol(tf->tf_hdr.ut_mtime, 12); + sb->st_dev = (off_t)tf->tf_pkg; + sb->st_ino = tf->tf_ofs; /* unique per tf_pkg */ return (0); } diff --git a/stand/userboot/test/test.c b/stand/userboot/test/test.c index aaff67717685..301069a4d953 100644 --- a/stand/userboot/test/test.c +++ b/stand/userboot/test/test.c @@ -224,15 +224,20 @@ test_seek(void *arg, void *h, uint64_t offset, int whence) } int -test_stat(void *arg, void *h, int *mode_return, int *uid_return, int *gid_return, - uint64_t *size_return) +test_stat(void *arg, void *h, struct stat *stp) { struct test_file *tf = h; - *mode_return = tf->tf_stat.st_mode; - *uid_return = tf->tf_stat.st_uid; - *gid_return = tf->tf_stat.st_gid; - *size_return = tf->tf_stat.st_size; + if (!stp) + return (-1); + memset(stp, 0, sizeof(struct stat)); + stp->st_mode = tf->tf_stat.st_mode; + stp->st_uid = tf->tf_stat.st_uid; + stp->st_gid = tf->tf_stat.st_gid; + stp->st_size = tf->tf_stat.st_size; + stp->st_ino = tf->tf_stat.st_ino; + stp->st_dev = tf->tf_stat.st_dev; + stp->st_mtime = tf->tf_stat.st_mtime; return (0); } diff --git a/stand/userboot/userboot.h b/stand/userboot/userboot.h index e8817aeb39a2..de0cdb6605c8 100644 --- a/stand/userboot/userboot.h +++ b/stand/userboot/userboot.h @@ -119,8 +119,7 @@ struct loader_callbacks { /* * Return some stat(2) related information about the file */ - int (*stat)(void *arg, void *h, int *mode_return, - int *uid_return, int *gid_return, uint64_t *size_return); + int (*stat)(void *arg, void *h, struct stat *stp); /* * Disk image i/o diff --git a/stand/userboot/userboot/conf.c b/stand/userboot/userboot/conf.c index 3a4417f576a4..af63528163d5 100644 --- a/stand/userboot/userboot/conf.c +++ b/stand/userboot/userboot/conf.c @@ -73,6 +73,11 @@ struct fs_ops *file_system[] = { NULL }; +/* to keep libsa happy */ +struct netif_driver *netif_drivers[] = { + NULL +}; + /* Exported for i386 only */ /* * Sort formats so that those that can detect based on arguments diff --git a/stand/userboot/userboot/host.c b/stand/userboot/userboot/host.c index 861856544aa2..c9ac01576e82 100644 --- a/stand/userboot/userboot/host.c +++ b/stand/userboot/userboot/host.c @@ -84,16 +84,8 @@ host_seek(struct open_file *f, off_t offset, int where) static int host_stat(struct open_file *f, struct stat *sb) { - int mode; - int uid; - int gid; - uint64_t size; - - CALLBACK(stat, f->f_fsdata, &mode, &uid, &gid, &size); - sb->st_mode = mode; - sb->st_uid = uid; - sb->st_gid = gid; - sb->st_size = size; + + CALLBACK(stat, f->f_fsdata, sb); return (0); } diff --git a/usr.sbin/bhyveload/bhyveload.c b/usr.sbin/bhyveload/bhyveload.c index 3764642c76ad..1b3be71745da 100644 --- a/usr.sbin/bhyveload/bhyveload.c +++ b/usr.sbin/bhyveload/bhyveload.c @@ -278,14 +278,19 @@ cb_seek(void *arg, void *h, uint64_t offset, int whence) } static int -cb_stat(void *arg, void *h, int *mode, int *uid, int *gid, uint64_t *size) +cb_stat(void *arg, void *h, struct stat *sbp) { struct cb_file *cf = h; - *mode = cf->cf_stat.st_mode; - *uid = cf->cf_stat.st_uid; - *gid = cf->cf_stat.st_gid; - *size = cf->cf_stat.st_size; + memset(sbp, 0, sizeof(struct stat)); + sbp->st_mode = cf->cf_stat.st_mode; + sbp->st_uid = cf->cf_stat.st_uid; + sbp->st_gid = cf->cf_stat.st_gid; + sbp->st_size = cf->cf_stat.st_size; + sbp->st_mtime = cf->cf_stat.st_mtime; + sbp->st_dev = cf->cf_stat.st_dev; + sbp->st_ino = cf->cf_stat.st_ino; + return (0); }