Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 12 Feb 2024 22:36:27 GMT
From:      "Simon J. Gerraty" <sjg@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: f616d61ab6b0 - main - libsecureboot do not report expected unverified files
Message-ID:  <202402122236.41CMaRCq001438@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by sjg:

URL: https://cgit.FreeBSD.org/src/commit/?id=f616d61ab6b071e5fbfdbae7033a9ef04c1444ad

commit f616d61ab6b071e5fbfdbae7033a9ef04c1444ad
Author:     Simon J. Gerraty <sjg@FreeBSD.org>
AuthorDate: 2024-02-12 22:35:01 +0000
Commit:     Simon J. Gerraty <sjg@FreeBSD.org>
CommitDate: 2024-02-12 22:35:01 +0000

    libsecureboot do not report expected unverified files
    
    By default only report unverified files at severity VE_WANT
    and above.  This inlcudes *.conf but not *.hints, *.cookie
    or *.tgz which get VE_TRY as their severity.
    
    If Verbose is set to 0, then VerifyFlags should default to 0 too.
    Thus the combination of
    
            module_verbose=0
            VE_VEBOSE=0
    
    is sufficient to make the loader almost totally silent.
    
    When verify_prep has to find_manifest and it is verified ok
    return VE_NOT_CHECKED to verify_file so that it can skip
    repeating verify_fd
    
    Also add better debugging output for is_verified and add_verify_status.
    
    vectx handle compressed modules
    
    When verifying a compressed module (.ko.gz or .ko.bz2)
    stat() reports the size as -1 (unknown).
    vectx_lseek needs to spot this during closing - and just read until
    EOF is hit.
    
    Note: because of the way libsa's open() works, verify_prep will see
    the path to be verified as module.ko not module.ko.bz2 etc.  This is
    actually ok, because we need a separate module.ko.bz2 entry so that
    the package can be verified, and the hash for module.ko is of the
    uncompressed file which is what vectx will see.
    
    Re-work local.trust.mk so site.trust.mk need only set
    VE_SIGN_URL_LIST (if using the mentioned signing server)
    
    interp.c: restrict interactive input
    
    Apply the same restrictions to interactive input as for
    unverified conf and hints files.
    
    Use version.veriexec when LOADER_VERIEXEC is yes
    
    Reviewed by:    kevans
    Sponsored by:   Juniper Networks, Inc.
    Differential Revision:  https://reviews.freebsd.org/D43810
---
 lib/libsecureboot/Makefile.inc       |   8 +-
 lib/libsecureboot/Makefile.libsa.inc |   7 +-
 lib/libsecureboot/h/verify_file.h    |   1 +
 lib/libsecureboot/local.trust.mk     | 143 +++++++++++++++--------------------
 lib/libsecureboot/vectx.c            |  26 +++++--
 lib/libsecureboot/verify_file.c      |  35 +++++++--
 stand/common/interp.c                |   8 ++
 stand/efi/loader/version.veriexec    |   7 ++
 stand/veriexec.mk                    |   3 +
 9 files changed, 136 insertions(+), 102 deletions(-)

diff --git a/lib/libsecureboot/Makefile.inc b/lib/libsecureboot/Makefile.inc
index ff40b919bad3..b09e44edc1b0 100644
--- a/lib/libsecureboot/Makefile.inc
+++ b/lib/libsecureboot/Makefile.inc
@@ -58,6 +58,10 @@ _2ndLAST_PEM_USE: .USE
 	sed -n "`grep -n .-BEGIN ${.ALLSRC:M*.pem} | tail -2 | \
 	sed 's,:.*,,' | xargs | (read a b; echo $$a,$$(($$b - 1)))`p" ${.ALLSRC:M*.pem} > ${.TARGET}
 
+# rules to populate the [tv]*.pem files we use to generate ta.h
+# and can add/alter VE_*_LIST as desired.
+.-include "local.trust.mk"
+
 # list of hashes we support
 VE_HASH_LIST?= SHA256
 
@@ -74,10 +78,6 @@ VE_SIGNATURE_EXT_LIST?= sig
 # needs to be yes for FIPS 140-2 compliance
 VE_SELF_TESTS?= no
 
-# rules to populate the [tv]*.pem files we use to generate ta.h
-# and can add/alter VE_*_LIST as desired.
-.-include "local.trust.mk"
-
 # this is what we use as our trust anchor
 CFLAGS+= -I. -DTRUST_ANCHOR_STR=ta_PEM
 
diff --git a/lib/libsecureboot/Makefile.libsa.inc b/lib/libsecureboot/Makefile.libsa.inc
index 76e0a91bc20a..907c8e8f7533 100644
--- a/lib/libsecureboot/Makefile.libsa.inc
+++ b/lib/libsecureboot/Makefile.libsa.inc
@@ -46,9 +46,12 @@ manifests.h:
 	echo '${VE_MANIFEST_LIST:@m@"$m",${.newline}@}'; \
 	echo 'NULL };' ) > ${.TARGET}
 
+# only add these if set
 XCFLAGS.verify_file+= \
-	-DVE_DEBUG_LEVEL=${VE_DEBUG_LEVEL:U0} \
-	-DVE_VERBOSE_DEFAULT=${VE_VERBOSE_DEFAULT:U0} \
+	${VE_DEBUG_LEVEL \
+	VE_VERBOSE_DEFAULT \
+	VE_VERIFY_FLAGS \
+	:L:@v@${$v:S,^,-D$v=,}@}
 
 .if !empty(MANIFEST_SKIP_ALWAYS)
 XCFLAGS.verify_file+= -DMANIFEST_SKIP_ALWAYS=\"${MANIFEST_SKIP_ALWAYS}\"
diff --git a/lib/libsecureboot/h/verify_file.h b/lib/libsecureboot/h/verify_file.h
index 88d758b27af4..f918ed6d0e38 100644
--- a/lib/libsecureboot/h/verify_file.h
+++ b/lib/libsecureboot/h/verify_file.h
@@ -46,6 +46,7 @@ int	verify_prep(int, const char *, off_t, struct stat *, const char *);
 void	ve_debug_set(int);
 char	*ve_error_get(void);
 void	ve_efi_init(void);
+void	ve_status_set(int, int);
 int	ve_status_get(int);
 int	load_manifest(const char *, const char *, const char *, struct stat *);
 int	pass_manifest(const char *, const char *);
diff --git a/lib/libsecureboot/local.trust.mk b/lib/libsecureboot/local.trust.mk
index 7b1e5f7ee97b..b009139a2f68 100644
--- a/lib/libsecureboot/local.trust.mk
+++ b/lib/libsecureboot/local.trust.mk
@@ -5,65 +5,69 @@
 # the signing server (http://www.crufty.net/sjg/blog/signing-server.htm)
 # for each key will provide the appropriate certificate chain on request
 
-# force these for Junos
-#MANIFEST_SKIP_ALWAYS= boot
-VE_HASH_LIST= \
-	SHA1 \
-	SHA256 \
-	SHA384 \
-	SHA512
-
-VE_SIGNATURE_LIST= \
-	ECDSA \
-	RSA
-
-VE_SIGNATURE_EXT_LIST= \
-	esig \
-	rsig
-
-VE_SELF_TESTS= yes
-
-.if ${MACHINE} == "host" && ${.CURDIR:T} == "tests"
-
-VE_SIGNATURE_LIST+= \
-	DEPRECATED_RSA_SHA1
+# allow site control
+.-include "site.trust.mk"
 
-VE_SIGNATURE_EXT_LIST+= \
-	sig
-.endif
+#VE_DEBUG_LEVEL?=3
+#VE_VERBOSE_DEFAULT?=2
 
-# add OpenPGP support - possibly dormant
-VE_SIGNATURE_LIST+= OPENPGP
-VE_SIGNATURE_EXT_LIST+= asc
+VE_HASH_LIST?= \
+	SHA256 \
+	SHA384 \
 
-# allow site override of all the above
-.-include "site.trust.mk"
+VE_SELF_TESTS?= yes
 
-SIGNER ?= ${SB_TOOLS_PATH:U/volume/buildtools/bin}/sign.py
+# client for the signing server above
+SIGNER?= /opt/sigs/sign.py
 
 .if exists(${SIGNER})
-SIGN_HOST ?= ${SB_SITE:Usvl}-junos-signer.juniper.net
-ECDSA_PORT:= ${133%y:L:gmtime}
-SIGN_ECDSA= ${PYTHON} ${SIGNER} -u ${SIGN_HOST}:${ECDSA_PORT} -h sha256
-RSA2_PORT:= ${163%y:L:gmtime}
-SIGN_RSA2=   ${PYTHON} ${SIGNER} -u ${SIGN_HOST}:${RSA2_PORT} -h sha256
+OPENPGP_SIGNER?= ${SIGNER:H}/openpgp-sign.py
+OPENPGP_SIGN_FLAGS= -a
+OPENPGP_SIGN_HOST?= localhost
+SIGN_HOST ?= localhost
+
+# A list of name/ext/url tuples.
+# name should be one of ECDSA, OPENPGP or RSA, they can be repeated
+# Order of ext list implies runtime preference so do not sort!
+VE_SIGN_URL_LIST?= \
+	ECDSA/esig/${SIGN_HOST}:${133%y:L:localtime} \
+	RSA/rsig/${SIGN_HOST}:${163%y:L:localtime} \
+	OPENPGP/asc/${OPENPGP_SIGN_HOST}:1234 \
+
+.for sig ext url in ${VE_SIGN_URL_LIST:@x@${x:H:H} ${x:H:T} ${x:T}@}
+SIGN_${sig}:= ${PYTHON} ${${sig}_SIGNER:U${SIGNER}} -u ${url} ${${sig}_SIGN_FLAGS:U-h sha256}
+
+VE_SIGNATURE_LIST+= ${sig}
+VE_SIGNATURE_EXT_LIST+= ${ext}
+
+_SIGN_${sig}_USE:	.USE
+	${SIGN_${sig}} ${.ALLSRC}
+
+_TA_${sig}_USE:       .USE
+	${SIGN_${sig}} -C ${.TARGET}
+
+.if ${sig} == "OPENPGP"
+ta_${sig:tl}.${ext}: _TA_${sig}_USE
+ta_${ext}.h: ta_${sig:tl}.${ext}
+.else
+${ext:S/sig/certs/}.pem: _TA_${sig}_USE
+# the last cert in the chain is the one we want
+ta_${ext}.pem: ${ext:S/sig/certs/}.pem _LAST_PEM_USE
+ta.h: ta_${ext}.pem
+.if ${VE_SELF_TESTS} != "no"
+# we use the 2nd last cert to test verification
+vc_${ext}.pem: ${ext:S/sig/certs/}.pem _2ndLAST_PEM_USE
+ta.h: vc_${ext}.pem
+.endif
+.endif
+.endfor
 
-# deal with quirk of our .esig format
-XCFLAGS.vets+= -DVE_ECDSA_HASH_AGAIN
+# cleanup duplicates
+VE_SIGNATURE_LIST:= ${VE_SIGNATURE_LIST:O:u}
 
-.if !empty(OPENPGP_SIGN_URL)
+.if target(ta_asc.h)
 XCFLAGS.opgp_key+= -DHAVE_TA_ASC_H
 
-VE_SIGNATURE_LIST+= OPENPGP
-VE_SIGNATURE_EXT_LIST+= asc
-
-SIGN_OPENPGP= ${PYTHON} ${SIGNER:H}/openpgp-sign.py -a -u ${OPENPGP_SIGN_URL}
-
-ta_openpgp.asc:
-	${SIGN_OPENPGP} -C ${.TARGET}
-
-ta_asc.h: ta_openpgp.asc
-
 .if ${VE_SELF_TESTS} != "no"
 # for self test
 vc_openpgp.asc: ta_openpgp.asc
@@ -74,48 +78,26 @@ ta_asc.h: vc_openpgp.asc
 .endif
 .endif
 
-rcerts.pem:
-	${SIGN_RSA2} -C ${.TARGET}
-
-ecerts.pem:
-	${SIGN_ECDSA} -C ${.TARGET}
-
-.if ${VE_SIGNATURE_LIST:tu:MECDSA} != ""
-# the last cert in the chain is the one we want
-ta_ec.pem: ecerts.pem _LAST_PEM_USE
-ta.h: ta_ec.pem
-.if ${VE_SELF_TESTS} != "no"
-# these are for verification self test
-vc_ec.pem: ecerts.pem _2ndLAST_PEM_USE
-ta.h: vc_ec.pem
-.endif
-.endif
-
-.if ${VE_SIGNATURE_LIST:tu:MRSA} != ""
-ta_rsa.pem: rcerts.pem _LAST_PEM_USE
-ta.h: ta_rsa.pem
-.if ${VE_SELF_TESTS} != "no"
-vc_rsa.pem: rcerts.pem _2ndLAST_PEM_USE
-ta.h: vc_rsa.pem
-.endif
-.endif
-
-# we take the mtime of this as our baseline time
-#BUILD_UTC_FILE= ecerts.pem
-#VE_DEBUG_LEVEL=3
-#VE_VERBOSE_DEFAULT=1
-
 .else
+VE_SIGNATURE_LIST?= RSA
+
 # you need to provide t*.pem or t*.asc files for each trust anchor
+# below assumes they are named ta_${ext}.pem eg ta_esig.pem for ECDSA
 .if empty(TRUST_ANCHORS)
 TRUST_ANCHORS!= cd ${.CURDIR} && 'ls' -1 *.pem t*.asc 2> /dev/null
 .endif
 .if empty(TRUST_ANCHORS) && ${MK_LOADER_EFI_SECUREBOOT} != "yes"
 .error Need TRUST_ANCHORS see ${.PARSEDIR}/README.rst
 .endif
+
 .if ${TRUST_ANCHORS:T:Mt*.pem} != ""
 ta.h: ${TRUST_ANCHORS:M*.pem}
+VE_SIGNATURE_EXT_LIST?= ${TRUST_ANCHORS:T:Mt*.pem:R:S/ta_//}
+.if ${VE_SIGNATURE_EXT_LIST:Mesig} != ""
+VE_SIGNATURE_LIST+= ECDSA
+.endif
 .endif
+
 .if ${TRUST_ANCHORS:T:Mt*.asc} != ""
 VE_SIGNATURE_LIST+= OPENPGP
 VE_SIGNATURE_EXT_LIST+= asc
@@ -124,4 +106,3 @@ ta_asc.h: ${TRUST_ANCHORS:M*.asc}
 # we take the mtime of this as our baseline time
 BUILD_UTC_FILE?= ${TRUST_ANCHORS:[1]}
 .endif
-
diff --git a/lib/libsecureboot/vectx.c b/lib/libsecureboot/vectx.c
index dba728421ce4..2d56830cd81d 100644
--- a/lib/libsecureboot/vectx.c
+++ b/lib/libsecureboot/vectx.c
@@ -306,19 +306,31 @@ vectx_lseek(struct vectx *ctx, off_t off, int whence)
 	DEBUG_PRINTF(3,
 	    ("%s(%s, %ld, %d)\n", __func__, ctx->vec_path, (long)off, whence));
 	if (whence == SEEK_END && off <= 0) {
-		if (ctx->vec_closing && ctx->vec_hashed < ctx->vec_size) {
-			DEBUG_PRINTF(3, ("%s: SEEK_END %ld\n",
-				__func__,
-				(long)(ctx->vec_size - ctx->vec_hashed)));
+		if (ctx->vec_size < 0) {
+			if (ctx->vec_closing) {
+				/* size unknown - read until EOF */
+				do {
+					n = vectx_read(ctx, buf, PAGE_SIZE);
+					if (n < 0)
+						return (n);
+				} while (n > 0);
+				return (ctx->vec_off);
+			}
+		} else {
+			if (ctx->vec_closing && ctx->vec_hashed < ctx->vec_size) {
+				DEBUG_PRINTF(3, ("%s: SEEK_END %ld\n",
+					__func__,
+					(long)(ctx->vec_size - ctx->vec_hashed)));
+			}
+			whence = SEEK_SET;
+			off += ctx->vec_size;
 		}
-		whence = SEEK_SET;
-		off += ctx->vec_size;
 	} else if (whence == SEEK_CUR) {
 		whence = SEEK_SET;
 		off += ctx->vec_off;
 	}
 	if (whence != SEEK_SET ||
-	    off > ctx->vec_size) {
+	    (off > ctx->vec_size && ctx->vec_size > 0)) {
 		printf("ERROR: %s: unsupported operation: whence=%d off=%ld -> %ld\n",
 		    __func__, whence, (long)ctx->vec_off, (long)off);
 		return (-1);
diff --git a/lib/libsecureboot/verify_file.c b/lib/libsecureboot/verify_file.c
index c123ea9e1088..753204a33b6a 100644
--- a/lib/libsecureboot/verify_file.c
+++ b/lib/libsecureboot/verify_file.c
@@ -82,7 +82,7 @@ static int Verbose = VE_VERBOSE_DEFAULT;
 /**
  * @brief set ve status for fd
  */
-static void
+void
 ve_status_set(int fd, int ves)
 {
 	if (fd >= 0 && fd < SOPEN_MAX) {
@@ -131,15 +131,21 @@ int
 is_verified(struct stat *stp)
 {
 	struct verify_status *vsp;
+	int rc = VE_NOT_CHECKED;
 
 	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);
+			    stp->st_ino == vsp->vs_ino) {
+				rc = vsp->vs_status;
+				break;
+			}
 		}
 	}
-	return (VE_NOT_CHECKED);
+	DEBUG_PRINTF(4, ("%s: dev=%lld,ino=%llu,status=%d\n",
+		__func__, (long long)stp->st_dev,
+		(unsigned long long)stp->st_ino, rc));
+	return (rc);
 }
 
 /* most recent first, since most likely to see repeated calls. */
@@ -156,6 +162,9 @@ add_verify_status(struct stat *stp, int status)
 		vsp->vs_status = status;
 		verified_files = vsp;
 	}
+	DEBUG_PRINTF(4, ("%s: dev=%lld,ino=%llu,status=%d\n",
+		__func__, (long long)stp->st_dev,
+		(unsigned long long)stp->st_ino, status));
 }
 
 
@@ -270,11 +279,14 @@ severity_guess(const char *filename)
 	/*
 	 * Some files like *.conf and *.hints may be unsigned,
 	 * a *.tgz is expected to have its own signed manifest.
+	 * We allow *.conf to get VE_WANT, but files we expect
+	 * to always be unverified get VE_TRY and we will not
+	 * report them.
 	 */
 	if ((cp = strrchr(filename, '.'))) {
-		if (strcmp(cp, ".conf") == 0 ||
-		    strcmp(cp, ".cookie") == 0 ||
+		if (strcmp(cp, ".cookie") == 0 ||
 		    strcmp(cp, ".hints") == 0 ||
+		    strcmp(cp, ".order") == 0 ||
 		    strcmp(cp, ".tgz") == 0)
 			return (VE_TRY);
 		if (strcmp(cp, ".4th") == 0 ||
@@ -398,6 +410,8 @@ void
 verify_report(const char *path, int severity, int status, struct stat *stp)
 {
 	if (status < 0 || status == VE_FINGERPRINT_IGNORE) {
+		if (Verbose < VE_VERBOSE_ALL && severity < VE_WANT)
+			return;
 		if (Verbose >= VE_VERBOSE_UNVERIFIED || severity > VE_TRY ||
 		    status <= VE_FINGERPRINT_WRONG) {
 			if (Verbose == VE_VERBOSE_DEBUG && stp != NULL)
@@ -462,9 +476,10 @@ verify_prep(int fd, const char *filename, off_t off, struct stat *stp,
 		caller, fd, filename, (long long)off, (long long)stp->st_dev,
 		(unsigned 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);
+		if (rc == VE_VERIFIED)
+			rc = VE_NOT_CHECKED;
 	} else {
 		ve_status_set(fd, rc);
 	}
@@ -511,7 +526,8 @@ verify_file(int fd, const char *filename, off_t off, int severity,
 	if (check_verbose) {
 		check_verbose = 0;
 		Verbose = getenv_int("VE_VERBOSE", VE_VERBOSE_DEFAULT);
-		VerifyFlags = getenv_int("VE_VERIFY_FLAGS", VEF_VERBOSE);
+		VerifyFlags = getenv_int("VE_VERIFY_FLAGS",
+		    Verbose ? VEF_VERBOSE : 0);
 #ifndef UNIT_TEST
 		ve_debug_set(getenv_int("VE_DEBUG_LEVEL", VE_DEBUG_LEVEL));
 #endif
@@ -523,6 +539,9 @@ verify_file(int fd, const char *filename, off_t off, int severity,
 		return (0);
 
 	if (rc != VE_FINGERPRINT_WRONG && loaded_manifests) {
+		if (rc != VE_NOT_CHECKED)
+			return (rc);
+
 		if (severity <= VE_GUESS)
 			severity = severity_guess(filename);
 #ifdef VE_PCR_SUPPORT
diff --git a/stand/common/interp.c b/stand/common/interp.c
index b71e0858e702..0f142902b4ac 100644
--- a/stand/common/interp.c
+++ b/stand/common/interp.c
@@ -35,6 +35,10 @@
 #include <string.h>
 #include "bootstrap.h"
 
+#ifdef LOADER_VERIEXEC
+#include <verify_file.h>
+#endif
+
 #define	MAXARGS	20			/* maximum number of arguments allowed */
 
 const char * volatile	interp_identifier;
@@ -79,6 +83,10 @@ interact(void)
 		input[0] = '\0';
 		interp_emit_prompt();
 		ngets(input, sizeof(input));
+#ifdef LOADER_VERIEXEC
+		/* some settings should be restritcted */
+		ve_status_set(-1, VE_UNVERIFIED_OK);
+#endif
 		interp_run(input);
 	}
 }
diff --git a/stand/efi/loader/version.veriexec b/stand/efi/loader/version.veriexec
new file mode 100644
index 000000000000..5c9292310c04
--- /dev/null
+++ b/stand/efi/loader/version.veriexec
@@ -0,0 +1,7 @@
+NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE.  The format of this
+file is important.  Make sure the current version number is on line 6.
+
+2.1:	SMBIOS 3 support
+2.0:	Secure boot support
+1.1:	Keep in sync with i386 version.
+0.1:	Initial i386 version. Derived from ia64.
diff --git a/stand/veriexec.mk b/stand/veriexec.mk
index 930e933be0a9..a0ff7d1e8489 100644
--- a/stand/veriexec.mk
+++ b/stand/veriexec.mk
@@ -1,4 +1,7 @@
 .if ${MK_LOADER_VERIEXEC} != "no"
+.if exists(${VERSION_FILE}.veriexec)
+VERSION_FILE:= ${VERSION_FILE}.veriexec
+.endif
 CFLAGS+= -DLOADER_VERIEXEC -I${SRCTOP}/lib/libsecureboot/h
 .if ${MK_LOADER_VERIEXEC_VECTX} != "no"
 CFLAGS+= -DLOADER_VERIEXEC_VECTX



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202402122236.41CMaRCq001438>