[PATCH v5 07/10] powerpc/fsl_booke/32: randomize the kernel image offset

Jason Yan yanaijie at huawei.com
Thu Aug 8 17:08:54 AEST 2019



On 2019/8/7 21:03, Michael Ellerman wrote:
> Jason Yan <yanaijie at huawei.com> writes:
>> After we have the basic support of relocate the kernel in some
>> appropriate place, we can start to randomize the offset now.
>>
>> Entropy is derived from the banner and timer, which will change every
>> build and boot. This not so much safe so additionally the bootloader may
>> pass entropy via the /chosen/kaslr-seed node in device tree.
>>
>> We will use the first 512M of the low memory to randomize the kernel
>> image. The memory will be split in 64M zones. We will use the lower 8
>> bit of the entropy to decide the index of the 64M zone. Then we chose a
>> 16K aligned offset inside the 64M zone to put the kernel in.
>>
>>      KERNELBASE
>>
>>          |-->   64M   <--|
>>          |               |
>>          +---------------+    +----------------+---------------+
>>          |               |....|    |kernel|    |               |
>>          +---------------+    +----------------+---------------+
>>          |                         |
>>          |----->   offset    <-----|
>>
>>                                kimage_vaddr
> 
> Can you drop this description / diagram and any other relevant design
> details in eg. Documentation/powerpc/kaslr-booke32.rst please?
> 

No problem.

> See cpu_families.rst for an example of how to incorporate the ASCII
> diagram.
>  >> diff --git a/arch/powerpc/kernel/kaslr_booke.c 
b/arch/powerpc/kernel/kaslr_booke.c
>> index 30f84c0321b2..52b59b05f906 100644
>> --- a/arch/powerpc/kernel/kaslr_booke.c
>> +++ b/arch/powerpc/kernel/kaslr_booke.c
>> @@ -34,15 +36,329 @@
>>   #include <asm/machdep.h>
>>   #include <asm/setup.h>
>>   #include <asm/paca.h>
>> +#include <asm/kdump.h>
>>   #include <mm/mmu_decl.h>
>> +#include <generated/compile.h>
>> +#include <generated/utsrelease.h>
>> +
>> +#ifdef DEBUG
>> +#define DBG(fmt...) pr_info(fmt)
>> +#else
>> +#define DBG(fmt...)
>> +#endif
> 
> Just use pr_debug()?
> 

Sounds better.

>> +struct regions {
>> +	unsigned long pa_start;
>> +	unsigned long pa_end;
>> +	unsigned long kernel_size;
>> +	unsigned long dtb_start;
>> +	unsigned long dtb_end;
>> +	unsigned long initrd_start;
>> +	unsigned long initrd_end;
>> +	unsigned long crash_start;
>> +	unsigned long crash_end;
>> +	int reserved_mem;
>> +	int reserved_mem_addr_cells;
>> +	int reserved_mem_size_cells;
>> +};
>>   
>>   extern int is_second_reloc;
>>   
>> +/* Simplified build-specific string for starting entropy. */
>> +static const char build_str[] = UTS_RELEASE " (" LINUX_COMPILE_BY "@"
>> +		LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION;
>> +
>> +static __init void kaslr_get_cmdline(void *fdt)
>> +{
>> +	int node = fdt_path_offset(fdt, "/chosen");
>> +
>> +	early_init_dt_scan_chosen(node, "chosen", 1, boot_command_line);
>> +}
>> +
>> +static unsigned long __init rotate_xor(unsigned long hash, const void *area,
>> +				       size_t size)
>> +{
>> +	size_t i;
>> +	const unsigned long *ptr = area;
>> +
>> +	for (i = 0; i < size / sizeof(hash); i++) {
>> +		/* Rotate by odd number of bits and XOR. */
>> +		hash = (hash << ((sizeof(hash) * 8) - 7)) | (hash >> 7);
>> +		hash ^= ptr[i];
>> +	}
>> +
>> +	return hash;
>> +}
> 
> That looks suspiciously like the version Kees wrote in 2013 in
> arch/x86/boot/compressed/kaslr.c ?
> 
> You should mention that in the change log at least.
> 

Oh yes, I should have do that. Thanks for reminding me.

>> +
>> +/* Attempt to create a simple but unpredictable starting entropy. */
> 
> It's simple, but I would argue unpredictable is not really true. A local
> attacker can probably fingerprint the kernel version, and also has
> access to the unflattened device tree, which means they can make
> educated guesses about the flattened tree size.
> 
> Be careful when copying comments :)
> 

It's true that the comment is not so precise. It's an 'attempt' to
create unpredictable entropy. And apparently the 'attempt' was failed.
I will try to rewrite the comment to reflect the code more precisely.

>> +static unsigned long __init get_boot_seed(void *fdt)
>> +{
>> +	unsigned long hash = 0;
>> +
>> +	hash = rotate_xor(hash, build_str, sizeof(build_str));
>> +	hash = rotate_xor(hash, fdt, fdt_totalsize(fdt));
>> +
>> +	return hash;
>> +}
>> +
>> +static __init u64 get_kaslr_seed(void *fdt)
>> +{
>> +	int node, len;
>> +	fdt64_t *prop;
>> +	u64 ret;
>> +
>> +	node = fdt_path_offset(fdt, "/chosen");
>> +	if (node < 0)
>> +		return 0;
>> +
>> +	prop = fdt_getprop_w(fdt, node, "kaslr-seed", &len);
>> +	if (!prop || len != sizeof(u64))
>> +		return 0;
>> +
>> +	ret = fdt64_to_cpu(*prop);
>> +	*prop = 0;
>> +	return ret;
>> +}
>> +
>> +static __init bool regions_overlap(u32 s1, u32 e1, u32 s2, u32 e2)
>> +{
>> +	return e1 >= s2 && e2 >= s1;
>> +}
> 
> There's a generic helper called memory_intersects(), though it takes
> void*. Might not be worth using, not sure.
> 

I will have a try to see if this can save some codes or not.

> ...
>>   static unsigned long __init kaslr_choose_location(void *dt_ptr, phys_addr_t size,
>>   						  unsigned long kernel_sz)
>>   {
>> -	/* return a fixed offset of 64M for now */
>> -	return SZ_64M;
>> +	unsigned long offset, random;
>> +	unsigned long ram, linear_sz;
>> +	unsigned long kaslr_offset;
>> +	u64 seed;
>> +	struct regions regions;
> 
> You pass that around to a lot of the functions, would it be simpler just
> to make it static global and __initdata ?
> 

Not sure if it's simpler. Let me have a try.

> cheers
> 
> 
> .
> 



More information about the Linuxppc-dev mailing list