Commit 7c08a261 authored by Palmer Dabbelt's avatar Palmer Dabbelt

Merge patch series "RISC-V: Parse DT for Zkr to seed KASLR"

Jesse Taube <jesse@rivosinc.com> says:

Add functions to pi/fdt_early.c to help parse the FDT to check if
the isa string has the Zkr extension. Then use the Zkr extension to
seed the KASLR base address.

The first two patches fix the visibility of symbols.

* b4-shazam-merge:
  RISC-V: Use Zkr to seed KASLR base address
  RISC-V: pi: Add kernel/pi/pi.h
  RISC-V: lib: Add pi aliases for string functions
  RISC-V: pi: Force hidden visibility for all symbol references

Link: https://lore.kernel.org/r/20240709173937.510084-1-jesse@rivosinc.comSigned-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parents dc1c8034 945302df
...@@ -5,6 +5,7 @@ KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) -fpie \ ...@@ -5,6 +5,7 @@ KBUILD_CFLAGS := $(subst $(CC_FLAGS_FTRACE),,$(KBUILD_CFLAGS)) -fpie \
-Os -DDISABLE_BRANCH_PROFILING $(DISABLE_STACKLEAK_PLUGIN) \ -Os -DDISABLE_BRANCH_PROFILING $(DISABLE_STACKLEAK_PLUGIN) \
$(call cc-option,-mbranch-protection=none) \ $(call cc-option,-mbranch-protection=none) \
-I$(srctree)/scripts/dtc/libfdt -fno-stack-protector \ -I$(srctree)/scripts/dtc/libfdt -fno-stack-protector \
-include $(srctree)/include/linux/hidden.h \
-D__DISABLE_EXPORTS -ffreestanding \ -D__DISABLE_EXPORTS -ffreestanding \
-fno-asynchronous-unwind-tables -fno-unwind-tables \ -fno-asynchronous-unwind-tables -fno-unwind-tables \
$(call cc-option,-fno-addrsig) $(call cc-option,-fno-addrsig)
...@@ -16,6 +17,7 @@ KBUILD_CFLAGS += -mcmodel=medany ...@@ -16,6 +17,7 @@ KBUILD_CFLAGS += -mcmodel=medany
CFLAGS_cmdline_early.o += -D__NO_FORTIFY CFLAGS_cmdline_early.o += -D__NO_FORTIFY
CFLAGS_lib-fdt_ro.o += -D__NO_FORTIFY CFLAGS_lib-fdt_ro.o += -D__NO_FORTIFY
CFLAGS_fdt_early.o += -D__NO_FORTIFY
$(obj)/%.pi.o: OBJCOPYFLAGS := --prefix-symbols=__pi_ \ $(obj)/%.pi.o: OBJCOPYFLAGS := --prefix-symbols=__pi_ \
--remove-section=.note.gnu.property \ --remove-section=.note.gnu.property \
...@@ -32,5 +34,5 @@ $(obj)/string.o: $(srctree)/lib/string.c FORCE ...@@ -32,5 +34,5 @@ $(obj)/string.o: $(srctree)/lib/string.c FORCE
$(obj)/ctype.o: $(srctree)/lib/ctype.c FORCE $(obj)/ctype.o: $(srctree)/lib/ctype.c FORCE
$(call if_changed_rule,cc_o_c) $(call if_changed_rule,cc_o_c)
obj-y := cmdline_early.pi.o fdt_early.pi.o string.pi.o ctype.pi.o lib-fdt.pi.o lib-fdt_ro.pi.o obj-y := cmdline_early.pi.o fdt_early.pi.o string.pi.o ctype.pi.o lib-fdt.pi.o lib-fdt_ro.pi.o archrandom_early.pi.o
extra-y := $(patsubst %.pi.o,%.o,$(obj-y)) extra-y := $(patsubst %.pi.o,%.o,$(obj-y))
// SPDX-License-Identifier: GPL-2.0-only
#include <asm/csr.h>
#include <linux/processor.h>
#include "pi.h"
/*
* To avoid rewriting code include asm/archrandom.h and create macros
* for the functions that won't be included.
*/
#undef riscv_has_extension_unlikely
#define riscv_has_extension_likely(...) false
#undef pr_err_once
#define pr_err_once(...)
#include <asm/archrandom.h>
u64 get_kaslr_seed_zkr(const uintptr_t dtb_pa)
{
unsigned long seed = 0;
if (!fdt_early_match_extension_isa((const void *)dtb_pa, "zkr"))
return 0;
if (!csr_seed_long(&seed))
return 0;
return seed;
}
...@@ -6,15 +6,9 @@ ...@@ -6,15 +6,9 @@
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/setup.h> #include <asm/setup.h>
static char early_cmdline[COMMAND_LINE_SIZE]; #include "pi.h"
/* static char early_cmdline[COMMAND_LINE_SIZE];
* Declare the functions that are exported (but prefixed) here so that LLVM
* does not complain it lacks the 'static' keyword (which, if added, makes
* LLVM complain because the function is actually unused in this file).
*/
u64 set_satp_mode_from_cmdline(uintptr_t dtb_pa);
bool set_nokaslr_from_cmdline(uintptr_t dtb_pa);
static char *get_early_cmdline(uintptr_t dtb_pa) static char *get_early_cmdline(uintptr_t dtb_pa)
{ {
......
...@@ -2,13 +2,9 @@ ...@@ -2,13 +2,9 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/libfdt.h> #include <linux/libfdt.h>
#include <linux/ctype.h>
/* #include "pi.h"
* Declare the functions that are exported (but prefixed) here so that LLVM
* does not complain it lacks the 'static' keyword (which, if added, makes
* LLVM complain because the function is actually unused in this file).
*/
u64 get_kaslr_seed(uintptr_t dtb_pa);
u64 get_kaslr_seed(uintptr_t dtb_pa) u64 get_kaslr_seed(uintptr_t dtb_pa)
{ {
...@@ -28,3 +24,162 @@ u64 get_kaslr_seed(uintptr_t dtb_pa) ...@@ -28,3 +24,162 @@ u64 get_kaslr_seed(uintptr_t dtb_pa)
*prop = 0; *prop = 0;
return ret; return ret;
} }
/**
* fdt_device_is_available - check if a device is available for use
*
* @fdt: pointer to the device tree blob
* @node: offset of the node whose property to find
*
* Returns true if the status property is absent or set to "okay" or "ok",
* false otherwise
*/
static bool fdt_device_is_available(const void *fdt, int node)
{
const char *status;
int statlen;
status = fdt_getprop(fdt, node, "status", &statlen);
if (!status)
return true;
if (statlen > 0) {
if (!strcmp(status, "okay") || !strcmp(status, "ok"))
return true;
}
return false;
}
/* Copy of fdt_nodename_eq_ */
static int fdt_node_name_eq(const void *fdt, int offset,
const char *s)
{
int olen;
int len = strlen(s);
const char *p = fdt_get_name(fdt, offset, &olen);
if (!p || olen < len)
/* short match */
return 0;
if (memcmp(p, s, len) != 0)
return 0;
if (p[len] == '\0')
return 1;
else if (!memchr(s, '@', len) && (p[len] == '@'))
return 1;
else
return 0;
}
/**
* isa_string_contains - check if isa string contains an extension
*
* @isa_str: isa string to search
* @ext_name: the extension to search for
*
* Returns true if the extension is in the given isa string,
* false otherwise
*/
static bool isa_string_contains(const char *isa_str, const char *ext_name)
{
size_t i, single_end, len = strlen(ext_name);
char ext_end;
/* Error must contain rv32/64 */
if (strlen(isa_str) < 4)
return false;
if (len == 1) {
single_end = strcspn(isa_str, "sSxXzZ");
/* Search for single chars between rv32/64 and multi-letter extensions */
for (i = 4; i < single_end; i++) {
if (tolower(isa_str[i]) == ext_name[0])
return true;
}
return false;
}
/* Skip to start of multi-letter extensions */
isa_str = strpbrk(isa_str, "sSxXzZ");
while (isa_str) {
if (strncasecmp(isa_str, ext_name, len) == 0) {
ext_end = isa_str[len];
/* Check if matches the whole extension. */
if (ext_end == '\0' || ext_end == '_')
return true;
}
/* Multi-letter extensions must be split from other multi-letter
* extensions with an "_", the end of a multi-letter extension will
* either be the null character or the "_" at the start of the next
* multi-letter extension.
*/
isa_str = strchr(isa_str, '_');
if (isa_str)
isa_str++;
}
return false;
}
/**
* early_cpu_isa_ext_available - check if cpu node has an extension
*
* @fdt: pointer to the device tree blob
* @node: offset of the cpu node
* @ext_name: the extension to search for
*
* Returns true if the cpu node has the extension,
* false otherwise
*/
static bool early_cpu_isa_ext_available(const void *fdt, int node, const char *ext_name)
{
const void *prop;
int len;
prop = fdt_getprop(fdt, node, "riscv,isa-extensions", &len);
if (prop && fdt_stringlist_contains(prop, len, ext_name))
return true;
prop = fdt_getprop(fdt, node, "riscv,isa", &len);
if (prop && isa_string_contains(prop, ext_name))
return true;
return false;
}
/**
* fdt_early_match_extension_isa - check if all cpu nodes have an extension
*
* @fdt: pointer to the device tree blob
* @ext_name: the extension to search for
*
* Returns true if the all available the cpu nodes have the extension,
* false otherwise
*/
bool fdt_early_match_extension_isa(const void *fdt, const char *ext_name)
{
int node, parent;
bool ret = false;
parent = fdt_path_offset(fdt, "/cpus");
if (parent < 0)
return false;
fdt_for_each_subnode(node, fdt, parent) {
if (!fdt_node_name_eq(fdt, node, "cpu"))
continue;
if (!fdt_device_is_available(fdt, node))
continue;
if (!early_cpu_isa_ext_available(fdt, node, ext_name))
return false;
ret = true;
}
return ret;
}
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _RISCV_PI_H_
#define _RISCV_PI_H_
#include <linux/types.h>
/*
* The following functions are exported (but prefixed). Declare them here so
* that LLVM does not complain it lacks the 'static' keyword (which, if
* added, makes LLVM complain because the function is unused).
*/
u64 get_kaslr_seed(uintptr_t dtb_pa);
u64 get_kaslr_seed_zkr(const uintptr_t dtb_pa);
bool set_nokaslr_from_cmdline(uintptr_t dtb_pa);
u64 set_satp_mode_from_cmdline(uintptr_t dtb_pa);
bool fdt_early_match_extension_isa(const void *fdt, const char *ext_name);
#endif /* _RISCV_PI_H_ */
...@@ -111,3 +111,5 @@ SYM_FUNC_START(__memset) ...@@ -111,3 +111,5 @@ SYM_FUNC_START(__memset)
ret ret
SYM_FUNC_END(__memset) SYM_FUNC_END(__memset)
SYM_FUNC_ALIAS_WEAK(memset, __memset) SYM_FUNC_ALIAS_WEAK(memset, __memset)
SYM_FUNC_ALIAS(__pi_memset, __memset)
SYM_FUNC_ALIAS(__pi___memset, __memset)
...@@ -120,3 +120,4 @@ strcmp_zbb: ...@@ -120,3 +120,4 @@ strcmp_zbb:
.option pop .option pop
#endif #endif
SYM_FUNC_END(strcmp) SYM_FUNC_END(strcmp)
SYM_FUNC_ALIAS(__pi_strcmp, strcmp)
...@@ -136,3 +136,4 @@ strncmp_zbb: ...@@ -136,3 +136,4 @@ strncmp_zbb:
.option pop .option pop
#endif #endif
SYM_FUNC_END(strncmp) SYM_FUNC_END(strncmp)
SYM_FUNC_ALIAS(__pi_strncmp, strncmp)
...@@ -1039,6 +1039,7 @@ static void __init pt_ops_set_late(void) ...@@ -1039,6 +1039,7 @@ static void __init pt_ops_set_late(void)
#ifdef CONFIG_RANDOMIZE_BASE #ifdef CONFIG_RANDOMIZE_BASE
extern bool __init __pi_set_nokaslr_from_cmdline(uintptr_t dtb_pa); extern bool __init __pi_set_nokaslr_from_cmdline(uintptr_t dtb_pa);
extern u64 __init __pi_get_kaslr_seed(uintptr_t dtb_pa); extern u64 __init __pi_get_kaslr_seed(uintptr_t dtb_pa);
extern u64 __init __pi_get_kaslr_seed_zkr(const uintptr_t dtb_pa);
static int __init print_nokaslr(char *p) static int __init print_nokaslr(char *p)
{ {
...@@ -1059,10 +1060,12 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa) ...@@ -1059,10 +1060,12 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
#ifdef CONFIG_RANDOMIZE_BASE #ifdef CONFIG_RANDOMIZE_BASE
if (!__pi_set_nokaslr_from_cmdline(dtb_pa)) { if (!__pi_set_nokaslr_from_cmdline(dtb_pa)) {
u64 kaslr_seed = __pi_get_kaslr_seed(dtb_pa); u64 kaslr_seed = __pi_get_kaslr_seed_zkr(dtb_pa);
u32 kernel_size = (uintptr_t)(&_end) - (uintptr_t)(&_start); u32 kernel_size = (uintptr_t)(&_end) - (uintptr_t)(&_start);
u32 nr_pos; u32 nr_pos;
if (kaslr_seed == 0)
kaslr_seed = __pi_get_kaslr_seed(dtb_pa);
/* /*
* Compute the number of positions available: we are limited * Compute the number of positions available: we are limited
* by the early page table that only has one PUD and we must * by the early page table that only has one PUD and we must
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment