diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/compiler.h | 40 | ||||
-rw-r--r-- | include/console.h | 14 | ||||
-rw-r--r-- | include/coverity.mk | 64 | ||||
-rw-r--r-- | include/endian.h | 21 | ||||
-rw-r--r-- | include/errors.h | 2 | ||||
-rw-r--r-- | include/fanalyzer.mk | 35 | ||||
-rw-r--r-- | include/guid.h | 2 | ||||
-rw-r--r-- | include/hexdump.h | 21 | ||||
-rw-r--r-- | include/ip4config2.h | 2 | ||||
-rw-r--r-- | include/ip6config.h | 2 | ||||
-rw-r--r-- | include/list.h | 11 | ||||
-rw-r--r-- | include/sbat.h | 54 | ||||
-rw-r--r-- | include/scan-build.mk | 38 | ||||
-rw-r--r-- | include/str.h | 218 | ||||
-rw-r--r-- | include/system/alloca.h | 16 | ||||
-rw-r--r-- | include/system/builtins_begin_.h | 65 | ||||
-rw-r--r-- | include/system/builtins_end_.h | 27 | ||||
-rw-r--r-- | include/system/ctype.h | 85 | ||||
-rw-r--r-- | include/system/efistdarg.h | 19 | ||||
-rw-r--r-- | include/system/inttypes.h | 13 | ||||
-rw-r--r-- | include/system/stdarg.h | 80 | ||||
-rw-r--r-- | include/system/stdio.h | 13 | ||||
-rw-r--r-- | include/system/stdlib.h | 28 | ||||
-rw-r--r-- | include/system/string.h | 82 | ||||
-rw-r--r-- | include/system/strings.h | 19 | ||||
-rw-r--r-- | include/test.h | 243 | ||||
-rw-r--r-- | include/test.mk | 58 | ||||
-rw-r--r-- | include/tpm.h | 4 | ||||
-rw-r--r-- | include/variables.h | 22 |
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 */ |