Index: lib/libsecureboot/h/libsecureboot.h =================================================================== --- lib/libsecureboot/h/libsecureboot.h +++ lib/libsecureboot/h/libsecureboot.h @@ -78,10 +78,11 @@ 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 Index: lib/libsecureboot/vectx.c =================================================================== --- lib/libsecureboot/vectx.c +++ lib/libsecureboot/vectx.c @@ -104,8 +104,8 @@ 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 @@ * 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 @@ */ 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) - printf("%serified %s\n", (rc <= 0) ? "Unv" : "V", - ctx->vec_path); + 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 && rc == VE_FINGERPRINT_WRONG) - panic("cannot continue"); + /* 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); + } free(ctx); return ((rc < 0) ? rc : 0); } Index: lib/libsecureboot/veopen.c =================================================================== --- lib/libsecureboot/veopen.c +++ lib/libsecureboot/veopen.c @@ -86,9 +86,11 @@ } 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 @@ } /* 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; Index: lib/libsecureboot/vepcr.c =================================================================== --- lib/libsecureboot/vepcr.c +++ lib/libsecureboot/vepcr.c @@ -25,6 +25,7 @@ #include __FBSDID("$FreeBSD$"); +#include #include "libsecureboot-priv.h" /* @@ -43,7 +44,16 @@ 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 @@ 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 @@ * @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 @@ 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; +} Index: lib/libsecureboot/verify_file.c =================================================================== --- lib/libsecureboot/verify_file.c +++ lib/libsecureboot/verify_file.c @@ -117,10 +117,12 @@ { 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 @@ 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 @@ #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 @@ #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 @@ 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 Index: lib/libsecureboot/vets.c =================================================================== --- lib/libsecureboot/vets.c +++ lib/libsecureboot/vets.c @@ -44,6 +44,10 @@ #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 @@ * 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 @@ 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 @@ 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) Index: stand/common/install.c =================================================================== --- stand/common/install.c +++ stand/common/install.c @@ -210,6 +210,13 @@ 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 @@ setenv("serverip", inet_ntoa(servip), 1); + if (proto == &tftp_fsops) { + tftpip.s_addr = servip.s_addr; + } + *pkgname = '/'; } else pkgname = s; Index: stand/libsa/pkgfs.c =================================================================== --- stand/libsa/pkgfs.c +++ stand/libsa/pkgfs.c @@ -46,6 +46,7 @@ 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 @@ }; #define PKG_BUFSIZE 512 -#define PKG_MAXCACHESZ 4096 +#define PKG_MAXCACHESZ 16384 #define PKG_FILEEXT ".tgz" @@ -334,6 +335,7 @@ char buf[512]; struct tarfile *tf; off_t delta; + off_t nofs; size_t sz, res; int error; @@ -359,6 +361,14 @@ } 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 @@ 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); } Index: stand/userboot/test/test.c =================================================================== --- stand/userboot/test/test.c +++ stand/userboot/test/test.c @@ -224,15 +224,20 @@ } 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); } Index: stand/userboot/userboot.h =================================================================== --- stand/userboot/userboot.h +++ stand/userboot/userboot.h @@ -119,8 +119,7 @@ /* * 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 Index: stand/userboot/userboot/conf.c =================================================================== --- stand/userboot/userboot/conf.c +++ stand/userboot/userboot/conf.c @@ -73,6 +73,11 @@ 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 Index: stand/userboot/userboot/host.c =================================================================== --- stand/userboot/userboot/host.c +++ stand/userboot/userboot/host.c @@ -84,16 +84,8 @@ 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); } Index: usr.sbin/bhyveload/bhyveload.c =================================================================== --- usr.sbin/bhyveload/bhyveload.c +++ usr.sbin/bhyveload/bhyveload.c @@ -278,14 +278,19 @@ } 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); }