Re: [PATCH v6 5/5] kaslr: add kaslr_mem=nn[KMG]!ss[KMG] to avoid memory regions
From: Luiz Capitulino
Date: Tue Jan 16 2018 - 11:34:40 EST
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.
>
> 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
> > >
> >
> >
>