[Skiboot] [PATCH v2 7/7] [RFC] secvar: add fuzzers
Daniel Axtens
dja at axtens.net
Thu Jul 8 17:10:40 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 5aeeb54d6ea8..cb3f943a7538 100644
--- a/libstb/secvar/test/Makefile.check
+++ b/libstb/secvar/test/Makefile.check
@@ -48,11 +48,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