[Skiboot] [PATCH 7/7] [RFC] secvar: add fuzzers

Daniel Axtens dja at axtens.net
Thu Jul 1 22:41:06 AEST 2021


Add several libfuzzer fuzzers.

To build the fuzzers: make CC=clang HOSTCC=clang fuzzers

There are 4 fuzzers all up, all in libstb/secvar/tests/

 - secvar-fuzz-db: a PK, KEK and DB key have been installed. Attempt to
   insert a random 'auth' structure as a db.

 - secvar-fuzz-dbx: a PK, KEK, and DB key have been installed. Attempt to
   insert a random 'auth' structure as a dbx.

 - secvar-fuzz-setup-mode: the databases are empty. Attempt to install a
   random 'auth' structure as a db. Attempt to install a known good KEK.

 - secvar-fuzz-pkcs7: fuzz mbedtls_pkcs7_parse_der specifically.

Each of them builds mbedtls and the edk2 code with ASAN and fuzzing
(-fsanitize=address,fuzzer-no-link)

Run them as:
libstb/secvar/test/secvar-fuzz-<whatever> <corpus dir>.

I created my starting corpus for db/dbx/setup-mode with the test data
from secvarctl, thanks Nick Child. I created the pkcs7 corpus with files
sitting on my hard drive.

TODO: this breaks building under gcc. It needs to be wrapped in some
sort of clang wrapper.

Signed-off-by: Daniel Axtens <dja at axtens.net>
---
 core/test/stubs.c                             |  11 +-
 libstb/secvar/test/Makefile.check             |  22 ++-
 libstb/secvar/test/secvar-fuzz-db.c           |   5 +
 libstb/secvar/test/secvar-fuzz-dbx.c          |   5 +
 libstb/secvar/test/secvar-fuzz-pkcs7.c        |  23 +++
 libstb/secvar/test/secvar-fuzz-setup-mode.c   |   4 +
 libstb/secvar/test/secvar-generic-fuzz-edk2.c | 177 ++++++++++++++++++
 7 files changed, 244 insertions(+), 3 deletions(-)
 create mode 100644 libstb/secvar/test/secvar-fuzz-db.c
 create mode 100644 libstb/secvar/test/secvar-fuzz-dbx.c
 create mode 100644 libstb/secvar/test/secvar-fuzz-pkcs7.c
 create mode 100644 libstb/secvar/test/secvar-fuzz-setup-mode.c
 create mode 100644 libstb/secvar/test/secvar-generic-fuzz-edk2.c

diff --git a/core/test/stubs.c b/core/test/stubs.c
index 0e97af2494b0..17ff18587715 100644
--- a/core/test/stubs.c
+++ b/core/test/stubs.c
@@ -12,17 +12,24 @@
 #include <compiler.h>
 #include "../../ccan/list/list.c"
 
-void _prlog(int log_level __attribute__((unused)), const char* fmt, ...) __attribute__((format (printf, 2, 3)));
+void _prlog(int log_level, const char* fmt, ...) __attribute__((format (printf, 2, 3)));
 
 #ifndef pr_fmt
 #define pr_fmt(fmt) fmt
 #endif
 #define prlog(l, f, ...) do { _prlog(l, pr_fmt(f), ##__VA_ARGS__); } while(0)
 
-void _prlog(int log_level __attribute__((unused)), const char* fmt, ...)
+void _prlog(int log_level, const char* fmt, ...)
 {
         va_list ap;
 
+	(void) log_level;
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+	if (log_level >= 3) {
+		return;
+	}
+#endif
+
         va_start(ap, fmt);
         vprintf(fmt, ap);
         va_end(ap);
diff --git a/libstb/secvar/test/Makefile.check b/libstb/secvar/test/Makefile.check
index 6cb1687d3a7e..51e3e345a741 100644
--- a/libstb/secvar/test/Makefile.check
+++ b/libstb/secvar/test/Makefile.check
@@ -45,11 +45,31 @@ $(SECVAR_TEST) : % : %.c $(HOST_MBEDTLS_OBJS)
 $(SECVAR_TEST:%=%-gcov): %-gcov : %.c % $(HOST_MBEDTLS_OBJS)
 	$(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) $(HOSTGCOVCFLAGS) $(HOST_MBEDTLS_CFLAGS) -I include -I . -I libfdt -lgcov -o $@ $< $(HOST_MBEDTLS_OBJS) core/test/stubs.o, $<)
 
+SECVAR_FUZZ = $(patsubst %.c, %, $(wildcard $(SECVAR_TEST_DIR)/secvar-fuzz-*.c))
+
+.PHONY : fuzzers
+fuzzers: $(SECVAR_FUZZ)
+
+comma := ,
+
+FUZZ_MBEDTLS_OBJS=$(MBEDTLS_OBJS:%.o=$(CRYPTO_DIR)/%.fuzz.o)
+%.fuzz.o: %.c
+	$(call Q, HOSTCC , $(HOSTCC) $(HOSTCFLAGS) $(HOST_MBEDTLS_CFLAGS) -fsanitize=address$(comma)fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -g -c -o $@ $<, $<)
+
+
+$(SECVAR_FUZZ) : core/test/stubs_fuzz.o
+core/test/stubs_fuzz.o: core/test/stubs.c
+	$(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) -fsanitize=address$(comma)fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -g -c -o $@ $<, $<)
+
+
+$(SECVAR_FUZZ) : % : %.c $(FUZZ_MBEDTLS_OBJS)
+	$(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) $(HOST_MBEDTLS_CFLAGS) -Og -g -fsanitize=address$(comma)fuzzer -I include -I . -I libfdt -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -o $@ $< $(FUZZ_MBEDTLS_OBJS) core/test/stubs_fuzz.o, $<)
+
 -include $(wildcard libstb/secvar/test/*.d)
 
 clean: secvar-test-clean
 
 secvar-test-clean:
-	$(RM) -f libstb/secvar/test/*.[od] $(SECVAR_TEST) $(SECVAR_TEST:%=%-gcov)
+	$(RM) -f libstb/secvar/test/*.[od] $(SECVAR_TEST) $(SECVAR_TEST:%=%-gcov) $(SECVAR_FUZZ)
 	$(RM) -f libstb/secvar/test/*.gcda libstb/secvar/test/*.gcno
 	$(RM) -f secboot.img
diff --git a/libstb/secvar/test/secvar-fuzz-db.c b/libstb/secvar/test/secvar-fuzz-db.c
new file mode 100644
index 000000000000..630db677378e
--- /dev/null
+++ b/libstb/secvar/test/secvar-fuzz-db.c
@@ -0,0 +1,5 @@
+#define VAR "db"
+#define ADD_PK
+#define ADD_KEK
+#define ADD_DB
+#include "secvar-generic-fuzz-edk2.c"
\ No newline at end of file
diff --git a/libstb/secvar/test/secvar-fuzz-dbx.c b/libstb/secvar/test/secvar-fuzz-dbx.c
new file mode 100644
index 000000000000..2a3c92ba75bc
--- /dev/null
+++ b/libstb/secvar/test/secvar-fuzz-dbx.c
@@ -0,0 +1,5 @@
+#define VAR "dbx"
+#define ADD_PK
+#define ADD_KEK
+#define ADD_DB
+#include "secvar-generic-fuzz-edk2.c"
\ No newline at end of file
diff --git a/libstb/secvar/test/secvar-fuzz-pkcs7.c b/libstb/secvar/test/secvar-fuzz-pkcs7.c
new file mode 100644
index 000000000000..74b80aa6b41a
--- /dev/null
+++ b/libstb/secvar/test/secvar-fuzz-pkcs7.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/* Copyright 2020 IBM Corp. */
+
+#define MBEDTLS_PKCS7_C
+#include "secvar_common_test.c"
+#include "../../crypto/pkcs7/pkcs7.c"
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {	
+
+	mbedtls_pkcs7 pkcs7;
+	int rc;
+
+	bzero(&pkcs7, sizeof(pkcs7));
+
+	rc = mbedtls_pkcs7_parse_der(Data, Size, &pkcs7);
+
+	if (rc >= 0)
+		mbedtls_pkcs7_free(&pkcs7);
+
+	return 0;
+}
\ No newline at end of file
diff --git a/libstb/secvar/test/secvar-fuzz-setup-mode.c b/libstb/secvar/test/secvar-fuzz-setup-mode.c
new file mode 100644
index 000000000000..614b8b729854
--- /dev/null
+++ b/libstb/secvar/test/secvar-fuzz-setup-mode.c
@@ -0,0 +1,4 @@
+#define VAR "PK"
+#define SETUP_MODE_SPECIAL
+#define RESET_VARS
+#include "secvar-generic-fuzz-edk2.c"
\ No newline at end of file
diff --git a/libstb/secvar/test/secvar-generic-fuzz-edk2.c b/libstb/secvar/test/secvar-generic-fuzz-edk2.c
new file mode 100644
index 000000000000..aa8dc479e3e0
--- /dev/null
+++ b/libstb/secvar/test/secvar-generic-fuzz-edk2.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/* Copyright 2020 IBM Corp. */
+
+#define MBEDTLS_PKCS7_C
+#include "secvar_common_test.c"
+#include "../backend/edk2-compat.c"
+#include "../backend/edk2-compat-process.c"
+#include "../secvar_util.c"
+#include "../../crypto/pkcs7/pkcs7.c"
+#include "./data/PK.h"
+#include "./data/KEK.h"
+#include "./data/db.h"
+#include "./data/dbx.h"
+
+/* Hardcoding HW KEY HASH to avoid emulating device-tree in unit-tests. */
+const unsigned char hw_key_hash[64] = {
+0xb6, 0xdf, 0xfe, 0x75, 0x53, 0xf9, 0x2e, 0xcb, 0x2b, 0x05, 0x55, 0x35, 0xd7, 0xda, 0xfe, 0x32, \
+0x98, 0x93, 0x35, 0x1e, 0xd7, 0x4b, 0xbb, 0x21, 0x6b, 0xa0, 0x56, 0xa7, 0x1e, 0x3c, 0x0b, 0x56, \
+0x6f, 0x0c, 0x4d, 0xbe, 0x31, 0x42, 0x13, 0x68, 0xcb, 0x32, 0x11, 0x6f, 0x13, 0xbb, 0xdd, 0x9e, \
+0x4f, 0xe3, 0x83, 0x8b, 0x1c, 0x6a, 0x2e, 0x07, 0xdb, 0x95, 0x16, 0xc9, 0x33, 0xaa, 0x20, 0xef
+};
+
+int reset_keystore(struct list_head *bank __unused) { return 0; }
+int verify_hw_key_hash(void)
+{
+	return OPAL_SUCCESS;
+}
+
+
+int add_hw_key_hash(struct list_head *bank)
+{
+	struct secvar *var;
+	uint32_t hw_key_hash_size = 64;
+
+	var = new_secvar("HWKH", 5, hw_key_hash,
+			hw_key_hash_size, SECVAR_FLAG_PROTECTED);
+	list_add_tail(bank, &var->link);
+
+	return OPAL_SUCCESS;
+}
+
+int delete_hw_key_hash(struct list_head *bank)
+{
+	struct secvar *var;
+
+	var = find_secvar("HWKH", 5, bank);
+	if (!var)
+		return OPAL_SUCCESS;
+
+	list_del(&var->link);
+	dealloc_secvar(var);
+
+	return OPAL_SUCCESS;
+}
+
+const char *secvar_test_name = "edk2-compat";
+
+int secvar_set_secure_mode(void) { return 0; };
+
+static void reset_vars()
+{
+	int rc = -1;
+	struct secvar *tmp;
+
+	rc = edk2_compat_pre_process(&variable_bank, &update_bank);
+	assert(OPAL_SUCCESS == rc);
+	assert(5 == list_length(&variable_bank));
+	tmp = find_secvar("TS", 3, &variable_bank);
+	assert(NULL != tmp);
+
+#ifdef ADD_PK
+	/* Add PK to update and .process(). */
+	tmp = new_secvar("PK", 3, PK_auth, PK_auth_len, 0);
+	assert(0 == edk2_compat_validate(tmp));
+	list_add_tail(&update_bank, &tmp->link);
+	assert(1 == list_length(&update_bank));
+
+	rc = edk2_compat_process(&variable_bank, &update_bank);
+	assert(OPAL_SUCCESS == rc);
+	assert(6 == list_length(&variable_bank));
+	assert(0 == list_length(&update_bank));
+	rc = edk2_compat_post_process(&variable_bank, &update_bank);
+	assert(5 == list_length(&variable_bank));
+	tmp = find_secvar("PK", 3, &variable_bank);
+	assert(NULL != tmp);
+	assert(0 != tmp->data_size);
+	assert(PK_auth_len > tmp->data_size); /* esl should be smaller without auth. */
+	assert(!setup_mode);
+#endif
+
+#ifdef ADD_KEK
+	/* Add valid KEK, .process(), succeeds. */
+	tmp = new_secvar("KEK", 4, KEK_auth, KEK_auth_len, 0);
+	assert(0 == edk2_compat_validate(tmp));
+	list_add_tail(&update_bank, &tmp->link);
+	assert(1 == list_length(&update_bank));
+
+	rc = edk2_compat_process(&variable_bank, &update_bank);
+	assert(OPAL_SUCCESS == rc);
+	assert(5 == list_length(&variable_bank));
+	assert(0 == list_length(&update_bank));
+	tmp = find_secvar("KEK", 4, &variable_bank);
+	assert(NULL != tmp);
+	assert(0 != tmp->data_size);
+#endif
+
+#ifdef ADD_DB
+	/* Add db, .process(), should succeed. */
+	tmp = new_secvar("db", 3, DB_auth, DB_auth_len, 0);
+	assert(0 == edk2_compat_validate(tmp));
+	list_add_tail(&update_bank, &tmp->link);
+	assert(1 == list_length(&update_bank));
+
+	rc = edk2_compat_process(&variable_bank, &update_bank);
+	assert(OPAL_SUCCESS == rc);
+	assert(5 == list_length(&variable_bank));
+	assert(0 == list_length(&update_bank));
+	tmp = find_secvar("db", 3, &variable_bank);
+	assert(NULL != tmp);
+	assert(0 != tmp->data_size);
+#endif
+}
+
+static void init()
+{
+	static bool inited = false;
+
+	if (inited)
+		return;
+
+	list_head_init(&variable_bank);
+	list_head_init(&update_bank);
+
+	secvar_storage.max_var_size = 4096;
+
+	reset_vars();
+
+	inited = true;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {	
+	struct secvar *tmp;
+
+	init();
+
+	tmp = new_secvar(VAR, sizeof (VAR), Data, Size, 0);
+	if (!tmp)
+		return 0;
+
+	if (0 != edk2_compat_validate(tmp)) {
+		dealloc_secvar(tmp);
+		return 0;
+	}
+
+	list_add_tail(&update_bank, &tmp->link);
+	assert(1 == list_length(&update_bank));
+
+	edk2_compat_process(&variable_bank, &update_bank);
+
+#ifdef SETUP_MODE_SPECIAL
+	tmp = new_secvar("KEK", 4, KEK_auth, KEK_auth_len, 0);
+	assert(0 == edk2_compat_validate(tmp));
+	list_add_tail(&update_bank, &tmp->link);
+	assert(1 == list_length(&update_bank));
+	edk2_compat_process(&variable_bank, &update_bank);
+#endif
+
+#ifdef RESET_VARS
+	clear_bank_list(&variable_bank);
+	reset_vars();
+#endif
+
+	clear_bank_list(&update_bank);
+	return 0;
+}
\ No newline at end of file
-- 
2.30.2



More information about the Skiboot mailing list