Skip to content

Commit 40c50c1

Browse files
committed
kexec, x86/purgatory: Unbreak it and clean it up
The purgatory code defines global variables which are referenced via a symbol lookup in the kexec code (core and arch). A recent commit addressing sparse warnings made these static and thereby broke kexec_file. Why did this happen? Simply because the whole machinery is undocumented and lacks any form of forward declarations. The variable names are unspecific and lack a prefix, so adding forward declarations creates shadow variables in the core code. Aside of that the code relies on magic constants and duplicate struct definitions with no way to ensure that these things stay in sync. The section placement of the purgatory variables happened by chance and not by design. Unbreak kexec and cleanup the mess: - Add proper forward declarations and document the usage - Use common struct definition - Use the proper common defines instead of magic constants - Add a purgatory_ prefix to have a proper name space - Use ARRAY_SIZE() instead of a homebrewn reimplementation - Add proper sections to the purgatory variables [ From Mike ] Fixes: 72042a8 ("x86/purgatory: Make functions and variables static") Reported-by: Mike Galbraith <<[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Cc: Nicholas Mc Guire <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Vivek Goyal <[email protected]> Cc: "Tobin C. Harding" <[email protected]> Link: http://lkml.kernel.org/r/alpine.DEB.2.20.1703101315140.3681@nanos Signed-off-by: Thomas Gleixner <[email protected]>
1 parent bba8376 commit 40c50c1

File tree

10 files changed

+78
-46
lines changed

10 files changed

+78
-46
lines changed

arch/powerpc/purgatory/trampoline.S

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,13 @@ dt_offset:
116116

117117
.data
118118
.balign 8
119-
.globl sha256_digest
120-
sha256_digest:
119+
.globl purgatory_sha256_digest
120+
purgatory_sha256_digest:
121121
.skip 32
122-
.size sha256_digest, . - sha256_digest
122+
.size purgatory_sha256_digest, . - purgatory_sha256_digest
123123

124124
.balign 8
125-
.globl sha_regions
126-
sha_regions:
125+
.globl purgatory_sha_regions
126+
purgatory_sha_regions:
127127
.skip 8 * 2 * 16
128-
.size sha_regions, . - sha_regions
128+
.size purgatory_sha_regions, . - purgatory_sha_regions

arch/x86/include/asm/purgatory.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#ifndef _ASM_X86_PURGATORY_H
2+
#define _ASM_X86_PURGATORY_H
3+
4+
#ifndef __ASSEMBLY__
5+
#include <linux/purgatory.h>
6+
7+
extern void purgatory(void);
8+
/*
9+
* These forward declarations serve two purposes:
10+
*
11+
* 1) Make sparse happy when checking arch/purgatory
12+
* 2) Document that these are required to be global so the symbol
13+
* lookup in kexec works
14+
*/
15+
extern unsigned long purgatory_backup_dest;
16+
extern unsigned long purgatory_backup_src;
17+
extern unsigned long purgatory_backup_sz;
18+
#endif /* __ASSEMBLY__ */
19+
20+
#endif /* _ASM_PURGATORY_H */

arch/x86/kernel/machine_kexec_64.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,19 +194,22 @@ static int arch_update_purgatory(struct kimage *image)
194194

195195
/* Setup copying of backup region */
196196
if (image->type == KEXEC_TYPE_CRASH) {
197-
ret = kexec_purgatory_get_set_symbol(image, "backup_dest",
197+
ret = kexec_purgatory_get_set_symbol(image,
198+
"purgatory_backup_dest",
198199
&image->arch.backup_load_addr,
199200
sizeof(image->arch.backup_load_addr), 0);
200201
if (ret)
201202
return ret;
202203

203-
ret = kexec_purgatory_get_set_symbol(image, "backup_src",
204+
ret = kexec_purgatory_get_set_symbol(image,
205+
"purgatory_backup_src",
204206
&image->arch.backup_src_start,
205207
sizeof(image->arch.backup_src_start), 0);
206208
if (ret)
207209
return ret;
208210

209-
ret = kexec_purgatory_get_set_symbol(image, "backup_sz",
211+
ret = kexec_purgatory_get_set_symbol(image,
212+
"purgatory_backup_sz",
210213
&image->arch.backup_src_sz,
211214
sizeof(image->arch.backup_src_sz), 0);
212215
if (ret)

arch/x86/purgatory/purgatory.c

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,19 @@
1010
* Version 2. See the file COPYING for more details.
1111
*/
1212

13+
#include <linux/bug.h>
14+
#include <asm/purgatory.h>
15+
1316
#include "sha256.h"
14-
#include "purgatory.h"
1517
#include "../boot/string.h"
1618

17-
struct sha_region {
18-
unsigned long start;
19-
unsigned long len;
20-
};
21-
22-
static unsigned long backup_dest;
23-
static unsigned long backup_src;
24-
static unsigned long backup_sz;
19+
unsigned long purgatory_backup_dest __section(.kexec-purgatory);
20+
unsigned long purgatory_backup_src __section(.kexec-purgatory);
21+
unsigned long purgatory_backup_sz __section(.kexec-purgatory);
2522

26-
static u8 sha256_digest[SHA256_DIGEST_SIZE] = { 0 };
23+
u8 purgatory_sha256_digest[SHA256_DIGEST_SIZE] __section(.kexec-purgatory);
2724

28-
struct sha_region sha_regions[16] = {};
25+
struct kexec_sha_region purgatory_sha_regions[KEXEC_SEGMENT_MAX] __section(.kexec-purgatory);
2926

3027
/*
3128
* On x86, second kernel requries first 640K of memory to boot. Copy
@@ -34,26 +31,28 @@ struct sha_region sha_regions[16] = {};
3431
*/
3532
static int copy_backup_region(void)
3633
{
37-
if (backup_dest)
38-
memcpy((void *)backup_dest, (void *)backup_src, backup_sz);
39-
34+
if (purgatory_backup_dest) {
35+
memcpy((void *)purgatory_backup_dest,
36+
(void *)purgatory_backup_src, purgatory_backup_sz);
37+
}
4038
return 0;
4139
}
4240

4341
static int verify_sha256_digest(void)
4442
{
45-
struct sha_region *ptr, *end;
43+
struct kexec_sha_region *ptr, *end;
4644
u8 digest[SHA256_DIGEST_SIZE];
4745
struct sha256_state sctx;
4846

4947
sha256_init(&sctx);
50-
end = &sha_regions[sizeof(sha_regions)/sizeof(sha_regions[0])];
51-
for (ptr = sha_regions; ptr < end; ptr++)
48+
end = purgatory_sha_regions + ARRAY_SIZE(purgatory_sha_regions);
49+
50+
for (ptr = purgatory_sha_regions; ptr < end; ptr++)
5251
sha256_update(&sctx, (uint8_t *)(ptr->start), ptr->len);
5352

5453
sha256_final(&sctx, digest);
5554

56-
if (memcmp(digest, sha256_digest, sizeof(digest)))
55+
if (memcmp(digest, purgatory_sha256_digest, sizeof(digest)))
5756
return 1;
5857

5958
return 0;

arch/x86/purgatory/purgatory.h

Lines changed: 0 additions & 8 deletions
This file was deleted.

arch/x86/purgatory/setup-x86_64.S

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* This source code is licensed under the GNU General Public License,
1010
* Version 2. See the file COPYING for more details.
1111
*/
12-
#include "purgatory.h"
12+
#include <asm/purgatory.h>
1313

1414
.text
1515
.globl purgatory_start

arch/x86/purgatory/sha256.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#ifndef SHA256_H
1111
#define SHA256_H
1212

13-
1413
#include <linux/types.h>
1514
#include <crypto/sha.h>
1615

include/linux/purgatory.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#ifndef _LINUX_PURGATORY_H
2+
#define _LINUX_PURGATORY_H
3+
4+
#include <linux/types.h>
5+
#include <crypto/sha.h>
6+
#include <uapi/linux/kexec.h>
7+
8+
struct kexec_sha_region {
9+
unsigned long start;
10+
unsigned long len;
11+
};
12+
13+
/*
14+
* These forward declarations serve two purposes:
15+
*
16+
* 1) Make sparse happy when checking arch/purgatory
17+
* 2) Document that these are required to be global so the symbol
18+
* lookup in kexec works
19+
*/
20+
extern struct kexec_sha_region purgatory_sha_regions[KEXEC_SEGMENT_MAX];
21+
extern u8 purgatory_sha256_digest[SHA256_DIGEST_SIZE];
22+
23+
#endif

kernel/kexec_file.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -614,13 +614,13 @@ static int kexec_calculate_store_digests(struct kimage *image)
614614
ret = crypto_shash_final(desc, digest);
615615
if (ret)
616616
goto out_free_digest;
617-
ret = kexec_purgatory_get_set_symbol(image, "sha_regions",
618-
sha_regions, sha_region_sz, 0);
617+
ret = kexec_purgatory_get_set_symbol(image, "purgatory_sha_regions",
618+
sha_regions, sha_region_sz, 0);
619619
if (ret)
620620
goto out_free_digest;
621621

622-
ret = kexec_purgatory_get_set_symbol(image, "sha256_digest",
623-
digest, SHA256_DIGEST_SIZE, 0);
622+
ret = kexec_purgatory_get_set_symbol(image, "purgatory_sha256_digest",
623+
digest, SHA256_DIGEST_SIZE, 0);
624624
if (ret)
625625
goto out_free_digest;
626626
}

kernel/kexec_internal.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,7 @@ int kimage_is_destination_range(struct kimage *image,
1515
extern struct mutex kexec_mutex;
1616

1717
#ifdef CONFIG_KEXEC_FILE
18-
struct kexec_sha_region {
19-
unsigned long start;
20-
unsigned long len;
21-
};
22-
18+
#include <linux/purgatory.h>
2319
void kimage_file_post_load_cleanup(struct kimage *image);
2420
#else /* CONFIG_KEXEC_FILE */
2521
static inline void kimage_file_post_load_cleanup(struct kimage *image) { }

0 commit comments

Comments
 (0)