Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1527143 > unrolled thread
| Started by | Dave Jiang <dave.jiang@intel.com> |
|---|---|
| First post | 2016-11-22 01:30 +0100 |
| Last post | 2016-11-24 20:40 +0100 |
| Articles | 8 — 5 participants |
Back to article view | Back to linux.kernel
[PATCH] x86: fix kaslr and memmap collision Dave Jiang <dave.jiang@intel.com> - 2016-11-22 01:30 +0100
Re: [PATCH] x86: fix kaslr and memmap collision Ingo Molnar <mingo@kernel.org> - 2016-11-22 09:50 +0100
Re: [PATCH] x86: fix kaslr and memmap collision Dan Williams <dan.j.williams@intel.com> - 2016-11-22 18:40 +0100
Re: [PATCH] x86: fix kaslr and memmap collision Kees Cook <keescook@chromium.org> - 2016-11-22 20:00 +0100
Re: [PATCH] x86: fix kaslr and memmap collision Dan Williams <dan.j.williams@intel.com> - 2016-11-22 20:10 +0100
Re: [PATCH] x86: fix kaslr and memmap collision Kees Cook <keescook@chromium.org> - 2016-11-22 23:40 +0100
Re: [PATCH] x86: fix kaslr and memmap collision Dave Chinner <david@fromorbit.com> - 2016-11-24 01:10 +0100
Re: [PATCH] x86: fix kaslr and memmap collision Dan Williams <dan.j.williams@intel.com> - 2016-11-24 20:40 +0100
| From | Dave Jiang <dave.jiang@intel.com> |
|---|---|
| Date | 2016-11-22 01:30 +0100 |
| Subject | [PATCH] x86: fix kaslr and memmap collision |
| Message-ID | <sG78d-8kM-3@gated-at.bofh.it> |
CONFIG_RANDOMIZE_BASE relocates the kernel to a random base address.
However it does not take into account the memmap= parameter passed in from
the kernel commandline. This results in the kernel sometimes being put in
the middle of the user memmap. Check has been added in the kaslr in order
to avoid the region marked by memmap.
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
---
arch/x86/boot/boot.h | 2 ++
arch/x86/boot/compressed/kaslr.c | 45 ++++++++++++++++++++++++++++++++++++++
arch/x86/boot/string.c | 25 +++++++++++++++++++++
3 files changed, 72 insertions(+)
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
index e5612f3..0d5fe5b 100644
--- a/arch/x86/boot/boot.h
+++ b/arch/x86/boot/boot.h
@@ -332,6 +332,8 @@ int strncmp(const char *cs, const char *ct, size_t count);
size_t strnlen(const char *s, size_t maxlen);
unsigned int atou(const char *s);
unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base);
+unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base);
+long simple_strtol(const char *cp, char **endp, unsigned int base);
size_t strlen(const char *s);
/* tty.c */
diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c
index a66854d..6fb8f1ec 100644
--- a/arch/x86/boot/compressed/kaslr.c
+++ b/arch/x86/boot/compressed/kaslr.c
@@ -11,6 +11,7 @@
*/
#include "misc.h"
#include "error.h"
+#include "../boot.h"
#include <generated/compile.h>
#include <linux/module.h>
@@ -61,6 +62,7 @@ enum mem_avoid_index {
MEM_AVOID_INITRD,
MEM_AVOID_CMDLINE,
MEM_AVOID_BOOTPARAMS,
+ MEM_AVOID_MEMMAP,
MEM_AVOID_MAX,
};
@@ -77,6 +79,37 @@ static bool mem_overlaps(struct mem_vector *one, struct mem_vector *two)
return true;
}
+#include "../../../../lib/cmdline.c"
+
+static int
+parse_memmap(char *p, unsigned long long *start, unsigned long long *size)
+{
+ char *oldp;
+
+ if (!p)
+ return -EINVAL;
+
+ /* we don't care about this option here */
+ if (!strncmp(p, "exactmap", 8))
+ return -EINVAL;
+
+ oldp = p;
+ *size = memparse(p, &p);
+ if (p == oldp)
+ return -EINVAL;
+
+ switch (*p) {
+ case '@':
+ case '#':
+ case '$':
+ case '!':
+ *start = memparse(p+1, &p);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
/*
* In theory, KASLR can put the kernel anywhere in the range of [16M, 64T).
* The mem_avoid array is used to store the ranges that need to be avoided
@@ -158,6 +191,8 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
u64 initrd_start, initrd_size;
u64 cmd_line, cmd_line_size;
char *ptr;
+ char arg[38];
+ unsigned long long memmap_start, memmap_size;
/*
* Avoid the region that is unsafe to overlap during
@@ -195,6 +230,16 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
add_identity_map(mem_avoid[MEM_AVOID_BOOTPARAMS].start,
mem_avoid[MEM_AVOID_BOOTPARAMS].size);
+ /* see if we have any memmap areas */
+ if (cmdline_find_option("memmap", arg, sizeof(arg)) > 0) {
+ int rc = parse_memmap(arg, &memmap_start, &memmap_size);
+
+ if (!rc) {
+ mem_avoid[MEM_AVOID_MEMMAP].start = memmap_start;
+ mem_avoid[MEM_AVOID_MEMMAP].size = memmap_size;
+ }
+ }
+
/* We don't need to set a mapping for setup_data. */
#ifdef CONFIG_X86_VERBOSE_BOOTUP
diff --git a/arch/x86/boot/string.c b/arch/x86/boot/string.c
index cc3bd58..7a376c1 100644
--- a/arch/x86/boot/string.c
+++ b/arch/x86/boot/string.c
@@ -122,6 +122,31 @@ unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int bas
}
/**
+ * simple_strtoul - convert a string to an unsigned long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)
+{
+ return simple_strtoull(cp, endp, base);
+}
+
+/**
+ * simple_strtol - convert a string to a signed long
+ * @cp: The start of the string
+ * @endp: A pointer to the end of the parsed string will be placed here
+ * @base: The number base to use
+ */
+long simple_strtol(const char *cp, char **endp, unsigned int base)
+{
+ if (*cp == '-')
+ return -simple_strtoul(cp + 1, endp, base);
+
+ return simple_strtoul(cp, endp, base);
+}
+
+/**
* strlen - Find the length of a string
* @s: The string to be sized
*/
[toc] | [next] | [standalone]
| From | Ingo Molnar <mingo@kernel.org> |
|---|---|
| Date | 2016-11-22 09:50 +0100 |
| Message-ID | <sGeW5-4Pc-15@gated-at.bofh.it> |
| In reply to | #1527143 |
* Dave Jiang <dave.jiang@intel.com> wrote:
> CONFIG_RANDOMIZE_BASE relocates the kernel to a random base address.
> However it does not take into account the memmap= parameter passed in from
> the kernel commandline.
memmap= parameters are often used as a list.
> [...] This results in the kernel sometimes being put in the middle of the user
> memmap. [...]
What does this mean? If memmap= is used to re-define the memory map then the
kernel getting in the middle of a RAM area is what we want, isn't it? What we
don't want is for the kernel to get into reserved areas, right?
> [...] Check has been added in the kaslr in order to avoid the region marked by
> memmap.
What does this mean?
> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
> ---
> arch/x86/boot/boot.h | 2 ++
> arch/x86/boot/compressed/kaslr.c | 45 ++++++++++++++++++++++++++++++++++++++
> arch/x86/boot/string.c | 25 +++++++++++++++++++++
> 3 files changed, 72 insertions(+)
>
> diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
> index e5612f3..0d5fe5b 100644
> --- a/arch/x86/boot/boot.h
> +++ b/arch/x86/boot/boot.h
> @@ -332,6 +332,8 @@ int strncmp(const char *cs, const char *ct, size_t count);
> size_t strnlen(const char *s, size_t maxlen);
> unsigned int atou(const char *s);
> unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base);
> +unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base);
> +long simple_strtol(const char *cp, char **endp, unsigned int base);
> size_t strlen(const char *s);
>
> /* tty.c */
> diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c
> index a66854d..6fb8f1ec 100644
> --- a/arch/x86/boot/compressed/kaslr.c
> +++ b/arch/x86/boot/compressed/kaslr.c
> @@ -11,6 +11,7 @@
> */
> #include "misc.h"
> #include "error.h"
> +#include "../boot.h"
>
> #include <generated/compile.h>
> #include <linux/module.h>
> @@ -61,6 +62,7 @@ enum mem_avoid_index {
> MEM_AVOID_INITRD,
> MEM_AVOID_CMDLINE,
> MEM_AVOID_BOOTPARAMS,
> + MEM_AVOID_MEMMAP,
> MEM_AVOID_MAX,
> };
>
> @@ -77,6 +79,37 @@ static bool mem_overlaps(struct mem_vector *one, struct mem_vector *two)
> return true;
> }
>
> +#include "../../../../lib/cmdline.c"
> +
> +static int
> +parse_memmap(char *p, unsigned long long *start, unsigned long long *size)
> +{
> + char *oldp;
> +
> + if (!p)
> + return -EINVAL;
> +
> + /* we don't care about this option here */
> + if (!strncmp(p, "exactmap", 8))
> + return -EINVAL;
> +
> + oldp = p;
> + *size = memparse(p, &p);
> + if (p == oldp)
> + return -EINVAL;
> +
> + switch (*p) {
> + case '@':
> + case '#':
> + case '$':
> + case '!':
> + *start = memparse(p+1, &p);
> + return 0;
> + }
> +
> + return -EINVAL;
> +}
> +
> /*
> * In theory, KASLR can put the kernel anywhere in the range of [16M, 64T).
> * The mem_avoid array is used to store the ranges that need to be avoided
> @@ -158,6 +191,8 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
> u64 initrd_start, initrd_size;
> u64 cmd_line, cmd_line_size;
> char *ptr;
> + char arg[38];
Where does the magic '38' come from?
> + unsigned long long memmap_start, memmap_size;
>
> /*
> * Avoid the region that is unsafe to overlap during
> @@ -195,6 +230,16 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
> add_identity_map(mem_avoid[MEM_AVOID_BOOTPARAMS].start,
> mem_avoid[MEM_AVOID_BOOTPARAMS].size);
>
> + /* see if we have any memmap areas */
> + if (cmdline_find_option("memmap", arg, sizeof(arg)) > 0) {
> + int rc = parse_memmap(arg, &memmap_start, &memmap_size);
> +
> + if (!rc) {
> + mem_avoid[MEM_AVOID_MEMMAP].start = memmap_start;
> + mem_avoid[MEM_AVOID_MEMMAP].size = memmap_size;
> + }
> + }
> +
This only handles a single (first) memmap argument, is that sufficient?
Thanks,
Ingo
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2016-11-22 18:40 +0100 |
| Message-ID | <sGnd0-1Py-13@gated-at.bofh.it> |
| In reply to | #1527309 |
[ replying for Dave since he's offline today and tomorrow ]
On Tue, Nov 22, 2016 at 12:47 AM, Ingo Molnar <mingo@kernel.org> wrote:
>
> * Dave Jiang <dave.jiang@intel.com> wrote:
>
>> CONFIG_RANDOMIZE_BASE relocates the kernel to a random base address.
>> However it does not take into account the memmap= parameter passed in from
>> the kernel commandline.
>
> memmap= parameters are often used as a list.
>
>> [...] This results in the kernel sometimes being put in the middle of the user
>> memmap. [...]
>
> What does this mean? If memmap= is used to re-define the memory map then the
> kernel getting in the middle of a RAM area is what we want, isn't it? What we
> don't want is for the kernel to get into reserved areas, right?
Right, this is about teaching kaslr to not land the kernel in newly
defined reserved regions that were not marked reserved in the initial
e820 map from platform firmware.
>> [...] Check has been added in the kaslr in order to avoid the region marked by
>> memmap.
>
> What does this mean?
Is this clearer? "Update the set of 'mem_avoid' entries to exclude
'memmap=' defined reserved regions from the set of valid address range
to land the kernel image."
>
>> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
>> ---
>> arch/x86/boot/boot.h | 2 ++
>> arch/x86/boot/compressed/kaslr.c | 45 ++++++++++++++++++++++++++++++++++++++
>> arch/x86/boot/string.c | 25 +++++++++++++++++++++
>> 3 files changed, 72 insertions(+)
>>
>> diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
>> index e5612f3..0d5fe5b 100644
>> --- a/arch/x86/boot/boot.h
>> +++ b/arch/x86/boot/boot.h
>> @@ -332,6 +332,8 @@ int strncmp(const char *cs, const char *ct, size_t count);
>> size_t strnlen(const char *s, size_t maxlen);
>> unsigned int atou(const char *s);
>> unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base);
>> +unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base);
>> +long simple_strtol(const char *cp, char **endp, unsigned int base);
>> size_t strlen(const char *s);
>>
>> /* tty.c */
>> diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c
>> index a66854d..6fb8f1ec 100644
>> --- a/arch/x86/boot/compressed/kaslr.c
>> +++ b/arch/x86/boot/compressed/kaslr.c
>> @@ -11,6 +11,7 @@
>> */
>> #include "misc.h"
>> #include "error.h"
>> +#include "../boot.h"
>>
>> #include <generated/compile.h>
>> #include <linux/module.h>
>> @@ -61,6 +62,7 @@ enum mem_avoid_index {
>> MEM_AVOID_INITRD,
>> MEM_AVOID_CMDLINE,
>> MEM_AVOID_BOOTPARAMS,
>> + MEM_AVOID_MEMMAP,
>> MEM_AVOID_MAX,
>> };
>>
>> @@ -77,6 +79,37 @@ static bool mem_overlaps(struct mem_vector *one, struct mem_vector *two)
>> return true;
>> }
>>
>> +#include "../../../../lib/cmdline.c"
>> +
>> +static int
>> +parse_memmap(char *p, unsigned long long *start, unsigned long long *size)
>> +{
>> + char *oldp;
>> +
>> + if (!p)
>> + return -EINVAL;
>> +
>> + /* we don't care about this option here */
>> + if (!strncmp(p, "exactmap", 8))
>> + return -EINVAL;
>> +
>> + oldp = p;
>> + *size = memparse(p, &p);
>> + if (p == oldp)
>> + return -EINVAL;
>> +
>> + switch (*p) {
>> + case '@':
>> + case '#':
>> + case '$':
>> + case '!':
>> + *start = memparse(p+1, &p);
>> + return 0;
>> + }
>> +
>> + return -EINVAL;
>> +}
>> +
>> /*
>> * In theory, KASLR can put the kernel anywhere in the range of [16M, 64T).
>> * The mem_avoid array is used to store the ranges that need to be avoided
>> @@ -158,6 +191,8 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
>> u64 initrd_start, initrd_size;
>> u64 cmd_line, cmd_line_size;
>> char *ptr;
>> + char arg[38];
>
> Where does the magic '38' come from?
>
>> + unsigned long long memmap_start, memmap_size;
>>
>> /*
>> * Avoid the region that is unsafe to overlap during
>> @@ -195,6 +230,16 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
>> add_identity_map(mem_avoid[MEM_AVOID_BOOTPARAMS].start,
>> mem_avoid[MEM_AVOID_BOOTPARAMS].size);
>>
>> + /* see if we have any memmap areas */
>> + if (cmdline_find_option("memmap", arg, sizeof(arg)) > 0) {
>> + int rc = parse_memmap(arg, &memmap_start, &memmap_size);
>> +
>> + if (!rc) {
>> + mem_avoid[MEM_AVOID_MEMMAP].start = memmap_start;
>> + mem_avoid[MEM_AVOID_MEMMAP].size = memmap_size;
>> + }
>> + }
>> +
>
> This only handles a single (first) memmap argument, is that sufficient?
No, you're right, we need to handle multiple ranges. Since the
mem_avoid array is statically allocated perhaps we can handle up to 4
memmap= entries, but past that point disable kaslr for that boot?
[toc] | [prev] | [next] | [standalone]
| From | Kees Cook <keescook@chromium.org> |
|---|---|
| Date | 2016-11-22 20:00 +0100 |
| Message-ID | <sGosq-2Ad-19@gated-at.bofh.it> |
| In reply to | #1527752 |
On Tue, Nov 22, 2016 at 9:26 AM, Dan Williams <dan.j.williams@intel.com> wrote:
> [ replying for Dave since he's offline today and tomorrow ]
>
> On Tue, Nov 22, 2016 at 12:47 AM, Ingo Molnar <mingo@kernel.org> wrote:
>>
>> * Dave Jiang <dave.jiang@intel.com> wrote:
>>
>>> CONFIG_RANDOMIZE_BASE relocates the kernel to a random base address.
>>> However it does not take into account the memmap= parameter passed in from
>>> the kernel commandline.
>>
>> memmap= parameters are often used as a list.
>>
>>> [...] This results in the kernel sometimes being put in the middle of the user
>>> memmap. [...]
>>
>> What does this mean? If memmap= is used to re-define the memory map then the
>> kernel getting in the middle of a RAM area is what we want, isn't it? What we
>> don't want is for the kernel to get into reserved areas, right?
>
> Right, this is about teaching kaslr to not land the kernel in newly
> defined reserved regions that were not marked reserved in the initial
> e820 map from platform firmware.
>
>>> [...] Check has been added in the kaslr in order to avoid the region marked by
>>> memmap.
>>
>> What does this mean?
>
> Is this clearer? "Update the set of 'mem_avoid' entries to exclude
> 'memmap=' defined reserved regions from the set of valid address range
> to land the kernel image."
>
>>
>>> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
>>> ---
>>> arch/x86/boot/boot.h | 2 ++
>>> arch/x86/boot/compressed/kaslr.c | 45 ++++++++++++++++++++++++++++++++++++++
>>> arch/x86/boot/string.c | 25 +++++++++++++++++++++
>>> 3 files changed, 72 insertions(+)
>>>
>>> diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
>>> index e5612f3..0d5fe5b 100644
>>> --- a/arch/x86/boot/boot.h
>>> +++ b/arch/x86/boot/boot.h
>>> @@ -332,6 +332,8 @@ int strncmp(const char *cs, const char *ct, size_t count);
>>> size_t strnlen(const char *s, size_t maxlen);
>>> unsigned int atou(const char *s);
>>> unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base);
>>> +unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base);
>>> +long simple_strtol(const char *cp, char **endp, unsigned int base);
>>> size_t strlen(const char *s);
>>>
>>> /* tty.c */
>>> diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c
>>> index a66854d..6fb8f1ec 100644
>>> --- a/arch/x86/boot/compressed/kaslr.c
>>> +++ b/arch/x86/boot/compressed/kaslr.c
>>> @@ -11,6 +11,7 @@
>>> */
>>> #include "misc.h"
>>> #include "error.h"
>>> +#include "../boot.h"
>>>
>>> #include <generated/compile.h>
>>> #include <linux/module.h>
>>> @@ -61,6 +62,7 @@ enum mem_avoid_index {
>>> MEM_AVOID_INITRD,
>>> MEM_AVOID_CMDLINE,
>>> MEM_AVOID_BOOTPARAMS,
>>> + MEM_AVOID_MEMMAP,
>>> MEM_AVOID_MAX,
>>> };
>>>
>>> @@ -77,6 +79,37 @@ static bool mem_overlaps(struct mem_vector *one, struct mem_vector *two)
>>> return true;
>>> }
>>>
>>> +#include "../../../../lib/cmdline.c"
>>> +
>>> +static int
>>> +parse_memmap(char *p, unsigned long long *start, unsigned long long *size)
>>> +{
>>> + char *oldp;
>>> +
>>> + if (!p)
>>> + return -EINVAL;
>>> +
>>> + /* we don't care about this option here */
>>> + if (!strncmp(p, "exactmap", 8))
>>> + return -EINVAL;
>>> +
>>> + oldp = p;
>>> + *size = memparse(p, &p);
>>> + if (p == oldp)
>>> + return -EINVAL;
>>> +
>>> + switch (*p) {
>>> + case '@':
>>> + case '#':
>>> + case '$':
>>> + case '!':
>>> + *start = memparse(p+1, &p);
>>> + return 0;
>>> + }
>>> +
>>> + return -EINVAL;
>>> +}
>>> +
>>> /*
>>> * In theory, KASLR can put the kernel anywhere in the range of [16M, 64T).
>>> * The mem_avoid array is used to store the ranges that need to be avoided
>>> @@ -158,6 +191,8 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
>>> u64 initrd_start, initrd_size;
>>> u64 cmd_line, cmd_line_size;
>>> char *ptr;
>>> + char arg[38];
>>
>> Where does the magic '38' come from?
>>
>>> + unsigned long long memmap_start, memmap_size;
>>>
>>> /*
>>> * Avoid the region that is unsafe to overlap during
>>> @@ -195,6 +230,16 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
>>> add_identity_map(mem_avoid[MEM_AVOID_BOOTPARAMS].start,
>>> mem_avoid[MEM_AVOID_BOOTPARAMS].size);
>>>
>>> + /* see if we have any memmap areas */
>>> + if (cmdline_find_option("memmap", arg, sizeof(arg)) > 0) {
>>> + int rc = parse_memmap(arg, &memmap_start, &memmap_size);
>>> +
>>> + if (!rc) {
>>> + mem_avoid[MEM_AVOID_MEMMAP].start = memmap_start;
>>> + mem_avoid[MEM_AVOID_MEMMAP].size = memmap_size;
>>> + }
>>> + }
>>> +
>>
>> This only handles a single (first) memmap argument, is that sufficient?
>
> No, you're right, we need to handle multiple ranges. Since the
> mem_avoid array is statically allocated perhaps we can handle up to 4
> memmap= entries, but past that point disable kaslr for that boot?
Yeah, that seems fine to me. I assume it's rare to have 4?
-Kees
--
Kees Cook
Nexus Security
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2016-11-22 20:10 +0100 |
| Message-ID | <sGoC5-2SE-19@gated-at.bofh.it> |
| In reply to | #1527851 |
On Tue, Nov 22, 2016 at 10:54 AM, Kees Cook <keescook@chromium.org> wrote:
> On Tue, Nov 22, 2016 at 9:26 AM, Dan Williams <dan.j.williams@intel.com> wrote:
>> [ replying for Dave since he's offline today and tomorrow ]
>>
>> On Tue, Nov 22, 2016 at 12:47 AM, Ingo Molnar <mingo@kernel.org> wrote:
>>>
>>> * Dave Jiang <dave.jiang@intel.com> wrote:
>>>
>>>> CONFIG_RANDOMIZE_BASE relocates the kernel to a random base address.
>>>> However it does not take into account the memmap= parameter passed in from
>>>> the kernel commandline.
>>>
>>> memmap= parameters are often used as a list.
>>>
>>>> [...] This results in the kernel sometimes being put in the middle of the user
>>>> memmap. [...]
>>>
>>> What does this mean? If memmap= is used to re-define the memory map then the
>>> kernel getting in the middle of a RAM area is what we want, isn't it? What we
>>> don't want is for the kernel to get into reserved areas, right?
>>
>> Right, this is about teaching kaslr to not land the kernel in newly
>> defined reserved regions that were not marked reserved in the initial
>> e820 map from platform firmware.
>>
>>>> [...] Check has been added in the kaslr in order to avoid the region marked by
>>>> memmap.
>>>
>>> What does this mean?
>>
>> Is this clearer? "Update the set of 'mem_avoid' entries to exclude
>> 'memmap=' defined reserved regions from the set of valid address range
>> to land the kernel image."
>>
>>>
>>>> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
>>>> ---
>>>> arch/x86/boot/boot.h | 2 ++
>>>> arch/x86/boot/compressed/kaslr.c | 45 ++++++++++++++++++++++++++++++++++++++
>>>> arch/x86/boot/string.c | 25 +++++++++++++++++++++
>>>> 3 files changed, 72 insertions(+)
>>>>
>>>> diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
>>>> index e5612f3..0d5fe5b 100644
>>>> --- a/arch/x86/boot/boot.h
>>>> +++ b/arch/x86/boot/boot.h
>>>> @@ -332,6 +332,8 @@ int strncmp(const char *cs, const char *ct, size_t count);
>>>> size_t strnlen(const char *s, size_t maxlen);
>>>> unsigned int atou(const char *s);
>>>> unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base);
>>>> +unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base);
>>>> +long simple_strtol(const char *cp, char **endp, unsigned int base);
>>>> size_t strlen(const char *s);
>>>>
>>>> /* tty.c */
>>>> diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c
>>>> index a66854d..6fb8f1ec 100644
>>>> --- a/arch/x86/boot/compressed/kaslr.c
>>>> +++ b/arch/x86/boot/compressed/kaslr.c
>>>> @@ -11,6 +11,7 @@
>>>> */
>>>> #include "misc.h"
>>>> #include "error.h"
>>>> +#include "../boot.h"
>>>>
>>>> #include <generated/compile.h>
>>>> #include <linux/module.h>
>>>> @@ -61,6 +62,7 @@ enum mem_avoid_index {
>>>> MEM_AVOID_INITRD,
>>>> MEM_AVOID_CMDLINE,
>>>> MEM_AVOID_BOOTPARAMS,
>>>> + MEM_AVOID_MEMMAP,
>>>> MEM_AVOID_MAX,
>>>> };
>>>>
>>>> @@ -77,6 +79,37 @@ static bool mem_overlaps(struct mem_vector *one, struct mem_vector *two)
>>>> return true;
>>>> }
>>>>
>>>> +#include "../../../../lib/cmdline.c"
>>>> +
>>>> +static int
>>>> +parse_memmap(char *p, unsigned long long *start, unsigned long long *size)
>>>> +{
>>>> + char *oldp;
>>>> +
>>>> + if (!p)
>>>> + return -EINVAL;
>>>> +
>>>> + /* we don't care about this option here */
>>>> + if (!strncmp(p, "exactmap", 8))
>>>> + return -EINVAL;
>>>> +
>>>> + oldp = p;
>>>> + *size = memparse(p, &p);
>>>> + if (p == oldp)
>>>> + return -EINVAL;
>>>> +
>>>> + switch (*p) {
>>>> + case '@':
>>>> + case '#':
>>>> + case '$':
>>>> + case '!':
>>>> + *start = memparse(p+1, &p);
>>>> + return 0;
>>>> + }
>>>> +
>>>> + return -EINVAL;
>>>> +}
>>>> +
>>>> /*
>>>> * In theory, KASLR can put the kernel anywhere in the range of [16M, 64T).
>>>> * The mem_avoid array is used to store the ranges that need to be avoided
>>>> @@ -158,6 +191,8 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
>>>> u64 initrd_start, initrd_size;
>>>> u64 cmd_line, cmd_line_size;
>>>> char *ptr;
>>>> + char arg[38];
>>>
>>> Where does the magic '38' come from?
>>>
>>>> + unsigned long long memmap_start, memmap_size;
>>>>
>>>> /*
>>>> * Avoid the region that is unsafe to overlap during
>>>> @@ -195,6 +230,16 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
>>>> add_identity_map(mem_avoid[MEM_AVOID_BOOTPARAMS].start,
>>>> mem_avoid[MEM_AVOID_BOOTPARAMS].size);
>>>>
>>>> + /* see if we have any memmap areas */
>>>> + if (cmdline_find_option("memmap", arg, sizeof(arg)) > 0) {
>>>> + int rc = parse_memmap(arg, &memmap_start, &memmap_size);
>>>> +
>>>> + if (!rc) {
>>>> + mem_avoid[MEM_AVOID_MEMMAP].start = memmap_start;
>>>> + mem_avoid[MEM_AVOID_MEMMAP].size = memmap_size;
>>>> + }
>>>> + }
>>>> +
>>>
>>> This only handles a single (first) memmap argument, is that sufficient?
>>
>> No, you're right, we need to handle multiple ranges. Since the
>> mem_avoid array is statically allocated perhaps we can handle up to 4
>> memmap= entries, but past that point disable kaslr for that boot?
>
> Yeah, that seems fine to me. I assume it's rare to have 4?
>
It should be rare to have *one* since ACPI 6.0 added support for
communicating persistent memory ranges. However there are legacy
nvdimm users that I know are doing at least 2, but I have hard time
imagining they would ever do more than 4.
[toc] | [prev] | [next] | [standalone]
| From | Kees Cook <keescook@chromium.org> |
|---|---|
| Date | 2016-11-22 23:40 +0100 |
| Message-ID | <sGrTk-4Sy-7@gated-at.bofh.it> |
| In reply to | #1527855 |
On Tue, Nov 22, 2016 at 11:01 AM, Dan Williams <dan.j.williams@intel.com> wrote:
> On Tue, Nov 22, 2016 at 10:54 AM, Kees Cook <keescook@chromium.org> wrote:
>> On Tue, Nov 22, 2016 at 9:26 AM, Dan Williams <dan.j.williams@intel.com> wrote:
>>> [ replying for Dave since he's offline today and tomorrow ]
>>>
>>> On Tue, Nov 22, 2016 at 12:47 AM, Ingo Molnar <mingo@kernel.org> wrote:
>>>>
>>>> * Dave Jiang <dave.jiang@intel.com> wrote:
>>>>
>>>>> CONFIG_RANDOMIZE_BASE relocates the kernel to a random base address.
>>>>> However it does not take into account the memmap= parameter passed in from
>>>>> the kernel commandline.
>>>>
>>>> memmap= parameters are often used as a list.
>>>>
>>>>> [...] This results in the kernel sometimes being put in the middle of the user
>>>>> memmap. [...]
>>>>
>>>> What does this mean? If memmap= is used to re-define the memory map then the
>>>> kernel getting in the middle of a RAM area is what we want, isn't it? What we
>>>> don't want is for the kernel to get into reserved areas, right?
>>>
>>> Right, this is about teaching kaslr to not land the kernel in newly
>>> defined reserved regions that were not marked reserved in the initial
>>> e820 map from platform firmware.
>>>
>>>>> [...] Check has been added in the kaslr in order to avoid the region marked by
>>>>> memmap.
>>>>
>>>> What does this mean?
>>>
>>> Is this clearer? "Update the set of 'mem_avoid' entries to exclude
>>> 'memmap=' defined reserved regions from the set of valid address range
>>> to land the kernel image."
>>>
>>>>
>>>>> Signed-off-by: Dave Jiang <dave.jiang@intel.com>
>>>>> ---
>>>>> arch/x86/boot/boot.h | 2 ++
>>>>> arch/x86/boot/compressed/kaslr.c | 45 ++++++++++++++++++++++++++++++++++++++
>>>>> arch/x86/boot/string.c | 25 +++++++++++++++++++++
>>>>> 3 files changed, 72 insertions(+)
>>>>>
>>>>> diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
>>>>> index e5612f3..0d5fe5b 100644
>>>>> --- a/arch/x86/boot/boot.h
>>>>> +++ b/arch/x86/boot/boot.h
>>>>> @@ -332,6 +332,8 @@ int strncmp(const char *cs, const char *ct, size_t count);
>>>>> size_t strnlen(const char *s, size_t maxlen);
>>>>> unsigned int atou(const char *s);
>>>>> unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base);
>>>>> +unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base);
>>>>> +long simple_strtol(const char *cp, char **endp, unsigned int base);
>>>>> size_t strlen(const char *s);
>>>>>
>>>>> /* tty.c */
>>>>> diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c
>>>>> index a66854d..6fb8f1ec 100644
>>>>> --- a/arch/x86/boot/compressed/kaslr.c
>>>>> +++ b/arch/x86/boot/compressed/kaslr.c
>>>>> @@ -11,6 +11,7 @@
>>>>> */
>>>>> #include "misc.h"
>>>>> #include "error.h"
>>>>> +#include "../boot.h"
>>>>>
>>>>> #include <generated/compile.h>
>>>>> #include <linux/module.h>
>>>>> @@ -61,6 +62,7 @@ enum mem_avoid_index {
>>>>> MEM_AVOID_INITRD,
>>>>> MEM_AVOID_CMDLINE,
>>>>> MEM_AVOID_BOOTPARAMS,
>>>>> + MEM_AVOID_MEMMAP,
>>>>> MEM_AVOID_MAX,
>>>>> };
>>>>>
>>>>> @@ -77,6 +79,37 @@ static bool mem_overlaps(struct mem_vector *one, struct mem_vector *two)
>>>>> return true;
>>>>> }
>>>>>
>>>>> +#include "../../../../lib/cmdline.c"
>>>>> +
>>>>> +static int
>>>>> +parse_memmap(char *p, unsigned long long *start, unsigned long long *size)
>>>>> +{
>>>>> + char *oldp;
>>>>> +
>>>>> + if (!p)
>>>>> + return -EINVAL;
>>>>> +
>>>>> + /* we don't care about this option here */
>>>>> + if (!strncmp(p, "exactmap", 8))
>>>>> + return -EINVAL;
>>>>> +
>>>>> + oldp = p;
>>>>> + *size = memparse(p, &p);
>>>>> + if (p == oldp)
>>>>> + return -EINVAL;
>>>>> +
>>>>> + switch (*p) {
>>>>> + case '@':
>>>>> + case '#':
>>>>> + case '$':
>>>>> + case '!':
>>>>> + *start = memparse(p+1, &p);
>>>>> + return 0;
>>>>> + }
>>>>> +
>>>>> + return -EINVAL;
>>>>> +}
>>>>> +
>>>>> /*
>>>>> * In theory, KASLR can put the kernel anywhere in the range of [16M, 64T).
>>>>> * The mem_avoid array is used to store the ranges that need to be avoided
>>>>> @@ -158,6 +191,8 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
>>>>> u64 initrd_start, initrd_size;
>>>>> u64 cmd_line, cmd_line_size;
>>>>> char *ptr;
>>>>> + char arg[38];
>>>>
>>>> Where does the magic '38' come from?
>>>>
>>>>> + unsigned long long memmap_start, memmap_size;
>>>>>
>>>>> /*
>>>>> * Avoid the region that is unsafe to overlap during
>>>>> @@ -195,6 +230,16 @@ static void mem_avoid_init(unsigned long input, unsigned long input_size,
>>>>> add_identity_map(mem_avoid[MEM_AVOID_BOOTPARAMS].start,
>>>>> mem_avoid[MEM_AVOID_BOOTPARAMS].size);
>>>>>
>>>>> + /* see if we have any memmap areas */
>>>>> + if (cmdline_find_option("memmap", arg, sizeof(arg)) > 0) {
>>>>> + int rc = parse_memmap(arg, &memmap_start, &memmap_size);
>>>>> +
>>>>> + if (!rc) {
>>>>> + mem_avoid[MEM_AVOID_MEMMAP].start = memmap_start;
>>>>> + mem_avoid[MEM_AVOID_MEMMAP].size = memmap_size;
>>>>> + }
>>>>> + }
>>>>> +
>>>>
>>>> This only handles a single (first) memmap argument, is that sufficient?
>>>
>>> No, you're right, we need to handle multiple ranges. Since the
>>> mem_avoid array is statically allocated perhaps we can handle up to 4
>>> memmap= entries, but past that point disable kaslr for that boot?
>>
>> Yeah, that seems fine to me. I assume it's rare to have 4?
>>
>
> It should be rare to have *one* since ACPI 6.0 added support for
> communicating persistent memory ranges. However there are legacy
> nvdimm users that I know are doing at least 2, but I have hard time
> imagining they would ever do more than 4.
Cool. As long as it announces KASLR being disabled (as in some of the
other conditions) that should be fine.
-Kees
--
Kees Cook
Nexus Security
[toc] | [prev] | [next] | [standalone]
| From | Dave Chinner <david@fromorbit.com> |
|---|---|
| Date | 2016-11-24 01:10 +0100 |
| Message-ID | <sGPLX-3nP-11@gated-at.bofh.it> |
| In reply to | #1527855 |
On Tue, Nov 22, 2016 at 11:01:32AM -0800, Dan Williams wrote: > On Tue, Nov 22, 2016 at 10:54 AM, Kees Cook <keescook@chromium.org> wrote: > > On Tue, Nov 22, 2016 at 9:26 AM, Dan Williams <dan.j.williams@intel.com> wrote: > >> No, you're right, we need to handle multiple ranges. Since the > >> mem_avoid array is statically allocated perhaps we can handle up to 4 > >> memmap= entries, but past that point disable kaslr for that boot? > > > > Yeah, that seems fine to me. I assume it's rare to have 4? > > > > It should be rare to have *one* since ACPI 6.0 added support for > communicating persistent memory ranges. However there are legacy > nvdimm users that I know are doing at least 2, but I have hard time > imagining they would ever do more than 4. I doubt it's rare amongst the people using RAM to emulate pmem for filesystem testing purposes. My "pmem" test VM always has at least 2 ranges set to give me two discrete pmem devices, and I have used 4 from time to time to do things like test multi-volume scratch XFS filesystems in xfstests (i.e. data, log and realtime volumes) so I didn't need to play games with partitioning or DM... Cheers, Dave. -- Dave Chinner david@fromorbit.com
[toc] | [prev] | [next] | [standalone]
| From | Dan Williams <dan.j.williams@intel.com> |
|---|---|
| Date | 2016-11-24 20:40 +0100 |
| Message-ID | <sH82d-72F-3@gated-at.bofh.it> |
| In reply to | #1528873 |
On Wed, Nov 23, 2016 at 4:04 PM, Dave Chinner <david@fromorbit.com> wrote: > On Tue, Nov 22, 2016 at 11:01:32AM -0800, Dan Williams wrote: >> On Tue, Nov 22, 2016 at 10:54 AM, Kees Cook <keescook@chromium.org> wrote: >> > On Tue, Nov 22, 2016 at 9:26 AM, Dan Williams <dan.j.williams@intel.com> wrote: >> >> No, you're right, we need to handle multiple ranges. Since the >> >> mem_avoid array is statically allocated perhaps we can handle up to 4 >> >> memmap= entries, but past that point disable kaslr for that boot? >> > >> > Yeah, that seems fine to me. I assume it's rare to have 4? >> > >> >> It should be rare to have *one* since ACPI 6.0 added support for >> communicating persistent memory ranges. However there are legacy >> nvdimm users that I know are doing at least 2, but I have hard time >> imagining they would ever do more than 4. > > I doubt it's rare amongst the people using RAM to emulate pmem for > filesystem testing purposes. My "pmem" test VM always has at least 2 > ranges set to give me two discrete pmem devices, and I have used 4 > from time to time to do things like test multi-volume scratch XFS > filesystems in xfstests (i.e. data, log and realtime volumes) so I > didn't need to play games with partitioning or DM... Right, but for testing do you need kaslr to be active? You can have as many memmap regions as you want, we'll just stop trying to find a random kernel base address after you've defined 4.
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web