Re: [PATCH v6 5/5] kaslr: add kaslr_mem=nn[KMG]!ss[KMG] to avoid memory regions

From: Baoquan He
Date: Tue Jan 16 2018 - 22:53:33 EST


On 01/16/18 at 11:34am, Luiz Capitulino wrote:
> On Tue, 16 Jan 2018 08:43:20 +0800
> Baoquan He <bhe@xxxxxxxxxx> wrote:
>
> > On 01/15/18 at 08:49pm, Chao Fan wrote:
> > > Hi Luiz,
> > >
> > > I don't know if this patch is OK for you.
> > > Of coure you can only use kaslr_mem=nn@ss to solve the 1G huge page
> > > issue. Because we know the region [0,1G] is not suitable for 1G huge
> > > page, so you can specify ksalr_mem=1G@0 of kaslr_mem=1G to solve
> > > your problem. But the regions may be too slow and is not good
> > > for the randomness.
> >
> > I guess you want to say:
> >
> > "Because we know the region [0,1G] is not suitable for 1G huge page, so
> > you can specify ksalr_mem=1G@0 or kaslr_mem=1G to solve your problem.
> > But the region may be too small and is not good for the randomness."
> >
> > Hi Luiz,
> >
> > For hugetlb issue, we can always suggest users adding "kaslr_mem=1G" to
> > kernel cmdline on KVM. Surely if users are very familiar with system
> > memory layout, they can specify "kaslr_mem=1G, kaslr_mem=1G@2G
> > kaslr_mem=1G@4G" for better kernel text KASLR. The "kaslr_mem=1G"
> > suggestion can be documented for redhat kvm usage. Any thought or
> > suggestion?
>
> I have to test it, but I'll only have time in one or two days.
>
> Btw, I think this series is a very good improvement over the current
> situation where the only option to solve the 1GB page problem is
> to disable kaslr entirely.
>
> However, I've discussed this problem with a few people and they think
> that it may be possible to change KASLR to extract the kernel to
> an already fragmented 1GB region, so that it doesn't split an otherwise
> good 1GB page. The advantage of this approach is that it's automatic
> and doesn't require the user to know the memory layout.

Hmm, I got what you mean. If we do in KALSR code, need parse kernel
cmdline to get hugepage information, and need find out those
unfragmented 1GB page, and this is only needed on KVM guest with small
memory, in fact with 4G memory. This is a cornor case. I am not sure if
it's good to only randomize kernel on the fragmented 1GB region, and
only under 4G region. I am not sure if it's good to do like that.

Thanks
Baoquan

> >
> > >
> > > So as Kess said, I put the regions suitable for 1G huge page to
> > > mem_avoid, you can use kaslr_mem=1G!1G to solve the problem in your
> > > email.
> > >
> > > Thanks,
> > > Chao Fan
> > >
> > > On Mon, Jan 15, 2018 at 08:40:16PM +0800, Chao Fan wrote:
> > > >In current code, kaslr choose the only suitable memory region for 1G
> > > >huge page, so the no suitable region for 1G huge page. So add this
> > > >feature to store these regions.
> > > >
> > > >Of coure, we can use memmap= to do this job. But memmap will be handled
> > > >in the later code, but kaslr_mem= only works in this period.
> > > >
> > > >It can help users to avoid more memory regions, not only the 1G huge
> > > >huge page issue.
> > > >
> > > >Signed-off-by: Chao Fan <fanc.fnst@xxxxxxxxxxxxxx>
> > > >---
> > > > arch/x86/boot/compressed/kaslr.c | 56 +++++++++++++++++++++++++++++++++++-----
> > > > 1 file changed, 50 insertions(+), 6 deletions(-)
> > > >
> > > >diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c
> > > >index fc531fa1f10c..c71189cf8d56 100644
> > > >--- a/arch/x86/boot/compressed/kaslr.c
> > > >+++ b/arch/x86/boot/compressed/kaslr.c
> > > >@@ -95,6 +95,18 @@ static bool memmap_too_large;
> > > > /* Store memory limit specified by "mem=nn[KMG]" or "memmap=nn[KMG]" */
> > > > unsigned long long mem_limit = ULLONG_MAX;
> > > >
> > > >+/*
> > > >+ * Only supporting at most 4 unusable memory regions for
> > > >+ * "kaslr_mem=nn[KMG]!ss[KMG]"
> > > >+ */
> > > >+#define MAX_KASLR_MEM_AVOID 4
> > > >+
> > > >+static bool kaslr_mem_avoid_too_large;
> > > >+
> > > >+enum kaslr_mem_type {
> > > >+ CMD_MEM_USABLE = 1,
> > > >+ CMD_MEM_AVOID,
> > > >+};
> > > >
> > > > enum mem_avoid_index {
> > > > MEM_AVOID_ZO_RANGE = 0,
> > > >@@ -103,6 +115,8 @@ enum mem_avoid_index {
> > > > MEM_AVOID_BOOTPARAMS,
> > > > MEM_AVOID_MEMMAP_BEGIN,
> > > > MEM_AVOID_MEMMAP_END = MEM_AVOID_MEMMAP_BEGIN + MAX_MEMMAP_REGIONS - 1,
> > > >+ MEM_AVOID_KASLR_MEM_BEGIN,
> > > >+ MEM_AVOID_KASLR_MEM_END = MEM_AVOID_KASLR_MEM_BEGIN + MAX_KASLR_MEM_AVOID - 1,
> > > > MEM_AVOID_MAX,
> > > > };
> > > >
> > > >@@ -217,7 +231,8 @@ static void mem_avoid_memmap(char *str)
> > > >
> > > > static int parse_kaslr_mem(char *p,
> > > > unsigned long long *start,
> > > >- unsigned long long *size)
> > > >+ unsigned long long *size,
> > > >+ int *cmd_type)
> > > > {
> > > > char *oldp;
> > > >
> > > >@@ -230,8 +245,13 @@ static int parse_kaslr_mem(char *p,
> > > > return -EINVAL;
> > > >
> > > > switch (*p) {
> > > >+ case '!' :
> > > >+ *start = memparse(p + 1, &p);
> > > >+ *cmd_type = CMD_MEM_AVOID;
> > > >+ return 0;
> > > > case '@':
> > > > *start = memparse(p + 1, &p);
> > > >+ *cmd_type = CMD_MEM_USABLE;
> > > > return 0;
> > > > default:
> > > > /*
> > > >@@ -240,6 +260,7 @@ static int parse_kaslr_mem(char *p,
> > > > * the region starts from 0.
> > > > */
> > > > *start = 0;
> > > >+ *cmd_type = CMD_MEM_USABLE;
> > > > return 0;
> > > > }
> > > >
> > > >@@ -248,26 +269,44 @@ static int parse_kaslr_mem(char *p,
> > > >
> > > > static void parse_kaslr_mem_regions(char *str)
> > > > {
> > > >- static int i;
> > > >+ static int i = 0, j = 0;
> > > >+ int cmd_type = 0;
> > > >
> > > > while (str && (i < MAX_KASLR_MEM_USABLE)) {
> > > > int rc;
> > > > unsigned long long start, size;
> > > > char *k = strchr(str, ',');
> > > >
> > > >+ if (i >= MAX_KASLR_MEM_USABLE && j >= MAX_KASLR_MEM_AVOID)
> > > >+ break;
> > > >+
> > > > if (k)
> > > > *k++ = 0;
> > > >
> > > >- rc = parse_kaslr_mem(str, &start, &size);
> > > >+ rc = parse_kaslr_mem(str, &start, &size, &cmd_type);
> > > > if (rc < 0)
> > > > break;
> > > > str = k;
> > > >
> > > >- mem_usable[i].start = start;
> > > >- mem_usable[i].size = size;
> > > >- i++;
> > > >+ if (cmd_type == CMD_MEM_USABLE) {
> > > >+ if (i >= MAX_KASLR_MEM_USABLE)
> > > >+ continue;
> > > >+ mem_usable[i].start = start;
> > > >+ mem_usable[i].size = size;
> > > >+ i++;
> > > >+ } else if (cmd_type == CMD_MEM_AVOID) {
> > > >+ if (j >= MAX_KASLR_MEM_AVOID)
> > > >+ continue;
> > > >+ mem_avoid[MEM_AVOID_KASLR_MEM_BEGIN + j].start = start;
> > > >+ mem_avoid[MEM_AVOID_KASLR_MEM_BEGIN + j].size = size;
> > > >+ j++;
> > > >+ }
> > > > }
> > > > num_usable_region = i;
> > > >+
> > > >+ /* More than 4 kaslr_mem avoid, fail kaslr */
> > > >+ if ((j >= MAX_KASLR_MEM_AVOID) && str)
> > > >+ kaslr_mem_avoid_too_large = true;
> > > > }
> > > >
> > > > static int handle_mem_filter(void)
> > > >@@ -799,6 +838,11 @@ static unsigned long find_random_phys_addr(unsigned long minimum,
> > > > return 0;
> > > > }
> > > >
> > > >+ /* Check if we had too many kaslr_mem avoid. */
> > > >+ if (kaslr_mem_avoid_too_large) {
> > > >+ debug_putstr("Aborted memory entries scan (more than 4 kaslr_mem avoid args)!\n");
> > > >+ return 0;
> > > >+ }
> > > > /* Make sure minimum is aligned. */
> > > > minimum = ALIGN(minimum, CONFIG_PHYSICAL_ALIGN);
> > > >
> > > >--
> > > >2.14.3
> > > >
> > >
> > >
> >
>