2018-12-28 12:17:18

by Dave Young

[permalink] [raw]
Subject: [PATCH V2] x86/kexec: fix a kexec_file_load failure

The code cleanup mentioned in Fixes tag changed the behavior of
kexec_locate_mem_hole. The kexec_locate_mem_hole will try to
allocate free memory only when kbuf.mem is initialized as zero.

But in x86 kexec_file_load implementation there are a few places
the kbuf.mem is reused like below:
/* kbuf initialized, kbuf.mem = 0 */
...
kexec_add_buffer()
...
kexec_add_buffer()

The second kexec_add_buffer will reuse previous kbuf but not
reinitialize the kbuf.mem.

Thus kexec_file_load failed because the sanity check failed.

So explictily reset kbuf.mem to fix the issue.

Fixes: b6664ba42f14 ("s390, kexec_file: drop arch_kexec_mem_walk()")
Signed-off-by: Dave Young <[email protected]>
Cc: <[email protected]>
---
V1 -> V2: use KEXEC_BUF_MEM_UNKNOWN in code.
arch/x86/kernel/crash.c | 1 +
arch/x86/kernel/kexec-bzimage64.c | 2 ++
2 files changed, 3 insertions(+)

diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index f631a3f15587..6b7890c7889b 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -469,6 +469,7 @@ int crash_load_segments(struct kimage *image)

kbuf.memsz = kbuf.bufsz;
kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
+ kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
ret = kexec_add_buffer(&kbuf);
if (ret) {
vfree((void *)image->arch.elf_headers);
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index 278cd07228dd..0d5efa34f359 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -434,6 +434,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
kbuf.memsz = PAGE_ALIGN(header->init_size);
kbuf.buf_align = header->kernel_alignment;
kbuf.buf_min = MIN_KERNEL_LOAD_ADDR;
+ kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
ret = kexec_add_buffer(&kbuf);
if (ret)
goto out_free_params;
@@ -448,6 +449,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
kbuf.bufsz = kbuf.memsz = initrd_len;
kbuf.buf_align = PAGE_SIZE;
kbuf.buf_min = MIN_INITRD_LOAD_ADDR;
+ kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
ret = kexec_add_buffer(&kbuf);
if (ret)
goto out_free_params;
--
2.17.0



2019-01-08 03:25:39

by Dave Young

[permalink] [raw]
Subject: Re: [PATCH V2] x86/kexec: fix a kexec_file_load failure

On 12/28/18 at 09:12am, Dave Young wrote:
> The code cleanup mentioned in Fixes tag changed the behavior of
> kexec_locate_mem_hole. The kexec_locate_mem_hole will try to
> allocate free memory only when kbuf.mem is initialized as zero.
>
> But in x86 kexec_file_load implementation there are a few places
> the kbuf.mem is reused like below:
> /* kbuf initialized, kbuf.mem = 0 */
> ...
> kexec_add_buffer()
> ...
> kexec_add_buffer()
>
> The second kexec_add_buffer will reuse previous kbuf but not
> reinitialize the kbuf.mem.
>
> Thus kexec_file_load failed because the sanity check failed.
>
> So explictily reset kbuf.mem to fix the issue.
>
> Fixes: b6664ba42f14 ("s390, kexec_file: drop arch_kexec_mem_walk()")
> Signed-off-by: Dave Young <[email protected]>
> Cc: <[email protected]>
> ---
> V1 -> V2: use KEXEC_BUF_MEM_UNKNOWN in code.
> arch/x86/kernel/crash.c | 1 +
> arch/x86/kernel/kexec-bzimage64.c | 2 ++
> 2 files changed, 3 insertions(+)
>
> diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
> index f631a3f15587..6b7890c7889b 100644
> --- a/arch/x86/kernel/crash.c
> +++ b/arch/x86/kernel/crash.c
> @@ -469,6 +469,7 @@ int crash_load_segments(struct kimage *image)
>
> kbuf.memsz = kbuf.bufsz;
> kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
> + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> ret = kexec_add_buffer(&kbuf);
> if (ret) {
> vfree((void *)image->arch.elf_headers);
> diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
> index 278cd07228dd..0d5efa34f359 100644
> --- a/arch/x86/kernel/kexec-bzimage64.c
> +++ b/arch/x86/kernel/kexec-bzimage64.c
> @@ -434,6 +434,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
> kbuf.memsz = PAGE_ALIGN(header->init_size);
> kbuf.buf_align = header->kernel_alignment;
> kbuf.buf_min = MIN_KERNEL_LOAD_ADDR;
> + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> ret = kexec_add_buffer(&kbuf);
> if (ret)
> goto out_free_params;
> @@ -448,6 +449,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
> kbuf.bufsz = kbuf.memsz = initrd_len;
> kbuf.buf_align = PAGE_SIZE;
> kbuf.buf_min = MIN_INITRD_LOAD_ADDR;
> + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> ret = kexec_add_buffer(&kbuf);
> if (ret)
> goto out_free_params;
> --
> 2.17.0
>


Ping, this is a regression issue, can we get this fixed?

Thanks
Dave

2019-01-08 05:26:23

by Baoquan He

[permalink] [raw]
Subject: Re: [PATCH V2] x86/kexec: fix a kexec_file_load failure

On 12/28/18 at 09:12am, Dave Young wrote:
> The code cleanup mentioned in Fixes tag changed the behavior of
> kexec_locate_mem_hole. The kexec_locate_mem_hole will try to
> allocate free memory only when kbuf.mem is initialized as zero.
>
> But in x86 kexec_file_load implementation there are a few places
> the kbuf.mem is reused like below:
> /* kbuf initialized, kbuf.mem = 0 */
> ...
> kexec_add_buffer()
> ...
> kexec_add_buffer()
>
> The second kexec_add_buffer will reuse previous kbuf but not
> reinitialize the kbuf.mem.
>
> Thus kexec_file_load failed because the sanity check failed.
>
> So explictily reset kbuf.mem to fix the issue.
>
> Fixes: b6664ba42f14 ("s390, kexec_file: drop arch_kexec_mem_walk()")
> Signed-off-by: Dave Young <[email protected]>
> Cc: <[email protected]>
> ---
> V1 -> V2: use KEXEC_BUF_MEM_UNKNOWN in code.
> arch/x86/kernel/crash.c | 1 +
> arch/x86/kernel/kexec-bzimage64.c | 2 ++
> 2 files changed, 3 insertions(+)
>
> diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
> index f631a3f15587..6b7890c7889b 100644
> --- a/arch/x86/kernel/crash.c
> +++ b/arch/x86/kernel/crash.c
> @@ -469,6 +469,7 @@ int crash_load_segments(struct kimage *image)
>

Wondering why this place doesn't need the initialization assignment.
Isn't it to assign in all places before kexec_add_buffer() calling?

/* Add backup segment. */
if (image->arch.backup_src_sz) {
}

> kbuf.memsz = kbuf.bufsz;
> kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
> + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> ret = kexec_add_buffer(&kbuf);
> if (ret) {
> vfree((void *)image->arch.elf_headers);
> diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
> index 278cd07228dd..0d5efa34f359 100644
> --- a/arch/x86/kernel/kexec-bzimage64.c
> +++ b/arch/x86/kernel/kexec-bzimage64.c
> @@ -434,6 +434,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
> kbuf.memsz = PAGE_ALIGN(header->init_size);
> kbuf.buf_align = header->kernel_alignment;
> kbuf.buf_min = MIN_KERNEL_LOAD_ADDR;

Same question for bzImage64_load(), there are three kexec_add_buffer()
calling, I only saw two initialization in this patch.

> + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> ret = kexec_add_buffer(&kbuf);
> if (ret)
> goto out_free_params;
> @@ -448,6 +449,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
> kbuf.bufsz = kbuf.memsz = initrd_len;
> kbuf.buf_align = PAGE_SIZE;
> kbuf.buf_min = MIN_INITRD_LOAD_ADDR;
> + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> ret = kexec_add_buffer(&kbuf);
> if (ret)
> goto out_free_params;
> --
> 2.17.0
>

2019-01-08 08:48:53

by Dave Young

[permalink] [raw]
Subject: Re: [PATCH V2] x86/kexec: fix a kexec_file_load failure

On 01/08/19 at 01:24pm, Baoquan He wrote:
> On 12/28/18 at 09:12am, Dave Young wrote:
> > The code cleanup mentioned in Fixes tag changed the behavior of
> > kexec_locate_mem_hole. The kexec_locate_mem_hole will try to
> > allocate free memory only when kbuf.mem is initialized as zero.
> >
> > But in x86 kexec_file_load implementation there are a few places
> > the kbuf.mem is reused like below:
> > /* kbuf initialized, kbuf.mem = 0 */
> > ...
> > kexec_add_buffer()
> > ...
> > kexec_add_buffer()
> >
> > The second kexec_add_buffer will reuse previous kbuf but not
> > reinitialize the kbuf.mem.
> >
> > Thus kexec_file_load failed because the sanity check failed.
> >
> > So explictily reset kbuf.mem to fix the issue.
> >
> > Fixes: b6664ba42f14 ("s390, kexec_file: drop arch_kexec_mem_walk()")
> > Signed-off-by: Dave Young <[email protected]>
> > Cc: <[email protected]>
> > ---
> > V1 -> V2: use KEXEC_BUF_MEM_UNKNOWN in code.
> > arch/x86/kernel/crash.c | 1 +
> > arch/x86/kernel/kexec-bzimage64.c | 2 ++
> > 2 files changed, 3 insertions(+)
> >
> > diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
> > index f631a3f15587..6b7890c7889b 100644
> > --- a/arch/x86/kernel/crash.c
> > +++ b/arch/x86/kernel/crash.c
> > @@ -469,6 +469,7 @@ int crash_load_segments(struct kimage *image)
> >
>
> Wondering why this place doesn't need the initialization assignment.
> Isn't it to assign in all places before kexec_add_buffer() calling?

C designated initializers will make sure to initialize it as zero.
We set KEXEC_BUF_MEM_UNKNOWN as 0 so it just works.

>
> /* Add backup segment. */
> if (image->arch.backup_src_sz) {
> }
>
> > kbuf.memsz = kbuf.bufsz;
> > kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
> > + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> > ret = kexec_add_buffer(&kbuf);
> > if (ret) {
> > vfree((void *)image->arch.elf_headers);
> > diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
> > index 278cd07228dd..0d5efa34f359 100644
> > --- a/arch/x86/kernel/kexec-bzimage64.c
> > +++ b/arch/x86/kernel/kexec-bzimage64.c
> > @@ -434,6 +434,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
> > kbuf.memsz = PAGE_ALIGN(header->init_size);
> > kbuf.buf_align = header->kernel_alignment;
> > kbuf.buf_min = MIN_KERNEL_LOAD_ADDR;
>
> Same question for bzImage64_load(), there are three kexec_add_buffer()
> calling, I only saw two initialization in this patch.
>
> > + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> > ret = kexec_add_buffer(&kbuf);
> > if (ret)
> > goto out_free_params;
> > @@ -448,6 +449,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
> > kbuf.bufsz = kbuf.memsz = initrd_len;
> > kbuf.buf_align = PAGE_SIZE;
> > kbuf.buf_min = MIN_INITRD_LOAD_ADDR;
> > + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> > ret = kexec_add_buffer(&kbuf);
> > if (ret)
> > goto out_free_params;
> > --
> > 2.17.0
> >

Thanks
Dave

2019-01-08 08:54:45

by Baoquan He

[permalink] [raw]
Subject: Re: [PATCH V2] x86/kexec: fix a kexec_file_load failure

On 01/08/19 at 04:46pm, Dave Young wrote:
> > Wondering why this place doesn't need the initialization assignment.
> > Isn't it to assign in all places before kexec_add_buffer() calling?
>
> C designated initializers will make sure to initialize it as zero.
> We set KEXEC_BUF_MEM_UNKNOWN as 0 so it just works.

Got it, it works, thanks. People may need check code to find out
KEXEC_BUF_MEM_UNKNOWN is 0, then realize this fact.

Other than this, it looks good to me, ack it.

Acked-by: Baoquan He <[email protected]>

Thanks
Baoquan

2019-01-08 09:13:37

by Dave Young

[permalink] [raw]
Subject: Re: [PATCH V2] x86/kexec: fix a kexec_file_load failure

On 01/08/19 at 04:51pm, Baoquan He wrote:
> On 01/08/19 at 04:46pm, Dave Young wrote:
> > > Wondering why this place doesn't need the initialization assignment.
> > > Isn't it to assign in all places before kexec_add_buffer() calling?
> >
> > C designated initializers will make sure to initialize it as zero.
> > We set KEXEC_BUF_MEM_UNKNOWN as 0 so it just works.
>
> Got it, it works, thanks. People may need check code to find out
> KEXEC_BUF_MEM_UNKNOWN is 0, then realize this fact.

Agreed, it is not very clear now. It's better to improve it with some explict
initial value since we have the macro. But since this is a regression
I suggest to fix the bug first, I can send a patch later for the
improvement.

Thanks!
>
> Other than this, it looks good to me, ack it.
>
> Acked-by: Baoquan He <[email protected]>
>
> Thanks
> Baoquan

2019-01-15 06:28:26

by Dave Young

[permalink] [raw]
Subject: Re: [PATCH V2] x86/kexec: fix a kexec_file_load failure

On 12/28/18 at 09:12am, Dave Young wrote:
> The code cleanup mentioned in Fixes tag changed the behavior of
> kexec_locate_mem_hole. The kexec_locate_mem_hole will try to
> allocate free memory only when kbuf.mem is initialized as zero.
>
> But in x86 kexec_file_load implementation there are a few places
> the kbuf.mem is reused like below:
> /* kbuf initialized, kbuf.mem = 0 */
> ...
> kexec_add_buffer()
> ...
> kexec_add_buffer()
>
> The second kexec_add_buffer will reuse previous kbuf but not
> reinitialize the kbuf.mem.
>
> Thus kexec_file_load failed because the sanity check failed.
>
> So explictily reset kbuf.mem to fix the issue.
>
> Fixes: b6664ba42f14 ("s390, kexec_file: drop arch_kexec_mem_walk()")
> Signed-off-by: Dave Young <[email protected]>
> Cc: <[email protected]>
> ---
> V1 -> V2: use KEXEC_BUF_MEM_UNKNOWN in code.
> arch/x86/kernel/crash.c | 1 +
> arch/x86/kernel/kexec-bzimage64.c | 2 ++
> 2 files changed, 3 insertions(+)
>
> diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
> index f631a3f15587..6b7890c7889b 100644
> --- a/arch/x86/kernel/crash.c
> +++ b/arch/x86/kernel/crash.c
> @@ -469,6 +469,7 @@ int crash_load_segments(struct kimage *image)
>
> kbuf.memsz = kbuf.bufsz;
> kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
> + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> ret = kexec_add_buffer(&kbuf);
> if (ret) {
> vfree((void *)image->arch.elf_headers);
> diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
> index 278cd07228dd..0d5efa34f359 100644
> --- a/arch/x86/kernel/kexec-bzimage64.c
> +++ b/arch/x86/kernel/kexec-bzimage64.c
> @@ -434,6 +434,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
> kbuf.memsz = PAGE_ALIGN(header->init_size);
> kbuf.buf_align = header->kernel_alignment;
> kbuf.buf_min = MIN_KERNEL_LOAD_ADDR;
> + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> ret = kexec_add_buffer(&kbuf);
> if (ret)
> goto out_free_params;
> @@ -448,6 +449,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
> kbuf.bufsz = kbuf.memsz = initrd_len;
> kbuf.buf_align = PAGE_SIZE;
> kbuf.buf_min = MIN_INITRD_LOAD_ADDR;
> + kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
> ret = kexec_add_buffer(&kbuf);
> if (ret)
> goto out_free_params;
> --
> 2.17.0
>

Andrew, Boris, can any of you take this patch? Without this fix we have a regression.

Thanks
Dave

Subject: [tip:x86/urgent] x86/kexec: Fix a kexec_file_load() failure

Commit-ID: 993a110319a4a60aadbd02f6defdebe048f7773b
Gitweb: https://git.kernel.org/tip/993a110319a4a60aadbd02f6defdebe048f7773b
Author: Dave Young <[email protected]>
AuthorDate: Fri, 28 Dec 2018 09:12:47 +0800
Committer: Borislav Petkov <[email protected]>
CommitDate: Tue, 15 Jan 2019 12:12:50 +0100

x86/kexec: Fix a kexec_file_load() failure

Commit

b6664ba42f14 ("s390, kexec_file: drop arch_kexec_mem_walk()")

changed the behavior of kexec_locate_mem_hole(): it will try to allocate
free memory only when kbuf.mem is initialized to zero.

However, x86's kexec_file_load() implementation reuses a struct
kexec_buf allocated on the stack and its kbuf.mem member gets set by
each kexec_add_buffer() invocation.

The second kexec_add_buffer() will reuse the same kbuf but not
reinitialize kbuf.mem.

Therefore, explictily reset kbuf.mem each time in order for
kexec_locate_mem_hole() to locate a free memory region each time.

[ bp: massage commit message. ]

Fixes: b6664ba42f14 ("s390, kexec_file: drop arch_kexec_mem_walk()")
Signed-off-by: Dave Young <[email protected]>
Signed-off-by: Borislav Petkov <[email protected]>
Acked-by: Baoquan He <[email protected]>
Cc: "Eric W. Biederman" <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: AKASHI Takahiro <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Martin Schwidefsky <[email protected]>
Cc: Philipp Rudo <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Vivek Goyal <[email protected]>
Cc: Yannik Sembritzki <[email protected]>
Cc: Yi Wang <[email protected]>
Cc: [email protected]
Cc: x86-ml <[email protected]>
Link: https://lkml.kernel.org/r/[email protected]
---
arch/x86/kernel/crash.c | 1 +
arch/x86/kernel/kexec-bzimage64.c | 2 ++
2 files changed, 3 insertions(+)

diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index c8b07d8ea5a2..17ffc869cab8 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -470,6 +470,7 @@ int crash_load_segments(struct kimage *image)

kbuf.memsz = kbuf.bufsz;
kbuf.buf_align = ELF_CORE_HEADER_ALIGN;
+ kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
ret = kexec_add_buffer(&kbuf);
if (ret) {
vfree((void *)image->arch.elf_headers);
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index 278cd07228dd..0d5efa34f359 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -434,6 +434,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
kbuf.memsz = PAGE_ALIGN(header->init_size);
kbuf.buf_align = header->kernel_alignment;
kbuf.buf_min = MIN_KERNEL_LOAD_ADDR;
+ kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
ret = kexec_add_buffer(&kbuf);
if (ret)
goto out_free_params;
@@ -448,6 +449,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel,
kbuf.bufsz = kbuf.memsz = initrd_len;
kbuf.buf_align = PAGE_SIZE;
kbuf.buf_min = MIN_INITRD_LOAD_ADDR;
+ kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
ret = kexec_add_buffer(&kbuf);
if (ret)
goto out_free_params;