Unverified Commit 79524ebe authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!3736 Add nokaslr memory region avoid support

Merge Pull Request from: @foyjog2 
 
Add nokaslr memory region avoid support.

Config Change
Add:
CONFIG_NOKASLR_MEM_RANGE

https://gitee.com/openeuler/kernel/issues/I8TANP 
 
Link:https://gitee.com/openeuler/kernel/pulls/3736

 

Reviewed-by: default avatarLiu Chao <liuchao173@huawei.com>
Reviewed-by: default avatarZhang Jianhua <chris.zjh@huawei.com>
Reviewed-by: default avatarLu Jialin <lujialin4@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents ca43323b d9acbc44
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -545,6 +545,7 @@ CONFIG_ARM64_PSEUDO_NMI=y
CONFIG_RELOCATABLE=y
CONFIG_RANDOMIZE_BASE=y
CONFIG_RANDOMIZE_MODULE_REGION_FULL=y
CONFIG_NOKASLR_MEM_RANGE=y
CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y
CONFIG_STACKPROTECTOR_PER_TASK=y
CONFIG_ASCEND_FEATURES=y
+44 −0
Original line number Diff line number Diff line
@@ -79,6 +79,9 @@ static unsigned long get_boot_seed(void)
/* Only supporting at most 4 unusable memmap regions with kaslr */
#define MAX_MEMMAP_REGIONS	4

#ifdef CONFIG_NOKASLR_MEM_RANGE
#define MAX_MEM_NOKASLR_REGIONS	4
#endif
static bool memmap_too_large;


@@ -98,6 +101,10 @@ enum mem_avoid_index {
	MEM_AVOID_BOOTPARAMS,
	MEM_AVOID_MEMMAP_BEGIN,
	MEM_AVOID_MEMMAP_END = MEM_AVOID_MEMMAP_BEGIN + MAX_MEMMAP_REGIONS - 1,
#ifdef CONFIG_NOKASLR_MEM_RANGE
	MEM_AVOID_MEM_NOKASLR_BEGIN,
	MEM_AVOID_MEM_NOKASLR_END = MEM_AVOID_MEM_NOKASLR_BEGIN + MAX_MEM_NOKASLR_REGIONS - 1,
#endif
	MEM_AVOID_MAX,
};

@@ -227,6 +234,39 @@ static void mem_avoid_memmap(enum parse_mode mode, char *str)
		memmap_too_large = true;
}

#ifdef CONFIG_NOKASLR_MEM_RANGE
static void mem_avoid_mem_nokaslr(char *str)
{
	int i = 0;

	while (str && (i < MAX_MEM_NOKASLR_REGIONS)) {
		char *oldstr;
		u64 start, end;
		char *k = strchr(str, ',');

		if (k)
			*k++ = 0;

		oldstr = str;
		start = memparse(str, &str);
		if (str == oldstr || *str != '-') {
			warn("Nokaslr values error.\n");
			break;
		}

		end = memparse(str + 1, &str);
		if (start >= end) {
			warn("Nokaslr values error, start should be less than end.\n");
			break;
		}

		mem_avoid[MEM_AVOID_MEM_NOKASLR_BEGIN + i].start = start;
		mem_avoid[MEM_AVOID_MEM_NOKASLR_BEGIN + i].size = end - start;
		str = k;
		i++;
	}
}
#endif
/* Store the number of 1GB huge pages which users specified: */
static unsigned long max_gb_huge_pages;

@@ -302,6 +342,10 @@ static void handle_mem_options(void)
		} else if (!strcmp(param, "efi_fake_mem")) {
			mem_avoid_memmap(PARSE_EFI, val);
		}
#ifdef CONFIG_NOKASLR_MEM_RANGE
		else if (!strcmp(param, "nokaslr") && val)
			mem_avoid_mem_nokaslr(val);
#endif
	}

	free(tmp_cmdline);
+1 −0
Original line number Diff line number Diff line
@@ -485,6 +485,7 @@ CONFIG_PHYSICAL_ALIGN=0x200000
CONFIG_DYNAMIC_MEMORY_LAYOUT=y
CONFIG_RANDOMIZE_MEMORY=y
CONFIG_RANDOMIZE_MEMORY_PHYSICAL_PADDING=0xa
CONFIG_NOKASLR_MEM_RANGE=y
CONFIG_HOTPLUG_CPU=y
# CONFIG_BOOTPARAM_HOTPLUG_CPU0 is not set
# CONFIG_DEBUG_HOTPLUG_CPU0 is not set
+118 −0
Original line number Diff line number Diff line
@@ -104,6 +104,124 @@ void free_avoid_memmap(void)
	}
}

#ifdef CONFIG_NOKASLR_MEM_RANGE
#define MAX_MEM_NOKASLR_REGIONS 4

struct mem_region {
	unsigned long long start;
	unsigned long long size;
};

static struct mem_region mem_nokaslr[MAX_MEM_NOKASLR_REGIONS];

void efi_parse_option_nokaslr_ranges(char *str)
{
	int i = 0;

	while (str && (i < MAX_MEM_NOKASLR_REGIONS)) {
		char *oldstr;
		u64 start, end;
		char *k = strchr(str, ',');

		if (k)
			*k++ = 0;

		oldstr = str;
		start = memparse(str, &str);
		if (str == oldstr || *str != '-') {
			efi_warn("Nokaslr values \"%s\" error.\n", oldstr);
			break;
		}
		end = memparse(str + 1, &str);
		if (start >= end) {
			efi_warn("Nokaslr values \"%s\" error, start >= end.\n", oldstr);
			break;
		}

		mem_nokaslr[i].start = start;
		mem_nokaslr[i].size = end - start;
		str = k;
		i++;
	}
}

static bool mem_overlaps(struct mem_region *one, struct mem_region *two)
{
	if (one->start + one->size <= two->start)
		return false;
	if (one->start >= two->start + two->size)
		return false;
	return true;
}

static bool mem_avoid_overlap(struct mem_region *region, struct mem_region *overlap)
{
	int i;
	u64 earliest = region->start + region->size;
	bool is_overlapping = false;

	for (i = 0; i < MAX_MEM_NOKASLR_REGIONS; i++) {
		if (mem_overlaps(region, &mem_nokaslr[i]) &&
		    mem_nokaslr[i].start < earliest) {
			*overlap = mem_nokaslr[i];
			earliest = overlap->start;
			is_overlapping = true;
		}
	}
	return is_overlapping;
}

unsigned long cal_slots_avoid_overlap(efi_memory_desc_t *md, unsigned long size, u8 cal_type,
					  unsigned long align_shift, unsigned long target)
{
	struct mem_region region, overlap;
	unsigned long region_end, first, last;
	unsigned long align = 1UL << align_shift;
	unsigned long total_slots = 0, slots;

	region.start = md->phys_addr;
	region_end = min(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - 1, (u64)ULONG_MAX);

	while (region.start < region_end) {
		first = round_up(region.start, align);
		last = round_down(region_end - size + 1, align);

		if (first > last)
			break;

		region.size = region_end - region.start + 1;

		if (!mem_avoid_overlap(&region, &overlap)) {
			slots = ((last - first) >> align_shift) + 1;
			total_slots += slots;

			if (cal_type == CAL_SLOTS_PHYADDR)
				return first + target * align;

			break;
		}

		if (overlap.start >= region.start + size) {
			slots = ((round_up(overlap.start - size + 1, align) - first) >>
				align_shift) + 1;
			total_slots += slots;

			if (cal_type == CAL_SLOTS_PHYADDR) {
				if (target > slots)
					target -= slots;
				else
					return first + target * align;
			}
		}

		/* Clip off the overlapping region and start over. */
		region.start = overlap.start + overlap.size;
	}

	return total_slots;
}
#endif

efi_status_t check_platform_features(void)
{
	u64 tg;
+6 −1
Original line number Diff line number Diff line
@@ -212,6 +212,11 @@ efi_status_t efi_parse_options(char const *cmdline)
			break;

		if (!strcmp(param, "nokaslr")) {
#if defined(CONFIG_NOKASLR_MEM_RANGE) && defined(CONFIG_ARM64)
			if (val)
				efi_parse_option_nokaslr_ranges(val);
			else
#endif
				efi_nokaslr = true;
		} else if (!strcmp(param, "quiet")) {
			efi_loglevel = CONSOLE_LOGLEVEL_QUIET;
Loading