Unverified Commit 8ed52b4b authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!3525 ARM: support kaslr feature in arm32 platform

Merge Pull Request from: @foyjog2 
 
support kaslr feature in arm32 platform, using CONFIG_RANDOMIZE_BASE=y to
enable this feature.

Issue
https://gitee.com/openeuler/kernel/issues/I8KNA9

Config Change
Add:
CONFIG_RANDOMIZE_BASE
CONFIG_RELOCATABLE 
 
Link:https://gitee.com/openeuler/kernel/pulls/3525

 

Reviewed-by: default avatarLu Jialin <lujialin4@huawei.com>
Reviewed-by: default avatarZhang Jianhua <chris.zjh@huawei.com>
Reviewed-by: default avatarZucheng Zheng <zhengzucheng@huawei.com>
Reviewed-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
Reviewed-by: default avatarLiu Chao <liuchao173@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parents 1bac188d acdc6399
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -1452,6 +1452,23 @@ config STACKPROTECTOR_PER_TASK
	  Enable this option to switch to a different method that uses a
	  different canary value for each task.

config RELOCATABLE
	bool
	depends on !XIP_KERNEL && !JUMP_LABEL
	select HAVE_ARCH_PREL32_RELOCATIONS

config RANDOMIZE_BASE
	bool "Randomize the address of the kernel image"
	depends on MMU && AUTO_ZRELADDR
	depends on !XIP_KERNEL && !ZBOOT_ROM && !JUMP_LABEL
	select RELOCATABLE
	select ARM_MODULE_PLTS if MODULES
	select MODULE_REL_CRCS if MODVERSIONS
	help
	  Randomizes the virtual and physical address at which the kernel
	  image is loaded, as a security feature that deters exploit attempts
	  relying on knowledge of the location of kernel internals.

endmenu

menu "Boot options"
+7 −0
Original line number Diff line number Diff line
@@ -51,6 +51,13 @@ CHECKFLAGS += -D__ARMEL__
KBUILD_LDFLAGS	+= -EL
endif

ifeq ($(CONFIG_RELOCATABLE),y)
KBUILD_CFLAGS		+= -include $(srctree)/include/linux/hidden.h
CFLAGS_KERNEL		+= -fpic
CFLAGS_MODULE		+= -fno-pic
LDFLAGS_vmlinux		+= -pie -shared -Bsymbolic
endif

#
# The Scalar Replacement of Aggregates (SRA) optimization pass in GCC 4.9 and
# later may result in code being generated that handles signed short and signed
+14 −3
Original line number Diff line number Diff line
@@ -84,10 +84,17 @@ compress-$(CONFIG_KERNEL_LZ4) = lz4_with_size

libfdt_objs := fdt_rw.o fdt_ro.o fdt_wip.o fdt.o

ifneq ($(CONFIG_ARM_ATAG_DTB_COMPAT)$(CONFIG_RANDOMIZE_BASE),)
OBJS	+= $(libfdt_objs)
ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y)
CFLAGS_REMOVE_atags_to_fdt.o += -Wframe-larger-than=${CONFIG_FRAME_WARN}
CFLAGS_atags_to_fdt.o += -Wframe-larger-than=1280
OBJS	+= $(libfdt_objs) atags_to_fdt.o
OBJS	+= atags_to_fdt.o
endif
ifeq ($(CONFIG_RANDOMIZE_BASE),y)
OBJS	+= kaslr.o
CFLAGS_kaslr.o := -I $(srctree)/scripts/dtc/libfdt
endif
endif
ifeq ($(CONFIG_USE_OF),y)
OBJS	+= $(libfdt_objs) fdt_check_mem_start.o
@@ -97,6 +104,10 @@ OBJS += lib1funcs.o ashldi3.o bswapsdi2.o

targets       := vmlinux vmlinux.lds piggy_data piggy.o \
		 head.o $(OBJS)
ifeq ($(CONFIG_RELOCATABLE),y)
HIDDEN_STR := -include $(srctree)/include/linux/hidden.h
KBUILD_CFLAGS := $(subst $(HIDDEN_STR), , $(KBUILD_CFLAGS))
endif

KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING

@@ -108,8 +119,8 @@ asflags-y := -DZIMAGE

# Supply kernel BSS size to the decompressor via a linker symbol.
KBSS_SZ = $(shell echo $$(($$($(NM) vmlinux | \
		sed -n -e 's/^\([^ ]*\) [ABD] __bss_start$$/-0x\1/p' \
		       -e 's/^\([^ ]*\) [ABD] __bss_stop$$/+0x\1/p') )) )
		sed -n -e 's/^\([^ ]*\) [ABDb] __bss_start$$/-0x\1/p' \
		       -e 's/^\([^ ]*\) [ABDb] __bss_stop$$/+0x\1/p') )) )
LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ)
# Supply ZRELADDR to the decompressor via a linker symbol.
ifneq ($(CONFIG_AUTO_ZRELADDR),y)
+131 −8
Original line number Diff line number Diff line
@@ -154,7 +154,7 @@
		 * in little-endian form.
		 */
		.macro	get_inflated_image_size, res:req, tmp1:req, tmp2:req
		adr	\res, .Linflated_image_size_offset
		adr_l	\res, .Linflated_image_size_offset
		ldr	\tmp1, [\res]
		add	\tmp1, \tmp1, \res	@ address of inflated image size

@@ -174,6 +174,25 @@
#endif
		.endm

		.macro  record_seed
#ifdef CONFIG_RANDOMIZE_BASE
		sub	ip, r1, ip, ror #1	@ poor man's kaslr seed, will
		sub	ip, r2, ip, ror #2	@ be superseded by kaslr-seed
		sub	ip, r3, ip, ror #3	@ from /chosen if present
		sub	ip, r4, ip, ror #5
		sub	ip, r5, ip, ror #8
		sub	ip, r6, ip, ror #13
		sub	ip, r7, ip, ror #21
		sub	ip, r8, ip, ror #3
		sub	ip, r9, ip, ror #24
		sub	ip, r10, ip, ror #27
		sub	ip, r11, ip, ror #19
		sub	ip, r13, ip, ror #14
		sub	ip, r14, ip, ror #2
		str_l	ip, __kaslr_seed, r9
#endif
		.endm

		.section ".start", "ax"
/*
 * sort out different calling conventions
@@ -222,6 +241,7 @@ start:
		__EFI_HEADER
1:
 ARM_BE8(	setend	be		)	@ go BE8 if compiled for BE8
		record_seed
 AR_CLASS(	mrs	r9, cpsr	)
#ifdef CONFIG_ARM_VIRT_EXT
		bl	__hyp_stub_install	@ get into SVC mode, reversibly
@@ -328,7 +348,7 @@ not_angel:
		orrcc	r4, r4, #1		@ remember we skipped cache_on
		blcs	cache_on

restart:	adr	r0, LC1
restart:	adr_l	r0, LC1
		ldr	sp, [r0]
		ldr	r6, [r0, #4]
		add	sp, sp, r0
@@ -446,6 +466,69 @@ restart: adr r0, LC1
dtb_check_done:
#endif

#ifdef CONFIG_RANDOMIZE_BASE
		ldr	r1, __kaslr_offset	@ check if the kaslr_offset is
		cmp	r1, #0			@ already set
		bne	1f

		stmfd	sp!, {r0-r3, ip, lr}
#ifdef CONFIG_ARCH_HISI
#ifdef CONFIG_ARM_APPENDED_DTB
#ifdef CONFIG_START_MEM_2M_ALIGN
		mov r0, r4
#ifdef CONFIG_CORTEX_A9
		lsr r0, r0, #20
		lsl r0, r0, #20
#else
		lsr r0, r0, #21
		lsl r0, r0, #21
#endif
		add r0, r0, #0x1000
		ldr r1, [r0]
#ifndef __ARMEB__
		ldr r2, =0xedfe0dd0    @ sig is 0xd00dfeed big endian
#else
		ldr r2, =0xd00dfeed
#endif
		cmp  r1, r2
		moveq r8, r0
#endif
#endif
#endif
		adr_l	r2, _text		@ start of zImage
		stmfd	sp!, {r2, r8, r10}	@ pass stack arguments

		ldr_l	r3, __kaslr_seed
#if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_V6K) || defined(CONFIG_CPU_V7)
		/*
		 * Get some pseudo-entropy from the low bits of the generic
		 * timer if it is implemented.
		 */
		mrc	p15, 0, r1, c0, c1, 1	@ read ID_PFR1 register
		tst	r1, #0x10000		@ have generic timer?
		mrrcne	p15, 1, r3, r1, c14	@ read CNTVCT
#endif
		adr_l	r0, __kaslr_offset	@ pass &__kaslr_offset in r0
		mov	r1, r4			@ pass base address
		mov	r2, r9			@ pass decompressed image size
		eor	r3, r3, r3, ror #16	@ pass pseudorandom seed
		bl	kaslr_early_init
		add	sp, sp, #12
		cmp	r0, #0
		addne	r4, r4, r0		@ add offset to base address
#ifdef CONFIG_VXBOOT
#ifdef CONFIG_START_MEM_2M_ALIGN
#ifdef CONFIG_CORTEX_A9
		adr r1, vx_edata
		strne   r6, [r1]
#endif
#endif
#endif
		ldmfd	sp!, {r0-r3, ip, lr}
		bne	restart
1:
#endif

/*
 * Check to see if we will overwrite ourselves.
 *   r4  = final kernel address (possibly with LSB set)
@@ -814,20 +897,24 @@ __setup_mmu: sub r3, r4, #16384 @ Page directory size
		teq	r0, r2
		bne	1b
/*
 * If ever we are running from Flash, then we surely want the cache
 * to be enabled also for our execution instance...  We map 2MB of it
 * so there is no map overlap problem for up to 1 MB compressed kernel.
 * If the execution is in RAM then we would only be duplicating the above.
 * Make sure our entire executable image (including payload) is mapped
 * cacheable, in case it is located outside the region we covered above.
 * (This may be the case if running from flash or with randomization enabled)
 * If the regions happen to overlap, we just duplicate some of the above.
 */
		orr	r1, r6, #0x04		@ ensure B is set for this
		orr	r1, r1, #3 << 10
		mov	r2, pc
		adr_l	r9, _end
		mov	r2, r2, lsr #20
		mov	r9, r9, lsr #20
		orr	r1, r1, r2, lsl #20
		add	r0, r3, r2, lsl #2
		str	r1, [r0], #4
		add	r9, r3, r9, lsl #2
0:		str	r1, [r0], #4
		add	r1, r1, #1048576
		str	r1, [r0]
		cmp	r0, r9
		bls	0b
		mov	pc, lr
ENDPROC(__setup_mmu)

@@ -1435,10 +1522,46 @@ __enter_kernel:
		mov	r0, #0			@ must be 0
		mov	r1, r7			@ restore architecture number
		mov	r2, r8			@ restore atags pointer
#ifdef CONFIG_RANDOMIZE_BASE
		ldr	r3, __kaslr_offset
		add	r4, r4, #4		@ skip first instruction
#endif
 ARM(		mov	pc, r4		)	@ call kernel
 M_CLASS(	add	r4, r4, #1	)	@ enter in Thumb mode for M class
 THUMB(		bx	r4		)	@ entry point is always ARM for A/R classes

#ifdef CONFIG_RANDOMIZE_BASE
		/*
		 * Minimal implementation of CRC-16 that does not use a
		 * lookup table and uses 32-bit wide loads, so it still
		 * performs reasonably well with the D-cache off. Equivalent
		 * to lib/crc16.c for input sizes that are 4 byte multiples.
		 */
ENTRY(__crc16)
		push	{r4, lr}
		ldr	r3, =0xa001     @ CRC-16 polynomial
0:		subs	r2, r2, #4
		popmi	{r4, pc}
		ldr	r4, [r1], #4
#ifdef __ARMEB__
		eor	ip, r4, r4, ror #16     @ endian swap
		bic	ip, ip, #0x00ff0000
		mov	r4, r4, ror #8
		eor	r4, r4, ip, lsr #8
#endif
		eor	r0, r0, r4
		.rept	32
		lsrs	r0, r0, #1
		eorcs	r0, r0, r3
		.endr
		b	0b
ENDPROC(__crc16)

		.align	2
__kaslr_seed:	.long	0
__kaslr_offset:	.long	0
#endif

reloc_code_end:

#ifdef CONFIG_EFI_STUB
+433 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 Linaro Ltd;  <ard.biesheuvel@linaro.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 */

#include <linux/libfdt_env.h>
#include <libfdt.h>
#include <linux/types.h>
#include <generated/compile.h>
#include <generated/utsrelease.h>
#include <generated/utsversion.h>
#include <linux/pgtable.h>

#include CONFIG_UNCOMPRESS_INCLUDE

struct regions {
	u32 pa_start;
	u32 pa_end;
	u32 image_size;
	u32 zimage_start;
	u32 zimage_size;
	u32 dtb_start;
	u32 dtb_size;
	u32 initrd_start;
	u32 initrd_size;
	int reserved_mem;
	int reserved_mem_addr_cells;
	int reserved_mem_size_cells;
};

extern u32 __crc16(u32 crc, u32 const input[], int byte_count);

static u32 __memparse(const char *val, const char **retptr)
{
	int base = 10;
	u32 ret = 0;

	if (*val == '0') {
		val++;
		if (*val == 'x' || *val == 'X') {
			val++;
			base = 16;
		} else {
			base = 8;
		}
	}

	while (*val != ',' && *val != ' ' && *val != '\0') {
		char c = *val++;

		switch (c) {
		case '0' ... '9':
			ret = ret * base + (c - '0');
			continue;
		case 'a' ... 'f':
			ret = ret * base + (c - 'a' + 10);
			continue;
		case 'A' ... 'F':
			ret = ret * base + (c - 'A' + 10);
			continue;
		case 'g':
		case 'G':
			ret <<= 10;
			fallthrough;
		case 'm':
		case 'M':
			ret <<= 10;
			fallthrough;
		case 'k':
		case 'K':
			ret <<= 10;
			break;
		default:
			if (retptr)
				*retptr = NULL;
			return 0;
		}
	}
	if (retptr)
		*retptr = val;
	return ret;
}

static bool regions_intersect(u32 s1, u32 e1, u32 s2, u32 e2)
{
	return e1 >= s2 && e2 >= s1;
}

static bool intersects_reserved_region(const void *fdt, u32 start,
				       u32 end, struct regions *regions)
{
	int subnode, len, i;
	u64 base, size;

	/* check for overlap with /memreserve/ entries */
	for (i = 0; i < fdt_num_mem_rsv(fdt); i++) {
		if (fdt_get_mem_rsv(fdt, i, &base, &size) < 0)
			continue;
		if (regions_intersect(start, end, base, base + size))
			return true;
	}

	if (regions->reserved_mem < 0)
		return false;

	/* check for overlap with static reservations in /reserved-memory */
	for (subnode = fdt_first_subnode(fdt, regions->reserved_mem);
	     subnode >= 0;
	     subnode = fdt_next_subnode(fdt, subnode)) {
		const fdt32_t *reg;

		len = 0;
		reg = fdt_getprop(fdt, subnode, "reg", &len);
		while (len >= (regions->reserved_mem_addr_cells +
			       regions->reserved_mem_size_cells)) {

			base = fdt32_to_cpu(reg[0]);
			if (regions->reserved_mem_addr_cells == 2)
				base = (base << 32) | fdt32_to_cpu(reg[1]);

			reg += regions->reserved_mem_addr_cells;
			len -= 4 * regions->reserved_mem_addr_cells;

			size = fdt32_to_cpu(reg[0]);
			if (regions->reserved_mem_size_cells == 2)
				size = (size << 32) | fdt32_to_cpu(reg[1]);

			reg += regions->reserved_mem_size_cells;
			len -= 4 * regions->reserved_mem_size_cells;

			if (base >= regions->pa_end)
				continue;

			if (regions_intersect(start, end, base,
					      min(base + size, (u64)U32_MAX)))
				return true;
		}
	}
	return false;
}

static bool intersects_occupied_region(const void *fdt, u32 start,
				       u32 end, struct regions *regions)
{
	if (regions_intersect(start, end, regions->zimage_start,
			      regions->zimage_start + regions->zimage_size))
		return true;

	if (regions_intersect(start, end, regions->initrd_start,
			      regions->initrd_start + regions->initrd_size))
		return true;

	if (regions_intersect(start, end, regions->dtb_start,
			      regions->dtb_start + regions->dtb_size))
		return true;

	return intersects_reserved_region(fdt, start, end, regions);
}

static u32 count_suitable_regions(const void *fdt, struct regions *regions,
				  u32 *bitmap)
{
	u32 pa, i = 0, ret = 0;

	for (pa = regions->pa_start; pa < regions->pa_end; pa += SZ_2M, i++) {
		if (!intersects_occupied_region(fdt, pa,
						pa + regions->image_size,
						regions)) {
			ret++;
		} else {
			/* set 'occupied' bit */
			bitmap[i >> 5] |= BIT(i & 0x1f);
		}
	}
	return ret;
}

/* The caller ensures that num is within the range of regions.*/
static u32 get_region_number(u32 num, u32 *bitmap, u32 size)
{
	u32 i, cnt = size * BITS_PER_BYTE * sizeof(u32);

	for (i = 0; i < cnt; i++) {
		if (bitmap[i >> 5] & BIT(i & 0x1f))
			continue;
		if (num-- == 0)
			break;
	}

	return i;
}

static void get_cell_sizes(const void *fdt, int node, int *addr_cells,
			   int *size_cells)
{
	const int *prop;
	int len;

	/*
	 * Retrieve the #address-cells and #size-cells properties
	 * from the 'node', or use the default if not provided.
	 */
	*addr_cells = *size_cells = 1;

	prop = fdt_getprop(fdt, node, "#address-cells", &len);
	if (len == 4)
		*addr_cells = fdt32_to_cpu(*prop);
	prop = fdt_getprop(fdt, node, "#size-cells", &len);
	if (len == 4)
		*size_cells = fdt32_to_cpu(*prop);
}

/*
 * Original method only consider the first memory node in dtb,
 * but there may be more than one memory nodes, we only consider
 * the memory node zImage exists.
 */
static u32 get_memory_end(const void *fdt, u32 zimage_start)
{
	int mem_node, address_cells, size_cells, len;
	const fdt32_t *reg;

	/* Look for a node called "memory" at the lowest level of the tree */
	mem_node = fdt_path_offset(fdt, "/memory");
	if (mem_node <= 0)
		return 0;

	get_cell_sizes(fdt, 0, &address_cells, &size_cells);

	while (mem_node >= 0) {
		/*
		 * Now find the 'reg' property of the /memory node, and iterate over
		 * the base/size pairs.
		 */
		len = 0;
		reg = fdt_getprop(fdt, mem_node, "reg", &len);
		while (len >= 4 * (address_cells + size_cells)) {
			u64 base, size;
			base = fdt32_to_cpu(reg[0]);
			if (address_cells == 2)
				base = (base << 32) | fdt32_to_cpu(reg[1]);

			reg += address_cells;
			len -= 4 * address_cells;

			size = fdt32_to_cpu(reg[0]);
			if (size_cells == 2)
				size = (size << 32) | fdt32_to_cpu(reg[1]);

			reg += size_cells;
			len -= 4 * size_cells;

			/* Get the base and size of the zimage memory node */
			if (zimage_start >= base && zimage_start < base + size)
				return base + size;
		}
		/* If current memory node is not the one zImage exists, then traverse next memory node. */
		mem_node = fdt_node_offset_by_prop_value(fdt, mem_node, "device_type", "memory", sizeof("memory"));
	}

	return 0;
}

static char *__strstr(const char *s1, const char *s2, int l2)
{
	int l1;

	l1 = strlen(s1);
	while (l1 >= l2) {
		l1--;
		if (!memcmp(s1, s2, l2))
			return (char *)s1;
		s1++;
	}
	return NULL;
}

static const char *get_cmdline_param(const char *cmdline, const char *param,
				     int param_size)
{
	static const char default_cmdline[] = CONFIG_CMDLINE;
	const char *p;

	if (!IS_ENABLED(CONFIG_CMDLINE_FORCE) && cmdline != NULL) {
		p = __strstr(cmdline, param, param_size);
		if (p == cmdline ||
		    (p > cmdline && *(p - 1) == ' '))
			return p;
	}

	if (IS_ENABLED(CONFIG_CMDLINE_FORCE)  ||
	    IS_ENABLED(CONFIG_CMDLINE_EXTEND)) {
		p = __strstr(default_cmdline, param, param_size);
		if (p == default_cmdline ||
		    (p > default_cmdline && *(p - 1) == ' '))
			return p;
	}
	return NULL;
}

u32 kaslr_early_init(u32 *kaslr_offset, u32 image_base, u32 image_size,
		     u32 seed, u32 zimage_start, const void *fdt,
		     u32 zimage_end)
{
	static const char __aligned(4) build_id[] = UTS_VERSION UTS_RELEASE;
	u32 bitmap[(VMALLOC_END - PAGE_OFFSET) / SZ_2M / 32] = {};
	struct regions regions;
	const char *command_line;
	const char *p;
	int chosen, len;
	u32 lowmem_top, count, num, mem_fdt;

	if (IS_ENABLED(CONFIG_EFI_STUB)) {
		extern u32 __efi_kaslr_offset;

		if (__efi_kaslr_offset == U32_MAX)
			return 0;
	}

	if (fdt_check_header(fdt))
		return 0;

	chosen = fdt_path_offset(fdt, "/chosen");
	if (chosen < 0)
		return 0;

	command_line = fdt_getprop(fdt, chosen, "bootargs", &len);

	/* check the command line for the presence of 'nokaslr' */
	p = get_cmdline_param(command_line, "nokaslr", sizeof("nokaslr") - 1);
	if (p != NULL)
		return 0;

	/* check the command line for the presence of 'vmalloc=' */
	p = get_cmdline_param(command_line, "vmalloc=", sizeof("vmalloc=") - 1);
	if (p != NULL)
		lowmem_top = VMALLOC_END - __memparse(p + 8, NULL) -
			     VMALLOC_OFFSET;
	else
		lowmem_top = VMALLOC_DEFAULT_BASE;

	regions.image_size = image_base % SZ_128M + round_up(image_size, SZ_2M);
	regions.pa_start = round_down(image_base, SZ_128M);
	regions.pa_end = lowmem_top - PAGE_OFFSET + regions.pa_start;
	regions.zimage_start = zimage_start;
	regions.zimage_size = zimage_end - zimage_start;
	regions.dtb_start = (u32)fdt;
	regions.dtb_size = fdt_totalsize(fdt);

	/*
	 * Stir up the seed a bit by taking the CRC of the DTB:
	 * hopefully there's a /chosen/kaslr-seed in there.
	 */
	seed = __crc16(seed, fdt, regions.dtb_size);

	/* stir a bit more using data that changes between builds */
	seed = __crc16(seed, (u32 *)build_id, sizeof(build_id));

	/* check for initrd on the command line */
	regions.initrd_start = regions.initrd_size = 0;
	p = get_cmdline_param(command_line, "initrd=", sizeof("initrd=") - 1);
	if (p != NULL) {
		regions.initrd_start = __memparse(p + 7, &p);
		if (*p++ == ',')
			regions.initrd_size = __memparse(p, NULL);
		if (regions.initrd_size == 0)
			regions.initrd_start = 0;
	}

	/* ... or in /chosen */
	if (regions.initrd_size == 0) {
		const fdt32_t *prop;
		u64 start = 0, end = 0;

		prop = fdt_getprop(fdt, chosen, "linux,initrd-start", &len);
		if (prop) {
			start = fdt32_to_cpu(prop[0]);
			if (len == 8)
				start = (start << 32) | fdt32_to_cpu(prop[1]);
		}

		prop = fdt_getprop(fdt, chosen, "linux,initrd-end", &len);
		if (prop) {
			end = fdt32_to_cpu(prop[0]);
			if (len == 8)
				end = (end << 32) | fdt32_to_cpu(prop[1]);
		}
		if (start != 0 && end != 0 && start < U32_MAX) {
			regions.initrd_start = start;
			regions.initrd_size = min_t(u64, end, U32_MAX) - start;
		}
	}

	/*
	 * check the memory nodes for the size of the lowmem region, traverse
	 * all memory nodes to find the node in which zImage exists, we
	 * randomize kernel only in the one zImage exists.
	 */
	mem_fdt = get_memory_end(fdt, zimage_start);
	if (mem_fdt)
		regions.pa_end = min(regions.pa_end, mem_fdt) - regions.image_size;
	else
		regions.pa_end = regions.pa_end - regions.image_size;

	/* check for a reserved-memory node and record its cell sizes */
	regions.reserved_mem = fdt_path_offset(fdt, "/reserved-memory");
	if (regions.reserved_mem >= 0)
		get_cell_sizes(fdt, regions.reserved_mem,
			       &regions.reserved_mem_addr_cells,
			       &regions.reserved_mem_size_cells);

	/*
	 * Iterate over the physical memory range covered by the lowmem region
	 * in 2 MB increments, and count each offset at which we don't overlap
	 * with any of the reserved regions for the zImage itself, the DTB,
	 * the initrd and any regions described as reserved in the device tree.
	 * If the region does overlap, set the respective bit in the bitmap[].
	 * Using this random value, we go over the bitmap and count zero bits
	 * until we counted enough iterations, and return the offset we ended
	 * up at.
	 */
	count = count_suitable_regions(fdt, &regions, bitmap);

	num = ((u16)seed * count) >> 16;

	*kaslr_offset = get_region_number(num, bitmap, sizeof(bitmap) / sizeof(u32)) * SZ_2M;

	return *kaslr_offset;
}
Loading