Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1362381 > unrolled thread

[PATCH v4 00/20] x86, boot: kaslr cleanup and 64bit kaslr support

Started byBaoquan He <bhe@redhat.com>
First post2016-03-22 08:40 +0100
Last post2016-03-23 23:50 +0100
Articles 11 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v4 00/20] x86, boot: kaslr cleanup and 64bit kaslr support Baoquan He <bhe@redhat.com> - 2016-03-22 08:40 +0100
    [PATCH v4 08/20] x86, kaslr: Get correct max_addr for relocs pointer Baoquan He <bhe@redhat.com> - 2016-03-22 08:40 +0100
      Re: [PATCH v4 08/20] x86, kaslr: Get correct max_addr for relocs pointer Kees Cook <keescook@chromium.org> - 2016-03-22 22:00 +0100
    [PATCH v4 19/20] x86, kaslr: Allow random address to be below loaded address Baoquan He <bhe@redhat.com> - 2016-03-22 08:40 +0100
      Re: [PATCH v4 19/20] x86, kaslr: Allow random address to be below  loaded address Kees Cook <keescook@chromium.org> - 2016-03-22 21:00 +0100
        Re: [PATCH v4 19/20] x86, kaslr: Allow random address to be below  loaded address Baoquan He <bhe@redhat.com> - 2016-03-23 02:50 +0100
      [PATCH v5 19/20] x86, kaslr: Allow random address to be below loaded  address Baoquan He <bhe@redhat.com> - 2016-03-23 10:00 +0100
    [PATCH v4 12/20] x86, boot: Add checking for memcpy Baoquan He <bhe@redhat.com> - 2016-03-22 08:40 +0100
    [PATCH v4 14/20] x86, kaslr: Add two functions which will be used later Baoquan He <bhe@redhat.com> - 2016-03-22 08:40 +0100
    Re: [PATCH v4 00/20] x86, boot: kaslr cleanup and 64bit kaslr support Kees Cook <keescook@chromium.org> - 2016-03-22 21:30 +0100
      Re: [PATCH v4 00/20] x86, boot: kaslr cleanup and 64bit kaslr support Kees Cook <keescook@chromium.org> - 2016-03-23 23:50 +0100

#1362381 — [PATCH v4 00/20] x86, boot: kaslr cleanup and 64bit kaslr support

FromBaoquan He <bhe@redhat.com>
Date2016-03-22 08:40 +0100
Subject[PATCH v4 00/20] x86, boot: kaslr cleanup and 64bit kaslr support
Message-ID<rfp4Z-1bB-5@gated-at.bofh.it>
***Background:
Previously a bug is reported that kdump didn't work when kaslr is enabled. During
discussing that bug fix, we found current kaslr has a limilation that it can
only randomize in 1GB region.

This is because in curent kaslr implementaion only physical address of kernel
loading is randomized. Then calculate the delta of physical address where
vmlinux was linked to load and where it is finally loaded. If delta is not
equal to 0, namely there's a new physical address where kernel is actually
decompressed, relocation handling need be done. Then delta is added to offset
of kernel symbol relocation, this makes the address of kernel text mapping move
delta long. Though in principle kernel can be randomized to any physical address,
kernel text mapping address space is limited and only 1G, namely as follows on
x86_64:
	[0xffffffff80000000, 0xffffffffc0000000)

In one word, kernel text physical address and virtual address randomization is
coupled. This causes the limitation.

Then hpa and Vivek suggested we should change this. To decouple the physical
address and virtual address randomization of kernel text and let them work
separately. Then kernel text physical address can be randomized in region
[16M, 64T), and kernel text virtual address can be randomized in region
[0xffffffff80000000, 0xffffffffc0000000).

***Problems we need solved:
  - For kernel boot from startup_32 case, only 0~4G identity mapping is built.
    If kernel will be randomly put anywhere from 16M to 64T at most, the price
    to build all region of identity mapping is too high. We need build the
    identity mapping on demand, not covering all physical address space.

  - Decouple the physical address and virtual address randomization of kernel
    text and let them work separately.

***Parts:
   - The 1st part is Yinghai's identity mapping building on demand patches.
     This is used to solve the first problem mentioned above.
     (Patch 09-10/19)
   - The 2nd part is decoupling the physical address and virtual address
     randomization of kernel text and letting them work separately patches
     based on Yinghai's ident mapping patches.
     (Patch 12-19/19)
   - The 3rd part is some clean up patches which Yinghai found when he reviewed
     my patches and the related code around.
     (Patch 01-08/19)

***Patch status:
This patchset went through several rounds of review.

    v1:
    - The first round can be found here:
	https://lwn.net/Articles/637115/

    v1->v2:
    - In 2nd round Yinghai made a big patchset including this kaslr fix and another
      setup_data related fix. The link is here:
       http://lists-archives.com/linux-kernel/28346903-x86-updated-patches-for-kaslr-and-setup_data-etc-for-v4-3.html
      You can get the code from Yinghai's git branch:
      git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-x86-v4.3-next

    v2->v3:
    - It only takes care of the kaslr related patches.
      For reviewers it's better to discuss only one issue in one thread.
        * I take off one patch as follows from Yinghai's because I think it's unnecessay. 
           - Patch 05/19 x86, kaslr: rename output_size to output_run_size
             output_size is enough to represen the value:
         	output_len > run_size ? output_len : run_size
       
        * I add Patch 04/19, it's a comment update patch. For other patches, I just
          adjust patch log and do several places of change comparing with 2nd round.
          Please check the change log under patch log of each patch for details.

        * Adjust sequence of several patches to make review easier. It doesn't
          affect codes.

    v3->v4:
    - Made changes according to Kees's comments.
      Add one patch 20/20 as Kees suggested to use KERNEL_IMAGE_SIZE as offset
      max of virtual random, meanwhile clean up useless CONFIG_RANDOM_OFFSET_MAX

        x86, kaslr: Use KERNEL_IMAGE_SIZE as the offset max for kernel virtual randomization

You can also get this patchset from my github:
   https://github.com/baoquan-he/linux.git kaslr-above-4G

Any comments about code changes, code comments, patch logs are welcome and
appreciated.

Baoquan He (9):
  x86, kaslr: Fix a bug that relocation can not be handled when kernel
    is loaded above 2G
  x86, kaskr: Update the description for decompressor worst case
  x86, kaslr: Introduce struct slot_area to manage randomization slot
    info
  x86, kaslr: Add two functions which will be used later
  x86, kaslr: Introduce fetch_random_virt_offset to randomize the kernel
    text mapping address
  x86, kaslr: Randomize physical and virtual address of kernel
    separately
  x86, kaslr: Add support of kernel physical address randomization above
    4G
  x86, kaslr: Remove useless codes
  x86, kaslr: Use KERNEL_IMAGE_SIZE as the offset max for kernel virtual
    randomization

Yinghai Lu (11):
  x86, kaslr: Remove not needed parameter for choose_kernel_location
  x86, boot: Move compressed kernel to end of buffer before
    decompressing
  x86, boot: Move z_extract_offset calculation to header.S
  x86, boot: Fix run_size calculation
  x86, kaslr: Clean up useless code related to run_size.
  x86, kaslr: Get correct max_addr for relocs pointer
  x86, kaslr: Consolidate mem_avoid array filling
  x86, boot: Split kernel_ident_mapping_init to another file
  x86, 64bit: Set ident_mapping for kaslr
  x86, boot: Add checking for memcpy
  x86, kaslr: Allow random address to be below loaded address

 arch/x86/Kconfig                       |  57 +++----
 arch/x86/boot/Makefile                 |  13 +-
 arch/x86/boot/compressed/Makefile      |  19 ++-
 arch/x86/boot/compressed/aslr.c        | 300 +++++++++++++++++++++++++--------
 arch/x86/boot/compressed/head_32.S     |  14 +-
 arch/x86/boot/compressed/head_64.S     |  15 +-
 arch/x86/boot/compressed/misc.c        |  89 +++++-----
 arch/x86/boot/compressed/misc.h        |  34 ++--
 arch/x86/boot/compressed/misc_pgt.c    |  93 ++++++++++
 arch/x86/boot/compressed/mkpiggy.c     |  28 +--
 arch/x86/boot/compressed/string.c      |  29 +++-
 arch/x86/boot/compressed/vmlinux.lds.S |   1 +
 arch/x86/boot/header.S                 |  22 ++-
 arch/x86/include/asm/boot.h            |  19 +++
 arch/x86/include/asm/page.h            |   5 +
 arch/x86/include/asm/page_64_types.h   |   5 +-
 arch/x86/kernel/asm-offsets.c          |   1 +
 arch/x86/kernel/vmlinux.lds.S          |   1 +
 arch/x86/mm/ident_map.c                |  74 ++++++++
 arch/x86/mm/init_32.c                  |   3 -
 arch/x86/mm/init_64.c                  |  74 +-------
 arch/x86/tools/calc_run_size.sh        |  42 -----
 22 files changed, 605 insertions(+), 333 deletions(-)
 create mode 100644 arch/x86/boot/compressed/misc_pgt.c
 create mode 100644 arch/x86/mm/ident_map.c
 delete mode 100644 arch/x86/tools/calc_run_size.sh

-- 
2.5.0

[toc] | [next] | [standalone]


#1362382 — [PATCH v4 08/20] x86, kaslr: Get correct max_addr for relocs pointer

FromBaoquan He <bhe@redhat.com>
Date2016-03-22 08:40 +0100
Subject[PATCH v4 08/20] x86, kaslr: Get correct max_addr for relocs pointer
Message-ID<rfp51-1bB-41@gated-at.bofh.it>
In reply to#1362381
From: Yinghai Lu <yinghai@kernel.org>

Relocation handling performs bounds checking on the relocated
addresses. The existing code uses output_len (VO size plus relocs
size) as the max address. This is not right since the max_addr check
should stop at the end of VO and exclude bss, brk, etc, which follows.
The valid range should be VO [_text, __bss_start] in the loaded
physical address space.

In this patch, add export for __bss_start to voffset.h and use it to
get the correct max_addr.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Baoquan He <bhe@redhat.com>
---
v2->v3:
    Adjust patch log.
v3->v4:
    Kees help rewrite the patch log

 arch/x86/boot/compressed/Makefile | 2 +-
 arch/x86/boot/compressed/misc.c   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index fef80fa..2e7c0ce 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -41,7 +41,7 @@ LDFLAGS_vmlinux := -T
 hostprogs-y	:= mkpiggy
 HOST_EXTRACFLAGS += -I$(srctree)/tools/include
 
-sed-voffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(_text\|_end\)$$/\#define VO_\2 _AC(0x\1,UL)/p'
+sed-voffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(_text\|__bss_start\|_end\)$$/\#define VO_\2 _AC(0x\1,UL)/p'
 
 quiet_cmd_voffset = VOFFSET $@
       cmd_voffset = $(NM) $< | sed -n $(sed-voffset) > $@
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index def6207..029f42f 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -259,7 +259,7 @@ static void handle_relocations(void *output, unsigned long output_len)
 	int *reloc;
 	unsigned long delta, map, ptr;
 	unsigned long min_addr = (unsigned long)output;
-	unsigned long max_addr = min_addr + output_len;
+	unsigned long max_addr = min_addr + (VO___bss_start - VO__text);
 
 	/*
 	 * Calculate the delta between where vmlinux was linked to load
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1362971 — Re: [PATCH v4 08/20] x86, kaslr: Get correct max_addr for relocs pointer

FromKees Cook <keescook@chromium.org>
Date2016-03-22 22:00 +0100
SubjectRe: [PATCH v4 08/20] x86, kaslr: Get correct max_addr for relocs pointer
Message-ID<rfBzc-1rA-9@gated-at.bofh.it>
In reply to#1362382
On Tue, Mar 22, 2016 at 12:32 AM, Baoquan He <bhe@redhat.com> wrote:
> From: Yinghai Lu <yinghai@kernel.org>
>
> Relocation handling performs bounds checking on the relocated
> addresses. The existing code uses output_len (VO size plus relocs
> size) as the max address. This is not right since the max_addr check
> should stop at the end of VO and exclude bss, brk, etc, which follows.
> The valid range should be VO [_text, __bss_start] in the loaded
> physical address space.
>
> In this patch, add export for __bss_start to voffset.h and use it to
> get the correct max_addr.
>
> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
> Cc: Baoquan He <bhe@redhat.com>

Acked-by: Kees Cook <keescook@chromium.org>

-Kees

> ---
> v2->v3:
>     Adjust patch log.
> v3->v4:
>     Kees help rewrite the patch log
>
>  arch/x86/boot/compressed/Makefile | 2 +-
>  arch/x86/boot/compressed/misc.c   | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> index fef80fa..2e7c0ce 100644
> --- a/arch/x86/boot/compressed/Makefile
> +++ b/arch/x86/boot/compressed/Makefile
> @@ -41,7 +41,7 @@ LDFLAGS_vmlinux := -T
>  hostprogs-y    := mkpiggy
>  HOST_EXTRACFLAGS += -I$(srctree)/tools/include
>
> -sed-voffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(_text\|_end\)$$/\#define VO_\2 _AC(0x\1,UL)/p'
> +sed-voffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(_text\|__bss_start\|_end\)$$/\#define VO_\2 _AC(0x\1,UL)/p'
>
>  quiet_cmd_voffset = VOFFSET $@
>        cmd_voffset = $(NM) $< | sed -n $(sed-voffset) > $@
> diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
> index def6207..029f42f 100644
> --- a/arch/x86/boot/compressed/misc.c
> +++ b/arch/x86/boot/compressed/misc.c
> @@ -259,7 +259,7 @@ static void handle_relocations(void *output, unsigned long output_len)
>         int *reloc;
>         unsigned long delta, map, ptr;
>         unsigned long min_addr = (unsigned long)output;
> -       unsigned long max_addr = min_addr + output_len;
> +       unsigned long max_addr = min_addr + (VO___bss_start - VO__text);
>
>         /*
>          * Calculate the delta between where vmlinux was linked to load
> --
> 2.5.0
>



-- 
Kees Cook
Chrome OS & Brillo Security

[toc] | [prev] | [next] | [standalone]


#1362383 — [PATCH v4 19/20] x86, kaslr: Allow random address to be below loaded address

FromBaoquan He <bhe@redhat.com>
Date2016-03-22 08:40 +0100
Subject[PATCH v4 19/20] x86, kaslr: Allow random address to be below loaded address
Message-ID<rfp51-1bB-47@gated-at.bofh.it>
In reply to#1362381
From: Yinghai Lu <yinghai@kernel.org>

Now new randomized output can only be chosen from regions above loaded
address. In this case, for bootloaders like kexec which always loads
kernel near the end of ram, it doesn't do randomization at all. Or kernel
is loaded in a very big starting address, we should not give up that area
is loaded in a very large address, then the area below the large loaded
address will be given up. This is not reasonable.

With correct tracking in mem_avoid  we can allow random output below
loaded address. With this change, though kexec can get random ouput
below its loaded address of kernel.

Now we just pick 512M as min_addr. If kernel loaded address is bigger than
512M, E.g 8G. Then [512M, 8G) can be added into random output candidate area.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
 arch/x86/boot/compressed/aslr.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
index ddfc3d0..d072ca7 100644
--- a/arch/x86/boot/compressed/aslr.c
+++ b/arch/x86/boot/compressed/aslr.c
@@ -446,7 +446,8 @@ void choose_kernel_location(unsigned char *input,
 				unsigned long output_size,
 				unsigned char **virt_offset)
 {
-	unsigned long random;
+	unsigned long random, min_addr;
+
 	*virt_offset = (unsigned char *)LOAD_PHYSICAL_ADDR;
 
 #ifdef CONFIG_HIBERNATION
@@ -467,8 +468,13 @@ void choose_kernel_location(unsigned char *input,
 	mem_avoid_init((unsigned long)input, input_size,
 		       (unsigned long)*output);
 
+	/* start from 512M */
+	min_addr = (unsigned long)*output;
+	if (min_addr > (512UL<<20))
+		min_addr = 512UL<<20;
+
 	/* Walk e820 and find a random address. */
-	random = find_random_phy_addr((unsigned long)*output, output_size);
+	random = find_random_phy_addr(min_addr, output_size);
 	if (!random)
 		debug_putstr("KASLR could not find suitable E820 region...\n");
 	else {
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1362936 — Re: [PATCH v4 19/20] x86, kaslr: Allow random address to be below loaded address

FromKees Cook <keescook@chromium.org>
Date2016-03-22 21:00 +0100
SubjectRe: [PATCH v4 19/20] x86, kaslr: Allow random address to be below loaded address
Message-ID<rfAD9-QP-25@gated-at.bofh.it>
In reply to#1362383
On Tue, Mar 22, 2016 at 12:32 AM, Baoquan He <bhe@redhat.com> wrote:
> From: Yinghai Lu <yinghai@kernel.org>
>
> Now new randomized output can only be chosen from regions above loaded
> address. In this case, for bootloaders like kexec which always loads
> kernel near the end of ram, it doesn't do randomization at all. Or kernel
> is loaded in a very big starting address, we should not give up that area
> is loaded in a very large address, then the area below the large loaded
> address will be given up. This is not reasonable.
>
> With correct tracking in mem_avoid  we can allow random output below
> loaded address. With this change, though kexec can get random ouput
> below its loaded address of kernel.
>
> Now we just pick 512M as min_addr. If kernel loaded address is bigger than
> 512M, E.g 8G. Then [512M, 8G) can be added into random output candidate area.
>
> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
> ---
>  arch/x86/boot/compressed/aslr.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
> index ddfc3d0..d072ca7 100644
> --- a/arch/x86/boot/compressed/aslr.c
> +++ b/arch/x86/boot/compressed/aslr.c
> @@ -446,7 +446,8 @@ void choose_kernel_location(unsigned char *input,
>                                 unsigned long output_size,
>                                 unsigned char **virt_offset)
>  {
> -       unsigned long random;
> +       unsigned long random, min_addr;
> +
>         *virt_offset = (unsigned char *)LOAD_PHYSICAL_ADDR;
>
>  #ifdef CONFIG_HIBERNATION
> @@ -467,8 +468,13 @@ void choose_kernel_location(unsigned char *input,
>         mem_avoid_init((unsigned long)input, input_size,
>                        (unsigned long)*output);
>
> +       /* start from 512M */
> +       min_addr = (unsigned long)*output;
> +       if (min_addr > (512UL<<20))
> +               min_addr = 512UL<<20;

The goal is to find a minimum address? I'm not sure this comment makes
sense. Shouldn't this be:

    /* Lower minimum to 512M. */
   min_addr = min_t(unsigned long, *output, 512UL << 20);

Or something like that?

> +
>         /* Walk e820 and find a random address. */
> -       random = find_random_phy_addr((unsigned long)*output, output_size);
> +       random = find_random_phy_addr(min_addr, output_size);
>         if (!random)
>                 debug_putstr("KASLR could not find suitable E820 region...\n");
>         else {
> --
> 2.5.0
>

-Kees

-- 
Kees Cook
Chrome OS & Brillo Security

[toc] | [prev] | [next] | [standalone]


#1363158 — Re: [PATCH v4 19/20] x86, kaslr: Allow random address to be below loaded address

FromBaoquan He <bhe@redhat.com>
Date2016-03-23 02:50 +0100
SubjectRe: [PATCH v4 19/20] x86, kaslr: Allow random address to be below loaded address
Message-ID<rfG5P-4yd-3@gated-at.bofh.it>
In reply to#1362936
On 03/22/16 at 12:54pm, Kees Cook wrote:
> On Tue, Mar 22, 2016 at 12:32 AM, Baoquan He <bhe@redhat.com> wrote:
> > From: Yinghai Lu <yinghai@kernel.org>
> >
> > Now new randomized output can only be chosen from regions above loaded
> > address. In this case, for bootloaders like kexec which always loads
> > kernel near the end of ram, it doesn't do randomization at all. Or kernel
> > is loaded in a very big starting address, we should not give up that area
> > is loaded in a very large address, then the area below the large loaded
> > address will be given up. This is not reasonable.
> >
> > With correct tracking in mem_avoid  we can allow random output below
> > loaded address. With this change, though kexec can get random ouput
> > below its loaded address of kernel.
> >
> > Now we just pick 512M as min_addr. If kernel loaded address is bigger than
> > 512M, E.g 8G. Then [512M, 8G) can be added into random output candidate area.
> >
> > Signed-off-by: Yinghai Lu <yinghai@kernel.org>
> > ---
> >  arch/x86/boot/compressed/aslr.c | 10 ++++++++--
> >  1 file changed, 8 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
> > index ddfc3d0..d072ca7 100644
> > --- a/arch/x86/boot/compressed/aslr.c
> > +++ b/arch/x86/boot/compressed/aslr.c
> > @@ -446,7 +446,8 @@ void choose_kernel_location(unsigned char *input,
> >                                 unsigned long output_size,
> >                                 unsigned char **virt_offset)
> >  {
> > -       unsigned long random;
> > +       unsigned long random, min_addr;
> > +
> >         *virt_offset = (unsigned char *)LOAD_PHYSICAL_ADDR;
> >
> >  #ifdef CONFIG_HIBERNATION
> > @@ -467,8 +468,13 @@ void choose_kernel_location(unsigned char *input,
> >         mem_avoid_init((unsigned long)input, input_size,
> >                        (unsigned long)*output);
> >
> > +       /* start from 512M */
> > +       min_addr = (unsigned long)*output;
> > +       if (min_addr > (512UL<<20))
> > +               min_addr = 512UL<<20;
> 
> The goal is to find a minimum address? I'm not sure this comment makes
> sense. Shouldn't this be:
> 
>     /* Lower minimum to 512M. */
>    min_addr = min_t(unsigned long, *output, 512UL << 20);
> 
> Or something like that?

Yes, the goal is to lower minimum to 512M. It's better to change it to
"Lower minimum to 512M" as you suggested. I will resend a new one with
this update into this thread.

Thanks a lot for your great suggestion for patch log, code change and
patch rearranging, and also appreciate your encouragement and patience.

Thanks
Baoquan

> 
> > +
> >         /* Walk e820 and find a random address. */
> > -       random = find_random_phy_addr((unsigned long)*output, output_size);
> > +       random = find_random_phy_addr(min_addr, output_size);
> >         if (!random)
> >                 debug_putstr("KASLR could not find suitable E820 region...\n");
> >         else {
> > --
> > 2.5.0
> >
> 
> -Kees
> 
> -- 
> Kees Cook
> Chrome OS & Brillo Security

[toc] | [prev] | [next] | [standalone]


#1363262 — [PATCH v5 19/20] x86, kaslr: Allow random address to be below loaded address

FromBaoquan He <bhe@redhat.com>
Date2016-03-23 10:00 +0100
Subject[PATCH v5 19/20] x86, kaslr: Allow random address to be below loaded address
Message-ID<rfMNZ-RM-15@gated-at.bofh.it>
In reply to#1362383
Now new randomized output can only be chosen from regions above loaded
address. In this case, for bootloaders like kexec which always loads
kernel near the end of ram, it doesn't do randomization at all. Or kernel
is loaded in a very big starting address, we should not give up that area
is loaded in a very large address, then the area below the large loaded
address will be given up. This is not reasonable.

With correct tracking in mem_avoid  we can allow random output below
loaded address. With this change, though kexec can get random ouput
below its loaded address of kernel.

Now we just pick 512M as min_addr. If kernel loaded address is bigger than
512M, E.g 8G. Then [512M, 8G) can be added into random output candidate area.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
---
v4->v5:
    Kees suggested changing the code comment related to minimum address
    to make it more understandable.

 arch/x86/boot/compressed/aslr.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
index ddfc3d0..bbd2d06 100644
--- a/arch/x86/boot/compressed/aslr.c
+++ b/arch/x86/boot/compressed/aslr.c
@@ -446,7 +446,8 @@ void choose_kernel_location(unsigned char *input,
 				unsigned long output_size,
 				unsigned char **virt_offset)
 {
-	unsigned long random;
+	unsigned long random, min_addr;
+
 	*virt_offset = (unsigned char *)LOAD_PHYSICAL_ADDR;
 
 #ifdef CONFIG_HIBERNATION
@@ -467,8 +468,13 @@ void choose_kernel_location(unsigned char *input,
 	mem_avoid_init((unsigned long)input, input_size,
 		       (unsigned long)*output);
 
+	/* Lower minimum to 512M. */
+	min_addr = (unsigned long)*output;
+	if (min_addr > (512UL<<20))
+		min_addr = 512UL<<20;
+
 	/* Walk e820 and find a random address. */
-	random = find_random_phy_addr((unsigned long)*output, output_size);
+	random = find_random_phy_addr(min_addr, output_size);
 	if (!random)
 		debug_putstr("KASLR could not find suitable E820 region...\n");
 	else {
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1362384 — [PATCH v4 12/20] x86, boot: Add checking for memcpy

FromBaoquan He <bhe@redhat.com>
Date2016-03-22 08:40 +0100
Subject[PATCH v4 12/20] x86, boot: Add checking for memcpy
Message-ID<rfp51-1bB-49@gated-at.bofh.it>
In reply to#1362381
From: Yinghai Lu <yinghai@kernel.org>

parse_elf is using local memcpy to move section to running position.
That memcpy actually only support no overlapping case or when dest < src.

Add checking in memcpy to find out the wrong case for future use, at
that time we will need to have backward memcpy for it.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
v2->v3:
    Add a declaration for error() since its declaration is in misc.h.
    But it's not included in compressed/string.c.
v3->v4:
    Remove the meanless code comment in error() as Kees suggested.

 arch/x86/boot/compressed/misc.c   |  9 ++-------
 arch/x86/boot/compressed/misc.h   |  2 ++
 arch/x86/boot/compressed/string.c | 29 +++++++++++++++++++++++++++--
 3 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 029f42f..c5f0ecf 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -114,9 +114,6 @@
 #undef memset
 #define memzero(s, n)	memset((s), 0, (n))
 
-
-static void error(char *m);
-
 /*
  * This is set up by the setup-routine at boot-time
  */
@@ -243,7 +240,7 @@ void __puthex(unsigned long value)
 	}
 }
 
-static void error(char *x)
+void error(char *x)
 {
 	error_putstr("\n\n");
 	error_putstr(x);
@@ -378,9 +375,7 @@ static void parse_elf(void *output)
 #else
 			dest = (void *)(phdr->p_paddr);
 #endif
-			memcpy(dest,
-			       output + phdr->p_offset,
-			       phdr->p_filesz);
+			memcpy(dest, output + phdr->p_offset, phdr->p_filesz);
 			break;
 		default: /* Ignore other PT_* */ break;
 		}
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
index 11736a6..39d0e9a 100644
--- a/arch/x86/boot/compressed/misc.h
+++ b/arch/x86/boot/compressed/misc.h
@@ -38,6 +38,8 @@ void __puthex(unsigned long value);
 #define error_putstr(__x)  __putstr(__x)
 #define error_puthex(__x)  __puthex(__x)
 
+void error(char *x);
+
 #ifdef CONFIG_X86_VERBOSE_BOOTUP
 
 #define debug_putstr(__x)  __putstr(__x)
diff --git a/arch/x86/boot/compressed/string.c b/arch/x86/boot/compressed/string.c
index 00e788b..3a935d0 100644
--- a/arch/x86/boot/compressed/string.c
+++ b/arch/x86/boot/compressed/string.c
@@ -1,7 +1,7 @@
 #include "../string.c"
 
 #ifdef CONFIG_X86_32
-void *memcpy(void *dest, const void *src, size_t n)
+void *__memcpy(void *dest, const void *src, size_t n)
 {
 	int d0, d1, d2;
 	asm volatile(
@@ -15,7 +15,7 @@ void *memcpy(void *dest, const void *src, size_t n)
 	return dest;
 }
 #else
-void *memcpy(void *dest, const void *src, size_t n)
+void *__memcpy(void *dest, const void *src, size_t n)
 {
 	long d0, d1, d2;
 	asm volatile(
@@ -30,6 +30,31 @@ void *memcpy(void *dest, const void *src, size_t n)
 }
 #endif
 
+extern void error(char *x);
+void *memcpy(void *dest, const void *src, size_t n)
+{
+	unsigned long start_dest, end_dest;
+	unsigned long start_src, end_src;
+	unsigned long max_start, min_end;
+
+	if (dest < src)
+		return __memcpy(dest, src, n);
+
+	start_dest = (unsigned long)dest;
+	end_dest = (unsigned long)dest + n;
+	start_src = (unsigned long)src;
+	end_src = (unsigned long)src + n;
+	max_start = (start_dest > start_src) ?  start_dest : start_src;
+	min_end = (end_dest < end_src) ? end_dest : end_src;
+
+	if (max_start >= min_end)
+		return __memcpy(dest, src, n);
+
+	error("memcpy does not support overlapping with dest > src!\n");
+
+	return dest;
+}
+
 void *memset(void *s, int c, size_t n)
 {
 	int i;
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1362386 — [PATCH v4 14/20] x86, kaslr: Add two functions which will be used later

FromBaoquan He <bhe@redhat.com>
Date2016-03-22 08:40 +0100
Subject[PATCH v4 14/20] x86, kaslr: Add two functions which will be used later
Message-ID<rfp51-1bB-45@gated-at.bofh.it>
In reply to#1362381
Function store_slot_info() is used to calculate the slot info of passed
in memory region and store it into slot_areas[].

Function mem_min_overlap is used to iterate all avoid regions to find the
one which overlap with it in the lowest address. E.g there's a memory
region[1024M, 2048M), after iterating all avoid regions we found the first
avoid region by starting address from low to high is [1536M, 1664M). With
this information we can split memory region [1024M, 1536M) out as the
avaliable slot area and save it into array slot_areas[].

Signed-off-by: Baoquan He <bhe@redhat.com>
---
 arch/x86/boot/compressed/aslr.c | 51 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
index 0431c19..44c6768 100644
--- a/arch/x86/boot/compressed/aslr.c
+++ b/arch/x86/boot/compressed/aslr.c
@@ -257,6 +257,40 @@ static bool mem_avoid_overlap(struct mem_vector *img)
 	return false;
 }
 
+static unsigned long
+mem_min_overlap(struct mem_vector *img, struct mem_vector *out)
+{
+	int i;
+	struct setup_data *ptr;
+	unsigned long min = img->start + img->size;
+
+	for (i = 0; i < MEM_AVOID_MAX; i++) {
+		if (mem_overlaps(img, &mem_avoid[i]) &&
+			(mem_avoid[i].start < min)) {
+			*out = mem_avoid[i];
+			min = mem_avoid[i].start;
+		}
+	}
+
+	/* Check all entries in the setup_data linked list. */
+	ptr = (struct setup_data *)(unsigned long)real_mode->hdr.setup_data;
+	while (ptr) {
+		struct mem_vector avoid;
+
+		avoid.start = (unsigned long)ptr;
+		avoid.size = sizeof(*ptr) + ptr->len;
+
+		if (mem_overlaps(img, &avoid) && (avoid.start < min)) {
+			*out = avoid;
+			min = avoid.start;
+		}
+
+		ptr = (struct setup_data *)(unsigned long)ptr->next;
+	}
+
+	return min;
+}
+
 static unsigned long slots[CONFIG_RANDOMIZE_BASE_MAX_OFFSET /
 			   CONFIG_PHYSICAL_ALIGN];
 
@@ -273,6 +307,23 @@ static unsigned long slot_max;
 
 static unsigned long slot_area_index;
 
+static void store_slot_info(struct mem_vector *region, unsigned long image_size)
+{
+	struct slot_area slot_area;
+
+	slot_area.addr = region->start;
+	if (image_size <= CONFIG_PHYSICAL_ALIGN)
+		slot_area.num = region->size / CONFIG_PHYSICAL_ALIGN;
+	else
+		slot_area.num = (region->size - image_size) /
+				CONFIG_PHYSICAL_ALIGN + 1;
+
+	if (slot_area.num > 0) {
+		slot_areas[slot_area_index++] = slot_area;
+		slot_max += slot_area.num;
+	}
+}
+
 static void slots_append(unsigned long addr)
 {
 	/* Overflowing the slots list should be impossible. */
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1362953

FromKees Cook <keescook@chromium.org>
Date2016-03-22 21:30 +0100
Message-ID<rfB6b-1hK-31@gated-at.bofh.it>
In reply to#1362381
On Tue, Mar 22, 2016 at 12:31 AM, Baoquan He <bhe@redhat.com> wrote:
> ***Background:
> Previously a bug is reported that kdump didn't work when kaslr is enabled. During
> discussing that bug fix, we found current kaslr has a limilation that it can
> only randomize in 1GB region.
>
> This is because in curent kaslr implementaion only physical address of kernel
> loading is randomized. Then calculate the delta of physical address where
> vmlinux was linked to load and where it is finally loaded. If delta is not
> equal to 0, namely there's a new physical address where kernel is actually
> decompressed, relocation handling need be done. Then delta is added to offset
> of kernel symbol relocation, this makes the address of kernel text mapping move
> delta long. Though in principle kernel can be randomized to any physical address,
> kernel text mapping address space is limited and only 1G, namely as follows on
> x86_64:
>         [0xffffffff80000000, 0xffffffffc0000000)
>
> In one word, kernel text physical address and virtual address randomization is
> coupled. This causes the limitation.
>
> Then hpa and Vivek suggested we should change this. To decouple the physical
> address and virtual address randomization of kernel text and let them work
> separately. Then kernel text physical address can be randomized in region
> [16M, 64T), and kernel text virtual address can be randomized in region
> [0xffffffff80000000, 0xffffffffc0000000).
>
> ***Problems we need solved:
>   - For kernel boot from startup_32 case, only 0~4G identity mapping is built.
>     If kernel will be randomly put anywhere from 16M to 64T at most, the price
>     to build all region of identity mapping is too high. We need build the
>     identity mapping on demand, not covering all physical address space.
>
>   - Decouple the physical address and virtual address randomization of kernel
>     text and let them work separately.
>
> ***Parts:
>    - The 1st part is Yinghai's identity mapping building on demand patches.
>      This is used to solve the first problem mentioned above.
>      (Patch 09-10/19)
>    - The 2nd part is decoupling the physical address and virtual address
>      randomization of kernel text and letting them work separately patches
>      based on Yinghai's ident mapping patches.
>      (Patch 12-19/19)
>    - The 3rd part is some clean up patches which Yinghai found when he reviewed
>      my patches and the related code around.
>      (Patch 01-08/19)
>
> ***Patch status:
> This patchset went through several rounds of review.
>
>     v1:
>     - The first round can be found here:
>         https://lwn.net/Articles/637115/
>
>     v1->v2:
>     - In 2nd round Yinghai made a big patchset including this kaslr fix and another
>       setup_data related fix. The link is here:
>        http://lists-archives.com/linux-kernel/28346903-x86-updated-patches-for-kaslr-and-setup_data-etc-for-v4-3.html
>       You can get the code from Yinghai's git branch:
>       git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-x86-v4.3-next
>
>     v2->v3:
>     - It only takes care of the kaslr related patches.
>       For reviewers it's better to discuss only one issue in one thread.
>         * I take off one patch as follows from Yinghai's because I think it's unnecessay.
>            - Patch 05/19 x86, kaslr: rename output_size to output_run_size
>              output_size is enough to represen the value:
>                 output_len > run_size ? output_len : run_size
>
>         * I add Patch 04/19, it's a comment update patch. For other patches, I just
>           adjust patch log and do several places of change comparing with 2nd round.
>           Please check the change log under patch log of each patch for details.
>
>         * Adjust sequence of several patches to make review easier. It doesn't
>           affect codes.
>
>     v3->v4:
>     - Made changes according to Kees's comments.
>       Add one patch 20/20 as Kees suggested to use KERNEL_IMAGE_SIZE as offset
>       max of virtual random, meanwhile clean up useless CONFIG_RANDOM_OFFSET_MAX
>
>         x86, kaslr: Use KERNEL_IMAGE_SIZE as the offset max for kernel virtual randomization

This series is looking good to me. I'm running tests under qemu now,
and things appear to work as advertised. :) I'll report back once I've
booted a few hundred times.

Ingo, what do you think of getting this into the x86 tree for some
testing in -next? For stuff I haven't already Acked, consider the
whole series as:

Reviewed-by: Kees Cook <keescook@chromium.org>

-Kees

>
> You can also get this patchset from my github:
>    https://github.com/baoquan-he/linux.git kaslr-above-4G
>
> Any comments about code changes, code comments, patch logs are welcome and
> appreciated.
>
> Baoquan He (9):
>   x86, kaslr: Fix a bug that relocation can not be handled when kernel
>     is loaded above 2G
>   x86, kaskr: Update the description for decompressor worst case
>   x86, kaslr: Introduce struct slot_area to manage randomization slot
>     info
>   x86, kaslr: Add two functions which will be used later
>   x86, kaslr: Introduce fetch_random_virt_offset to randomize the kernel
>     text mapping address
>   x86, kaslr: Randomize physical and virtual address of kernel
>     separately
>   x86, kaslr: Add support of kernel physical address randomization above
>     4G
>   x86, kaslr: Remove useless codes
>   x86, kaslr: Use KERNEL_IMAGE_SIZE as the offset max for kernel virtual
>     randomization
>
> Yinghai Lu (11):
>   x86, kaslr: Remove not needed parameter for choose_kernel_location
>   x86, boot: Move compressed kernel to end of buffer before
>     decompressing
>   x86, boot: Move z_extract_offset calculation to header.S
>   x86, boot: Fix run_size calculation
>   x86, kaslr: Clean up useless code related to run_size.
>   x86, kaslr: Get correct max_addr for relocs pointer
>   x86, kaslr: Consolidate mem_avoid array filling
>   x86, boot: Split kernel_ident_mapping_init to another file
>   x86, 64bit: Set ident_mapping for kaslr
>   x86, boot: Add checking for memcpy
>   x86, kaslr: Allow random address to be below loaded address
>
>  arch/x86/Kconfig                       |  57 +++----
>  arch/x86/boot/Makefile                 |  13 +-
>  arch/x86/boot/compressed/Makefile      |  19 ++-
>  arch/x86/boot/compressed/aslr.c        | 300 +++++++++++++++++++++++++--------
>  arch/x86/boot/compressed/head_32.S     |  14 +-
>  arch/x86/boot/compressed/head_64.S     |  15 +-
>  arch/x86/boot/compressed/misc.c        |  89 +++++-----
>  arch/x86/boot/compressed/misc.h        |  34 ++--
>  arch/x86/boot/compressed/misc_pgt.c    |  93 ++++++++++
>  arch/x86/boot/compressed/mkpiggy.c     |  28 +--
>  arch/x86/boot/compressed/string.c      |  29 +++-
>  arch/x86/boot/compressed/vmlinux.lds.S |   1 +
>  arch/x86/boot/header.S                 |  22 ++-
>  arch/x86/include/asm/boot.h            |  19 +++
>  arch/x86/include/asm/page.h            |   5 +
>  arch/x86/include/asm/page_64_types.h   |   5 +-
>  arch/x86/kernel/asm-offsets.c          |   1 +
>  arch/x86/kernel/vmlinux.lds.S          |   1 +
>  arch/x86/mm/ident_map.c                |  74 ++++++++
>  arch/x86/mm/init_32.c                  |   3 -
>  arch/x86/mm/init_64.c                  |  74 +-------
>  arch/x86/tools/calc_run_size.sh        |  42 -----
>  22 files changed, 605 insertions(+), 333 deletions(-)
>  create mode 100644 arch/x86/boot/compressed/misc_pgt.c
>  create mode 100644 arch/x86/mm/ident_map.c
>  delete mode 100644 arch/x86/tools/calc_run_size.sh
>
> --
> 2.5.0
>



-- 
Kees Cook
Chrome OS & Brillo Security

[toc] | [prev] | [next] | [standalone]


#1363769

FromKees Cook <keescook@chromium.org>
Date2016-03-23 23:50 +0100
Message-ID<rfZLc-1IM-13@gated-at.bofh.it>
In reply to#1362953
On Tue, Mar 22, 2016 at 1:25 PM, Kees Cook <keescook@chromium.org> wrote:
> On Tue, Mar 22, 2016 at 12:31 AM, Baoquan He <bhe@redhat.com> wrote:
>> ***Background:
>> Previously a bug is reported that kdump didn't work when kaslr is enabled. During
>> discussing that bug fix, we found current kaslr has a limilation that it can
>> only randomize in 1GB region.
>>
>> This is because in curent kaslr implementaion only physical address of kernel
>> loading is randomized. Then calculate the delta of physical address where
>> vmlinux was linked to load and where it is finally loaded. If delta is not
>> equal to 0, namely there's a new physical address where kernel is actually
>> decompressed, relocation handling need be done. Then delta is added to offset
>> of kernel symbol relocation, this makes the address of kernel text mapping move
>> delta long. Though in principle kernel can be randomized to any physical address,
>> kernel text mapping address space is limited and only 1G, namely as follows on
>> x86_64:
>>         [0xffffffff80000000, 0xffffffffc0000000)
>>
>> In one word, kernel text physical address and virtual address randomization is
>> coupled. This causes the limitation.
>>
>> Then hpa and Vivek suggested we should change this. To decouple the physical
>> address and virtual address randomization of kernel text and let them work
>> separately. Then kernel text physical address can be randomized in region
>> [16M, 64T), and kernel text virtual address can be randomized in region
>> [0xffffffff80000000, 0xffffffffc0000000).
>>
>> ***Problems we need solved:
>>   - For kernel boot from startup_32 case, only 0~4G identity mapping is built.
>>     If kernel will be randomly put anywhere from 16M to 64T at most, the price
>>     to build all region of identity mapping is too high. We need build the
>>     identity mapping on demand, not covering all physical address space.
>>
>>   - Decouple the physical address and virtual address randomization of kernel
>>     text and let them work separately.
>>
>> ***Parts:
>>    - The 1st part is Yinghai's identity mapping building on demand patches.
>>      This is used to solve the first problem mentioned above.
>>      (Patch 09-10/19)
>>    - The 2nd part is decoupling the physical address and virtual address
>>      randomization of kernel text and letting them work separately patches
>>      based on Yinghai's ident mapping patches.
>>      (Patch 12-19/19)
>>    - The 3rd part is some clean up patches which Yinghai found when he reviewed
>>      my patches and the related code around.
>>      (Patch 01-08/19)
>>
>> ***Patch status:
>> This patchset went through several rounds of review.
>>
>>     v1:
>>     - The first round can be found here:
>>         https://lwn.net/Articles/637115/
>>
>>     v1->v2:
>>     - In 2nd round Yinghai made a big patchset including this kaslr fix and another
>>       setup_data related fix. The link is here:
>>        http://lists-archives.com/linux-kernel/28346903-x86-updated-patches-for-kaslr-and-setup_data-etc-for-v4-3.html
>>       You can get the code from Yinghai's git branch:
>>       git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-x86-v4.3-next
>>
>>     v2->v3:
>>     - It only takes care of the kaslr related patches.
>>       For reviewers it's better to discuss only one issue in one thread.
>>         * I take off one patch as follows from Yinghai's because I think it's unnecessay.
>>            - Patch 05/19 x86, kaslr: rename output_size to output_run_size
>>              output_size is enough to represen the value:
>>                 output_len > run_size ? output_len : run_size
>>
>>         * I add Patch 04/19, it's a comment update patch. For other patches, I just
>>           adjust patch log and do several places of change comparing with 2nd round.
>>           Please check the change log under patch log of each patch for details.
>>
>>         * Adjust sequence of several patches to make review easier. It doesn't
>>           affect codes.
>>
>>     v3->v4:
>>     - Made changes according to Kees's comments.
>>       Add one patch 20/20 as Kees suggested to use KERNEL_IMAGE_SIZE as offset
>>       max of virtual random, meanwhile clean up useless CONFIG_RANDOM_OFFSET_MAX
>>
>>         x86, kaslr: Use KERNEL_IMAGE_SIZE as the offset max for kernel virtual randomization
>
> This series is looking good to me. I'm running tests under qemu now,
> and things appear to work as advertised. :) I'll report back once I've
> booted a few hundred times.

My qemu isn't implementing rdrand, so my entropy source is poor, but I
had 7322 successful boots, with 6356 unique physical memory positions
and 487 unique virtual memory positions.

With 48G of physical memory, I'd expect to see more physical positions
(i.e. for a 24M kernel (using 12 slots), avoiding the first 512M (256
slots), I'd expect to see closer to 24308 positions (48G / 2M - 12 -
256)). The 487 is pretty close to the max 512 slots. Still, my entropy
source wasn't great, so that's probably the issue. Getting this
retested with rdrand would be nice. Regardless, no hangs. :)

-Kees

>
> Ingo, what do you think of getting this into the x86 tree for some
> testing in -next? For stuff I haven't already Acked, consider the
> whole series as:
>
> Reviewed-by: Kees Cook <keescook@chromium.org>

-- 
Kees Cook
Chrome OS & Brillo Security

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web