From 29c5b02046fcd6f1489e4a6448dd80a4bde414ce Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Tue, 28 Apr 2026 12:57:27 -0500 Subject: [PATCH] linuxkm/: finish support for stabilization of .rodata_wolfcrypt segment in WC_SYM_RELOC_TABLES (FIPS) kernel module builds: linuxkm/Makefile: update the GENERATE_RELOC_TAB recipe to generate both wc_linuxkm_pie_text_reloc_tab[] and wc_linuxkm_pie_rodata_reloc_tab. linuxkm/linuxkm-fips-hash-wrapper.sh: add handling for wc_linuxkm_pie_rodata_reloc_tab. linuxkm/linuxkm-fips-hash.c: add handling for rodata_reloc_tab.*. linuxkm/linuxkm_memory.c: * refactor find_reloc_tab_offset() to be segment-agnostic and tolerate empty reloc tabs. * refactor wc_reloc_normalize_segment(): * to be segment-agnostic, * identify the src segment dynamically, * return BAD_FUNC_ARG where previously returning literal -1, * use seg_in_out_len arg to accommodate size skew between input and output (not currently used), and * rename working vars for better mnemonicitude. * update wc_fips_generate_hash() to * handle seg_map->rodata_reloc_tab, * use new calling convention for wc_reloc_normalize_segment(), and * add wc_reloc_normalize_segment() loop for .rodata_wolfcrypt. linuxkm/linuxkm_memory.h and linuxkm/linuxkm_wc_port.h: rename WOLFSSL_TEXT_SEGMENT_CANONICALIZER* to WOLFSSL_SEGMENT_CANONICALIZER*, with backward-compat provisions. linuxkm/module_hooks.c: * add wc_linuxkm_normalize_relocations_noresize() backward-compat wrapper. * wolfssl_init(): add .rodata_wolfcrypt relocation handling alongside existing .text_wolfcrypt handling, and update for new wc_reloc_normalize_segment() calling convention. * add seg_map.rodata_reloc_tab initialization. * update wc_linuxkm_normalize_relocations() to be segment-agnostic and use new wc_reloc_normalize_segment() calling convention. --- linuxkm/Makefile | 57 +++-- linuxkm/linuxkm-fips-hash-wrapper.sh | 4 + linuxkm/linuxkm-fips-hash.c | 24 ++ linuxkm/linuxkm_memory.c | 351 +++++++++++++++++++-------- linuxkm/linuxkm_memory.h | 18 +- linuxkm/linuxkm_wc_port.h | 31 ++- linuxkm/module_hooks.c | 77 +++++- 7 files changed, 413 insertions(+), 149 deletions(-) diff --git a/linuxkm/Makefile b/linuxkm/Makefile index f28f058738..0c1cdfaa11 100644 --- a/linuxkm/Makefile +++ b/linuxkm/Makefile @@ -157,30 +157,48 @@ GENERATE_SECTION_MAP := $(AWK) 'BEGIN { printf("") >ENVIRON["SECTION_MAP"]; } \ }' GENERATE_RELOC_TAB := $(AWK) ' \ - BEGIN { \ - n=0; \ + function open_seg(seg) { \ + seen_seg[seg] = 1; \ + printf("%s\n ", \ + "WOLFSSL_LOCAL const struct wc_reloc_table_ent wc_linuxkm_pie_" seg "_reloc_tab[] = { "); \ + cur_seg = seg; \ + } \ + function close_cur_seg() { \ + print " { .offset = ~0U, .dest_offset = ~0U, .dest_addend = 0, .dest_segment = WC_R_SEG_NONE, .reloc_type = WC_R_NONE } };"; \ + print "WOLFSSL_LOCAL const unsigned int wc_linuxkm_pie_" cur_seg "_reloc_tab_length = (unsigned int)(sizeof wc_linuxkm_pie_" cur_seg "_reloc_tab / sizeof wc_linuxkm_pie_" cur_seg "_reloc_tab[0]);"; \ + cur_seg = ""; \ + } \ + BEGIN { \ bad_relocs=0; \ print "\#include "; \ print "\#include "; \ - printf("%s\n ", \ - "WOLFSSL_LOCAL const struct wc_reloc_table_ent wc_linuxkm_pie_text_reloc_tab[] = { "); \ + print ""; \ if ("SECTION_MAP" in ENVIRON) { \ while (getline 0) \ section_map[$$1] = $$2; \ close(ENVIRON["SECTION_MAP"]); \ } \ } \ - /^Relocation section '\''\.rela?\.text_wolfcrypt'\''/ { \ - p=1; \ - next; \ - } \ + \ /^Relocation section/ { \ - p=0; \ + if (cur_seg) { \ + close_cur_seg(); \ + } \ + { \ + if (match($$0, "^Relocation section '\''\\.rela?\\.(text|rodata)_wolfcrypt'\''", a)) {\ + open_seg(a[1]); \ + next; \ + } \ + } \ + } \ + \ + { \ + if (! cur_seg) \ + next; \ } \ /^0/ { \ - if (p) { \ - if ($$3 !~ "^(R_X86_64_PLT32|R_X86_64_PC32|R_AARCH64_.*|R_ARM.*)$$") { \ - print "Unexpected relocation type:\n" $$0 >"/dev/stderr"; \ + if ($$3 !~ "^(R_X86_.*|R_AARCH64_.*|R_ARM.*)$$") { \ + print "Unexpected relocation type in " cur_seg ":\n" $$0 >"/dev/stderr"; \ ++bad_relocs; \ } \ if ($$5 in section_map) \ @@ -224,15 +242,22 @@ GENERATE_RELOC_TAB := $(AWK) ' \ strtonum("0x" $$4), \ $$6 strtonum("0x" $$7), \ section_tag, reloc_type); \ - } \ } \ END { \ + if (cur_seg) { \ + close_cur_seg(); \ + } \ + n = split("text rodata", segs, " "); \ + for (i = 1; i <= n; ++i) { \ + if (! (segs[i] in seen_seg)) { \ + open_seg(segs[i]); \ + close_cur_seg(); \ + } \ + } \ if (bad_relocs) { \ print "Found " bad_relocs " unresolvable relocations." >"/dev/stderr"; \ exit(1); \ } \ - print " { .offset = ~0U, .dest_offset = ~0U, .dest_addend = 0, .dest_segment = WC_R_SEG_NONE, .reloc_type = WC_R_NONE } };"; \ - print "WOLFSSL_LOCAL const unsigned int wc_linuxkm_pie_text_reloc_tab_length = (unsigned int)(sizeof wc_linuxkm_pie_text_reloc_tab / sizeof wc_linuxkm_pie_text_reloc_tab[0]);"; \ }' ifeq "$(V)" "1" @@ -384,7 +409,7 @@ $(MODULE_TOP)/libwolfssl-user-build/src/.libs/libwolfssl.so: $(LIBWOLFSSL_NAME). @ echo 'Using existing Makefile for libwolfssl.so.' @else @ echo -n 'Configuring user libwolfssl.so...' - @ $(FRESH_ENV) ./configure $(QFLAG) $(VFLAG) --disable-jobserver --enable-cryptonly --enable-fips="$$FIPS_FLAVOR" CFLAGS='-DWC_SYM_RELOC_TABLES_SUPPORT -DWOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE -DWOLFSSL_USER_SETTINGS -DWOLFSSL_USER_SETTINGS_ASM' $(if $(HOSTCC),CC='$(HOSTCC)') + @ $(FRESH_ENV) ./configure $(QFLAG) $(VFLAG) --disable-jobserver --enable-cryptonly --enable-fips="$$FIPS_FLAVOR" CFLAGS='-DWC_SYM_RELOC_TABLES_SUPPORT -DWOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE -DWOLFSSL_USER_SETTINGS -DWOLFSSL_USER_SETTINGS_ASM -DDEBUG_LINUXKM_PIE_SUPPORT' $(if $(HOSTCC),CC='$(HOSTCC)') @ echo ' done.' @fi @echo -n 'Building user libwolfssl.so...' diff --git a/linuxkm/linuxkm-fips-hash-wrapper.sh b/linuxkm/linuxkm-fips-hash-wrapper.sh index 9f68b82f61..1018d30c15 100755 --- a/linuxkm/linuxkm-fips-hash-wrapper.sh +++ b/linuxkm/linuxkm-fips-hash-wrapper.sh @@ -50,6 +50,8 @@ readarray -t fenceposts < <(readelf --wide --sections --symbols "$mod_path" | "$ BEGIN { fips_fenceposts["wc_linuxkm_pie_text_reloc_tab"] = "text_reloc_tab.start"; fips_fenceposts["wc_linuxkm_pie_text_reloc_tab_length"] = "text_reloc_tab.len_start"; + fips_fenceposts["wc_linuxkm_pie_rodata_reloc_tab"] = "rodata_reloc_tab.start"; + fips_fenceposts["wc_linuxkm_pie_rodata_reloc_tab_length"] = "rodata_reloc_tab.len_start"; fips_fenceposts["verifyCore"] = "verifyCore_start"; fips_fenceposts["wolfCrypt_FIPS_first"] = "fips_text_start"; fips_fenceposts["wolfCrypt_FIPS_last"] = "fips_text_end"; @@ -57,6 +59,8 @@ BEGIN { fips_fenceposts["wolfCrypt_FIPS_ro_end"] = "fips_rodata_end"; singleton_ends["wc_linuxkm_pie_text_reloc_tab"] = "text_reloc_tab.end"; singleton_ends["wc_linuxkm_pie_text_reloc_tab_length"] = "text_reloc_tab.len_end"; + singleton_ends["wc_linuxkm_pie_rodata_reloc_tab"] = "rodata_reloc_tab.end"; + singleton_ends["wc_linuxkm_pie_rodata_reloc_tab_length"] = "rodata_reloc_tab.len_end"; singleton_ends["verifyCore"] = "verifyCore_end"; } diff --git a/linuxkm/linuxkm-fips-hash.c b/linuxkm/linuxkm-fips-hash.c index 59719f51ac..ff327f0ceb 100644 --- a/linuxkm/linuxkm-fips-hash.c +++ b/linuxkm/linuxkm-fips-hash.c @@ -108,6 +108,10 @@ int main(int argc, char **argv) FENCEPOST_OPT(text_reloc_tab.end), FENCEPOST_OPT(text_reloc_tab.len_start), FENCEPOST_OPT(text_reloc_tab.len_end), + FENCEPOST_OPT(rodata_reloc_tab.start), + FENCEPOST_OPT(rodata_reloc_tab.end), + FENCEPOST_OPT(rodata_reloc_tab.len_start), + FENCEPOST_OPT(rodata_reloc_tab.len_end), FENCEPOST_OPT(fips_text_start), FENCEPOST_OPT(fips_text_end), FENCEPOST_OPT(rodata_start), @@ -232,6 +236,10 @@ int main(int argc, char **argv) (seg_map.text_reloc_tab.end == ~0UL) || (seg_map.text_reloc_tab.len_start == ~0UL) || (seg_map.text_reloc_tab.len_end == ~0UL) || + (seg_map.rodata_reloc_tab.start == ~0UL) || + (seg_map.rodata_reloc_tab.end == ~0UL) || + (seg_map.rodata_reloc_tab.len_start == ~0UL) || + (seg_map.rodata_reloc_tab.len_end == ~0UL) || (seg_map.fips_text_start == ~0UL) || (seg_map.fips_text_end == ~0UL) || (seg_map.rodata_start == ~0UL) || @@ -278,6 +286,17 @@ int main(int argc, char **argv) exit(1); } + if ((seg_map.rodata_reloc_tab.start >= seg_map.rodata_reloc_tab.end) || + (seg_map.rodata_reloc_tab.end >= (unsigned long)st.st_size) || + (seg_map.rodata_reloc_tab.len_start >= seg_map.rodata_reloc_tab.len_end) || + (seg_map.rodata_reloc_tab.len_end >= (unsigned long)st.st_size)) + { + fprintf(stderr, "%s: supplied rodata_reloc_tab fencepost(s) are out of bounds " + "for supplied module %s with length %lu.\n", + progname, mod_path, (unsigned long)st.st_size); + exit(1); + } + mod_map = (byte *)mmap(NULL, st.st_size, inplace ? PROT_READ | PROT_WRITE : PROT_READ, (inplace ? MAP_SHARED : MAP_PRIVATE) | MAP_POPULATE, @@ -296,6 +315,11 @@ int main(int argc, char **argv) seg_map.text_reloc_tab.len_start += (unsigned long)mod_map; seg_map.text_reloc_tab.len_end += (unsigned long)mod_map; + seg_map.rodata_reloc_tab.start += (unsigned long)mod_map; + seg_map.rodata_reloc_tab.end += (unsigned long)mod_map; + seg_map.rodata_reloc_tab.len_start += (unsigned long)mod_map; + seg_map.rodata_reloc_tab.len_end += (unsigned long)mod_map; + seg_map.verifyCore_start += (unsigned long)mod_map; seg_map.verifyCore_end += (unsigned long)mod_map; seg_map.fips_text_start += (unsigned long)mod_map; diff --git a/linuxkm/linuxkm_memory.c b/linuxkm/linuxkm_memory.c index 01f816a73b..9969a7fc73 100644 --- a/linuxkm/linuxkm_memory.c +++ b/linuxkm/linuxkm_memory.c @@ -74,44 +74,41 @@ static const struct reloc_layout_ent { }; static inline long find_reloc_tab_offset( - const struct wc_reloc_table_segments *seg_map, const struct wc_reloc_table_ent reloc_tab[], word32 reloc_tab_len, - size_t text_in_offset) + size_t seg_in_offset) { long ret; unsigned long hop; + + if (seg_in_offset >= (size_t)reloc_tab[reloc_tab_len - 1].offset) { + RELOC_DEBUG_PRINTF("ERROR: %s failed.\n", __FUNCTION__); + return BAD_FUNC_ARG; + } + if (reloc_tab_len <= 1) { - RELOC_DEBUG_PRINTF("ERROR: %s failed.\n", __FUNCTION__); - return -1; - } - if (text_in_offset >= (size_t)(seg_map->text_end - seg_map->text_start)) { - RELOC_DEBUG_PRINTF("ERROR: %s failed.\n", __FUNCTION__); - return -1; - } - if (text_in_offset >= (size_t)reloc_tab[reloc_tab_len - 1].offset) { - RELOC_DEBUG_PRINTF("ERROR: %s failed.\n", __FUNCTION__); - return -1; + /* empty relocation table. */ + return 0; } for (ret = 0, hop = reloc_tab_len >> 1; hop; hop >>= 1) { - if (text_in_offset == (size_t)reloc_tab[ret].offset) + if (seg_in_offset == (size_t)reloc_tab[ret].offset) break; - else if (text_in_offset > (size_t)reloc_tab[ret].offset) + else if (seg_in_offset > (size_t)reloc_tab[ret].offset) ret += hop; else if (ret) ret -= hop; } while ((ret < (long)reloc_tab_len - 1) && - ((size_t)reloc_tab[ret].offset < text_in_offset)) + ((size_t)reloc_tab[ret].offset < seg_in_offset)) ++ret; while ((ret > 0) && - ((size_t)reloc_tab[ret - 1].offset >= text_in_offset)) + ((size_t)reloc_tab[ret - 1].offset >= seg_in_offset)) --ret; #ifdef DEBUG_LINUXKM_PIE_SUPPORT @@ -128,35 +125,65 @@ static inline long find_reloc_tab_offset( #define wc_get_unaligned(v) ({ typeof(*(v)) _v_aligned; XMEMCPY((void *)&_v_aligned, (void *)(v), sizeof _v_aligned); _v_aligned; }) #define wc_put_unaligned(v, v_out) do { typeof(v) _v = (v); XMEMCPY((void *)(v_out), (void *)&_v, sizeof(typeof(*(v_out)))); } while (0) -ssize_t wc_reloc_normalize_text( - const byte *text_in, - size_t text_in_len, - byte *text_out, +ssize_t wc_reloc_normalize_segment( + const byte *seg_in, + size_t *seg_in_out_len, + byte *seg_out, ssize_t *cur_index_p, const struct wc_reloc_table_segments *seg_map, struct wc_reloc_counts *reloc_counts) { ssize_t i; - size_t text_in_offset; + size_t seg_in_offset; const struct wc_reloc_table_ent *last_reloc; /* for error-checking order in reloc_tab[] */ int n_text_r = 0, n_rodata_r = 0, n_rwdata_r = 0, n_bss_r = 0, n_other_r = 0, n_oob_r = 0; - const struct wc_reloc_table_ent *reloc_tab = (const struct wc_reloc_table_ent *)seg_map->text_reloc_tab.start; - const word32 reloc_tab_len = *(const word32 *)seg_map->text_reloc_tab.len_start; + const struct wc_reloc_table_ent *reloc_tab; + word32 reloc_tab_len; + uintptr_t src_seg_start; +#ifdef DEBUG_LINUXKM_PIE_SUPPORT + uintptr_t src_seg_end; + const char *src_seg_name; +#endif - if ((text_in_len == 0) || - ((uintptr_t)text_in < seg_map->text_start) || - ((uintptr_t)(text_in + text_in_len) > seg_map->text_end)) + if (*seg_in_out_len == 0) + return BAD_FUNC_ARG; + + if (((uintptr_t)seg_in >= seg_map->text_start) && + ((uintptr_t)(seg_in + *seg_in_out_len) <= seg_map->text_end)) { - RELOC_DEBUG_PRINTF("ERROR: %s returning -1 with span %llx-%llx versus segment %llx-%llx.\n", + reloc_tab = (const struct wc_reloc_table_ent *)seg_map->text_reloc_tab.start; + reloc_tab_len = *(const word32 *)seg_map->text_reloc_tab.len_start; + src_seg_start = seg_map->text_start; +#ifdef DEBUG_LINUXKM_PIE_SUPPORT + src_seg_end = seg_map->text_end; + src_seg_name = "text"; +#endif + } + else if (((uintptr_t)seg_in >= seg_map->rodata_start) && + ((uintptr_t)(seg_in + *seg_in_out_len) <= seg_map->rodata_end)) + { + reloc_tab = (const struct wc_reloc_table_ent *)seg_map->rodata_reloc_tab.start; + reloc_tab_len = *(const word32 *)seg_map->rodata_reloc_tab.len_start; + src_seg_start = seg_map->rodata_start; +#ifdef DEBUG_LINUXKM_PIE_SUPPORT + src_seg_end = seg_map->rodata_end; + src_seg_name = "rodata"; +#endif + } + else + { + RELOC_DEBUG_PRINTF("ERROR: %s returning BAD_FUNC_ARG with span %llx-%llx versus text %llx-%llx and rodata %llx-%llx.\n", __FUNCTION__, - (unsigned long long)(uintptr_t)text_in, - (unsigned long long)(uintptr_t)(text_in + text_in_len), + (unsigned long long)(uintptr_t)seg_in, + (unsigned long long)(uintptr_t)(seg_in + *seg_in_out_len), (unsigned long long)seg_map->text_start, - (unsigned long long)seg_map->text_end); - return -1; + (unsigned long long)seg_map->text_end, + (unsigned long long)seg_map->rodata_start, + (unsigned long long)seg_map->rodata_end); + return BAD_FUNC_ARG; } - text_in_offset = (uintptr_t)text_in - seg_map->text_start; + seg_in_offset = (uintptr_t)seg_in - src_seg_start; if (cur_index_p) i = *cur_index_p; @@ -164,25 +191,28 @@ ssize_t wc_reloc_normalize_text( i = -1; if (i == -1) - i = find_reloc_tab_offset(seg_map, reloc_tab, reloc_tab_len, text_in_offset); + i = find_reloc_tab_offset(reloc_tab, reloc_tab_len, seg_in_offset); if (i < 0) return i; WC_SANITIZE_DISABLE(); - memcpy(text_out, text_in, text_in_len); + memcpy(seg_out, seg_in, *seg_in_out_len); WC_SANITIZE_ENABLE(); + /* note, if there are no relocations in the src seg, the loop isn't entered + * at all, and we return without further ado. + */ for (last_reloc = &reloc_tab[i > 0 ? i-1 : 0]; (size_t)i < reloc_tab_len - 1; ++i) { const struct wc_reloc_table_ent *next_reloc = &reloc_tab[i]; enum wc_reloc_dest_segment dest_seg; - uintptr_t seg_beg; + uintptr_t dest_seg_start; #ifdef DEBUG_LINUXKM_PIE_SUPPORT - uintptr_t seg_end; - const char *seg_name; + uintptr_t dest_seg_end; + const char *dest_seg_name; #endif word64 reloc_buf = 0; const struct reloc_layout_ent *layout; @@ -196,7 +226,7 @@ ssize_t wc_reloc_normalize_text( if (last_reloc->offset > next_reloc->offset) { RELOC_DEBUG_PRINTF("BUG: out-of-order offset found at reloc_tab[%zd]: %u > %u\n", i, last_reloc->offset, next_reloc->offset); - return -1; + return BAD_FUNC_ARG; } last_reloc = next_reloc; @@ -204,7 +234,7 @@ ssize_t wc_reloc_normalize_text( if (next_reloc->reloc_type >= (sizeof reloc_layouts / sizeof reloc_layouts[0])) { RELOC_DEBUG_PRINTF("BUG: unknown relocation type %u found at reloc_tab[%zd]\n", next_reloc->reloc_type, i); - return -1; + return BAD_FUNC_ARG; } layout = &reloc_layouts[next_reloc->reloc_type]; @@ -217,7 +247,7 @@ ssize_t wc_reloc_normalize_text( default: RELOC_DEBUG_PRINTF("BUG: unexpected relocation width %llu found at reloc_tab[%lld], reloc type %u\n", (unsigned long long)layout->width, (long long)i, next_reloc->reloc_type); - return -1; + return BAD_FUNC_ARG; } /* provisionally assign the destination segment from the reloc record -- @@ -227,23 +257,23 @@ ssize_t wc_reloc_normalize_text( dest_seg = next_reloc->dest_segment; /* next_reloc_rel is the offset of the relocation relative to the start - * of the current text chunk (text_in). i.e., text_in + next_reloc_rel + * of the current text chunk (seg_in). i.e., seg_in + next_reloc_rel * is the start of the relocation. */ - next_reloc_rel = next_reloc->offset - text_in_offset; + next_reloc_rel = next_reloc->offset - seg_in_offset; - if (next_reloc_rel >= text_in_len) { + if (next_reloc_rel >= *seg_in_out_len) { /* no more relocations in this buffer. */ break; } - if ((text_in_len < WC_BITS_TO_BYTES(layout->width)) || - (next_reloc_rel > text_in_len - WC_BITS_TO_BYTES(layout->width))) + if ((*seg_in_out_len < WC_BITS_TO_BYTES(layout->width)) || + (next_reloc_rel > *seg_in_out_len - WC_BITS_TO_BYTES(layout->width))) { /* relocation straddles buffer at end -- caller will try again with * that relocation at the start. */ - text_in_len = next_reloc_rel; + *seg_in_out_len = next_reloc_rel; break; } @@ -257,61 +287,61 @@ ssize_t wc_reloc_normalize_text( */ switch (layout->width) { case 32: - reloc_buf = (word64)(sword64)(wc_get_unaligned((sword32 *)&text_out[next_reloc_rel]) & (sword32)layout->mask); + reloc_buf = (word64)(sword64)(wc_get_unaligned((sword32 *)&seg_out[next_reloc_rel]) & (sword32)layout->mask); break; case 64: - reloc_buf = (word64)(sword64)(wc_get_unaligned((sword64 *)&text_out[next_reloc_rel]) & (sword64)layout->mask); + reloc_buf = (word64)(sword64)(wc_get_unaligned((sword64 *)&seg_out[next_reloc_rel]) & (sword64)layout->mask); break; case 16: - reloc_buf = (word64)(sword64)(wc_get_unaligned((sword16 *)&text_out[next_reloc_rel]) & (sword16)layout->mask); + reloc_buf = (word64)(sword64)(wc_get_unaligned((sword16 *)&seg_out[next_reloc_rel]) & (sword16)layout->mask); break; } } else { switch (layout->width) { case 32: - reloc_buf = (word64)(wc_get_unaligned((word32 *)&text_out[next_reloc_rel]) & (word32)layout->mask); + reloc_buf = (word64)(wc_get_unaligned((word32 *)&seg_out[next_reloc_rel]) & (word32)layout->mask); break; case 64: - reloc_buf = (word64)(wc_get_unaligned((word64 *)&text_out[next_reloc_rel]) & layout->mask); + reloc_buf = (word64)(wc_get_unaligned((word64 *)&seg_out[next_reloc_rel]) & layout->mask); break; case 16: - reloc_buf = (word64)(wc_get_unaligned((word16 *)&text_out[next_reloc_rel]) & (word16)layout->mask); + reloc_buf = (word64)(wc_get_unaligned((word16 *)&seg_out[next_reloc_rel]) & (word16)layout->mask); break; } } switch (dest_seg) { case WC_R_SEG_TEXT: - seg_beg = seg_map->text_start; + dest_seg_start = seg_map->text_start; ++n_text_r; #ifdef DEBUG_LINUXKM_PIE_SUPPORT - seg_end = seg_map->text_end; - seg_name = "text"; + dest_seg_end = seg_map->text_end; + dest_seg_name = "text"; #endif break; case WC_R_SEG_RODATA: - seg_beg = seg_map->rodata_start; + dest_seg_start = seg_map->rodata_start; ++n_rodata_r; #ifdef DEBUG_LINUXKM_PIE_SUPPORT - seg_end = seg_map->rodata_end; - seg_name = "rodata"; + dest_seg_end = seg_map->rodata_end; + dest_seg_name = "rodata"; #endif break; case WC_R_SEG_RWDATA: - seg_beg = seg_map->data_start; + dest_seg_start = seg_map->data_start; ++n_rwdata_r; #ifdef DEBUG_LINUXKM_PIE_SUPPORT - seg_end = seg_map->data_end; - seg_name = "data"; + dest_seg_end = seg_map->data_end; + dest_seg_name = "data"; #endif break; case WC_R_SEG_BSS: - seg_beg = seg_map->bss_start; + dest_seg_start = seg_map->bss_start; ++n_bss_r; #ifdef DEBUG_LINUXKM_PIE_SUPPORT - seg_end = seg_map->bss_end; - seg_name = "bss"; + dest_seg_end = seg_map->bss_end; + dest_seg_name = "bss"; #endif break; default: @@ -319,10 +349,10 @@ ssize_t wc_reloc_normalize_text( dest_seg = WC_R_SEG_OTHER; FALL_THROUGH; case WC_R_SEG_OTHER: - seg_beg = 0; + dest_seg_start = 0; #ifdef DEBUG_LINUXKM_PIE_SUPPORT - seg_end = 0; - seg_name = "other"; + dest_seg_end = 0; + dest_seg_name = "other"; #endif break; } @@ -344,33 +374,35 @@ ssize_t wc_reloc_normalize_text( * baked into the reloc_tab for each relocation. */ if (layout->is_relative) - reloc_buf = reloc_buf + (uintptr_t)next_reloc->offset - (uintptr_t)next_reloc->dest_addend - (seg_beg - seg_map->text_start); + reloc_buf = reloc_buf + (uintptr_t)next_reloc->offset - (uintptr_t)next_reloc->dest_addend - (dest_seg_start - src_seg_start); else - reloc_buf = reloc_buf - seg_beg - (uintptr_t)next_reloc->dest_addend; + reloc_buf = reloc_buf - dest_seg_start - (uintptr_t)next_reloc->dest_addend; } else { reloc_buf = (word64)next_reloc->dest_offset; } #ifdef DEBUG_LINUXKM_PIE_SUPPORT - if (reloc_buf >= seg_end - seg_beg) { + if (reloc_buf >= dest_seg_end - dest_seg_start) { ++n_oob_r; - RELOC_DEBUG_PRINTF("WARNING: normalized value is out of bounds (%s0x%llx) at index %lld, text offset 0x%x, reloc type %s, " - "dest seg .%s_wolfcrypt, offset from text to dest segment %s0x%llx, raw dest addr %s0x%llx, " - "seg span 0x%llx - 0x%llx, seg size 0x%llx, text base 0x%llx\n", + RELOC_DEBUG_PRINTF("WARNING: normalized value is out of bounds (%s0x%llx) at index %lld, %s offset 0x%x, reloc type %s, " + "src seg .%s_wolfcrypt, dest seg .%s_wolfcrypt, offset from src to dest segment %s0x%llx, raw dest addr %s0x%llx, " + "seg span 0x%llx - 0x%llx, seg size 0x%llx, src seg 0x%llx-0x%llx\n", (long long)reloc_buf < 0 ? "-" : "", (long long)reloc_buf < 0 ? -(long long)reloc_buf : (long long)reloc_buf, (long long)i, + src_seg_name, next_reloc->offset, layout->name, - seg_name, - seg_beg < seg_map->text_start ? "-" : "+", - seg_beg < seg_map->text_start ? (unsigned long long)seg_map->text_start - seg_beg : seg_beg - (unsigned long long)seg_map->text_start, + src_seg_name, + dest_seg_name, + dest_seg_start < src_seg_start ? "-" : "+", + dest_seg_start < src_seg_start ? (unsigned long long)src_seg_start - dest_seg_start : dest_seg_start - (unsigned long long)src_seg_start, (layout->is_signed && ((long long)raw_dest_addr < 0)) ? "-" : "", (layout->is_signed && ((long long)raw_dest_addr < 0)) ? (unsigned long long)-(long long)raw_dest_addr : raw_dest_addr, - (unsigned long long)seg_beg, - (unsigned long long)seg_end, - (unsigned long long)(seg_end - seg_beg), - (unsigned long long)seg_map->text_start); + (unsigned long long)dest_seg_start, + (unsigned long long)dest_seg_end, + (unsigned long long)(dest_seg_end - dest_seg_start), + (unsigned long long)src_seg_start, (unsigned long long)src_seg_end); } #endif } @@ -414,8 +446,8 @@ ssize_t wc_reloc_normalize_text( break; default: - RELOC_DEBUG_PRINTF("BUG: unrecognized relocation type %u in reloc record %zu, text offset 0x%x\n", - (unsigned)next_reloc->reloc_type, i, reloc_tab[i].offset); + RELOC_DEBUG_PRINTF("BUG: unrecognized relocation type %u in reloc record %zu, %s offset 0x%x\n", + (unsigned)next_reloc->reloc_type, i, src_seg_name, reloc_tab[i].offset); ++n_oob_r; dest_seg = WC_R_SEG_OTHER; } @@ -427,8 +459,8 @@ ssize_t wc_reloc_normalize_text( reloc_buf = 0; ++n_other_r; - RELOC_DEBUG_PRINTF("found non-wolfcrypt relocation at index %lld, text offset 0x%x.\n", - (long long)i, reloc_tab[i].offset); + RELOC_DEBUG_PRINTF("found non-wolfcrypt relocation at index %lld, %s offset 0x%x.\n", + (long long)i, src_seg_name, reloc_tab[i].offset); } /* xor in a label identifying the dest segment and reloc type. */ @@ -438,13 +470,13 @@ ssize_t wc_reloc_normalize_text( /* write the modified reloc_buf to the destination buffer. */ switch (layout->width) { case 32: - wc_put_unaligned((word32)reloc_buf, (word32 *)&text_out[next_reloc_rel]); + wc_put_unaligned((word32)reloc_buf, (word32 *)&seg_out[next_reloc_rel]); break; case 64: - wc_put_unaligned(reloc_buf, (word64 *)&text_out[next_reloc_rel]); + wc_put_unaligned(reloc_buf, (word64 *)&seg_out[next_reloc_rel]); break; case 16: - wc_put_unaligned((word16)reloc_buf, (word16 *)&text_out[next_reloc_rel]); + wc_put_unaligned((word16)reloc_buf, (word16 *)&seg_out[next_reloc_rel]); break; } } @@ -458,15 +490,15 @@ ssize_t wc_reloc_normalize_text( } if ((n_other_r > 0) || (n_oob_r > 0)) - RELOC_DEBUG_PRINTF("text_in=%llx relocs=%d/%d/%d/%d/%d/%d ret = %llu\n", - (unsigned long long)(uintptr_t)text_in, n_text_r, n_rodata_r, + RELOC_DEBUG_PRINTF("seg_in=%llx relocs=%d/%d/%d/%d/%d/%d ret = %llu\n", + (unsigned long long)(uintptr_t)seg_in, n_text_r, n_rodata_r, n_rwdata_r, n_bss_r, n_other_r, n_oob_r, - (unsigned long long)text_in_len); + (unsigned long long)*seg_in_out_len); if (cur_index_p) *cur_index_p = i; - return (ssize_t)text_in_len; + return (ssize_t)*seg_in_out_len; } #endif /* WC_SYM_RELOC_TABLES || WC_SYM_RELOC_TABLES_SUPPORT */ @@ -559,6 +591,12 @@ int wc_fips_generate_hash( RELOC_DEBUG_PRINTF("assert failed.\n"); return BAD_FUNC_ARG; } + if ((seg_map->rodata_reloc_tab.start == 0) || + (seg_map->rodata_reloc_tab.len_start == 0)) + { + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_FUNC_ARG; + } } else { if ((seg_map->text_reloc_tab.end == 0) || @@ -567,6 +605,12 @@ int wc_fips_generate_hash( RELOC_DEBUG_PRINTF("assert failed.\n"); return BAD_FUNC_ARG; } + if ((seg_map->rodata_reloc_tab.end == 0) || + (seg_map->rodata_reloc_tab.len_end == 0)) + { + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_FUNC_ARG; + } } #endif @@ -577,6 +621,8 @@ int wc_fips_generate_hash( || ((seg_map->text_reloc_tab.end != 0) && (seg_map->text_reloc_tab.start >= seg_map->text_reloc_tab.end)) || ((seg_map->text_reloc_tab.len_end != 0) && (seg_map->text_reloc_tab.len_start >= seg_map->text_reloc_tab.len_end)) || + ((seg_map->rodata_reloc_tab.end != 0) && (seg_map->rodata_reloc_tab.start >= seg_map->rodata_reloc_tab.end)) || + ((seg_map->rodata_reloc_tab.len_end != 0) && (seg_map->rodata_reloc_tab.len_start >= seg_map->rodata_reloc_tab.len_end)) || (seg_map->text_start >= seg_map->text_end) || (seg_map->rodata_start >= seg_map->rodata_end) || (seg_map->data_start >= seg_map->data_end) || @@ -596,6 +642,8 @@ int wc_fips_generate_hash( || (seg_map->text_reloc_tab.start < seg_map->start) || (seg_map->text_reloc_tab.len_start < seg_map->start) || + (seg_map->rodata_reloc_tab.start < seg_map->start) || + (seg_map->rodata_reloc_tab.len_start < seg_map->start) || (seg_map->text_start < seg_map->start) || (seg_map->rodata_start < seg_map->start) || (seg_map->data_start < seg_map->start) || @@ -618,6 +666,10 @@ int wc_fips_generate_hash( (seg_map->text_reloc_tab.end > seg_map->end)) || ((seg_map->text_reloc_tab.len_end != 0) && (seg_map->text_reloc_tab.len_end > seg_map->end)) || + ((seg_map->rodata_reloc_tab.end != 0) && + (seg_map->rodata_reloc_tab.end > seg_map->end)) || + ((seg_map->rodata_reloc_tab.len_end != 0) && + (seg_map->rodata_reloc_tab.len_end > seg_map->end)) || (seg_map->text_end > seg_map->end) || (seg_map->rodata_end > seg_map->end) || (seg_map->data_end > seg_map->end) || @@ -680,6 +732,56 @@ int wc_fips_generate_hash( return BAD_FUNC_ARG; } } + + if ((seg_map->rodata_reloc_tab.len_end != 0) && + (seg_map->rodata_reloc_tab.len_end - seg_map->rodata_reloc_tab.len_start != sizeof(word32))) + { + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_FUNC_ARG; + } + else if (seg_map->rodata_reloc_tab.len_start & (sizeof(word32) - 1)) { + /* fprintf(stderr, "%s: seg_map->rodata_reloc_tab.len_start isn't properly aligned: 0x%llx.\n", progname, ( + unsigned long long)seg_map->rodata_reloc_tab.len_start); */ + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_ALIGN_E; + } + else { + /* Note we don't currently handle modules that are endian-conflicted + * with the build host -- that'll be caught here, when reloc_tab_len is + * a nonsense byte-swapped value, or the final reloc_tab ent has + * nonsense flags. + */ + word32 reloc_tab_len = *(const word32 *)seg_map->rodata_reloc_tab.len_start; + const struct wc_reloc_table_ent *reloc_tab = (const struct wc_reloc_table_ent *)seg_map->rodata_reloc_tab.start; + if (reloc_tab_len == 0) { + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_FUNC_ARG; + } + else if ((seg_map->end != 0) && + ((unsigned long)(reloc_tab + reloc_tab_len) > seg_map->end)) + { + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_FUNC_ARG; + } + else if ((reloc_tab[reloc_tab_len - 1].dest_segment != WC_R_SEG_NONE) || + (reloc_tab[reloc_tab_len - 1].reloc_type != WC_R_NONE)) + { + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_FUNC_ARG; + } + else if ((seg_map->rodata_reloc_tab.end != 0) && + (seg_map->rodata_reloc_tab.end - seg_map->rodata_reloc_tab.start != sizeof(struct wc_reloc_table_ent) * *(const word32 *)seg_map->rodata_reloc_tab.len_start)) + { + /* + fprintf(stderr, "%s: wc_linuxkm_pie_rodata_reloc_tab_length from module (%u) is inconsistent with actual rodata_reloc_tab size %llu.\n", + progname, + *(const word32 *)seg_map->rodata_reloc_tab.len_start, + (unsigned long long)(seg_map->rodata_reloc_tab.end - seg_map->rodata_reloc_tab.start)); + */ + RELOC_DEBUG_PRINTF("assert failed.\n"); + return BAD_FUNC_ARG; + } + } #endif if (out_size == NULL) { @@ -728,9 +830,10 @@ int wc_fips_generate_hash( #if defined(WC_SYM_RELOC_TABLES) || defined(WC_SYM_RELOC_TABLES_SUPPORT) { - ssize_t cur_reloc_index = -1; + ssize_t cur_reloc_index; const byte *text_p = (const byte *)seg_map->fips_text_start; - byte *buf = XMALLOC(WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); + const byte *rodata_p = (const byte *)seg_map->fips_rodata_start; + byte *buf = XMALLOC(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (! buf) { ret = MEMORY_E; @@ -738,23 +841,23 @@ int wc_fips_generate_hash( goto out; } + cur_reloc_index = -1; while (text_p < (const byte *)seg_map->fips_text_end) { - /* wc_reloc_normalize_text() does its own WC_SANITIZE_DISABLE()s, so - * we defer it here. - */ - ssize_t progress = wc_reloc_normalize_text( + size_t text_in_out_len = min(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, + (size_t)((const byte *)seg_map->fips_text_end - text_p)); + ssize_t progress = wc_reloc_normalize_segment( text_p, - min(WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ, (word32)((const byte *)seg_map->fips_text_end - text_p)), + &text_in_out_len, buf, &cur_reloc_index, seg_map, reloc_counts); if (progress <= 0) { - ret = IN_CORE_FIPS_E; - RELOC_DEBUG_PRINTF("wc_reloc_normalize_text() failed.\n"); + RELOC_DEBUG_PRINTF("wc_reloc_normalize_segment() for text failed: %zd.\n", progress); + ret = progress ? (int)progress : IN_CORE_FIPS_E; break; } - ret = hmac_update(hmac_ctx, buf, (word32)progress); + ret = hmac_update(hmac_ctx, buf, (word32)text_in_out_len); if (ret) { RELOC_DEBUG_PRINTF("hmac_update() failed.\n"); break; @@ -762,15 +865,53 @@ int wc_fips_generate_hash( text_p += progress; } + cur_reloc_index = -1; + while (rodata_p < (const byte *)seg_map->fips_rodata_end) { + size_t rodata_in_out_len = min(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, + (size_t)((const byte *)seg_map->fips_rodata_end - rodata_p)); + /* don't hash verifyCore or changing verifyCore will change hash */ + if ((rodata_p < (const byte *)seg_map->verifyCore_end) && + (rodata_p + rodata_in_out_len >= (const byte *)seg_map->verifyCore_start)) + { + rodata_in_out_len = (size_t)((const byte *)seg_map->verifyCore_start - rodata_p); + if (rodata_in_out_len == 0) { + rodata_p = (const byte *)seg_map->verifyCore_end; + /* force recomputation of relocation offset when skipping + * a span (not processed by wc_reloc_normalize_segment()). + */ + cur_reloc_index = -1; + continue; + } + } + + ssize_t progress = wc_reloc_normalize_segment( + rodata_p, + &rodata_in_out_len, + buf, + &cur_reloc_index, + seg_map, + reloc_counts); + if (progress <= 0) { + RELOC_DEBUG_PRINTF("wc_reloc_normalize_segment() for rodata failed: %zd.\n", progress); + ret = progress ? (int)progress : IN_CORE_FIPS_E; + break; + } + ret = hmac_update(hmac_ctx, buf, (word32)rodata_in_out_len); + if (ret) { + RELOC_DEBUG_PRINTF("hmac_update() failed.\n"); + break; + } + rodata_p += progress; + } + XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER); } - WC_SANITIZE_DISABLE(); -#else +#else /* ! (WC_SYM_RELOC_TABLES || WC_SYM_RELOC_TABLES_SUPPORT) */ + (void)reloc_counts; WC_SANITIZE_DISABLE(); ret = hmac_update(hmac_ctx, (byte *)(wc_ptr_t)seg_map->fips_text_start, (word32)(seg_map->fips_text_end - seg_map->fips_text_start)); -#endif /* !WOLFSSL_LINUXKM_PIE_REDIRECT_TABLE */ if (ret) { RELOC_DEBUG_PRINTF("ERROR: hmac_update failed: err %d\n", ret); @@ -795,6 +936,8 @@ int wc_fips_generate_hash( WC_SANITIZE_ENABLE(); +#endif /* ! (WC_SYM_RELOC_TABLES || WC_SYM_RELOC_TABLES_SUPPORT) */ + if (ret) { RELOC_DEBUG_PRINTF("ERROR: hmac_update failed: err %d\n", ret); ret = BAD_STATE_E; diff --git a/linuxkm/linuxkm_memory.h b/linuxkm/linuxkm_memory.h index c60a734b8e..76e681da80 100644 --- a/linuxkm/linuxkm_memory.h +++ b/linuxkm/linuxkm_memory.h @@ -175,7 +175,7 @@ struct wc_reloc_counts { #elif defined(HAVE_FIPS) /* barebones FIPS fencepost representation -- no provision for - * wc_reloc_normalize_text() + * wc_reloc_normalize_segment() */ struct wc_reloc_table_segments { @@ -216,18 +216,10 @@ struct wc_reloc_counts { #define WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ #endif -WOLFSSL_API ssize_t wc_reloc_normalize_text( - const byte *text_in, - size_t text_in_len, - byte *text_out, - ssize_t *cur_index_p, - const struct wc_reloc_table_segments *seg_map, - struct wc_reloc_counts *reloc_counts); - -WOLFSSL_API ssize_t wc_reloc_normalize_rodata( - const byte *rodata_in, - size_t rodata_in_len, - byte *rodata_out, +WOLFSSL_API ssize_t wc_reloc_normalize_segment( + const byte *seg_in, + size_t *seg_in_out_len, + byte *seg_out, ssize_t *cur_index_p, const struct wc_reloc_table_segments *seg_map, struct wc_reloc_counts *reloc_counts); diff --git a/linuxkm/linuxkm_wc_port.h b/linuxkm/linuxkm_wc_port.h index 22255af456..c359277e34 100644 --- a/linuxkm/linuxkm_wc_port.h +++ b/linuxkm/linuxkm_wc_port.h @@ -876,15 +876,33 @@ __wc_bss_end[]; extern ssize_t wc_linuxkm_normalize_relocations( - const u8 *text_in, - size_t text_in_len, - u8 *text_out, + const u8 *seg_in, + size_t *seg_in_out_len, + u8 *seg_out, ssize_t *cur_index_p); + extern ssize_t wc_linuxkm_normalize_relocations_noresize( + const u8 *seg_in, + size_t seg_in_len, + u8 *seg_out, + ssize_t *cur_index_p); + + #ifndef WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ + #define WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ 8192 + #endif + + #ifndef WOLFSSL_SEGMENT_CANONICALIZER + #define WOLFSSL_SEGMENT_CANONICALIZER(seg_in, seg_in_out_len, seg_out, cur_index_p) \ + wc_linuxkm_normalize_relocations(seg_in, seg_in_out_len, seg_out, cur_index_p) + #endif + + /* backward-compatible wrappers */ #ifndef WOLFSSL_TEXT_SEGMENT_CANONICALIZER #define WOLFSSL_TEXT_SEGMENT_CANONICALIZER(text_in, text_in_len, text_out, cur_index_p) \ - wc_linuxkm_normalize_relocations(text_in, text_in_len, text_out, cur_index_p) - #define WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ 8192 + wc_linuxkm_normalize_relocations_noresize(text_in, text_in_len, text_out, cur_index_p) + #endif + #ifndef WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ + #define WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ #endif #ifdef CONFIG_MIPS @@ -896,6 +914,7 @@ struct wolfssl_linuxkm_pie_redirect_table { #ifdef HAVE_FIPS typeof(wc_linuxkm_normalize_relocations) *wc_linuxkm_normalize_relocations; + typeof(wc_linuxkm_normalize_relocations_noresize) *wc_linuxkm_normalize_relocations_noresize; #endif #ifndef __ARCH_MEMCMP_NO_REDIRECT @@ -1234,6 +1253,8 @@ #ifdef HAVE_FIPS #define wc_linuxkm_normalize_relocations \ WC_PIE_INDIRECT_SYM(wc_linuxkm_normalize_relocations) + #define wc_linuxkm_normalize_relocations_noresize \ + WC_PIE_INDIRECT_SYM(wc_linuxkm_normalize_relocations_noresize) #endif #ifndef __ARCH_MEMCMP_NO_REDIRECT diff --git a/linuxkm/module_hooks.c b/linuxkm/module_hooks.c index 90a695aa45..03b6e2e44e 100644 --- a/linuxkm/module_hooks.c +++ b/linuxkm/module_hooks.c @@ -711,13 +711,15 @@ static int wolfssl_init(void) { unsigned int text_hash = hash_span((const u8 *)__wc_text_start, (const u8 *)__wc_text_end, 1); unsigned int rodata_hash = hash_span((const u8 *)__wc_rodata_start, (const u8 *)__wc_rodata_end, 1); - u8 *canon_buf = malloc(WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ); + u8 *canon_buf = malloc(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ); ssize_t cur_reloc_index = -1; const u8 *text_p = (const u8 *)__wc_text_start; + const u8 *rodata_p = (const u8 *)__wc_rodata_start; unsigned int stabilized_text_hash = 1; + unsigned int stabilized_rodata_hash = 1; if (! canon_buf) { - pr_err("ERROR: malloc(%d) for WOLFSSL_TEXT_SEGMENT_CANONICALIZER failed: %ld.\n", WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ, PTR_ERR(canon_buf)); + pr_err("ERROR: malloc(%d) for WOLFSSL_*_SEGMENT_CANONICALIZER failed: %ld.\n", WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, PTR_ERR(canon_buf)); return -ECANCELED; } @@ -725,14 +727,15 @@ static int wolfssl_init(void) reloc_counts.other = 0; while (text_p < (const u8 *)__wc_text_end) { + size_t text_in_out_len = min(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, + (size_t)((const u8 *)__wc_text_end - text_p)); ssize_t progress = - WOLFSSL_TEXT_SEGMENT_CANONICALIZER( + WOLFSSL_SEGMENT_CANONICALIZER( text_p, - min(WOLFSSL_TEXT_SEGMENT_CANONICALIZER_BUFSIZ, - (word32)((const u8 *)__wc_text_end - text_p)), + &text_in_out_len, canon_buf, &cur_reloc_index); if (progress <= 0) { - pr_err("ERROR: progress=%ld from WOLFSSL_TEXT_SEGMENT_CANONICALIZER() at offset %x (text=%x-%x).\n", + pr_err("ERROR: progress=%ld from WOLFSSL_SEGMENT_CANONICALIZER() at offset %x (text=%x-%x).\n", (long)progress, (unsigned)(uintptr_t)text_p, (unsigned)(uintptr_t)__wc_text_start, @@ -740,10 +743,32 @@ static int wolfssl_init(void) free(canon_buf); return -ECANCELED; } - stabilized_text_hash = hash_span(canon_buf, canon_buf + progress, stabilized_text_hash); + stabilized_text_hash = hash_span(canon_buf, canon_buf + text_in_out_len, stabilized_text_hash); text_p += progress; } + /* note verifyCore is hashed along with the rest of .rodata_wolfcrypt. */ + while (rodata_p < (const u8 *)__wc_rodata_end) { + size_t rodata_in_out_len = min(WOLFSSL_SEGMENT_CANONICALIZER_BUFSIZ, + (size_t)((const u8 *)__wc_rodata_end - rodata_p)); + ssize_t progress = + WOLFSSL_SEGMENT_CANONICALIZER( + rodata_p, + &rodata_in_out_len, + canon_buf, &cur_reloc_index); + if (progress <= 0) { + pr_err("ERROR: progress=%ld from WOLFSSL_SEGMENT_CANONICALIZER() at offset %x (rodata=%x-%x).\n", + (long)progress, + (unsigned)(uintptr_t)rodata_p, + (unsigned)(uintptr_t)__wc_rodata_start, + (unsigned)(uintptr_t)__wc_rodata_end); + free(canon_buf); + return -ECANCELED; + } + stabilized_rodata_hash = hash_span(canon_buf, canon_buf + rodata_in_out_len, stabilized_rodata_hash); + rodata_p += progress; + } + free(canon_buf); canon_buf = 0; @@ -1120,6 +1145,8 @@ MODULE_VERSION(LIBWOLFSSL_VERSION_STRING); extern const struct wc_reloc_table_ent wc_linuxkm_pie_text_reloc_tab[]; extern const unsigned int wc_linuxkm_pie_text_reloc_tab_length; +extern const struct wc_reloc_table_ent wc_linuxkm_pie_rodata_reloc_tab[]; +extern const unsigned int wc_linuxkm_pie_rodata_reloc_tab_length; static const struct wc_reloc_table_segments seg_map = { .start = 0, .end = 0, @@ -1129,6 +1156,10 @@ static const struct wc_reloc_table_segments seg_map = { .text_reloc_tab.end = 0, .text_reloc_tab.len_start = (size_t)(uintptr_t)&wc_linuxkm_pie_text_reloc_tab_length, .text_reloc_tab.len_end = 0, + .rodata_reloc_tab.start = (size_t)(uintptr_t)wc_linuxkm_pie_rodata_reloc_tab, + .rodata_reloc_tab.end = 0, + .rodata_reloc_tab.len_start = (size_t)(uintptr_t)&wc_linuxkm_pie_rodata_reloc_tab_length, + .rodata_reloc_tab.len_end = 0, #ifdef HAVE_FIPS #ifdef WC_USE_PIE_FENCEPOSTS_FOR_FIPS .fips_text_start = (size_t)(uintptr_t)__wc_text_start, @@ -1161,12 +1192,12 @@ static const struct wc_reloc_table_segments seg_map = { }; ssize_t wc_linuxkm_normalize_relocations( - const u8 *text_in, - size_t text_in_len, - u8 *text_out, + const u8 *seg_in, + size_t *seg_in_out_len, + u8 *seg_out, ssize_t *cur_index_p) { - return wc_reloc_normalize_text(text_in, text_in_len, text_out, cur_index_p, &seg_map, + return wc_reloc_normalize_segment(seg_in, seg_in_out_len, seg_out, cur_index_p, &seg_map, #ifdef DEBUG_LINUXKM_PIE_SUPPORT &reloc_counts #else @@ -1175,6 +1206,28 @@ ssize_t wc_linuxkm_normalize_relocations( ); } +ssize_t wc_linuxkm_normalize_relocations_noresize( + const u8 *seg_in, + size_t seg_in_len, + u8 *seg_out, + ssize_t *cur_index_p) +{ + ssize_t ret; + ret = wc_reloc_normalize_segment(seg_in, &seg_in_len, seg_out, cur_index_p, &seg_map, +#ifdef DEBUG_LINUXKM_PIE_SUPPORT + &reloc_counts +#else + NULL +#endif + ); + if (ret < 0) + return ret; + if ((size_t)ret != seg_in_len) + return -EINVAL; + else + return seg_in_len; +} + #elif defined(HAVE_FIPS) static const struct wc_reloc_table_segments seg_map = { @@ -1227,6 +1280,8 @@ static int set_up_wolfssl_linuxkm_pie_redirect_table(void) { #ifdef HAVE_FIPS wolfssl_linuxkm_pie_redirect_table.wc_linuxkm_normalize_relocations = wc_linuxkm_normalize_relocations; + wolfssl_linuxkm_pie_redirect_table.wc_linuxkm_normalize_relocations_noresize = + wc_linuxkm_normalize_relocations_noresize; #endif #ifndef __ARCH_MEMCMP_NO_REDIRECT