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


Groups > linux.kernel > #1379329 > unrolled thread

[PATCH v5 00/21] x86, boot: KASLR cleanup and 64-bit improvements

Started byKees Cook <keescook@chromium.org>
First post2016-04-15 00:30 +0200
Last post2016-04-16 11:10 +0200
Articles 20 on this page of 39 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v5 00/21] x86, boot: KASLR cleanup and 64-bit improvements Kees Cook <keescook@chromium.org> - 2016-04-15 00:30 +0200
    [PATCH v5 05/21] x86, boot: Calculate decompression size during boot not build Kees Cook <keescook@chromium.org> - 2016-04-15 00:30 +0200
      Re: [PATCH v5 05/21] x86, boot: Calculate decompression size during  boot not build Ingo Molnar <mingo@kernel.org> - 2016-04-15 10:20 +0200
        Re: [PATCH v5 05/21] x86, boot: Calculate decompression size during  boot not build Kees Cook <keescook@chromium.org> - 2016-04-15 21:20 +0200
    [PATCH v5 21/21] x86, KASLR: Allow randomization below load address Kees Cook <keescook@chromium.org> - 2016-04-15 00:30 +0200
    [PATCH v5 09/21] x86, KASLR: Correctly bounds-check relocations Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
    [PATCH v5 20/21] x86, KASLR: Remove unused slot tracking code Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
    [PATCH v5 01/21] x86, KASLR: Remove unneeded boot_params argument Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
      Re: [PATCH v5 01/21] x86, KASLR: Remove unneeded boot_params argument Ingo Molnar <mingo@kernel.org> - 2016-04-15 09:30 +0200
        Re: [PATCH v5 01/21] x86, KASLR: Remove unneeded boot_params argument Kees Cook <keescook@chromium.org> - 2016-04-15 21:00 +0200
    [PATCH v5 19/21] x86, KASLR: Add physical address randomization >4G Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
    [PATCH v5 13/21] x86, boot: Report overlap failures in memcpy Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
      Re: [PATCH v5 13/21] x86, boot: Report overlap failures in memcpy Lasse Collin <lasse.collin@tukaani.org> - 2016-04-15 17:00 +0200
        Re: [PATCH v5 13/21] x86, boot: Report overlap failures in memcpy Kees Cook <keescook@chromium.org> - 2016-04-15 21:30 +0200
    [PATCH v5 02/21] x86, KASLR: Handle kernel relocation above 2G Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
      Re: [PATCH v5 02/21] x86, KASLR: Handle kernel relocation above 2G Ingo Molnar <mingo@kernel.org> - 2016-04-15 09:50 +0200
        Re: [PATCH v5 02/21] x86, KASLR: Handle kernel relocation above 2G Kees Cook <keescook@chromium.org> - 2016-04-15 21:10 +0200
    [PATCH v5 16/21] x86, KASLR: Add virtual address choosing function Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
    [PATCH v5 15/21] x86, KASLR: Add slot_area support functions Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
    [PATCH v5 04/21] x86, boot: Move compressed kernel to end of decompression buffer Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
      Re: [PATCH v5 04/21] x86, boot: Move compressed kernel to end of  decompression buffer Ingo Molnar <mingo@kernel.org> - 2016-04-15 10:20 +0200
        Re: [PATCH v5 04/21] x86, boot: Move compressed kernel to end of  decompression buffer Kees Cook <keescook@chromium.org> - 2016-04-18 19:00 +0200
      Re: [PATCH v5 04/21] x86, boot: Move compressed kernel to end of  decompression buffer Ingo Molnar <mingo@kernel.org> - 2016-04-15 11:10 +0200
    [PATCH v5 12/21] x86, 64bit: Set ident_mapping for KASLR Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
    [PATCH v5 08/21] x86, KASLR: Clean up unused code from old run_size Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
    [PATCH v5 14/21] x86, KASLR: Add slot_area to manage random slots Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
    [PATCH v5 17/21] x86, KASLR: Clarify purpose of each get_random_long Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
    [PATCH v5 11/21] x86, boot: Split out kernel_ident_mapping_init Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
    [PATCH v5 10/21] x86, KASLR: Consolidate mem_avoid entries Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
    [PATCH v5 03/21] x86, KASLR: Drop CONFIG_RANDOMIZE_BASE_MAX_OFFSET Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
      Re: [PATCH v5 03/21] x86, KASLR: Drop  CONFIG_RANDOMIZE_BASE_MAX_OFFSET Ingo Molnar <mingo@kernel.org> - 2016-04-15 10:10 +0200
        Re: [PATCH v5 03/21] x86, KASLR: Drop CONFIG_RANDOMIZE_BASE_MAX_OFFSET Kees Cook <keescook@chromium.org> - 2016-04-15 21:20 +0200
          Re: [PATCH v5 03/21] x86, KASLR: Drop  CONFIG_RANDOMIZE_BASE_MAX_OFFSET Ingo Molnar <mingo@kernel.org> - 2016-04-16 10:50 +0200
    [PATCH v5 06/21] x86, KASLR: Update description for decompressor worst case size Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
      Re: [PATCH v5 06/21] x86, KASLR: Update description for  decompressor worst case size Lasse Collin <lasse.collin@tukaani.org> - 2016-04-15 18:20 +0200
    [PATCH v5 07/21] x86, boot: Fix run_size calculation Kees Cook <keescook@chromium.org> - 2016-04-15 00:40 +0200
      Re: [PATCH v5 07/21] x86, boot: Fix run_size calculation Ingo Molnar <mingo@kernel.org> - 2016-04-15 10:40 +0200
        Re: [PATCH v5 07/21] x86, boot: Fix run_size calculation Kees Cook <keescook@chromium.org> - 2016-04-15 21:30 +0200
          Re: [PATCH v5 07/21] x86, boot: Fix run_size calculation Ingo Molnar <mingo@kernel.org> - 2016-04-16 11:10 +0200

Page 1 of 2  [1] 2  Next page →


#1379329 — [PATCH v5 00/21] x86, boot: KASLR cleanup and 64-bit improvements

FromKees Cook <keescook@chromium.org>
Date2016-04-15 00:30 +0200
Subject[PATCH v5 00/21] x86, boot: KASLR cleanup and 64-bit improvements
Message-ID<rnXVT-YO-3@gated-at.bofh.it>
This is v5 of the x86 KASLR improvement series from Yinghai, Baoquan,
and myself. The current branch lives here:
http://git.kernel.org/cgit/linux/kernel/git/kees/linux.git/log/?h=kaslr/highmem

***Background:
Bugs have been reported around kdump, kexec, and some netboot situations
that didn't work when KASLR was enabled. While discussing the bugs, it
was found that the current KASLR implementation had various limitations,
but most importantly that it can only randomize in a 1GB region of
physical memory.

The current KASLR implementaion only randomizes the base physical
address of the kernel. If the delta from build-time load address and
KASLR run-time load address (i.e. the physical address of where the
kernel actually decompressed) is not equal to 0, relocation handling is
performed using the delta. Though in principle kernel can be randomized
to any physical address, the physical kernel text mapping address space
is limited to 1G and the virtual address is just offset by the same
amount. On x86_64 the result is the following range:
        [0xffffffff80000000, 0xffffffffc0000000)

hpa and Vivek suggested we should change this by decoupling 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 that needed solving:
  - When booting from the startup_32 case, only a 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 clean-up and improvements to help the rest of the series.
     (Patches 01-10)
   - The 2nd part is Yinghai's building of identity mappings on demand.
     This is used to solve the first problem mentioned above.
     (Patches 11-12)
   - The 3rd part is Baoquan's decoupling the physical address and virtual
     address randomization of kernel text and letting them work separately,
     based on Yinghai's ident mapping patches.
     (Patches 13-21)

I've boot tested this a bunch on 32-bit and 64-bit, and things appear
to be working as expected. I've cleaned up the changelogs, improved
some comments, refactored a few things, etc. Changes are noted in the
individual changelogs.

Thanks!

-Kees

v4->v5:
- rewrote all the changelogs, and several comments.
- refactored e820 parser to use a while loop instead of goto.
- rearranged removal of CONFIG_RANDOMIZE_BASE_MAX_OFFSET to earlier.
- additionally dropped KERNEL_IMAGE_SIZE_DEFAULT
- refactored minimum address calculation
- refactored slot offset calculation for readability
- fixed 32-bit boot failures
- fixed CONFIG_RANDOMIZE_BASE=n boot failure
- improved debug reporting

[Baoquan's histroy]
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

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.

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

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

[toc] | [next] | [standalone]


#1379331 — [PATCH v5 05/21] x86, boot: Calculate decompression size during boot not build

FromKees Cook <keescook@chromium.org>
Date2016-04-15 00:30 +0200
Subject[PATCH v5 05/21] x86, boot: Calculate decompression size during boot not build
Message-ID<rnXVU-YO-17@gated-at.bofh.it>
In reply to#1379329
From: Yinghai Lu <yinghai@kernel.org>

Currently z_extract_offset is calculated in boot/compressed/mkpiggy.c.
This doesn't work well because mkpiggy.c doesn't know the details of the
decompressor in use. As a result, it can only make an estimation, which
has risks:

 - output + output_len (VO) could be much bigger than input + input_len
   (ZO). In this case, the decompressed kernel plus relocs could overwrite
   the decompression code while it is running.

 - The head code of ZO could be bigger than z_extract_offset. In this case
   an overwrite could happen when the head code is running to move ZO to
   the end of buffer. Though currently the size of the head code is very
   small it's still a potential risk. Since there is no rule to limit the
   size of the head code of ZO, it runs the risk of suddenly becoming a
   (hard to find) bug.

Instead, this moves the z_extract_offset calculation into header.S, and
makes adjustments to be sure that the above two cases can never happen.

Since we have (previously) made ZO always be located against the end of
decompression buffer, z_extract_offset is only used here to calculate an
appropriate buffer size (INIT_SIZE), and is not longer used elsewhere. As
such, it can be removed from voffset.h.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
[kees: rewrote changelog]
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/x86/boot/Makefile             |  2 +-
 arch/x86/boot/compressed/misc.c    |  5 +----
 arch/x86/boot/compressed/mkpiggy.c | 15 +--------------
 arch/x86/boot/header.S             | 23 ++++++++++++++++++++++-
 4 files changed, 25 insertions(+), 20 deletions(-)

diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index b1ef9e489084..942f7dabfb1e 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -95,7 +95,7 @@ targets += voffset.h
 $(obj)/voffset.h: vmlinux FORCE
 	$(call if_changed,voffset)
 
-sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|z_.*\)$$/\#define ZO_\2 0x\1/p'
+sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [ABCDGRSTVW] \(startup_32\|startup_64\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|input_data\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p'
 
 quiet_cmd_zoffset = ZOFFSET $@
       cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index c4477d5f3fff..e2a998f8c304 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -83,13 +83,10 @@
  * To avoid problems with the compressed data's meta information an extra 18
  * bytes are needed.  Leading to the formula:
  *
- * extra_bytes = (uncompressed_size >> 12) + 32768 + 18 + decompressor_size.
+ * extra_bytes = (uncompressed_size >> 12) + 32768 + 18.
  *
  * Adding 8 bytes per 32K is a bit excessive but much easier to calculate.
  * Adding 32768 instead of 32767 just makes for round numbers.
- * Adding the decompressor_size is necessary as it musht live after all
- * of the data as well.  Last I measured the decompressor is about 14K.
- * 10K of actual data and 4K of bss.
  *
  */
 
diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c
index b980046c3329..a613c84d9b88 100644
--- a/arch/x86/boot/compressed/mkpiggy.c
+++ b/arch/x86/boot/compressed/mkpiggy.c
@@ -21,8 +21,7 @@
  * ----------------------------------------------------------------------- */
 
 /*
- * Compute the desired load offset from a compressed program; outputs
- * a small assembly wrapper with the appropriate symbols defined.
+ * outputs a small assembly wrapper with the appropriate symbols defined.
  */
 
 #include <stdlib.h>
@@ -35,7 +34,6 @@ int main(int argc, char *argv[])
 {
 	uint32_t olen;
 	long ilen;
-	unsigned long offs;
 	unsigned long run_size;
 	FILE *f = NULL;
 	int retval = 1;
@@ -67,15 +65,6 @@ int main(int argc, char *argv[])
 	ilen = ftell(f);
 	olen = get_unaligned_le32(&olen);
 
-	/*
-	 * Now we have the input (compressed) and output (uncompressed)
-	 * sizes, compute the necessary decompression offset...
-	 */
-
-	offs = (olen > ilen) ? olen - ilen : 0;
-	offs += olen >> 12;	/* Add 8 bytes for each 32K block */
-	offs += 64*1024 + 128;	/* Add 64K + 128 bytes slack */
-	offs = (offs+4095) & ~4095; /* Round to a 4K boundary */
 	run_size = atoi(argv[2]);
 
 	printf(".section \".rodata..compressed\",\"a\",@progbits\n");
@@ -83,8 +72,6 @@ int main(int argc, char *argv[])
 	printf("z_input_len = %lu\n", ilen);
 	printf(".globl z_output_len\n");
 	printf("z_output_len = %lu\n", (unsigned long)olen);
-	printf(".globl z_extract_offset\n");
-	printf("z_extract_offset = 0x%lx\n", offs);
 	printf(".globl z_run_size\n");
 	printf("z_run_size = %lu\n", run_size);
 
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 6236b9ec4b76..6565dcb2b899 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -440,7 +440,28 @@ setup_data:		.quad 0			# 64-bit physical pointer to
 
 pref_address:		.quad LOAD_PHYSICAL_ADDR	# preferred load addr
 
-#define ZO_INIT_SIZE	(ZO__end - ZO_startup_32 + ZO_z_extract_offset)
+/* Check arch/x86/boot/compressed/misc.c for the formula of extra_bytes*/
+#define ZO_z_extra_bytes	((ZO_z_output_len >> 12) + 65536 + 128)
+#if ZO_z_output_len > ZO_z_input_len
+#define ZO_z_extract_offset	(ZO_z_output_len + ZO_z_extra_bytes - \
+				 ZO_z_input_len)
+#else
+#define ZO_z_extract_offset	ZO_z_extra_bytes
+#endif
+
+/*
+ * extract_offset has to be bigger than ZO head section. Otherwise
+ * during head code running to move ZO to end of buffer, it will
+ * overwrite head code itself.
+ */
+#if (ZO__ehead - ZO_startup_32) > ZO_z_extract_offset
+#define ZO_z_min_extract_offset ((ZO__ehead - ZO_startup_32 + 4095) & ~4095)
+#else
+#define ZO_z_min_extract_offset ((ZO_z_extract_offset + 4095) & ~4095)
+#endif
+
+#define ZO_INIT_SIZE	(ZO__end - ZO_startup_32 + ZO_z_min_extract_offset)
+
 #define VO_INIT_SIZE	(VO__end - VO__text)
 #if ZO_INIT_SIZE > VO_INIT_SIZE
 #define INIT_SIZE ZO_INIT_SIZE
-- 
2.6.3

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


#1379537 — Re: [PATCH v5 05/21] x86, boot: Calculate decompression size during boot not build

FromIngo Molnar <mingo@kernel.org>
Date2016-04-15 10:20 +0200
SubjectRe: [PATCH v5 05/21] x86, boot: Calculate decompression size during boot not build
Message-ID<ro78S-8qx-13@gated-at.bofh.it>
In reply to#1379331
* Kees Cook <keescook@chromium.org> wrote:

> From: Yinghai Lu <yinghai@kernel.org>
> 
> Currently z_extract_offset is calculated in boot/compressed/mkpiggy.c.

What is the high level meaning of z_extract_offset? I cannot tell without reading 
the code - and the point of changelogs is for them to be readable without having 
to read the code.

The rest of the changelog is pretty good.

Thanks,

	Ingo

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


#1380141 — Re: [PATCH v5 05/21] x86, boot: Calculate decompression size during boot not build

FromKees Cook <keescook@chromium.org>
Date2016-04-15 21:20 +0200
SubjectRe: [PATCH v5 05/21] x86, boot: Calculate decompression size during boot not build
Message-ID<rohrA-81o-17@gated-at.bofh.it>
In reply to#1379537
On Fri, Apr 15, 2016 at 1:12 AM, Ingo Molnar <mingo@kernel.org> wrote:
>
> * Kees Cook <keescook@chromium.org> wrote:
>
>> From: Yinghai Lu <yinghai@kernel.org>
>>
>> Currently z_extract_offset is calculated in boot/compressed/mkpiggy.c.
>
> What is the high level meaning of z_extract_offset? I cannot tell without reading
> the code - and the point of changelogs is for them to be readable without having
> to read the code.

I'll clarify it in the changelog. (FWIW, it's the offset into the
extraction buffer where it's safe to put the data-to-be-extracted).

> The rest of the changelog is pretty good.

Thanks!

-Kees

-- 
Kees Cook
Chrome OS & Brillo Security

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


#1379332 — [PATCH v5 21/21] x86, KASLR: Allow randomization below load address

FromKees Cook <keescook@chromium.org>
Date2016-04-15 00:30 +0200
Subject[PATCH v5 21/21] x86, KASLR: Allow randomization below load address
Message-ID<rnXVU-YO-13@gated-at.bofh.it>
In reply to#1379329
From: Yinghai Lu <yinghai@kernel.org>

Currently the physical randomization's lower boundary is the load
address. For bootloaders that load kernels into very high memory
(e.g. kexec), this means randomization takes place in a very small window
at the top of memory, ignoring the large region of physical memory below
the load address.

Since mem_avoid is already correctly tracking the regions that must be
avoided, this patch changes the minimum address to which ever is less:
512M (to conservatively avoid unknown things in lower memory) or the
load address. Now, for example, if the kernel is loaded at 8G, [512M,
8G) will be added into possible physical memory positions.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
[kees: rewrote changelog, refactor to use min()]
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/x86/boot/compressed/aslr.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
index e83d3bb3808b..864a51863b45 100644
--- a/arch/x86/boot/compressed/aslr.c
+++ b/arch/x86/boot/compressed/aslr.c
@@ -459,7 +459,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
@@ -480,8 +481,11 @@ void choose_kernel_location(unsigned char *input,
 	mem_avoid_init((unsigned long)input, input_size,
 		       (unsigned long)*output);
 
+	/* Low end should be the smaller of 512M or initial location. */
+	min_addr = min((unsigned long)*output, 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.6.3

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


#1379334 — [PATCH v5 09/21] x86, KASLR: Correctly bounds-check relocations

FromKees Cook <keescook@chromium.org>
Date2016-04-15 00:40 +0200
Subject[PATCH v5 09/21] x86, KASLR: Correctly bounds-check relocations
Message-ID<rnY5z-14p-1@gated-at.bofh.it>
In reply to#1379329
From: Yinghai Lu <yinghai@kernel.org>

Relocation handling performs bounds checking on the resulting calculated
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.

This patch adds an export for __bss_start in voffset.h and uses it to
get the correct max_addr.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Cc: Baoquan He <bhe@redhat.com>
[kees: rewrote changelog]
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 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 81a8d0fd34eb..aa421126556d 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -45,7 +45,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 6adb5b827aca..562d647289ac 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.6.3

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


#1379335 — [PATCH v5 20/21] x86, KASLR: Remove unused slot tracking code

FromKees Cook <keescook@chromium.org>
Date2016-04-15 00:40 +0200
Subject[PATCH v5 20/21] x86, KASLR: Remove unused slot tracking code
Message-ID<rnY5A-14p-5@gated-at.bofh.it>
In reply to#1379329
From: Baoquan He <bhe@redhat.com>

Since struct slot_area and its new algorithm are used to track and select
memory ranges, the slots[] array and its associated functions are not
needed any more. This patch removes them.

Signed-off-by: Baoquan He <bhe@redhat.com>
[kees: rewrote changelog]
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/x86/boot/compressed/aslr.c | 22 ----------------------
 1 file changed, 22 deletions(-)

diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
index 0587eac3e05d..e83d3bb3808b 100644
--- a/arch/x86/boot/compressed/aslr.c
+++ b/arch/x86/boot/compressed/aslr.c
@@ -113,17 +113,6 @@ struct mem_vector {
 #define MEM_AVOID_MAX 4
 static struct mem_vector mem_avoid[MEM_AVOID_MAX];
 
-static bool mem_contains(struct mem_vector *region, struct mem_vector *item)
-{
-	/* Item at least partially before region. */
-	if (item->start < region->start)
-		return false;
-	/* Item at least partially after region. */
-	if (item->start + item->size > region->start + region->size)
-		return false;
-	return true;
-}
-
 static bool mem_overlaps(struct mem_vector *one, struct mem_vector *two)
 {
 	/* Item one is entirely before item two. */
@@ -292,8 +281,6 @@ mem_min_overlap(struct mem_vector *img, struct mem_vector *out)
 	return min;
 }
 
-static unsigned long slots[KERNEL_IMAGE_SIZE / CONFIG_PHYSICAL_ALIGN];
-
 struct slot_area {
 	unsigned long addr;
 	int num;
@@ -324,15 +311,6 @@ static void store_slot_info(struct mem_vector *region, unsigned long image_size)
 	}
 }
 
-static void slots_append(unsigned long addr)
-{
-	/* Overflowing the slots list should be impossible. */
-	if (slot_max >= KERNEL_IMAGE_SIZE / CONFIG_PHYSICAL_ALIGN)
-		return;
-
-	slots[slot_max++] = addr;
-}
-
 static unsigned long slots_fetch_random(void)
 {
 	unsigned long random;
-- 
2.6.3

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


#1379336 — [PATCH v5 01/21] x86, KASLR: Remove unneeded boot_params argument

FromKees Cook <keescook@chromium.org>
Date2016-04-15 00:40 +0200
Subject[PATCH v5 01/21] x86, KASLR: Remove unneeded boot_params argument
Message-ID<rnY5A-14p-3@gated-at.bofh.it>
In reply to#1379329
From: Yinghai Lu <yinghai@kernel.org>

Since the boot_params can be found using the real_mode global variable,
there is no need to pass around a pointer to it. This slightly simplifies
the choose_kernel_location function and its callers.

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
[kees: rewrote changelog]
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/x86/boot/compressed/aslr.c | 5 ++---
 arch/x86/boot/compressed/misc.c | 2 +-
 arch/x86/boot/compressed/misc.h | 6 ++----
 3 files changed, 5 insertions(+), 8 deletions(-)

diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
index 6a9b96b4624d..622aa881c6ab 100644
--- a/arch/x86/boot/compressed/aslr.c
+++ b/arch/x86/boot/compressed/aslr.c
@@ -295,8 +295,7 @@ static unsigned long find_random_addr(unsigned long minimum,
 	return slots_fetch_random();
 }
 
-unsigned char *choose_kernel_location(struct boot_params *boot_params,
-				      unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
 				      unsigned long input_size,
 				      unsigned char *output,
 				      unsigned long output_size)
@@ -316,7 +315,7 @@ unsigned char *choose_kernel_location(struct boot_params *boot_params,
 	}
 #endif
 
-	boot_params->hdr.loadflags |= KASLR_FLAG;
+	real_mode->hdr.loadflags |= KASLR_FLAG;
 
 	/* Record the various known unsafe memory ranges. */
 	mem_avoid_init((unsigned long)input, input_size,
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 79dac1758e7c..f35ad9eb1bf1 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -428,7 +428,7 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap,
 	 * the entire decompressed kernel plus relocation table, or the
 	 * entire decompressed kernel plus .bss and .brk sections.
 	 */
-	output = choose_kernel_location(real_mode, input_data, input_len, output,
+	output = choose_kernel_location(input_data, input_len, output,
 					output_len > run_size ? output_len
 							      : run_size);
 
diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h
index 3783dc3e10b3..dcf01c22400e 100644
--- a/arch/x86/boot/compressed/misc.h
+++ b/arch/x86/boot/compressed/misc.h
@@ -67,8 +67,7 @@ int cmdline_find_option_bool(const char *option);
 
 #if CONFIG_RANDOMIZE_BASE
 /* aslr.c */
-unsigned char *choose_kernel_location(struct boot_params *boot_params,
-				      unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
 				      unsigned long input_size,
 				      unsigned char *output,
 				      unsigned long output_size);
@@ -76,8 +75,7 @@ unsigned char *choose_kernel_location(struct boot_params *boot_params,
 bool has_cpuflag(int flag);
 #else
 static inline
-unsigned char *choose_kernel_location(struct boot_params *boot_params,
-				      unsigned char *input,
+unsigned char *choose_kernel_location(unsigned char *input,
 				      unsigned long input_size,
 				      unsigned char *output,
 				      unsigned long output_size)
-- 
2.6.3

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


#1379508 — Re: [PATCH v5 01/21] x86, KASLR: Remove unneeded boot_params argument

FromIngo Molnar <mingo@kernel.org>
Date2016-04-15 09:30 +0200
SubjectRe: [PATCH v5 01/21] x86, KASLR: Remove unneeded boot_params argument
Message-ID<ro6mt-7Go-7@gated-at.bofh.it>
In reply to#1379336
* Kees Cook <keescook@chromium.org> wrote:

> From: Yinghai Lu <yinghai@kernel.org>
> 
> Since the boot_params can be found using the real_mode global variable, there is 
> no need to pass around a pointer to it. This slightly simplifies the 
> choose_kernel_location function and its callers.

Yeah, so I really wanted to apply this series because the changelogs are now very 
nice, but got held up by the very first patch again ...

Guys, 'real_mode' totally sucks as a variable name!

By removing a seemingly unnecessary parameter, you made the code actively worse to 
read...

So please make a second patch on top of this one that renames 'real_mode' to 
something that both displays what it is about (it sure isn't mainly about real 
mode only!!), and also expresses that it's a global variable, not some local 
function parameter.

In arch/x86/ we usually achieve that via prefixing it with x86_ or so. So 
something like 'x86_boot_params' would work for me. I realize that this is 
somewhat special, because this is pre-relocation code so we really have to be 
careful about pointers - so maybe name it x86_boot_params_rm or so.

Also, I had a look at the whole file you are patching, 
arch/x86/boot/compressed/misc.c, and for heaven's sake, please first improve the 
comments on top of that file before further complicating that code with KASLR 
details! Right now it consists of various low level ramblings choke full of typos. 
No mention of where KASLR fits into the picture at all!

Right now it says:

 * misc.c
 *
 * This is a collection of several routines from gzip-1.0.3
 * adapted for Linux.

Which was perhaps true 15 years ago, but sure it's not true today! We do 
relocation and KASLR processing in this path as well, which is just as important 
as running the decompressor. Also, gzip is not the only decompressor we support.

The high level purpose of the code in this file should be explained first, and the 
file should probably be renamed to something like extract.c - to signal that this 
file is about extracting a kernel image and preparing it for execution (i.e. 
relinking it, etc.). It's (much!) more than just pure decompression.

Likewise, decompress_kernel() should be renamed to extract_kernel().

The low level explanations in extract.c should be moved to the function that is 
affected by those details. The top of the file should only contain general 
explanations, a high level description of in what state the kernel is when we call 
this code, and the sort of stuff we do in that code.

The credits should be collected into a single, coherent block. Unnecessary fluff 
should be cut.

Furthermore, I see similar problems with arch/x86/boot/compressed/aslr.c: for 
example it has no high level description at the top of the file _at all_. WTF is 
this with writing security-sensitive code that has no high level design 
description whatsoever?? Also, why is it named aslr.c, why not kaslr.c? We do have 
both KASLR and ASLR code in the kernel, confusing naming on the source code level 
sure does not help.

Also, what's this thing about choose_kernel_location()? That name is actively 
hiding the fact that the main purpose of that function is to randomize things ... 

It should be named x86_randomize_kernel_address() or so.

We need to stop making a mess of the x86 boot code! This is a highly critical 
piece of kernel code that every single x86 Linux user will execute, we should 
improve its visual presentation and general readability to the level of being 
proud of it ...

Thanks,

	Ingo

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


#1380125 — Re: [PATCH v5 01/21] x86, KASLR: Remove unneeded boot_params argument

FromKees Cook <keescook@chromium.org>
Date2016-04-15 21:00 +0200
SubjectRe: [PATCH v5 01/21] x86, KASLR: Remove unneeded boot_params argument
Message-ID<roh8e-7AR-17@gated-at.bofh.it>
In reply to#1379508
On Fri, Apr 15, 2016 at 12:29 AM, Ingo Molnar <mingo@kernel.org> wrote:
>
> * Kees Cook <keescook@chromium.org> wrote:
>
>> From: Yinghai Lu <yinghai@kernel.org>
>>
>> Since the boot_params can be found using the real_mode global variable, there is
>> no need to pass around a pointer to it. This slightly simplifies the
>> choose_kernel_location function and its callers.
>
> Yeah, so I really wanted to apply this series because the changelogs are now very
> nice, but got held up by the very first patch again ...

Thanks for reading through everything! I'll be going through it all
and fixing up what you mentioned (along with anything else that jumps
out at me).

> Guys, 'real_mode' totally sucks as a variable name!

In our defense, that variable name predates git history. ;)
Regardless, I'll get it renamed.

> By removing a seemingly unnecessary parameter, you made the code actively worse to
> read...
>
> So please make a second patch on top of this one that renames 'real_mode' to
> something that both displays what it is about (it sure isn't mainly about real
> mode only!!), and also expresses that it's a global variable, not some local
> function parameter.
>
> In arch/x86/ we usually achieve that via prefixing it with x86_ or so. So
> something like 'x86_boot_params' would work for me. I realize that this is
> somewhat special, because this is pre-relocation code so we really have to be
> careful about pointers - so maybe name it x86_boot_params_rm or so.
>
> Also, I had a look at the whole file you are patching,
> arch/x86/boot/compressed/misc.c, and for heaven's sake, please first improve the
> comments on top of that file before further complicating that code with KASLR
> details! Right now it consists of various low level ramblings choke full of typos.
> No mention of where KASLR fits into the picture at all!
>
> Right now it says:
>
>  * misc.c
>  *
>  * This is a collection of several routines from gzip-1.0.3
>  * adapted for Linux.
>
> Which was perhaps true 15 years ago, but sure it's not true today! We do
> relocation and KASLR processing in this path as well, which is just as important
> as running the decompressor. Also, gzip is not the only decompressor we support.
>
> The high level purpose of the code in this file should be explained first, and the
> file should probably be renamed to something like extract.c - to signal that this
> file is about extracting a kernel image and preparing it for execution (i.e.
> relinking it, etc.). It's (much!) more than just pure decompression.
>
> Likewise, decompress_kernel() should be renamed to extract_kernel().

I'll get these all cleaned up. Yay comment-bit-rot. :)

> The low level explanations in extract.c should be moved to the function that is
> affected by those details. The top of the file should only contain general
> explanations, a high level description of in what state the kernel is when we call
> this code, and the sort of stuff we do in that code.
>
> The credits should be collected into a single, coherent block. Unnecessary fluff
> should be cut.
>
> Furthermore, I see similar problems with arch/x86/boot/compressed/aslr.c: for
> example it has no high level description at the top of the file _at all_. WTF is
> this with writing security-sensitive code that has no high level design
> description whatsoever?? Also, why is it named aslr.c, why not kaslr.c? We do have
> both KASLR and ASLR code in the kernel, confusing naming on the source code level
> sure does not help.
>
> Also, what's this thing about choose_kernel_location()? That name is actively
> hiding the fact that the main purpose of that function is to randomize things ...
>
> It should be named x86_randomize_kernel_address() or so.

When naming this I wanted to make it clear that the only thing it was
doing was picking a location. The move is done by the decompressor.
I'll try to clarify the name of the function.

> We need to stop making a mess of the x86 boot code! This is a highly critical
> piece of kernel code that every single x86 Linux user will execute, we should
> improve its visual presentation and general readability to the level of being
> proud of it ...

I totally agree. :) There is a bit of a culture of "don't change it
just to rename things" which I try to avoid colliding with. In this
case, though, they would all seriously improve readability.

-Kees

-- 
Kees Cook
Chrome OS & Brillo Security

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


#1379340 — [PATCH v5 19/21] x86, KASLR: Add physical address randomization >4G

FromKees Cook <keescook@chromium.org>
Date2016-04-15 00:40 +0200
Subject[PATCH v5 19/21] x86, KASLR: Add physical address randomization >4G
Message-ID<rnY5A-14p-21@gated-at.bofh.it>
In reply to#1379329
From: Baoquan He <bhe@redhat.com>

This patch exchanges the prior slots[] array for the new slot_areas[]
array, and lifts the limitation of KERNEL_IMAGE_SIZE on the physical
address offset for 64-bit. As before, process_e820_entry walks memory and
populates slot_areas[], splitting on any detected mem_avoid collisions.

Signed-off-by: Baoquan He <bhe@redhat.com>
[kees: rewrote changelog, refactored goto into while, limit 32-bit to 1G]
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/x86/boot/compressed/aslr.c | 92 ++++++++++++++++++++++++++++++-----------
 1 file changed, 68 insertions(+), 24 deletions(-)

diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
index 53ceaa0a08b9..0587eac3e05d 100644
--- a/arch/x86/boot/compressed/aslr.c
+++ b/arch/x86/boot/compressed/aslr.c
@@ -335,25 +335,42 @@ static void slots_append(unsigned long addr)
 
 static unsigned long slots_fetch_random(void)
 {
+	unsigned long random;
+	int i;
+
 	/* Handle case of no slots stored. */
 	if (slot_max == 0)
 		return 0;
 
-	return slots[get_random_long("Physical") % slot_max];
+	random = get_random_long("Physical") % slot_max;
+
+	for (i = 0; i < slot_area_index; i++) {
+		if (random >= slot_areas[i].num) {
+			random -= slot_areas[i].num;
+			continue;
+		}
+		return slot_areas[i].addr + random * CONFIG_PHYSICAL_ALIGN;
+	}
+
+	if (i == slot_area_index)
+		debug_putstr("slots_fetch_random() failed!?\n");
+	return 0;
 }
 
 static void process_e820_entry(struct e820entry *entry,
 			       unsigned long minimum,
 			       unsigned long image_size)
 {
-	struct mem_vector region, img;
+	struct mem_vector region, out;
+	struct slot_area slot_area;
+	unsigned long min, start_orig;
 
 	/* Skip non-RAM entries. */
 	if (entry->type != E820_RAM)
 		return;
 
-	/* Ignore entries entirely above our maximum. */
-	if (entry->addr >= KERNEL_IMAGE_SIZE)
+	/* On 32-bit, ignore entries entirely above our maximum. */
+	if (IS_ENABLED(CONFIG_X86_32) && entry->addr >= KERNEL_IMAGE_SIZE)
 		return;
 
 	/* Ignore entries entirely below our minimum. */
@@ -363,31 +380,54 @@ static void process_e820_entry(struct e820entry *entry,
 	region.start = entry->addr;
 	region.size = entry->size;
 
-	/* Potentially raise address to minimum location. */
-	if (region.start < minimum)
-		region.start = minimum;
+	/* Give up if slot area array is full. */
+	while (slot_area_index < MAX_SLOT_AREA) {
+		start_orig = region.start;
 
-	/* Potentially raise address to meet alignment requirements. */
-	region.start = ALIGN(region.start, CONFIG_PHYSICAL_ALIGN);
+		/* Potentially raise address to minimum location. */
+		if (region.start < minimum)
+			region.start = minimum;
 
-	/* Did we raise the address above the bounds of this e820 region? */
-	if (region.start > entry->addr + entry->size)
-		return;
+		/* Potentially raise address to meet alignment needs. */
+		region.start = ALIGN(region.start, CONFIG_PHYSICAL_ALIGN);
 
-	/* Reduce size by any delta from the original address. */
-	region.size -= region.start - entry->addr;
+		/* Did we raise the address above this e820 region? */
+		if (region.start > entry->addr + entry->size)
+			return;
 
-	/* Reduce maximum size to fit end of image within maximum limit. */
-	if (region.start + region.size > KERNEL_IMAGE_SIZE)
-		region.size = KERNEL_IMAGE_SIZE - region.start;
+		/* Reduce size by any delta from the original address. */
+		region.size -= region.start - start_orig;
 
-	/* Walk each aligned slot and check for avoided areas. */
-	for (img.start = region.start, img.size = image_size ;
-	     mem_contains(&region, &img) ;
-	     img.start += CONFIG_PHYSICAL_ALIGN) {
-		if (mem_avoid_overlap(&img))
-			continue;
-		slots_append(img.start);
+		/* On 32-bit, reduce region size to fit within max size. */
+		if (IS_ENABLED(CONFIG_X86_32) &&
+		    region.start + region.size > KERNEL_IMAGE_SIZE)
+			region.size = KERNEL_IMAGE_SIZE - region.start;
+
+		/* Return if region can't contain decompressed kernel */
+		if (region.size < image_size)
+			return;
+
+		/* If nothing overlaps, store the region and return. */
+		if (!mem_avoid_overlap(&region)) {
+			store_slot_info(&region, image_size);
+			return;
+		}
+
+		/* Other wise, find the lowest overlap. */
+		min = mem_min_overlap(&region, &out);
+
+		/* Store the region if it can hold at least image_size. */
+		if (min > region.start + image_size) {
+			struct mem_vector tmp;
+
+			tmp.start = region.start;
+			tmp.size = min - region.start;
+			store_slot_info(&tmp, image_size);
+		}
+
+		/* Clip off the overlapping region and start over. */
+		region.size -= out.start - region.start + out.size;
+		region.start = out.start + out.size;
 	}
 }
 
@@ -403,6 +443,10 @@ static unsigned long find_random_phy_addr(unsigned long minimum,
 	/* Verify potential e820 positions, appending to slots list. */
 	for (i = 0; i < real_mode->e820_entries; i++) {
 		process_e820_entry(&real_mode->e820_map[i], minimum, size);
+		if (slot_area_index == MAX_SLOT_AREA) {
+			debug_putstr("Aborted e820 scan (slot_areas full)!\n");
+			break;
+		}
 	}
 
 	return slots_fetch_random();
-- 
2.6.3

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


#1379341 — [PATCH v5 13/21] x86, boot: Report overlap failures in memcpy

FromKees Cook <keescook@chromium.org>
Date2016-04-15 00:40 +0200
Subject[PATCH v5 13/21] x86, boot: Report overlap failures in memcpy
Message-ID<rnY5A-14p-17@gated-at.bofh.it>
In reply to#1379329
From: Yinghai Lu <yinghai@kernel.org>

parse_elf is using a local memcpy to move sections to their final running
position. However, this memcpy only supports non-overlapping arguments
(or dest < src).

To avoid future hard-to-debug surprises, this adds checking in memcpy to
detect the unhandled condition (which should not be happening currently).

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
[kees: rewrote changelog]
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 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 562d647289ac..c47ac162d3bd 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 11736a6a6670..39d0e9a53736 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 00e788be1db9..3a935d0c82a8 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.6.3

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


#1379888 — Re: [PATCH v5 13/21] x86, boot: Report overlap failures in memcpy

FromLasse Collin <lasse.collin@tukaani.org>
Date2016-04-15 17:00 +0200
SubjectRe: [PATCH v5 13/21] x86, boot: Report overlap failures in memcpy
Message-ID<rodnY-4BO-3@gated-at.bofh.it>
In reply to#1379341
On 2016-04-14 Kees Cook wrote:
> From: Yinghai Lu <yinghai@kernel.org>
> 
> parse_elf is using a local memcpy to move sections to their final
> running position. However, this memcpy only supports non-overlapping
> arguments (or dest < src).

The same copy of memcpy is used by the decompressors too.

> To avoid future hard-to-debug surprises, this adds checking in memcpy
> to detect the unhandled condition (which should not be happening
> currently).

It's already a minor surprise that memcpy is expected to work for
overlapping buffers at all. It could be good to have a comment about
it because "scroll" and parse_elf seem to rely on it.

On the other hand, the new code and error message take quite a few bytes
of space, so a complete memmove can be smaller:

void *memmove(void *dest, const void *src, size_t n)
{
	unsigned char *d = dest;
	const unsigned char *s = src;

	if (d <= s || d - s >= n)
		return __memcpy(dest, src, n);

	while (n-- > 0)
		d[n] = s[n];

	return dest;
}

Note that memmove is needed by lib/decompress_unxz.c. It contains its
own small version inside a "#ifndef memmove" block. That #ifndef should
be taken into account when adding a memmove symbol. Changing
decompress_unxz.c is fine but then one needs to think about other
archs too.

-- 
Lasse Collin  |  IRC: Larhzu @ IRCnet & Freenode

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


#1380175 — Re: [PATCH v5 13/21] x86, boot: Report overlap failures in memcpy

FromKees Cook <keescook@chromium.org>
Date2016-04-15 21:30 +0200
SubjectRe: [PATCH v5 13/21] x86, boot: Report overlap failures in memcpy
Message-ID<rohBh-86m-45@gated-at.bofh.it>
In reply to#1379888
On Fri, Apr 15, 2016 at 7:42 AM, Lasse Collin <lasse.collin@tukaani.org> wrote:
> On 2016-04-14 Kees Cook wrote:
>> From: Yinghai Lu <yinghai@kernel.org>
>>
>> parse_elf is using a local memcpy to move sections to their final
>> running position. However, this memcpy only supports non-overlapping
>> arguments (or dest < src).
>
> The same copy of memcpy is used by the decompressors too.
>
>> To avoid future hard-to-debug surprises, this adds checking in memcpy
>> to detect the unhandled condition (which should not be happening
>> currently).
>
> It's already a minor surprise that memcpy is expected to work for
> overlapping buffers at all. It could be good to have a comment about
> it because "scroll" and parse_elf seem to rely on it.
>
> On the other hand, the new code and error message take quite a few bytes
> of space, so a complete memmove can be smaller:
>
> void *memmove(void *dest, const void *src, size_t n)
> {
>         unsigned char *d = dest;
>         const unsigned char *s = src;
>
>         if (d <= s || d - s >= n)
>                 return __memcpy(dest, src, n);
>
>         while (n-- > 0)
>                 d[n] = s[n];
>
>         return dest;
> }
>
> Note that memmove is needed by lib/decompress_unxz.c. It contains its
> own small version inside a "#ifndef memmove" block. That #ifndef should
> be taken into account when adding a memmove symbol. Changing
> decompress_unxz.c is fine but then one needs to think about other
> archs too.

Awesome, thanks! I'd much prefer to fully fix this instead of just
throwing a warning. I'll get this added.

-Kees

-- 
Kees Cook
Chrome OS & Brillo Security

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


#1379342 — [PATCH v5 02/21] x86, KASLR: Handle kernel relocation above 2G

FromKees Cook <keescook@chromium.org>
Date2016-04-15 00:40 +0200
Subject[PATCH v5 02/21] x86, KASLR: Handle kernel relocation above 2G
Message-ID<rnY5A-14p-25@gated-at.bofh.it>
In reply to#1379329
From: Baoquan He <bhe@redhat.com>

When processing the relocation table, the offset used to calculate the
relocation is an int. This is sufficient for calculating the physical
address of the relocs entry on 32-bit systems and on 64-bit systems when
the relocation is under 2G. To handle relocations above 2G (seen in
situations like kexec, netboot, etc), this offset needs to be calculated
using a long to avoid wrapping and miscalculating the relocation.

Signed-off-by: Baoquan He <bhe@redhat.com>
[kees: rewrote changelog]
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/x86/boot/compressed/misc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index f35ad9eb1bf1..c4477d5f3fff 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -295,7 +295,7 @@ static void handle_relocations(void *output, unsigned long output_len)
 	 * So we work backwards from the end of the decompressed image.
 	 */
 	for (reloc = output + output_len - sizeof(*reloc); *reloc; reloc--) {
-		int extended = *reloc;
+		long extended = *reloc;
 		extended += map;
 
 		ptr = (unsigned long)extended;
-- 
2.6.3

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


#1379517 — Re: [PATCH v5 02/21] x86, KASLR: Handle kernel relocation above 2G

FromIngo Molnar <mingo@kernel.org>
Date2016-04-15 09:50 +0200
SubjectRe: [PATCH v5 02/21] x86, KASLR: Handle kernel relocation above 2G
Message-ID<ro6FP-7VI-7@gated-at.bofh.it>
In reply to#1379342
* Kees Cook <keescook@chromium.org> wrote:

> From: Baoquan He <bhe@redhat.com>
> 
> When processing the relocation table, the offset used to calculate the
> relocation is an int. This is sufficient for calculating the physical
> address of the relocs entry on 32-bit systems and on 64-bit systems when
> the relocation is under 2G. To handle relocations above 2G (seen in
> situations like kexec, netboot, etc), this offset needs to be calculated
> using a long to avoid wrapping and miscalculating the relocation.
> 
> Signed-off-by: Baoquan He <bhe@redhat.com>
> [kees: rewrote changelog]
> Signed-off-by: Kees Cook <keescook@chromium.org>
> ---
>  arch/x86/boot/compressed/misc.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
> index f35ad9eb1bf1..c4477d5f3fff 100644
> --- a/arch/x86/boot/compressed/misc.c
> +++ b/arch/x86/boot/compressed/misc.c
> @@ -295,7 +295,7 @@ static void handle_relocations(void *output, unsigned long output_len)
>  	 * So we work backwards from the end of the decompressed image.
>  	 */
>  	for (reloc = output + output_len - sizeof(*reloc); *reloc; reloc--) {
> -		int extended = *reloc;
> +		long extended = *reloc;
>  		extended += map;
>  
>  		ptr = (unsigned long)extended;

This patch and the code it patches is just plain sloppy. See this cast? This is an 
object lesson of why type casts in C are actively dangerous, they have hidden the 
32-bit truncation bug you've fixed with this patch.

But the primary bug, the cast, should be fixed! Together with all the other casts 
of 'extended'.

Also, the boot code should be reviewed for unnecessary casts, it seems to be a 
disease:

 triton:~/tip> git grep -cE '\(unsigned.*;$' arch/x86/boot/compressed/
 arch/x86/boot/compressed/aslr.c:14
 arch/x86/boot/compressed/eboot.c:41
 arch/x86/boot/compressed/misc.c:5
 arch/x86/boot/compressed/misc.h:2
 arch/x86/boot/compressed/mkpiggy.c:1
 arch/x86/boot/compressed/string.c:4

For example the type dance and overloaded usage that choose_kernel_location() does 
with the 'random' local variable in aslr.c is disgusting:

void choose_kernel_location(unsigned char *input,
				unsigned long input_size,
				unsigned char **output,
				unsigned long output_size,
				unsigned char **virt_offset)
{
	unsigned long random, min_addr;

	*virt_offset = (unsigned char *)LOAD_PHYSICAL_ADDR;

#ifdef CONFIG_HIBERNATION
	if (!cmdline_find_option_bool("kaslr")) {
		debug_putstr("KASLR disabled by default...\n");
		return;
	}
#else
	if (cmdline_find_option_bool("nokaslr")) {
		debug_putstr("KASLR disabled by cmdline...\n");
		return;
	}
#endif

	real_mode->hdr.loadflags |= KASLR_FLAG;

	/* Record the various known unsafe memory ranges. */
	mem_avoid_init((unsigned long)input, input_size,
		       (unsigned long)*output);

	/* Low end should be the smaller of 512M or initial location. */
	min_addr = min((unsigned long)*output, 512UL << 20);

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

	/* Pick random virtual address starting from LOAD_PHYSICAL_ADDR. */
	if (IS_ENABLED(CONFIG_X86_64))
		random = find_random_virt_offset(LOAD_PHYSICAL_ADDR,
						 output_size);
	*virt_offset = (unsigned char *)random;
}

Firstly, 'random' is a libc function name. We generally don't overload those.

Secondly, it's a random what? Variable names should make it plenty obvious. So it 
should probably be named 'random_addr'.

Third:

	/* Walk e820 and find a random address. */
	random = find_random_phy_addr(min_addr, output_size);

yeah, so what that comment tells us we knew already, due to the function name! 
What the comment should _really_ talk about is the high level purpose. Something 
like: 'Walk the e820 map and find a random free RAM address to which we can still 
decompress the whole kernel' would work so much better ...

Fourth, this function has seven (!!) type casts. We can sure do better.

Fifth:

        /* Pick random virtual address starting from LOAD_PHYSICAL_ADDR. */
        if (IS_ENABLED(CONFIG_X86_64))
                random = find_random_virt_offset(LOAD_PHYSICAL_ADDR,
                                                 output_size);
        *virt_offset = (unsigned char *)random;

So the purpose of this whole function is to pick _two_ random addresses: the 
random physical address to place the kernel at, and on x86_64, to also randomize 
the kernel virtual address, right? So exactly which comment tells us that it's 
about this? Names like 'choose_kernel_location' are singular and are actively 
misleading about this ...

... and then I haven't even mentioned small details like the imbalanced curly 
braces.

This code sucks, and I'm not surprised at all that it was broken. It should be 
improved before we can feature-extend it.

Thanks,

	Ingo

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


#1380128 — Re: [PATCH v5 02/21] x86, KASLR: Handle kernel relocation above 2G

FromKees Cook <keescook@chromium.org>
Date2016-04-15 21:10 +0200
SubjectRe: [PATCH v5 02/21] x86, KASLR: Handle kernel relocation above 2G
Message-ID<rohhT-7Wy-5@gated-at.bofh.it>
In reply to#1379517
On Fri, Apr 15, 2016 at 12:47 AM, Ingo Molnar <mingo@kernel.org> wrote:
>
> * Kees Cook <keescook@chromium.org> wrote:
>
>> From: Baoquan He <bhe@redhat.com>
>>
>> When processing the relocation table, the offset used to calculate the
>> relocation is an int. This is sufficient for calculating the physical
>> address of the relocs entry on 32-bit systems and on 64-bit systems when
>> the relocation is under 2G. To handle relocations above 2G (seen in
>> situations like kexec, netboot, etc), this offset needs to be calculated
>> using a long to avoid wrapping and miscalculating the relocation.
>>
>> Signed-off-by: Baoquan He <bhe@redhat.com>
>> [kees: rewrote changelog]
>> Signed-off-by: Kees Cook <keescook@chromium.org>
>> ---
>>  arch/x86/boot/compressed/misc.c | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
>> index f35ad9eb1bf1..c4477d5f3fff 100644
>> --- a/arch/x86/boot/compressed/misc.c
>> +++ b/arch/x86/boot/compressed/misc.c
>> @@ -295,7 +295,7 @@ static void handle_relocations(void *output, unsigned long output_len)
>>        * So we work backwards from the end of the decompressed image.
>>        */
>>       for (reloc = output + output_len - sizeof(*reloc); *reloc; reloc--) {
>> -             int extended = *reloc;
>> +             long extended = *reloc;
>>               extended += map;
>>
>>               ptr = (unsigned long)extended;
>
> This patch and the code it patches is just plain sloppy. See this cast? This is an
> object lesson of why type casts in C are actively dangerous, they have hidden the
> 32-bit truncation bug you've fixed with this patch.
>
> But the primary bug, the cast, should be fixed! Together with all the other casts
> of 'extended'.

In my defense, there's a ton of mixing of pointers vs unsigned longs
all through-out the boot code. And relocations are special since
they're explicitly designed to be sign-extended, etc. I'll clean
things up as best as I can.

>
> Also, the boot code should be reviewed for unnecessary casts, it seems to be a
> disease:
>
>  triton:~/tip> git grep -cE '\(unsigned.*;$' arch/x86/boot/compressed/
>  arch/x86/boot/compressed/aslr.c:14
>  arch/x86/boot/compressed/eboot.c:41
>  arch/x86/boot/compressed/misc.c:5
>  arch/x86/boot/compressed/misc.h:2
>  arch/x86/boot/compressed/mkpiggy.c:1
>  arch/x86/boot/compressed/string.c:4
>
> For example the type dance and overloaded usage that choose_kernel_location() does
> with the 'random' local variable in aslr.c is disgusting:
>
> void choose_kernel_location(unsigned char *input,
>                                 unsigned long input_size,
>                                 unsigned char **output,
>                                 unsigned long output_size,
>                                 unsigned char **virt_offset)
> {
>         unsigned long random, min_addr;
>
>         *virt_offset = (unsigned char *)LOAD_PHYSICAL_ADDR;
>
> #ifdef CONFIG_HIBERNATION
>         if (!cmdline_find_option_bool("kaslr")) {
>                 debug_putstr("KASLR disabled by default...\n");
>                 return;
>         }
> #else
>         if (cmdline_find_option_bool("nokaslr")) {
>                 debug_putstr("KASLR disabled by cmdline...\n");
>                 return;
>         }
> #endif
>
>         real_mode->hdr.loadflags |= KASLR_FLAG;
>
>         /* Record the various known unsafe memory ranges. */
>         mem_avoid_init((unsigned long)input, input_size,
>                        (unsigned long)*output);
>
>         /* Low end should be the smaller of 512M or initial location. */
>         min_addr = min((unsigned long)*output, 512UL << 20);
>
>         /* Walk e820 and find a random address. */
>         random = find_random_phy_addr(min_addr, output_size);
>         if (!random)
>                 debug_putstr("KASLR could not find suitable E820 region...\n");
>         else {
>                 if ((unsigned long)*output != random) {
>                         fill_pagetable(random, output_size);
>                         switch_pagetable();
>                         *output = (unsigned char *)random;
>                 }
>         }
>
>         /* Pick random virtual address starting from LOAD_PHYSICAL_ADDR. */
>         if (IS_ENABLED(CONFIG_X86_64))
>                 random = find_random_virt_offset(LOAD_PHYSICAL_ADDR,
>                                                  output_size);
>         *virt_offset = (unsigned char *)random;
> }
>
> Firstly, 'random' is a libc function name. We generally don't overload those.
>
> Secondly, it's a random what? Variable names should make it plenty obvious. So it
> should probably be named 'random_addr'.
>
> Third:
>
>         /* Walk e820 and find a random address. */
>         random = find_random_phy_addr(min_addr, output_size);
>
> yeah, so what that comment tells us we knew already, due to the function name!
> What the comment should _really_ talk about is the high level purpose. Something
> like: 'Walk the e820 map and find a random free RAM address to which we can still
> decompress the whole kernel' would work so much better ...
>
> Fourth, this function has seven (!!) type casts. We can sure do better.

Between the e820 values, the asm linkages, the relocations, etc,
there's a lot of mixing of types. As mentioned, I'll clean it up.

> Fifth:
>
>         /* Pick random virtual address starting from LOAD_PHYSICAL_ADDR. */
>         if (IS_ENABLED(CONFIG_X86_64))
>                 random = find_random_virt_offset(LOAD_PHYSICAL_ADDR,
>                                                  output_size);
>         *virt_offset = (unsigned char *)random;
>
> So the purpose of this whole function is to pick _two_ random addresses: the
> random physical address to place the kernel at, and on x86_64, to also randomize
> the kernel virtual address, right? So exactly which comment tells us that it's
> about this? Names like 'choose_kernel_location' are singular and are actively
> misleading about this ...
>
> ... and then I haven't even mentioned small details like the imbalanced curly
> braces.

I'll bite: which braces jumped out at you? I ran all this through
checkpatch.pl in the hopes of finding style mistakes... Is it the
mixing of single-line code with multi-line code in the if statements?

>
> This code sucks, and I'm not surprised at all that it was broken. It should be
> improved before we can feature-extend it.
>
> Thanks,
>
>         Ingo

-Kees

-- 
Kees Cook
Chrome OS & Brillo Security

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


#1379343 — [PATCH v5 16/21] x86, KASLR: Add virtual address choosing function

FromKees Cook <keescook@chromium.org>
Date2016-04-15 00:40 +0200
Subject[PATCH v5 16/21] x86, KASLR: Add virtual address choosing function
Message-ID<rnY5A-14p-27@gated-at.bofh.it>
In reply to#1379329
From: Baoquan He <bhe@redhat.com>

To support randomizing the kernel virtual address separately from the
physical address, this patch adds find_random_virt_offset() to choose
a slot anywhere between LOAD_PHYSICAL_ADDR and KERNEL_IMAGE_SIZE.
Since this address is virtual, not physical, we can place the kernel
anywhere in this region, as long as it is aligned and (in the case of
kernel being larger than the slot size) placed with enough room to load
the entire kernel image.

Signed-off-by: Baoquan He <bhe@redhat.com>
[kees: rewrote changelog, refactor slot calculation for readability]
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/x86/boot/compressed/aslr.c | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/arch/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c
index b06618000732..b527ff10372a 100644
--- a/arch/x86/boot/compressed/aslr.c
+++ b/arch/x86/boot/compressed/aslr.c
@@ -407,6 +407,29 @@ static unsigned long find_random_addr(unsigned long minimum,
 	return slots_fetch_random();
 }
 
+static unsigned long find_random_virt_offset(unsigned long minimum,
+				  unsigned long image_size)
+{
+	unsigned long slots, random;
+
+	/* Make sure minimum is aligned. */
+	minimum = ALIGN(minimum, CONFIG_PHYSICAL_ALIGN);
+	/* Align image_size for easy slot calculations. */
+	image_size = ALIGN(image_size, CONFIG_PHYSICAL_ALIGN);
+
+	/*
+	 * There are how many CONFIG_PHYSICAL_ALIGN-sized slots
+	 * that can hold image_size within the range of minimum to
+	 * KERNEL_IMAGE_SIZE?
+	 */
+	slots = (KERNEL_IMAGE_SIZE - minimum - image_size) /
+		 CONFIG_PHYSICAL_ALIGN + 1;
+
+	random = get_random_long() % slots;
+
+	return random * CONFIG_PHYSICAL_ALIGN + minimum;
+}
+
 unsigned char *choose_kernel_location(unsigned char *input,
 				      unsigned long input_size,
 				      unsigned char *output,
-- 
2.6.3

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


#1379344 — [PATCH v5 15/21] x86, KASLR: Add slot_area support functions

FromKees Cook <keescook@chromium.org>
Date2016-04-15 00:40 +0200
Subject[PATCH v5 15/21] x86, KASLR: Add slot_area support functions
Message-ID<rnY5B-14p-37@gated-at.bofh.it>
In reply to#1379329
From: Baoquan He <bhe@redhat.com>

The function store_slot_info() is used to calculate the slot info of the
passed-in memory region and stores it into slot_areas[] after adjusting
for alignment and size requirements.

The function mem_min_overlap() is used to iterate over all mem_avoid
regions to find the earliest mem_avoid address that conflicts with the
given memory region. (For example, with the region [1024M, 2048M), if
there is a mem_avoid of [1536M, 1664M), this returns 1536M.) This can
be used to split memory regions when building the slot_area array.

Signed-off-by: Baoquan He <bhe@redhat.com>
[kees: rewrote changelog]
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 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 abe618d489ea..b06618000732 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[KERNEL_IMAGE_SIZE / CONFIG_PHYSICAL_ALIGN];
 
 struct slot_area {
@@ -272,6 +306,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.6.3

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


#1379345 — [PATCH v5 04/21] x86, boot: Move compressed kernel to end of decompression buffer

FromKees Cook <keescook@chromium.org>
Date2016-04-15 00:40 +0200
Subject[PATCH v5 04/21] x86, boot: Move compressed kernel to end of decompression buffer
Message-ID<rnY5B-14p-29@gated-at.bofh.it>
In reply to#1379329
From: Yinghai Lu <yinghai@kernel.org>

This change makes later calculations about where the kernel is located
easier to reason about. To better understand this change, we must first
clarify what VO and ZO are. They were introduced in commits by hpa:

77d1a49 x86, boot: make symbols from the main vmlinux available
37ba7ab x86, boot: make kernel_alignment adjustable; new bzImage fields

Specifically:

VO:
- uncompressed kernel image
- size: VO__end - VO__text ("VO_INIT_SIZE" define)

ZO:
- bootable compressed kernel image (boot/compressed/vmlinux)
- head text + compressed kernel (VO and relocs table) + decompressor code
- size: ZO__end - ZO_startup_32 ("ZO_INIT_SIZE" define, though see below)

The INIT_SIZE definition is used to find the larger of the two image sizes:

 #define ZO_INIT_SIZE    (ZO__end - ZO_startup_32 + ZO_z_extract_offset)
 #define VO_INIT_SIZE    (VO__end - VO__text)
 #if ZO_INIT_SIZE > VO_INIT_SIZE
 #define INIT_SIZE ZO_INIT_SIZE
 #else
 #define INIT_SIZE VO_INIT_SIZE
 #endif

The current code uses extract_offset to decide where to position the
copied ZO (i.e. ZO starts at extract_offset). (This is why ZO_INIT_SIZE
currently includes the extract_offset.)

When INIT_SIZE is bigger than VO_INIT_SIZE (uncommon but possible),
the copied ZO occupies the memory from extract_offset to the end of
decompression buffer. It overlaps with the soon-to-be-uncompressed kernel
like this:

                            |-----compressed kernel image------|
                            V                                  V
0                       extract_offset                      +INIT_SIZE
|-----------|---------------|-------------------------|--------|
            |               |                         |        |
          VO__text      startup_32 of ZO          VO__end    ZO__end
            ^                                         ^
            |-------uncompressed kernel image---------|

When INIT_SIZE is equal to VO_INIT_SIZE (likely) there's still space
left from end of ZO to the end of decompressing buffer, like below.

                            |-compressed kernel image-|
                            V                         V
0                       extract_offset                      +INIT_SIZE
|-----------|---------------|-------------------------|--------|
            |               |                         |        |
          VO__text      startup_32 of ZO          ZO__end    VO__end
            ^                                                  ^
            |------------uncompressed kernel image-------------|

To simplify calculations and avoid special cases, it is cleaner to
always place the compressed kernel image in memory so that ZO__end
is at the end of the decompression buffer, instead of placing that
start extract_offset as is currently done.

This patch adds BP_init_size (which is the INIT_SIZE as passed in from
the boot_params) into asm-offsets.c to make it visible to the assembly
code. Then when moving the ZO, it calculates the starting position of
the copied ZO (via BP_init_size and the ZO run size) so that the VO__end
will be at the end of the decompression buffer. To make the position
calculation safe, the end of ZO is page aligned (and a comment is added
to the existing VO alignment for good measure).

Signed-off-by: Yinghai Lu <yinghai@kernel.org>
[kees: rewrote changelog]
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/x86/boot/compressed/head_32.S     | 11 +++++++++--
 arch/x86/boot/compressed/head_64.S     |  8 ++++++--
 arch/x86/boot/compressed/mkpiggy.c     |  3 ---
 arch/x86/boot/compressed/vmlinux.lds.S |  1 +
 arch/x86/kernel/asm-offsets.c          |  1 +
 arch/x86/kernel/vmlinux.lds.S          |  2 +-
 6 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
index 8ef964ddc18e..0c140f99c602 100644
--- a/arch/x86/boot/compressed/head_32.S
+++ b/arch/x86/boot/compressed/head_32.S
@@ -148,7 +148,9 @@ preferred_addr:
 1:
 
 	/* Target address to relocate to for decompression */
-	addl	$z_extract_offset, %ebx
+	movl    BP_init_size(%esi), %eax
+	subl    $_end, %eax
+	addl    %eax, %ebx
 
 	/* Set up the stack */
 	leal	boot_stack_end(%ebx), %esp
@@ -210,8 +212,13 @@ relocated:
 				/* push arguments for decompress_kernel: */
 	pushl	$z_run_size	/* size of kernel with .bss and .brk */
 	pushl	$z_output_len	/* decompressed length, end of relocs */
-	leal	z_extract_offset_negative(%ebx), %ebp
+
+	movl    BP_init_size(%esi), %eax
+	subl    $_end, %eax
+	movl    %ebx, %ebp
+	subl    %eax, %ebp
 	pushl	%ebp		/* output address */
+
 	pushl	$z_input_len	/* input_len */
 	leal	input_data(%ebx), %eax
 	pushl	%eax		/* input_data */
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index b0c0d16ef58d..67dd8d300c61 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -102,7 +102,9 @@ ENTRY(startup_32)
 1:
 
 	/* Target address to relocate to for decompression */
-	addl	$z_extract_offset, %ebx
+	movl	BP_init_size(%esi), %eax
+	subl	$_end, %eax
+	addl	%eax, %ebx
 
 /*
  * Prepare for entering 64 bit mode
@@ -330,7 +332,9 @@ preferred_addr:
 1:
 
 	/* Target address to relocate to for decompression */
-	leaq	z_extract_offset(%rbp), %rbx
+	movl	BP_init_size(%rsi), %ebx
+	subl	$_end, %ebx
+	addq	%rbp, %rbx
 
 	/* Set up the stack */
 	leaq	boot_stack_end(%rbx), %rsp
diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c
index d8222f213182..b980046c3329 100644
--- a/arch/x86/boot/compressed/mkpiggy.c
+++ b/arch/x86/boot/compressed/mkpiggy.c
@@ -85,9 +85,6 @@ int main(int argc, char *argv[])
 	printf("z_output_len = %lu\n", (unsigned long)olen);
 	printf(".globl z_extract_offset\n");
 	printf("z_extract_offset = 0x%lx\n", offs);
-	/* z_extract_offset_negative allows simplification of head_32.S */
-	printf(".globl z_extract_offset_negative\n");
-	printf("z_extract_offset_negative = -0x%lx\n", offs);
 	printf(".globl z_run_size\n");
 	printf("z_run_size = %lu\n", run_size);
 
diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S
index 34d047c98284..e24e0a0c90c9 100644
--- a/arch/x86/boot/compressed/vmlinux.lds.S
+++ b/arch/x86/boot/compressed/vmlinux.lds.S
@@ -70,5 +70,6 @@ SECTIONS
 		_epgtable = . ;
 	}
 #endif
+	. = ALIGN(PAGE_SIZE);	/* keep ZO size page aligned */
 	_end = .;
 }
diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
index 5c042466f274..674134e9f5e5 100644
--- a/arch/x86/kernel/asm-offsets.c
+++ b/arch/x86/kernel/asm-offsets.c
@@ -80,6 +80,7 @@ void common(void) {
 	OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch);
 	OFFSET(BP_version, boot_params, hdr.version);
 	OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment);
+	OFFSET(BP_init_size, boot_params, hdr.init_size);
 	OFFSET(BP_pref_address, boot_params, hdr.pref_address);
 	OFFSET(BP_code32_start, boot_params, hdr.code32_start);
 
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 4c941f88d405..9297a002d8e5 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -334,7 +334,7 @@ SECTIONS
 		__brk_limit = .;
 	}
 
-	. = ALIGN(PAGE_SIZE);
+	. = ALIGN(PAGE_SIZE);		/* keep VO_INIT_SIZE page aligned */
 	_end = .;
 
         STABS_DEBUG
-- 
2.6.3

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


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | linux.kernel


csiph-web