svn commit: r359307 - in head: lib/libsecureboot lib/libsecureboot/h stand/common stand/libsa stand/userboot stand/userboot/test stand/userboot/userboot usr.sbin/bhyveload

Simon J. Gerraty sjg at FreeBSD.org
Wed Mar 25 19:21:18 UTC 2020


Author: sjg
Date: Wed Mar 25 19:12:19 2020
New Revision: 359307
URL: https://svnweb.freebsd.org/changeset/base/359307

Log:
  Fix pkgfs stat so it satisfies libsecureboot
  
  We need a valid st_dev, st_ino and st_mtime
  to correctly track which files have been verified
  and to update our notion of time.
  
  ve_utc_set(): ignore utc if it would jump our current time
  by more than VE_UTC_MAX_JUMP (20 years).
  
  Allow testing of install command via userboot.
  Need to fix its stat implementation too.
  
  bhyveload also needs stat fixed - due to change to userboot.h
  
  Call ve_error_get() from vectx_close() when hash is wrong.
  
  Track the names of files we have hashed into pcr
  
  For the purposes of measured boot, it is important
  to be able to reproduce the hash reflected in
  loader.ve.pcr
  so loader.ve.hashed provides a list of names in the order they
  were added.
  
  Reviewed by:	imp
  MFC after:	1 week
  Sponsored by:	Juniper Networks
  Differential Revision:	https://reviews.freebsd.org//D24027

Modified:
  head/lib/libsecureboot/h/libsecureboot.h
  head/lib/libsecureboot/vectx.c
  head/lib/libsecureboot/veopen.c
  head/lib/libsecureboot/vepcr.c
  head/lib/libsecureboot/verify_file.c
  head/lib/libsecureboot/vets.c
  head/stand/common/install.c
  head/stand/libsa/pkgfs.c
  head/stand/userboot/test/test.c
  head/stand/userboot/userboot.h
  head/stand/userboot/userboot/conf.c
  head/stand/userboot/userboot/host.c
  head/usr.sbin/bhyveload/bhyveload.c

Modified: head/lib/libsecureboot/h/libsecureboot.h
==============================================================================
--- head/lib/libsecureboot/h/libsecureboot.h	Wed Mar 25 18:20:37 2020	(r359306)
+++ head/lib/libsecureboot/h/libsecureboot.h	Wed Mar 25 19:12:19 2020	(r359307)
@@ -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

Modified: head/lib/libsecureboot/vectx.c
==============================================================================
--- head/lib/libsecureboot/vectx.c	Wed Mar 25 18:20:37 2020	(r359306)
+++ head/lib/libsecureboot/vectx.c	Wed Mar 25 19:12:19 2020	(r359307)
@@ -104,8 +104,8 @@ vectx_open(int fd, const char *path, off_t off, struct
 	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 cha
 		 */
 		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);
 }

Modified: head/lib/libsecureboot/veopen.c
==============================================================================
--- head/lib/libsecureboot/veopen.c	Wed Mar 25 18:20:37 2020	(r359306)
+++ head/lib/libsecureboot/veopen.c	Wed Mar 25 19:12:19 2020	(r359307)
@@ -86,9 +86,11 @@ fingerprint_info_add(const char *filename, const char 
 		}
 		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 
 	}
 	/* 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;

Modified: head/lib/libsecureboot/vepcr.c
==============================================================================
--- head/lib/libsecureboot/vepcr.c	Wed Mar 25 18:20:37 2020	(r359306)
+++ head/lib/libsecureboot/vepcr.c	Wed Mar 25 19:12:19 2020	(r359307)
@@ -25,6 +25,7 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include <sys/queue.h>
 #include "libsecureboot-priv.h"
 
 /*
@@ -43,8 +44,17 @@ __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;
+}

Modified: head/lib/libsecureboot/verify_file.c
==============================================================================
--- head/lib/libsecureboot/verify_file.c	Wed Mar 25 18:20:37 2020	(r359306)
+++ head/lib/libsecureboot/verify_file.c	Wed Mar 25 19:12:19 2020	(r359307)
@@ -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, s
 			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, i
 #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

Modified: head/lib/libsecureboot/vets.c
==============================================================================
--- head/lib/libsecureboot/vets.c	Wed Mar 25 18:20:37 2020	(r359306)
+++ head/lib/libsecureboot/vets.c	Wed Mar 25 19:12:19 2020	(r359307)
@@ -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_ha
 
 	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)

Modified: head/stand/common/install.c
==============================================================================
--- head/stand/common/install.c	Wed Mar 25 18:20:37 2020	(r359306)
+++ head/stand/common/install.c	Wed Mar 25 19:12:19 2020	(r359307)
@@ -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;
@@ -236,6 +243,10 @@ install(char *pkgname)
 			goto invalid_url;
 
 		setenv("serverip", inet_ntoa(servip), 1);
+
+		if (proto == &tftp_fsops) {
+			tftpip.s_addr = servip.s_addr;
+		}
 
 		*pkgname = '/';
 	} else

Modified: head/stand/libsa/pkgfs.c
==============================================================================
--- head/stand/libsa/pkgfs.c	Wed Mar 25 18:20:37 2020	(r359306)
+++ head/stand/libsa/pkgfs.c	Wed Mar 25 19:12:19 2020	(r359307)
@@ -46,6 +46,7 @@ static int   pkg_read(struct open_file *, void *, size
 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);
 }
 

Modified: head/stand/userboot/test/test.c
==============================================================================
--- head/stand/userboot/test/test.c	Wed Mar 25 18:20:37 2020	(r359306)
+++ head/stand/userboot/test/test.c	Wed Mar 25 19:12:19 2020	(r359307)
@@ -224,15 +224,20 @@ test_seek(void *arg, void *h, uint64_t offset, int whe
 }
 
 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);
 }
 

Modified: head/stand/userboot/userboot.h
==============================================================================
--- head/stand/userboot/userboot.h	Wed Mar 25 18:20:37 2020	(r359306)
+++ head/stand/userboot/userboot.h	Wed Mar 25 19:12:19 2020	(r359307)
@@ -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

Modified: head/stand/userboot/userboot/conf.c
==============================================================================
--- head/stand/userboot/userboot/conf.c	Wed Mar 25 18:20:37 2020	(r359306)
+++ head/stand/userboot/userboot/conf.c	Wed Mar 25 19:12:19 2020	(r359307)
@@ -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

Modified: head/stand/userboot/userboot/host.c
==============================================================================
--- head/stand/userboot/userboot/host.c	Wed Mar 25 18:20:37 2020	(r359306)
+++ head/stand/userboot/userboot/host.c	Wed Mar 25 19:12:19 2020	(r359307)
@@ -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);
 }
 

Modified: head/usr.sbin/bhyveload/bhyveload.c
==============================================================================
--- head/usr.sbin/bhyveload/bhyveload.c	Wed Mar 25 18:20:37 2020	(r359306)
+++ head/usr.sbin/bhyveload/bhyveload.c	Wed Mar 25 19:12:19 2020	(r359307)
@@ -278,14 +278,19 @@ cb_seek(void *arg, void *h, uint64_t offset, int whenc
 }
 
 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);
 }
 


More information about the svn-src-all mailing list