aboutsummaryrefslogtreecommitdiff
path: root/lib/libsecureboot
diff options
context:
space:
mode:
authorSimon J. Gerraty <sjg@FreeBSD.org>2020-03-25 19:12:19 +0000
committerSimon J. Gerraty <sjg@FreeBSD.org>2020-03-25 19:12:19 +0000
commit53f151f90603580d0c0a8fa1840ba1262958a7c1 (patch)
tree78969ebac620eb68b5a22beb561b91e35c99db70 /lib/libsecureboot
parent7c63520c42754642acce60c7be5fc9676e3e3266 (diff)
downloadsrc-53f151f90603580d0c0a8fa1840ba1262958a7c1.tar.gz
src-53f151f90603580d0c0a8fa1840ba1262958a7c1.zip
Notes
Diffstat (limited to 'lib/libsecureboot')
-rw-r--r--lib/libsecureboot/h/libsecureboot.h3
-rw-r--r--lib/libsecureboot/vectx.c24
-rw-r--r--lib/libsecureboot/veopen.c8
-rw-r--r--lib/libsecureboot/vepcr.c79
-rw-r--r--lib/libsecureboot/verify_file.c26
-rw-r--r--lib/libsecureboot/vets.c16
6 files changed, 126 insertions, 30 deletions
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)
- 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);
}
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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/queue.h>
#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)