Skip to content

Commit ab6b1d1

Browse files
bauermanntorvalds
authored andcommitted
powerpc: ima: send the kexec buffer to the next kernel
The IMA kexec buffer allows the currently running kernel to pass the measurement list via a kexec segment to the kernel that will be kexec'd. This is the architecture-specific part of setting up the IMA kexec buffer for the next kernel. It will be used in the next patch. Link: http://lkml.kernel.org/r/1480554346-29071-6-git-send-email-zohar@linux.vnet.ibm.com Signed-off-by: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com> Acked-by: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Andreas Steffen <andreas.steffen@strongswan.org> Cc: Dmitry Kasatkin <dmitry.kasatkin@gmail.com> Cc: Josh Sklar <sklar@linux.vnet.ibm.com> Cc: Dave Young <dyoung@redhat.com> Cc: Vivek Goyal <vgoyal@redhat.com> Cc: Baoquan He <bhe@redhat.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Stewart Smith <stewart@linux.vnet.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent d158847 commit ab6b1d1

File tree

5 files changed

+129
-6
lines changed

5 files changed

+129
-6
lines changed

arch/powerpc/include/asm/ima.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#ifndef _ASM_POWERPC_IMA_H
22
#define _ASM_POWERPC_IMA_H
33

4+
struct kimage;
5+
46
int ima_get_kexec_buffer(void **addr, size_t *size);
57
int ima_free_kexec_buffer(void);
68

@@ -10,4 +12,18 @@ void remove_ima_buffer(void *fdt, int chosen_node);
1012
static inline void remove_ima_buffer(void *fdt, int chosen_node) {}
1113
#endif
1214

15+
#ifdef CONFIG_IMA_KEXEC
16+
int arch_ima_add_kexec_buffer(struct kimage *image, unsigned long load_addr,
17+
size_t size);
18+
19+
int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node);
20+
#else
21+
static inline int setup_ima_buffer(const struct kimage *image, void *fdt,
22+
int chosen_node)
23+
{
24+
remove_ima_buffer(fdt, chosen_node);
25+
return 0;
26+
}
27+
#endif /* CONFIG_IMA_KEXEC */
28+
1329
#endif /* _ASM_POWERPC_IMA_H */

arch/powerpc/include/asm/kexec.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,21 @@ static inline bool kdump_in_progress(void)
9494
#ifdef CONFIG_KEXEC_FILE
9595
extern struct kexec_file_ops kexec_elf64_ops;
9696

97+
#ifdef CONFIG_IMA_KEXEC
98+
#define ARCH_HAS_KIMAGE_ARCH
99+
100+
struct kimage_arch {
101+
phys_addr_t ima_buffer_addr;
102+
size_t ima_buffer_size;
103+
};
104+
#endif
105+
97106
int setup_purgatory(struct kimage *image, const void *slave_code,
98107
const void *fdt, unsigned long kernel_load_addr,
99108
unsigned long fdt_load_addr);
100-
int setup_new_fdt(void *fdt, unsigned long initrd_load_addr,
101-
unsigned long initrd_len, const char *cmdline);
109+
int setup_new_fdt(const struct kimage *image, void *fdt,
110+
unsigned long initrd_load_addr, unsigned long initrd_len,
111+
const char *cmdline);
102112
int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size);
103113
#endif /* CONFIG_KEXEC_FILE */
104114

arch/powerpc/kernel/ima_kexec.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,3 +130,94 @@ void remove_ima_buffer(void *fdt, int chosen_node)
130130
if (!ret)
131131
pr_debug("Removed old IMA buffer reservation.\n");
132132
}
133+
134+
#ifdef CONFIG_IMA_KEXEC
135+
/**
136+
* arch_ima_add_kexec_buffer - do arch-specific steps to add the IMA buffer
137+
*
138+
* Architectures should use this function to pass on the IMA buffer
139+
* information to the next kernel.
140+
*
141+
* Return: 0 on success, negative errno on error.
142+
*/
143+
int arch_ima_add_kexec_buffer(struct kimage *image, unsigned long load_addr,
144+
size_t size)
145+
{
146+
image->arch.ima_buffer_addr = load_addr;
147+
image->arch.ima_buffer_size = size;
148+
149+
return 0;
150+
}
151+
152+
static int write_number(void *p, u64 value, int cells)
153+
{
154+
if (cells == 1) {
155+
u32 tmp;
156+
157+
if (value > U32_MAX)
158+
return -EINVAL;
159+
160+
tmp = cpu_to_be32(value);
161+
memcpy(p, &tmp, sizeof(tmp));
162+
} else if (cells == 2) {
163+
u64 tmp;
164+
165+
tmp = cpu_to_be64(value);
166+
memcpy(p, &tmp, sizeof(tmp));
167+
} else
168+
return -EINVAL;
169+
170+
return 0;
171+
}
172+
173+
/**
174+
* setup_ima_buffer - add IMA buffer information to the fdt
175+
* @image: kexec image being loaded.
176+
* @fdt: Flattened device tree for the next kernel.
177+
* @chosen_node: Offset to the chosen node.
178+
*
179+
* Return: 0 on success, or negative errno on error.
180+
*/
181+
int setup_ima_buffer(const struct kimage *image, void *fdt, int chosen_node)
182+
{
183+
int ret, addr_cells, size_cells, entry_size;
184+
u8 value[16];
185+
186+
remove_ima_buffer(fdt, chosen_node);
187+
if (!image->arch.ima_buffer_size)
188+
return 0;
189+
190+
ret = get_addr_size_cells(&addr_cells, &size_cells);
191+
if (ret)
192+
return ret;
193+
194+
entry_size = 4 * (addr_cells + size_cells);
195+
196+
if (entry_size > sizeof(value))
197+
return -EINVAL;
198+
199+
ret = write_number(value, image->arch.ima_buffer_addr, addr_cells);
200+
if (ret)
201+
return ret;
202+
203+
ret = write_number(value + 4 * addr_cells, image->arch.ima_buffer_size,
204+
size_cells);
205+
if (ret)
206+
return ret;
207+
208+
ret = fdt_setprop(fdt, chosen_node, "linux,ima-kexec-buffer", value,
209+
entry_size);
210+
if (ret < 0)
211+
return -EINVAL;
212+
213+
ret = fdt_add_mem_rsv(fdt, image->arch.ima_buffer_addr,
214+
image->arch.ima_buffer_size);
215+
if (ret)
216+
return -EINVAL;
217+
218+
pr_debug("IMA buffer at 0x%llx, size = 0x%zx\n",
219+
image->arch.ima_buffer_addr, image->arch.ima_buffer_size);
220+
221+
return 0;
222+
}
223+
#endif /* CONFIG_IMA_KEXEC */

arch/powerpc/kernel/kexec_elf_64.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
627627
goto out;
628628
}
629629

630-
ret = setup_new_fdt(fdt, initrd_load_addr, initrd_len, cmdline);
630+
ret = setup_new_fdt(image, fdt, initrd_load_addr, initrd_len, cmdline);
631631
if (ret)
632632
goto out;
633633

arch/powerpc/kernel/machine_kexec_file_64.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size)
210210

211211
/*
212212
* setup_new_fdt - modify /chosen and memory reservation for the next kernel
213+
* @image: kexec image being loaded.
213214
* @fdt: Flattened device tree for the next kernel.
214215
* @initrd_load_addr: Address where the next initrd will be loaded.
215216
* @initrd_len: Size of the next initrd, or 0 if there will be none.
@@ -218,8 +219,9 @@ int delete_fdt_mem_rsv(void *fdt, unsigned long start, unsigned long size)
218219
*
219220
* Return: 0 on success, or negative errno on error.
220221
*/
221-
int setup_new_fdt(void *fdt, unsigned long initrd_load_addr,
222-
unsigned long initrd_len, const char *cmdline)
222+
int setup_new_fdt(const struct kimage *image, void *fdt,
223+
unsigned long initrd_load_addr, unsigned long initrd_len,
224+
const char *cmdline)
223225
{
224226
int ret, chosen_node;
225227
const void *prop;
@@ -329,7 +331,11 @@ int setup_new_fdt(void *fdt, unsigned long initrd_load_addr,
329331
}
330332
}
331333

332-
remove_ima_buffer(fdt, chosen_node);
334+
ret = setup_ima_buffer(image, fdt, chosen_node);
335+
if (ret) {
336+
pr_err("Error setting up the new device tree.\n");
337+
return ret;
338+
}
333339

334340
ret = fdt_setprop(fdt, chosen_node, "linux,booted-from-kexec", NULL, 0);
335341
if (ret) {

0 commit comments

Comments
 (0)