summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorSteve McIntyre <steve@einval.com>2021-03-23 23:49:46 +0000
committerSteve McIntyre <steve@einval.com>2021-03-23 23:49:46 +0000
commit1251a7ba86fc40a6aad8b4fecdbca2b61808d9fa (patch)
tree2125fda549aaca55cb49a48d54be77dec7fbf3df /include
parent85b409232ce89b34626df9d72abedf5d4f5ccef6 (diff)
parent031e5cce385d3f96b1caa1d53495332a7eb03749 (diff)
downloadefi-boot-shim-debian/15.3-1.tar.gz
efi-boot-shim-debian/15.3-1.zip
Update upstream source from tag 'upstream/15.3'debian/15.3-1
Update to upstream version '15.3' with Debian dir 1b484f1c1ac270604a5a1451b34de4b0865c6211
Diffstat (limited to 'include')
-rw-r--r--include/compiler.h40
-rw-r--r--include/console.h14
-rw-r--r--include/coverity.mk64
-rw-r--r--include/endian.h21
-rw-r--r--include/errors.h2
-rw-r--r--include/fanalyzer.mk35
-rw-r--r--include/guid.h2
-rw-r--r--include/hexdump.h21
-rw-r--r--include/ip4config2.h2
-rw-r--r--include/ip6config.h2
-rw-r--r--include/list.h11
-rw-r--r--include/sbat.h54
-rw-r--r--include/scan-build.mk38
-rw-r--r--include/str.h218
-rw-r--r--include/system/alloca.h16
-rw-r--r--include/system/builtins_begin_.h65
-rw-r--r--include/system/builtins_end_.h27
-rw-r--r--include/system/ctype.h85
-rw-r--r--include/system/efistdarg.h19
-rw-r--r--include/system/inttypes.h13
-rw-r--r--include/system/stdarg.h80
-rw-r--r--include/system/stdio.h13
-rw-r--r--include/system/stdlib.h28
-rw-r--r--include/system/string.h82
-rw-r--r--include/system/strings.h19
-rw-r--r--include/test.h243
-rw-r--r--include/test.mk58
-rw-r--r--include/tpm.h4
-rw-r--r--include/variables.h22
29 files changed, 1172 insertions, 126 deletions
diff --git a/include/compiler.h b/include/compiler.h
index 4e44840d..18576724 100644
--- a/include/compiler.h
+++ b/include/compiler.h
@@ -3,6 +3,28 @@
#ifndef COMPILER_H_
#define COMPILER_H_
+/*
+ * These are special ones that get our unit tests in trouble with the
+ * compiler optimizer dropping out tests...
+ */
+#ifdef NONNULL
+# undef NONNULL
+#endif
+#ifdef RETURNS_NONNULL
+# undef RETURNS_NONNULL
+#endif
+#ifdef SHIM_UNIT_TEST
+# define NONNULL(first, args...)
+# define RETURNS_NONNULL
+#else
+# define NONNULL(first, args...) __attribute__((__nonnull__(first, ## args)))
+#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)))
+# define RETURNS_NONNULL __attribute__((__returns_nonnull__))
+#else
+# define RETURNS_NONNULL
+#endif
+#endif
+
#ifndef UNUSED
#define UNUSED __attribute__((__unused__))
#endif
@@ -12,6 +34,9 @@
#ifndef PUBLIC
#define PUBLIC __attribute__((__visibility__ ("default")))
#endif
+#ifndef DEPRECATED
+#define DEPRECATED __attribute__((__deprecated__))
+#endif
#ifndef DESTRUCTOR
#define DESTRUCTOR __attribute__((destructor))
#endif
@@ -21,12 +46,15 @@
#ifndef ALIAS
#define ALIAS(x) __attribute__((weak, alias (#x)))
#endif
-#ifndef NONNULL
+#ifndef ALLOCFUNC
+#define ALLOCFUNC(dealloc, dealloc_arg) __attribute__((__malloc__(dealloc, dealloc_arg)))
#endif
-#define NONNULL(first, args...) __attribute__((__nonnull__(first, ## args)))
#ifndef PRINTF
#define PRINTF(first, args...) __attribute__((__format__(printf, first, ## args)))
#endif
+#ifndef PURE
+#define PURE __attribute__((__pure__))
+#endif
#ifndef FLATTEN
#define FLATTEN __attribute__((__flatten__))
#endif
@@ -56,6 +84,9 @@
#endif
#ifndef __CONCAT
+#define __CONCAT(a, b) a ## b
+#endif
+#ifndef __CONCAT3
#define __CONCAT3(a, b, c) a ## b ## c
#endif
#ifndef CAT
@@ -152,5 +183,10 @@
#define MIN(a, b) ({(a) < (b) ? (a) : (b);})
#define MAX(a, b) ({(a) <= (b) ? (b) : (a);})
+/**
+ * Builtins that don't go in string.h
+ */
+#define unreachable() __builtin_unreachable()
+
#endif /* !COMPILER_H_ */
// vim:fenc=utf-8:tw=75:et
diff --git a/include/console.h b/include/console.h
index b2ab5fe4..f56b1231 100644
--- a/include/console.h
+++ b/include/console.h
@@ -17,9 +17,9 @@
EFI_STATUS
console_get_keystroke(EFI_INPUT_KEY *key);
-UINTN
+UINTN EFIAPI
console_print(const CHAR16 *fmt, ...);
-UINTN
+UINTN EFIAPI
console_print_at(UINTN col, UINTN row, const CHAR16 *fmt, ...);
void
console_print_box_at(CHAR16 *str_arr[], int highlight,
@@ -92,6 +92,7 @@ struct _EFI_CONSOLE_CONTROL_PROTOCOL {
extern VOID console_fini(VOID);
extern VOID setup_verbosity(VOID);
extern UINT32 verbose;
+#ifndef SHIM_UNIT_TEST
#define dprint_(fmt, ...) ({ \
UINTN __dprint_ret = 0; \
if (verbose) \
@@ -101,8 +102,13 @@ extern UINT32 verbose;
#define dprint(fmt, ...) \
dprint_(L"%a:%d:%a() " fmt, __FILE__, __LINE__ - 1, __func__, \
##__VA_ARGS__)
-extern EFI_STATUS
-vdprint_(const CHAR16 *fmt, const char *file, int line, const char *func, va_list args);
+#else
+#define dprint_(...)
+#define dprint(fmt, ...)
+#endif
+
+extern EFI_STATUS EFIAPI vdprint_(const CHAR16 *fmt, const char *file, int line,
+ const char *func, ms_va_list args);
#define vdprint(fmt, ...) \
vdprint_(fmt, __FILE__, __LINE__ - 1, __func__, ##__VA_ARGS__)
diff --git a/include/coverity.mk b/include/coverity.mk
new file mode 100644
index 00000000..93d83853
--- /dev/null
+++ b/include/coverity.mk
@@ -0,0 +1,64 @@
+COV_EMAIL=$(call get-config,coverity.email)
+COV_TOKEN=$(call get-config,coverity.token)
+COV_URL=$(call get-config,coverity.url)
+COV_FILE=$(NAME)-coverity-$(VERSION)-$(COMMIT_ID).tar.bz2
+
+include $(TOPDIR)/Make.rules
+
+define prop
+$(if $(findstring undefined,$(origin $(1))),,$(1)="$($1)")
+endef
+
+PROPOGATE_MAKE_FLAGS = ARCH ARCH_SUFFIX COLOR CC COMPILER CROSS_COMPILE
+
+MAKEARGS = $(foreach x,$(PROPOGATE_MAKE_FLAGS),$(call prop,$(x)))
+
+cov-clean :
+ @rm -vf $(NAME)-coverity-*.tar.*
+ @if [ -d cov-int ]; then rm -rf cov-int && echo "removed 'cov-int'"; fi
+
+cov-file : | $(COV_FILE)
+
+$(COV_FILE) : | cov-int
+ tar caf $@ cov-int
+
+cov-upload : | cov-file
+ @if [ -n "$(COV_URL)" ] && \
+ [ -n "$(COV_TOKEN)" ] && \
+ [ -n "$(COV_EMAIL)" ] ; \
+ then \
+ echo curl --form token=$(COV_TOKEN) --form email="$(COV_EMAIL)" --form file=@"$(COV_FILE)" --form version=$(VERSION).1 --form description="$(COMMIT_ID)" "$(COV_URL)" ; \
+ curl --form token=$(COV_TOKEN) --form email="$(COV_EMAIL)" --form file=@"$(COV_FILE)" --form version=$(VERSION).1 --form description="$(COMMIT_ID)" "$(COV_URL)" ; \
+ else \
+ echo Coverity output is in $(COV_FILE) ; \
+ fi
+
+cov-build-unchecked-cryptlib : | clean-cryptlib-objs
+cov-build-unchecked-cryptlib : Cryptlib/libcryptlib.a
+
+cov-build-unchecked-openssl : | clean-openssl-objs
+cov-build-unchecked-openssl : Cryptlib/OpenSSL/libopenssl.a
+
+cov-build-all : CCACHE_DISABLE=1
+cov-build-all : | clean clean-shim-objs clean-cryptlib-objs clean-openssl-objs
+ +cov-build --dir cov-int $(MAKE) $(MAKEARGS) CCACHE_DISABLE=1 all
+
+coverity-no-openssl : | cov-test
+coverity-no-openssl : clean-shim-objs clean-cryptlib-objs cov-build-unchecked-openssl cov-build-all cov-file cov-upload
+
+coverity-no-cryptlib : | cov-test
+coverity-no-cryptlib : clean-shim-objs cov-build-unchecked-openssl cov-build-unchecked-cryptlib cov-build-all cov-file cov-upload
+
+coverity : | cov-test
+coverity : coverity-no-openssl cov-file cov-upload
+
+coverity-all : | cov-test
+coverity-all : clean cov-build-all cov-file cov-upload
+
+clean : | cov-clean
+
+COV_BUILD ?= $(shell x=$$(which --skip-alias --skip-functions cov-build 2>/dev/null) ; [ -n "$$x" ] && echo "$$x")
+
+cov-test : ; $(if $(findstring /,$(COV_BUILD)),,$(error cov-build not found))
+
+.PHONY : coverity cov-upload cov-clean cov-file cov-test
diff --git a/include/endian.h b/include/endian.h
new file mode 100644
index 00000000..1c4a21de
--- /dev/null
+++ b/include/endian.h
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * endian.h - bswap decls that can't go in compiler.h
+ * Copyright Peter Jones <pjones@redhat.com>
+ */
+#ifdef SHIM_UNIT_TEST
+#include_next <endian.h>
+#endif
+#ifndef SHIM_ENDIAN_H_
+#define SHIM_ENDIAN_H_
+
+#include <stdint.h>
+
+#include "system/builtins_begin_.h"
+mkbi1_(uint16_t, bswap16, uint16_t, x)
+mkbi1_(uint32_t, bswap32, uint32_t, x)
+mkbi1_(uint64_t, bswap64, uint64_t, x)
+#include "system/builtins_end_.h"
+
+#endif /* !SHIM_ENDIAN_H_ */
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/errors.h b/include/errors.h
index 1c6cf528..67d821e0 100644
--- a/include/errors.h
+++ b/include/errors.h
@@ -3,8 +3,6 @@
#ifndef SHIM_ERRORS_H
#define SHIM_ERRORS_H
-#include <efierr.h>
-
#ifndef EFI_INCOMPATIBLE_VERSION
#define EFI_INCOMPATIBLE_VERSION EFIERR(25)
#endif
diff --git a/include/fanalyzer.mk b/include/fanalyzer.mk
new file mode 100644
index 00000000..e0bf4d75
--- /dev/null
+++ b/include/fanalyzer.mk
@@ -0,0 +1,35 @@
+GCC_BINARY ?= $(shell x=$$(which --skip-alias --skip-functions gcc 2>/dev/null) ; [ -n "$$x" ] && echo "$$x")
+
+fanalyzer-test : ; $(if $(findstring /,$(GCC_BINARY)),,$(error gcc not found))
+
+define prop
+$(if $(findstring undefined,$(origin $(1))),,$(eval export $(1)))
+endef
+
+PROPOGATE_MAKE_FLAGS = ARCH ARCH_SUFFIX COLOR CC COMPILER CROSS_COMPILE DASHJ
+
+MAKEARGS = $(foreach x,$(PROPOGATE_MAKE_FLAGS),$(call prop,$(x)))
+
+fanalyzer : | fanalyzer-test
+fanalyzer : fanalyzer-no-openssl
+
+fanalyzer-build-unchecked-cryptlib : Cryptlib/libcryptlib.a
+
+fanalyzer-build-unchecked-openssl : Cryptlib/OpenSSL/libopenssl.a
+
+fanalyzer-build-all : COMPILER=gcc
+fanalyzer-build-all : CCACHE_DISABLE=1
+fanalyzer-build-all : FEATUREFLAGS+=-fanalyzer
+fanalyzer-build-all : WERRFLAGS=-Werror=analyzer-null-dereference
+fanalyzer-build-all : all
+
+fanalyzer-no-openssl : | fanalyzer-test
+fanalyzer-no-openssl : clean-shim-objs clean-cryptlib-objs fanalyzer-build-unchecked-openssl fanalyzer-build-all
+
+fanalyzer-no-cryptlib : | fanalyzer-test
+fanalyzer-no-cryptlib : clean-shim-objs fanalyzer-build-unchecked-openssl fanalyzer-build-unchecked-cryptlib fanalyzer-build-all
+
+fanalyzer-all : | fanalyzer-test
+fanalyzer-all : clean fanalyzer-build-all
+
+.PHONY : fanalyzer fanalyzer-build fanalyzer-all fanalyzer-build-all fanalyzer-clean
diff --git a/include/guid.h b/include/guid.h
index 114e8707..07a19a91 100644
--- a/include/guid.h
+++ b/include/guid.h
@@ -3,8 +3,6 @@
#ifndef SHIM_GUID_H
#define SHIM_GUID_H
-#include <efi.h>
-
extern EFI_GUID BDS_GUID;
extern EFI_GUID GV_GUID;
extern EFI_GUID SIG_DB;
diff --git a/include/hexdump.h b/include/hexdump.h
index 8b8b4557..381e1a68 100644
--- a/include/hexdump.h
+++ b/include/hexdump.h
@@ -3,7 +3,8 @@
#ifndef STATIC_HEXDUMP_H
#define STATIC_HEXDUMP_H
-#include <stdint.h>
+#include "shim.h"
+#include "include/console.h"
static inline unsigned long UNUSED
prepare_hex(const void *data, size_t size, char *buf, unsigned int position)
@@ -47,8 +48,6 @@ prepare_hex(const void *data, size_t size, char *buf, unsigned int position)
return ret;
}
-#define isprint(c) ((c) >= 0x20 && (c) <= 0x7e)
-
static inline void UNUSED
prepare_text(const void *data, size_t size, char *buf, unsigned int position)
{
@@ -80,8 +79,9 @@ prepare_text(const void *data, size_t size, char *buf, unsigned int position)
* variadic hexdump formatted
* think of it as: printf("%s%s\n", vformat(fmt, ap), hexdump(data,size));
*/
-static inline void UNUSED
-vhexdumpf(const char *file, int line, const char *func, const CHAR16 * const fmt, const void *data, unsigned long size, size_t at, va_list ap)
+static inline void UNUSED EFIAPI
+vhexdumpf(const char *file, int line, const char *func, const CHAR16 *const fmt,
+ const void *data, unsigned long size, size_t at, ms_va_list ap)
{
unsigned long display_offset = at;
unsigned long offset = 0;
@@ -114,14 +114,15 @@ vhexdumpf(const char *file, int line, const char *func, const CHAR16 * const fmt
* hexdump formatted
* think of it as: printf("%s%s", format(fmt, ...), hexdump(data,size)[lineN]);
*/
-static inline void UNUSED
-hexdumpf(const char *file, int line, const char *func, const CHAR16 * const fmt, const void *data, unsigned long size, size_t at, ...)
+static inline void UNUSED EFIAPI
+hexdumpf(const char *file, int line, const char *func, const CHAR16 *const fmt,
+ const void *data, unsigned long size, size_t at, ...)
{
- va_list ap;
+ ms_va_list ap;
- va_start(ap, at);
+ ms_va_start(ap, at);
vhexdumpf(file, line, func, fmt, data, size, at, ap);
- va_end(ap);
+ ms_va_end(ap);
}
static inline void UNUSED
diff --git a/include/ip4config2.h b/include/ip4config2.h
index 0955bc26..8fd8dfcb 100644
--- a/include/ip4config2.h
+++ b/include/ip4config2.h
@@ -9,8 +9,6 @@
#ifndef SHIM_IP4CONFIG2_H
#define SHIM_IP4CONFIG2_H
-#include <efiip.h>
-
typedef struct _EFI_IP4_CONFIG2_PROTOCOL EFI_IP4_CONFIG2_PROTOCOL;
diff --git a/include/ip6config.h b/include/ip6config.h
index 8d9025b7..58cef532 100644
--- a/include/ip6config.h
+++ b/include/ip6config.h
@@ -8,8 +8,6 @@
#ifndef SHIM_IP6CONFIG_H
#define SHIM_IP6CONFIG_H
-#include <efiip.h>
-
typedef struct _EFI_IP6_CONFIG_PROTOCOL EFI_IP6_CONFIG_PROTOCOL;
///
diff --git a/include/list.h b/include/list.h
index ad87b45b..1d36e163 100644
--- a/include/list.h
+++ b/include/list.h
@@ -102,5 +102,16 @@ list_del(struct list_head *entry)
for (pos = (head)->prev, n = pos->prev; pos != (head); \
pos = n, n = pos->prev)
+static inline size_t
+list_size(struct list_head *entry)
+{
+ list_t *pos;
+ size_t i = 0;
+ list_for_each(pos, entry) {
+ i++;
+ }
+ return i;
+}
+
#endif /* !LIST_H_ */
// vim:fenc=utf-8:tw=75:noet
diff --git a/include/sbat.h b/include/sbat.h
index ffde202d..5db82379 100644
--- a/include/sbat.h
+++ b/include/sbat.h
@@ -1,24 +1,58 @@
// SPDX-License-Identifier: BSD-2-Clause-Patent
/*
- * sbat.c - parse SBAT data from the .rsrc section data
+ * sbat.c - parse SBAT data from the .sbat section data
*/
#ifndef SBAT_H_
#define SBAT_H_
+#define SBAT_VAR_SIG "sbat,"
+#define SBAT_VAR_VERSION "1,"
+#define SBAT_VAR_DATE "2021030218"
+#define SBAT_VAR SBAT_VAR_SIG SBAT_VAR_VERSION SBAT_VAR_DATE "\n"
+
+#define UEFI_VAR_NV_BS \
+ (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS)
+#define UEFI_VAR_NV_BS_RT \
+ (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | \
+ EFI_VARIABLE_RUNTIME_ACCESS)
+#define UEFI_VAR_NV_BS_TIMEAUTH \
+ (UEFI_VAR_NV_BS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)
+
+#if defined(ENABLE_SHIM_DEVEL)
+#define SBAT_VAR_NAME L"SBAT_DEVEL"
+#define SBAT_VAR_NAME8 "SBAT_DEVEL"
+#define SBAT_RT_VAR_NAME L"SbatRT_DEVEL"
+#define SBAT_RT_VAR_NAME8 "SbatRT_DEVEL"
+#define SBAT_VAR_ATTRS UEFI_VAR_NV_BS_RT
+#else
+#define SBAT_VAR_NAME L"SBAT"
+#define SBAT_VAR_NAME8 "SBAT"
+#define SBAT_RT_VAR_NAME L"SbatRT"
+#define SBAT_RT_VAR_NAME8 "SbatRT"
+#define SBAT_VAR_ATTRS UEFI_VAR_NV_BS
+#endif
+
extern UINTN _sbat, _esbat;
-struct sbat_var {
+struct sbat_var_entry {
const CHAR8 *component_name;
const CHAR8 *component_generation;
+ /*
+ * This column is only actually on the "sbat" version entry
+ */
+ const CHAR8 *sbat_datestamp;
list_t list;
};
extern list_t sbat_var;
+#define SBAT_VAR_COLUMNS ((sizeof (struct sbat_var_entry) - sizeof(list_t)) / sizeof(CHAR8 *))
+#define SBAT_VAR_REQUIRED_COLUMNS (SBAT_VAR_COLUMNS - 1)
EFI_STATUS parse_sbat_var(list_t *entries);
void cleanup_sbat_var(list_t *entries);
+EFI_STATUS set_sbat_uefi_variable(void);
-struct sbat_entry {
+struct sbat_section_entry {
const CHAR8 *component_name;
const CHAR8 *component_generation;
const CHAR8 *vendor_name;
@@ -26,11 +60,19 @@ struct sbat_entry {
const CHAR8 *vendor_version;
const CHAR8 *vendor_url;
};
+#define SBAT_SECTION_COLUMNS (sizeof (struct sbat_section_entry) / sizeof(CHAR8 *))
-EFI_STATUS parse_sbat(char *sbat_base, size_t sbat_size, size_t *sbats, struct sbat_entry ***sbat);
-void cleanup_sbat_entries(size_t n, struct sbat_entry **entries);
+EFI_STATUS
+parse_sbat_section(char *section_base, size_t section_size, size_t *n,
+ struct sbat_section_entry ***entriesp);
+void cleanup_sbat_section_entries(size_t n, struct sbat_section_entry **entries);
-EFI_STATUS verify_sbat(size_t n, struct sbat_entry **entries);
+EFI_STATUS verify_sbat(size_t n, struct sbat_section_entry **entries);
+#ifdef SHIM_UNIT_TEST
+EFI_STATUS parse_sbat_var_data(list_t *entries, UINT8 *data, UINTN datasize);
+EFI_STATUS verify_sbat_helper(list_t *sbat_var, size_t n,
+ struct sbat_section_entry **entries);
+#endif /* !SHIM_UNIT_TEST */
#endif /* !SBAT_H_ */
// vim:fenc=utf-8:tw=75:noet
diff --git a/include/scan-build.mk b/include/scan-build.mk
new file mode 100644
index 00000000..3ed7660e
--- /dev/null
+++ b/include/scan-build.mk
@@ -0,0 +1,38 @@
+SCAN_BUILD ?= $(shell x=$$(which --skip-alias --skip-functions scan-build 2>/dev/null) ; [ -n "$$x" ] && echo "$$x")
+
+scan-test : ; $(if $(findstring /,$(SCAN_BUILD)),,$(error scan-build not found))
+
+define prop
+$(if $(findstring undefined,$(origin $(1))),,$(1)="$($1)")
+endef
+
+PROPOGATE_MAKE_FLAGS = ARCH ARCH_SUFFIX COLOR CC COMPILER CROSS_COMPILE DASHJ
+
+MAKEARGS = $(foreach x,$(PROPOGATE_MAKE_FLAGS),$(call prop,$(x)))
+
+scan-clean :
+ @if [[ -d scan-results ]]; then rm -rf scan-results && echo "removed 'scan-results'"; fi
+
+scan : | scan-test
+scan : clean-shim-objs clean-cryptlib-objs scan-build-no-openssl
+
+scan-build-unchecked-cryptlib : Cryptlib/libcryptlib.a
+
+scan-build-unchecked-openssl : Cryptlib/OpenSSL/libopenssl.a
+
+scan-build-all : CCACHE_DISABLE=1
+scan-build-all : COMPILER=clang
+scan-build-all : | scan-test
+scan-build-all :
+ +scan-build -o scan-results make $(MAKEARGS) $(DASHJ) CCACHE_DISABLE=1 all
+
+scan-build-no-openssl : | scan-test
+scan-build-no-openssl : clean-shim-objs clean-cryptlib-objs scan-build-unchecked-openssl scan-build-all
+
+scan-build-no-cryptlib : | scan-test
+scan-build-no-cryptlib : clean-shim-objs scan-build-unchecked-cryptlib scan-build-unchecked-openssl scan-build-all
+
+scan-all : | scan-test
+scan-all : clean scan-build-all
+
+.PHONY : scan-build scan-clean
diff --git a/include/str.h b/include/str.h
index a6fbfefd..d433e6ec 100644
--- a/include/str.h
+++ b/include/str.h
@@ -3,110 +3,150 @@
#ifndef SHIM_STR_H
#define SHIM_STR_H
-static inline __attribute__((unused)) unsigned long
-strnlena(const CHAR8 *s, unsigned long n)
+#if __GNUC__ > 6
+#ifdef SHIM_UNIT_TEST
+#pragma GCC diagnostic error "-Wnonnull-compare"
+#else
+#pragma GCC diagnostic ignored "-Wnonnull-compare"
+#endif
+#endif
+
+static inline UNUSED RETURNS_NONNULL NONNULL(1)
+char *
+strnchrnul(const char *s, size_t max, int c)
{
- unsigned long i;
- for (i = 0; i < n; i++)
- if (s[i] == '\0')
- break;
- return i;
-}
-
-static inline
-__attribute__((unused))
-CHAR8 *
-strncpya(CHAR8 *dest, const CHAR8 *src, unsigned long n)
-{
- unsigned long i;
-
- for (i = 0; i < n && src[i] != '\0'; i++)
- dest[i] = src[i];
- for (; i < n; i++)
- dest[i] = '\0';
+ unsigned int i;
- return dest;
-}
+ if (!s || !max)
+ return (char *)s;
-static inline
-__attribute__((unused))
-CHAR8 *
-strcata(CHAR8 *dest, const CHAR8 *src)
-{
- unsigned long dest_len = strlena(dest);
- unsigned long i;
+ for (i = 0; i < max && s[i] != '\0' && s[i] != c; i++)
+ ;
- for (i = 0; src[i] != '\0'; i++)
- dest[dest_len + i] = src[i];
- dest[dest_len + i] = '\0';
+ if (i == max)
+ i--;
- return dest;
+ return (char *)&s[i];
}
-static inline
-__attribute__((unused))
-CHAR8 *
-strndupa(const CHAR8 * const src, const UINTN srcmax)
+/**
+ * strntoken: tokenize a string, with a limit
+ * str: your string (will be modified)
+ * max: maximum number of bytes to ever touch
+ * delims: string of one character delimeters, any of which will tokenize
+ * *token: the token we're passing back (must be a pointer to NULL initially)
+ * state: a pointer to one char of state for between calls
+ *
+ * Ensure that both token and state are preserved across calls. Do:
+ * char state = 0;
+ * char *token = NULL;
+ * for (...) {
+ * valid = strntoken(...)
+ * not:
+ * char state = 0;
+ * for (...) {
+ * char *token = NULL;
+ * valid = strntoken(...)
+ *
+ * - it will not test bytes beyond str[max-1]
+ * - it will not set *token to an address beyond &str[max-1]
+ * - it will set *token to &str[max-1] without testing &str[max-2] for
+ * &str[max-1] == str
+ * - sequences of multiple delimeters will result in empty (pointer to '\0')
+ * tokens.
+ * - it expects you to update str and max on successive calls.
+ *
+ * return:
+ * true means it hasn't tested str[max-1] yet and token is valid
+ * false means it got to a NUL or str[max-1] and token is invalid
+ */
+static inline UNUSED NONNULL(1, 3, 4) int
+strntoken(char *str, size_t max, const char *delims, char **token, char *state)
{
- UINTN len;
- CHAR8 *news = NULL;
-
- if (!src || !srcmax)
- return news;
-
- len = strnlena(src, srcmax);
- news = AllocateZeroPool(len + 1);
- if (news)
- strncpya(news, src, len);
- return news;
-}
+ char *tokend;
+ const char *delim;
+ int isdelim = 0;
+ int state_is_delim = 0;
+
+ if (!str || !max || !delims || !token || !state)
+ return 0;
+
+ tokend = &str[max-1];
+ if (!str || max == 0 || !delims || !token)
+ return 0;
+
+ /*
+ * the very special case of "" with max=1, where we have no prior
+ * state to let us know this is the same as right after a delim
+ */
+ if (*token == NULL && max == 1 && *str == '\0') {
+ state_is_delim = 1;
+ }
-static inline
-__attribute__((unused))
-CHAR8 *
-translate_slashes(CHAR8 *out, const char *str)
-{
- int i;
- int j;
- if (str == NULL || out == NULL)
- return NULL;
-
- for (i = 0, j = 0; str[i] != '\0'; i++, j++) {
- if (str[i] == '\\') {
- out[j] = '/';
- if (str[i+1] == '\\')
- i++;
- } else
- out[j] = str[i];
+ for (delim = delims; *delim; delim++) {
+ char *tmp = NULL;
+ if (*token && *delim == *state)
+ state_is_delim = 1;
+ tmp = strnchrnul(str, max, *delim);
+ if (tmp < tokend)
+ tokend = tmp;
+ if (*tokend == *delim)
+ isdelim = 1;
+ }
+ *token = str;
+ if (isdelim) {
+ *state = *tokend;
+ *tokend = '\0';
+ return 1;
}
- out[j] = '\0';
- return out;
+ return state_is_delim;
}
-static inline UNUSED CHAR8 *
-strchrnula(const CHAR8 *s, int c)
-{
- unsigned int i;
-
- if (s == NULL)
- return NULL;
+#define UTF8_BOM { 0xef, 0xbb, 0xbf }
+#define UTF8_BOM_SIZE 3
- for (i = 0; s[i] != '\000' && s[i] != c; i++)
- ;
-
- return (CHAR8 *)&s[i];
-}
-
-static inline UNUSED CHAR8 *
-strchra(const CHAR8 *s, int c)
+static inline UNUSED NONNULL(1) BOOLEAN
+is_utf8_bom(CHAR8 *buf, size_t bufsize)
{
- const CHAR8 *s1;
+ unsigned char bom[] = UTF8_BOM;
- s1 = strchrnula(s, c);
- if (!s1 || s1[0] == '\000')
- return NULL;
-
- return (CHAR8 *)s1;
+ return CompareMem(buf, bom, MIN(UTF8_BOM_SIZE, bufsize)) == 0;
}
+/**
+ * parse CSV data from data to end.
+ * *data points to the first byte of the data
+ * end points to a NUL byte at the end of the data
+ * n_columns number of columns per entry
+ * list the list head we're adding to
+ *
+ * On success, list will be populated with individually allocate a list of
+ * struct csv_list objects, with one column per entry of the "columns" array,
+ * filled left to right with up to n_columns elements, or NULL when a csv line
+ * does not have enough elements.
+ *
+ * Note that the data will be modified; all comma, linefeed, and newline
+ * characters will be set to '\000'. Additionally, consecutive linefeed and
+ * newline characters will not result in rows in the results.
+ *
+ * On failure, list will be empty and all entries on it will have been freed,
+ * using free_csv_list(), whether they were there before calling
+ * parse_csv_data or not.
+ */
+
+struct csv_row {
+ list_t list; /* this is a linked list */
+ size_t n_columns; /* this is how many columns are actually populated */
+ char *columns[0]; /* these are pointers to columns */
+};
+
+EFI_STATUS parse_csv_data(char *data, char *end, size_t n_columns,
+ list_t *list);
+void free_csv_list(list_t *list);
+
+#ifdef SHIM_UNIT_TEST
+void NONNULL(1, 3, 4)
+parse_csv_line(char * line, size_t max, size_t *n_columns, const char *columns[]);
+#endif
+
#endif /* SHIM_STR_H */
diff --git a/include/system/alloca.h b/include/system/alloca.h
new file mode 100644
index 00000000..a9d1aab1
--- /dev/null
+++ b/include/system/alloca.h
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+#ifdef SHIM_UNIT_TEST
+#include_next <alloca.h>
+#else
+#ifndef _ALLOCA_H
+#define _ALLOCA_H
+
+#include <builtins_begin_.h>
+mkbi1_(void *, alloca, size_t, size)
+#define alloca_with_align(size, alignment) __builtin_alloca_with_align(size, alignment)
+#define alloca_with_align_and_max(size, alignment, max) __builtin_alloca_with_align_and_max(size, alignment, max)
+#include <builtins_end_.h>
+
+#endif /* !_ALLOCA_H */
+#endif
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/system/builtins_begin_.h b/include/system/builtins_begin_.h
new file mode 100644
index 00000000..2686c41c
--- /dev/null
+++ b/include/system/builtins_begin_.h
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/**
+ * macros to build function declarations with the same types as builtins
+ * that we apparently really cannot depend on.
+ */
+
+/*
+ * Clang's __builtin_whatever and __typeof__ are broken thusly:
+ * In file included from MokManager.c:2:
+ * In file included from shim.h:47:
+ * include/system/string.h:29:1: error: builtin functions must be directly called
+ * mkbi1_(long int, ffsl, long int, x)
+ * ^
+ */
+#if defined(__clang__)
+
+#ifndef mkbi1_
+#define mkbi1_(rtype, x, typea, a) rtype x(typea a);
+#endif
+
+#ifndef mkbi2_
+#define mkbi2_(rtype, x, typea, a, typeb, b) rtype x(typea a, typeb b);
+#endif
+
+#ifndef mkbi3_
+#define mkbi3_(rtype, x, typea, a, typeb, b, typec, c) rtype x(typea a, typeb b, typec c);
+#endif
+
+#ifndef mkdepbi1_
+#define mkdepbi1_(rtype, x, typea, a) rtype x(typea a);
+#endif
+
+#ifndef mkdepbi2_
+#define mkdepbi2_(rtype, x, typea, a, typeb, b) rtype x(typea a, typeb b);
+#endif
+
+#else /* !__clang__ */
+
+#ifndef mkbi_cat_
+#define mkbi_cat_(a, b) a##b
+#endif
+
+#ifndef mkbi1_
+#define mkbi1_(rtype, x, typea, a) __typeof__(mkbi_cat_(__builtin_, x)) x;
+#endif
+
+#ifndef mkbi2_
+#define mkbi2_(rtype, x, typea, a, typeb, b) __typeof__(mkbi_cat_(__builtin_, x)) x;
+#endif
+
+#ifndef mkbi3_
+#define mkbi3_(rtype, x, typea, a, typeb, b, typec, c) __typeof__(mkbi_cat_(__builtin_, x)) x;
+#endif
+
+#ifndef mkdepbi1_
+#define mkdepbi1_(rtype, x, typea, a) __typeof__(mkbi_cat_(__builtin_, x)) x;
+#endif
+
+#ifndef mkdepbi2_
+#define mkdepbi2_(rtype, x, typea, a, typeb, b) __typeof__(mkbi_cat_(__builtin_, x)) x;
+#endif
+
+#endif /* !__clang__ */
+
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/system/builtins_end_.h b/include/system/builtins_end_.h
new file mode 100644
index 00000000..0bcd7661
--- /dev/null
+++ b/include/system/builtins_end_.h
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+
+#ifdef mkbi1_
+#undef mkbi1_
+#endif
+
+#ifdef mkbi2_
+#undef mkbi2_
+#endif
+
+#ifdef mkbi3_
+#undef mkbi3_
+#endif
+
+#ifdef mkdepbi1_
+#undef mkdepbi1_
+#endif
+
+#ifdef mkdepbi2_
+#undef mkdepbi2_
+#endif
+
+#ifdef mkbi_cat_
+#undef mkbi_cat_
+#endif
+
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/system/ctype.h b/include/system/ctype.h
new file mode 100644
index 00000000..65e7348f
--- /dev/null
+++ b/include/system/ctype.h
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * ctype.h - standard ctype functions
+ */
+#ifdef SHIM_UNIT_TEST
+#include_next <ctype.h>
+#else
+#ifndef _CTYPE_H
+#define _CTYPE_H
+
+#define isprint(c) ((c) >= 0x20 && (c) <= 0x7e)
+
+/* Determines if a particular character is a decimal-digit character */
+static inline __attribute__((__unused__)) int
+isdigit(int c)
+{
+ //
+ // <digit> ::= [0-9]
+ //
+ return (('0' <= (c)) && ((c) <= '9'));
+}
+
+/* Determine if an integer represents character that is a hex digit */
+static inline __attribute__((__unused__)) int
+isxdigit(int c)
+{
+ //
+ // <hexdigit> ::= [0-9] | [a-f] | [A-F]
+ //
+ return ((('0' <= (c)) && ((c) <= '9')) ||
+ (('a' <= (c)) && ((c) <= 'f')) ||
+ (('A' <= (c)) && ((c) <= 'F')));
+}
+
+/* Determines if a particular character represents a space character */
+static inline __attribute__((__unused__)) int
+isspace(int c)
+{
+ //
+ // <space> ::= [ ]
+ //
+ return ((c) == ' ');
+}
+
+/* Determine if a particular character is an alphanumeric character */
+static inline __attribute__((__unused__)) int
+isalnum(int c)
+{
+ //
+ // <alnum> ::= [0-9] | [a-z] | [A-Z]
+ //
+ return ((('0' <= (c)) && ((c) <= '9')) ||
+ (('a' <= (c)) && ((c) <= 'z')) ||
+ (('A' <= (c)) && ((c) <= 'Z')));
+}
+
+/* Determines if a particular character is in upper case */
+static inline __attribute__((__unused__)) int
+isupper(int c)
+{
+ //
+ // <uppercase letter> := [A-Z]
+ //
+ return (('A' <= (c)) && ((c) <= 'Z'));
+}
+
+/* Convert character to lowercase */
+static inline __attribute__((__unused__)) int
+tolower(int c)
+{
+ if (('A' <= (c)) && ((c) <= 'Z')) {
+ return (c - ('A' - 'a'));
+ }
+ return (c);
+}
+
+static inline __attribute__((__unused__)) int
+toupper(int c)
+{
+ return ((c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c);
+}
+
+#endif /* !_CTYPE_H */
+#endif /* !SHIM_UNIT_TEST */
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/system/efistdarg.h b/include/system/efistdarg.h
new file mode 100644
index 00000000..034977cc
--- /dev/null
+++ b/include/system/efistdarg.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * efistdarg.h - AAAARGGGG
+ * Copyright Peter Jones <pjones@redhat.com>
+ */
+
+#ifndef SHIM_UNIT_TEST
+#ifndef _EFISTDARG_H_
+#define _EFISTDARG_H_
+
+#ifndef GNU_EFI_USE_EXTERNAL_STDARG
+#define GNU_EFI_USE_EXTERNAL_STDARG
+#endif
+
+#include <stdarg.h>
+
+#endif /* !_EFISTDARG_H_ */
+#endif
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/system/inttypes.h b/include/system/inttypes.h
new file mode 100644
index 00000000..a35b0090
--- /dev/null
+++ b/include/system/inttypes.h
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+#ifdef SHIM_UNIT_TEST
+#include_next <inttypes.h>
+#else
+#ifndef _INTTYPES_H
+#define _INTTYPES_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#endif /* !INTTYPES_H_ */
+#endif
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/system/stdarg.h b/include/system/stdarg.h
new file mode 100644
index 00000000..4c956f70
--- /dev/null
+++ b/include/system/stdarg.h
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * stdarg.h - try to make consistent va_* handling for EFI
+ */
+#ifndef _STDARG_H
+
+/*
+ * clang doesn't know about __builtin_sysv_va_list, apparently.
+ */
+#ifdef __clang__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic warning "-Wcpp"
+typedef __builtin_va_list __builtin_sysv_va_list;
+#warning clang builds may not work at all for anything other than scan-build
+#pragma GCC diagnostic pop
+#endif
+
+#ifndef GNU_EFI_USE_EXTERNAL_STDARG
+#define GNU_EFI_USE_EXTERNAL_STDARG
+#endif
+
+#ifdef SHIM_UNIT_TEST
+#include_next <stdarg.h>
+#endif
+
+#if defined(__aarch64__) || defined(__arm__) || defined(__i386__) || \
+ defined(__i486__) || defined(__i686__)
+
+typedef __builtin_va_list ms_va_list;
+typedef __builtin_va_list __builtin_ms_va_list;
+#define ms_va_copy(dest, start) __builtin_va_copy(dest, start)
+#define ms_va_start(marker, arg) __builtin_va_start(marker, arg)
+#define ms_va_arg(marker, type) __builtin_va_arg(marker, type)
+#define ms_va_end(marker) __builtin_va_end(marker)
+
+typedef __builtin_va_list sysv_va_list;
+#define sysv_va_copy(dest, start) __builtin_va_copy(dest, start)
+#define sysv_va_start(marker, arg) __builtin_va_start(marker, arg)
+#define sysv_va_arg(marker, type) __builtin_va_arg(marker, type)
+#define sysv_va_end(marker) __builtin_va_end(marker)
+/*
+ * OpenSSL's X509ConstructCertificateStack needs this.
+ */
+typedef __builtin_va_list VA_LIST;
+#define VA_COPY(dest, start) __builtin_va_copy(dest, start)
+#define VA_START(marker, arg) __builtin_va_start(marker, arg)
+#define VA_END(marker) __builtin_va_end(marker)
+#define VA_ARG(marker, type) __builtin_va_arg(marker, type)
+
+#elif defined(__x86_64__)
+
+typedef __builtin_ms_va_list ms_va_list;
+#define ms_va_copy(dest, start) __builtin_ms_va_copy(dest, start)
+#define ms_va_start(marker, arg) __builtin_ms_va_start(marker, arg)
+#define ms_va_arg(marker, type) __builtin_va_arg(marker, type)
+#define ms_va_end(marker) __builtin_ms_va_end(marker)
+typedef __builtin_sysv_va_list sysv_va_list;
+#define sysv_va_copy(dest, start) __builtin_sysv_va_copy(dest, start)
+#define sysv_va_start(marker, arg) __builtin_sysv_va_start(marker, arg)
+#define sysv_va_arg(marker, type) __builtin_va_arg(marker, type)
+#define sysv_va_end(marker) __builtin_sysv_va_end(marker)
+/*
+ * OpenSSL's X509ConstructCertificateStack needs this.
+ */
+typedef __builtin_ms_va_list VA_LIST;
+#define VA_COPY(dest, start) __builtin_ms_va_copy(dest, start)
+#define VA_START(marker, arg) __builtin_ms_va_start(marker, arg)
+#define VA_END(marker) __builtin_ms_va_end(marker)
+#define VA_ARG(marker, type) __builtin_va_arg(marker, type)
+
+#else
+#error what arch is this
+#endif
+
+#ifndef _STDARG_H
+#define _STDARG_H
+#endif /* !_STDARG_H #2 */
+
+#endif /* !_STDARG_H */
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/system/stdio.h b/include/system/stdio.h
new file mode 100644
index 00000000..6ea60d71
--- /dev/null
+++ b/include/system/stdio.h
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * stdio.h - sigh
+ */
+#ifdef SHIM_UNIT_TEST
+#include_next <stdio.h>
+#else
+#ifndef _STDIO_H
+#define _STDIO_H
+
+#endif /* !_STDIO_H */
+#endif
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/system/stdlib.h b/include/system/stdlib.h
new file mode 100644
index 00000000..da7d3af9
--- /dev/null
+++ b/include/system/stdlib.h
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+#ifdef SHIM_UNIT_TEST
+#include_next <stdlib.h>
+#else
+#ifndef _STDLIB_H
+#define _STDLIB_H
+
+/*
+ * I don't know why, but openssl expects to get size_t from stdlib.h
+ * instead of stddef.h, so... whatever.
+ */
+#include <stddef.h>
+
+static inline void abort(void) { }
+
+#include <builtins_begin_.h>
+mkbi1_(int, abs, int, j)
+mkbi1_(long int, labs, long int, j)
+mkbi1_(long long int, llabs, long long int, j)
+
+#ifdef _INTTYPES_H
+mkbi1_(intmax_t, imaxabs, intmax_t, j)
+#endif /* _INTTYPES_H */
+#include <builtins_end_.h>
+
+#endif /* !_STDLIB_H */
+#endif
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/system/string.h b/include/system/string.h
new file mode 100644
index 00000000..2b366df7
--- /dev/null
+++ b/include/system/string.h
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+#ifdef SHIM_UNIT_TEST
+#include_next <string.h>
+
+__typeof__(strlen) shim_strlen;
+__typeof__(strcmp) shim_strcmp;
+__typeof__(strncmp) shim_strncmp;
+__typeof__(strncasecmp) shim_strncasecmp;
+__typeof__(strcasecmp) shim_strcasecmp;
+__typeof__(strrchr) shim_strrchr;
+__typeof__(strrchr) shim_strrchr;
+__typeof__(strnlen) shim_strnlen;
+__typeof__(strcpy) shim_strcpy;
+__typeof__(strncpy) shim_strncpy;
+__typeof__(strdup) shim_strdup;
+__typeof__(strndup) shim_strndup;
+__typeof__(stpcpy) shim_stpcpy;
+__typeof__(strchrnul) shim_strchrnul;
+__typeof__(strchr) shim_strchr;
+
+#else
+#ifndef _STRING_H
+#define _STRING_H
+
+#include <stddef.h>
+
+#include <builtins_begin_.h>
+
+mkbi1_(long int, ffsl, long int, x)
+mkbi1_(long int, clzl, long int, x)
+mkbi1_(long int, ctzl, long int, x)
+mkbi1_(long int, clrsbl, long int, x)
+mkbi1_(long int, popcountl, long int, x)
+mkbi1_(long int, parityl, long int, x)
+mkbi1_(long long int, ffsll, long long int, x)
+mkbi1_(long long int, clzll, long long int, x)
+mkbi1_(long long int, ctzll, long long int, x)
+mkbi1_(long long int, clrsbll, long long int, x)
+mkbi1_(long long int, popcountll, long long int, x)
+mkbi1_(long long int, parityll, long long int, x)
+
+mkbi3_(int, bcmp, const void *, s1, const void *, s2, size_t, n)
+mkbi3_(void, bcopy, const void *, src, void *, dest, size_t, n)
+mkbi2_(void, bzero, void *, s, size_t, n)
+mkdepbi2_(char *, index, const char *, s, int, c)
+mkbi3_(void *, memchr, const void *, s, int, c, size_t, n)
+mkbi3_(int, memcmp, const void *, s1, const void *, s2, size_t, n)
+mkbi3_(void *, memcpy, void *, dest, const void *, src, size_t, n)
+mkbi3_(void *, memmove, void *, dest, const void *, src, size_t, n)
+mkbi3_(void *, mempcpy, void *, dest, const void *, src, size_t, n)
+mkdepbi2_(char *, rindex, const char *, s, int, c)
+mkdepbi2_(char *, stpcpy, char *, dest, const char *, src)
+mkbi3_(char *, stpncpy, char *, dest, const char *, src, size_t, n)
+mkdepbi2_(int, strcasecmp, const char *, s1, const char *, s2)
+mkdepbi2_(char *, strcat, char *, dest, const char *, src)
+mkdepbi2_(char *, strchr, const char *, s, int, c)
+mkdepbi2_(int, strcmp, const char *, s1, const char *, s2)
+mkdepbi2_(char *, strcpy, char *, dest, const char *, src)
+mkdepbi2_(size_t, strcspn, const char *, s, const char *, reject)
+mkdepbi1_(char *, strdup, const char *, s)
+mkbi2_(char *, strndup, const char *, s, size_t, n)
+mkdepbi1_(size_t, strlen, const char *, s)
+mkbi3_(int, strncasecmp, const char *, s1, const char *, s2, size_t, n)
+mkbi3_(char *, strncat, char *, dest, const char *, src, size_t, n)
+mkbi3_(int, strncmp, const char *, s1, const char *, s2, size_t, n)
+mkbi3_(char *, strncpy, char *, dest, const char *, src, size_t, n)
+#if defined(__GNUC__) && __GNUC__ >= 9
+mkbi2_(size_t, strnlen, const char *, s1, size_t, n)
+#else
+size_t strnlen(const char * s1, size_t n);
+#endif
+mkdepbi2_(char *, strpbrk, const char *, s, const char *, accept)
+mkdepbi2_(char *, strrchr, const char *, s, int, c)
+mkdepbi2_(size_t, strspn, const char *, s, const char *, accept)
+mkdepbi2_(char *, strstr, const char *, haystack, const char *, needle)
+
+mkbi3_(void *, memset, void *, s, int, c, size_t, n);
+
+#include <builtins_end_.h>
+
+#endif /* _STRING_H */
+#endif
diff --git a/include/system/strings.h b/include/system/strings.h
new file mode 100644
index 00000000..99bc05f2
--- /dev/null
+++ b/include/system/strings.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+#ifdef SHIM_UNIT_TEST
+#include_next <strings.h>
+#else
+#ifndef _STRINGS_H
+#define _STRINGS_H
+
+#include <builtins_begin_.h>
+mkbi1_(int, ffs, int, x)
+mkbi1_(int, clz, int, x)
+mkbi1_(int, ctz, int, x)
+mkbi1_(int, clrsb, int, x)
+mkbi1_(int, popcount, int, x)
+mkbi1_(int, parity, int, x)
+#include <builtins_end_.h>
+
+#endif /* !_STRINGS_H */
+#endif
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/test.h b/include/test.h
new file mode 100644
index 00000000..012ffc51
--- /dev/null
+++ b/include/test.h
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+/*
+ * test.h - fake a bunch of EFI types so we can build test harnesses with libc
+ * Copyright Peter Jones <pjones@redhat.com>
+ */
+
+#ifdef SHIM_UNIT_TEST
+#ifndef TEST_H_
+#define TEST_H_
+
+#include <stdarg.h>
+
+#if defined(__aarch64__)
+#include <aarch64/efibind.h>
+#elif defined(__arm__)
+#include <arm/efibind.h>
+#elif defined(__i386__) || defined(__i486__) || defined(__i686__)
+#include <ia32/efibind.h>
+#elif defined(__x86_64__)
+#include <x86_64/efibind.h>
+#else
+#error what arch is this
+#endif
+
+#include <efidef.h>
+
+#include <efidevp.h>
+#include <efiprot.h>
+#include <eficon.h>
+#include <efiapi.h>
+#include <efierr.h>
+
+#include <efipxebc.h>
+#include <efinet.h>
+#include <efiip.h>
+
+#include <stdlib.h>
+
+#define ZeroMem(buf, sz) memset(buf, 0, sz)
+#define SetMem(buf, sz, value) memset(buf, value, sz)
+#define CopyMem(dest, src, len) memcpy(dest, src, len)
+#define CompareMem(dest, src, len) memcmp(dest, src, len)
+
+#include <assert.h>
+
+#define AllocateZeroPool(x) calloc(1, (x))
+#define AllocatePool(x) malloc(x)
+#define FreePool(x) free(x)
+#define ReallocatePool(old, oldsz, newsz) realloc(old, newsz)
+
+extern int debug;
+#ifdef dprint
+#undef dprint
+#define dprint(fmt, ...) {( if (debug) printf("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__); })
+#endif
+
+#define eassert(cond, fmt, ...) \
+ ({ \
+ if (!(cond)) { \
+ printf("%s:%d:" fmt, __func__, __LINE__, \
+ ##__VA_ARGS__); \
+ } \
+ assert(cond); \
+ })
+
+#define assert_true_as_expr(a, status, fmt, ...) \
+ ({ \
+ int rc_ = 0; \
+ if (!(a)) { \
+ printf("%s:%d:got %lld, expected nonzero " fmt, \
+ __func__, __LINE__, (long long)(a), \
+ ##__VA_ARGS__); \
+ printf("%s:%d:Assertion `%s' failed.\n", __func__, \
+ __LINE__, __stringify(!(a))); \
+ rc_ = status; \
+ } \
+ rc_; \
+ })
+#define assert_nonzero_as_expr(a, ...) assert_true_as_expr(a, ##__VA_ARGS__)
+
+#define assert_false_as_expr(a, status, fmt, ...) \
+ ({ \
+ int rc_ = 0; \
+ if (a) { \
+ printf("%s:%d:got %lld, expected zero " fmt, __func__, \
+ __LINE__, (long long)(a), ##__VA_ARGS__); \
+ printf("%s:%d:Assertion `%s' failed.\n", __func__, \
+ __LINE__, __stringify(a)); \
+ rc_ = status; \
+ } \
+ rc_; \
+ })
+#define assert_zero_as_expr(a, ...) assert_false_as_expr(a, ##__VA_ARGS__)
+
+#define assert_positive_as_expr(a, status, fmt, ...) \
+ ({ \
+ int rc_ = 0; \
+ if ((a) <= 0) { \
+ printf("%s:%d:got %lld, expected > 0 " fmt, __func__, \
+ __LINE__, (long long)(a), ##__VA_ARGS__); \
+ printf("%s:%d:Assertion `%s' failed.\n", __func__, \
+ __LINE__, __stringify((a) <= 0)); \
+ rc_ = status; \
+ } \
+ rc_; \
+ })
+
+#define assert_negative_as_expr(a, status, fmt, ...) \
+ ({ \
+ int rc_ = 0; \
+ if ((a) >= 0) { \
+ printf("%s:%d:got %lld, expected < 0 " fmt, __func__, \
+ __LINE__, (long long)(a), ##__VA_ARGS__); \
+ printf("%s:%d:Assertion `%s' failed.\n", __func__, \
+ __LINE__, __stringify((a) >= 0)); \
+ rc_ = status; \
+ } \
+ rc_; \
+ })
+
+#define assert_equal_as_expr(a, b, status, fmt, ...) \
+ ({ \
+ int rc_ = 0; \
+ if (!((a) == (b))) { \
+ printf("%s:%d:" fmt, __func__, __LINE__, (a), (b), \
+ ##__VA_ARGS__); \
+ printf("%s:%d:Assertion `%s' failed.\n", __func__, \
+ __LINE__, __stringify(a == b)); \
+ rc_ = status; \
+ } \
+ rc_; \
+ })
+
+#define assert_as_expr(cond, status, fmt, ...) \
+ ({ \
+ int rc_ = 0; \
+ if (!(cond)) { \
+ printf("%s:%d:" fmt, __func__, __LINE__, \
+ ##__VA_ARGS__); \
+ printf("%s:%d:Assertion `%s' failed.\n", __func__, \
+ __LINE__, __stringify(cond)); \
+ rc_ = status; \
+ } \
+ rc_; \
+ })
+
+#define assert_true_return(a, status, fmt, ...) \
+ ({ \
+ int rc_ = assert_true_as_expr(a, status, fmt, ##__VA_ARGS__); \
+ if (rc_ != 0) \
+ return rc_; \
+ })
+#define assert_nonzero_return(a, ...) assert_true_return(a, ##__VA_ARGS__)
+
+#define assert_false_return(a, status, fmt, ...) \
+ ({ \
+ int rc_ = assert_false_as_expr(a, status, fmt, ##__VA_ARGS__); \
+ if (rc_ != 0) \
+ return rc_; \
+ })
+#define assert_zero_return(a, ...) assert_false_return(a, ##__VA_ARGS__)
+
+#define assert_positive_return(a, status, fmt, ...) \
+ ({ \
+ int rc_ = assert_positive_as_expr(a, status, fmt, \
+ ##__VA_ARGS__); \
+ if (rc_ != 0) \
+ return rc_; \
+ })
+
+#define assert_negative_return(a, status, fmt, ...) \
+ ({ \
+ int rc_ = assert_negative_as_expr(a, status, fmt, \
+ ##__VA_ARGS__); \
+ if (rc_ != 0) \
+ return rc_; \
+ })
+
+#define assert_equal_return(a, b, status, fmt, ...) \
+ ({ \
+ int rc_ = assert_equal_as_expr(a, b, status, fmt, \
+ ##__VA_ARGS__); \
+ if (rc_ != 0) \
+ return rc_; \
+ })
+
+#define assert_return(cond, status, fmt, ...) \
+ ({ \
+ int rc_ = assert_as_expr(cond, status, fmt, ##__VA_ARGS__); \
+ if (rc_ != 0) \
+ return rc_; \
+ })
+
+#define assert_goto(cond, label, fmt, ...) \
+ ({ \
+ if (!(cond)) { \
+ printf("%s:%d:" fmt, __func__, __LINE__, \
+ ##__VA_ARGS__); \
+ printf("%s:%d:Assertion `%s' failed.\n", __func__, \
+ __LINE__, __stringify(cond)); \
+ goto label; \
+ } \
+ })
+
+#define assert_equal_goto(a, b, label, fmt, ...) \
+ ({ \
+ if (!((a) == (b))) { \
+ printf("%s:%d:" fmt, __func__, __LINE__, (a), (b), \
+ ##__VA_ARGS__); \
+ printf("%s:%d:Assertion `%s' failed.\n", __func__, \
+ __LINE__, __stringify(a == b)); \
+ goto label; \
+ } \
+ })
+
+#define assert_negative_goto(a, label, fmt, ...) \
+ ({ \
+ int rc_ = assert_negative_as_expr(a, -1, fmt, ##__VA_ARGS__); \
+ if (rc_ != 0) \
+ goto label; \
+ })
+
+#define assert_positive_goto(a, label, fmt, ...) \
+ ({ \
+ int rc_ = assert_positive_as_expr(a, -1, fmt, ##__VA_ARGS__); \
+ if (rc_ != 0) \
+ goto label; \
+ })
+
+#define test(x, ...) \
+ ({ \
+ int rc; \
+ printf("running %s\n", __stringify(x)); \
+ rc = x(__VA_ARGS__); \
+ if (rc < 0) \
+ status = 1; \
+ printf("%s: %s\n", __stringify(x), \
+ rc < 0 ? "failed" : "passed"); \
+ })
+
+#endif /* !TEST_H_ */
+#endif /* SHIM_UNIT_TEST */
+// vim:fenc=utf-8:tw=75:noet
diff --git a/include/test.mk b/include/test.mk
new file mode 100644
index 00000000..62cf983a
--- /dev/null
+++ b/include/test.mk
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+# test.mk - makefile to make local test programs
+#
+
+.SUFFIXES:
+
+CC = gcc
+VALGRIND ?=
+DEBUG_PRINTS ?= 0
+CFLAGS = -O2 -ggdb -std=gnu11 \
+ -isystem $(TOPDIR)/include/system \
+ $(EFI_INCLUDES) \
+ -Iinclude -iquote . \
+ -fshort-wchar -flto -fno-builtin \
+ -Wall \
+ -Wextra \
+ -Wsign-compare \
+ -Wno-deprecated-declarations \
+ -Wno-pointer-sign \
+ -Wno-unused \
+ -Werror \
+ -Werror=nonnull \
+ $(shell $(CC) -Werror=nonnull-compare -E -x c /dev/null >/dev/null 2>&1 && echo -Werror=nonnull-compare) \
+ $(ARCH_DEFINES) \
+ -DEFI_FUNCTION_WRAPPER \
+ -DGNU_EFI_USE_MS_ABI -DPAGE_SIZE=4096 \
+ -DSHIM_UNIT_TEST \
+ "-DDEFAULT_DEBUG_PRINT_STATE=$(DEBUG_PRINTS)"
+
+$(wildcard test-*.c) :: %.c : test-random.h
+$(patsubst %.c,%,$(wildcard test-*.c)) :: | test-random.h
+$(patsubst %.c,%.o,$(wildcard test-*.c)) : | test-random.h
+
+test-random.h:
+ dd if=/dev/urandom bs=512 count=17 of=random.bin
+ xxd -i random.bin test-random.h
+
+test-sbat_FILES = csv.c
+test-str_FILES = lib/string.c
+
+tests := $(patsubst %.c,%,$(wildcard test-*.c))
+
+$(tests) :: test-% : test.c test-%.c $(test-%_FILES)
+ $(CC) $(CFLAGS) -o $@ $^ $(wildcard $*.c) $(test-$*_FILES)
+ $(VALGRIND) ./$@
+
+test : $(tests)
+
+clean :
+ @rm -vf test-random.h random.bin
+
+all : clean test
+
+.PHONY: $(tests) all test clean
+.SECONDARY: random.bin
+
+# vim:ft=make
diff --git a/include/tpm.h b/include/tpm.h
index d5245875..877d4f93 100644
--- a/include/tpm.h
+++ b/include/tpm.h
@@ -3,10 +3,7 @@
#ifndef SHIM_TPM_H
#define SHIM_TPM_H
-#include <efilib.h>
-
#define TPM_ALG_SHA 0x00000004
-#define EV_IPL 0x0000000d
EFI_STATUS tpm_log_event(EFI_PHYSICAL_ADDRESS buf, UINTN size, UINT8 pcr,
const CHAR8 *description);
@@ -176,6 +173,7 @@ typedef struct efi_tpm2_protocol efi_tpm2_protocol_t;
typedef UINT32 TCG_EVENTTYPE;
+#define EV_IPL 0x0000000d
#define EV_EFI_EVENT_BASE ((TCG_EVENTTYPE) 0x80000000)
#define EV_EFI_VARIABLE_DRIVER_CONFIG (EV_EFI_EVENT_BASE + 1)
#define EV_EFI_VARIABLE_BOOT (EV_EFI_EVENT_BASE + 2)
diff --git a/include/variables.h b/include/variables.h
index 09d97c31..493f433f 100644
--- a/include/variables.h
+++ b/include/variables.h
@@ -40,6 +40,12 @@ get_variable(const CHAR16 * const var, UINT8 **data, UINTN *len, EFI_GUID owner)
EFI_STATUS
get_variable_attr(const CHAR16 * const var, UINT8 **data, UINTN *len, EFI_GUID owner, UINT32 *attributes);
EFI_STATUS
+get_variable_size(const CHAR16 * const var, EFI_GUID owner, UINTN *lenp);
+EFI_STATUS
+set_variable(CHAR16 *var, EFI_GUID owner, UINT32 attributes, UINTN datasize, void *data);
+EFI_STATUS
+del_variable(CHAR16 *var, EFI_GUID owner);
+EFI_STATUS
find_in_esl(UINT8 *Data, UINTN DataSize, UINT8 *key, UINTN keylen);
EFI_STATUS
find_in_variable_esl(const CHAR16 * const var, EFI_GUID owner, UINT8 *key, UINTN keylen);
@@ -58,12 +64,20 @@ EFI_STATUS
variable_enroll_hash(const CHAR16 * const var, EFI_GUID owner,
UINT8 hash[SHA256_DIGEST_SIZE]);
EFI_STATUS
-variable_create_esl(const uint8_t *cert, const size_t cert_len,
- const EFI_GUID *type, const EFI_GUID *owner,
+variable_create_esl(const EFI_SIGNATURE_DATA *first_sig, const size_t howmany,
+ const EFI_GUID *type, const UINT32 sig_size,
uint8_t **out, size_t *outlen);
EFI_STATUS
-fill_esl(const uint8_t *data, const size_t data_len,
- const EFI_GUID *type, const EFI_GUID *owner,
+variable_create_esl_with_one_signature(const uint8_t* data, const size_t data_len,
+ const EFI_GUID *type, const EFI_GUID *owner,
+ uint8_t **out, size_t *outlen);
+EFI_STATUS
+fill_esl(const EFI_SIGNATURE_DATA *first_sig, const size_t howmany,
+ const EFI_GUID *type, const UINT32 sig_size,
uint8_t *out, size_t *outlen);
+EFI_STATUS
+fill_esl_with_one_signature(const uint8_t *data, const uint32_t data_len,
+ const EFI_GUID *type, const EFI_GUID *owner,
+ uint8_t *out, size_t *outlen);
#endif /* SHIM_VARIABLES_H */