Skip to content

Commit 28e93c8

Browse files
bauermannhnaz
authored andcommitted
IMA: demonstration code for kexec buffer passing
This shows how kernel code can use the kexec buffer passing mechanism to pass information to the next kernel. This patch is not intended to be committed. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Thiago Jung Bauermann <[email protected]> Cc: Eric Biederman <[email protected]> Cc: Benjamin Herrenschmidt <[email protected]> Cc: Dave Young <[email protected]> Cc: Vivek Goyal <[email protected]> Cc: Baoquan He <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: Stewart Smith <[email protected]> Cc: Mimi Zohar <[email protected]> Cc: Eric Richter <[email protected]> Cc: Balbir Singh <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 3c57090 commit 28e93c8

File tree

5 files changed

+131
-0
lines changed

5 files changed

+131
-0
lines changed

include/linux/ima.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#define _LINUX_IMA_H
1212

1313
#include <linux/fs.h>
14+
#include <linux/kexec.h>
1415
struct linux_binprm;
1516

1617
#ifdef CONFIG_IMA
@@ -23,6 +24,10 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
2324
enum kernel_read_file_id id);
2425
extern void ima_post_path_mknod(struct dentry *dentry);
2526

27+
#ifdef CONFIG_KEXEC_FILE
28+
extern void ima_add_kexec_buffer(struct kimage *image);
29+
#endif
30+
2631
#else
2732
static inline int ima_bprm_check(struct linux_binprm *bprm)
2833
{
@@ -60,6 +65,12 @@ static inline void ima_post_path_mknod(struct dentry *dentry)
6065
return;
6166
}
6267

68+
#ifdef CONFIG_KEXEC_FILE
69+
static inline void ima_add_kexec_buffer(struct kimage *image)
70+
{
71+
}
72+
#endif
73+
6374
#endif /* CONFIG_IMA */
6475

6576
#ifdef CONFIG_IMA_APPRAISE

kernel/kexec_file.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/mutex.h>
2020
#include <linux/list.h>
2121
#include <linux/fs.h>
22+
#include <linux/ima.h>
2223
#include <crypto/hash.h>
2324
#include <crypto/sha.h>
2425
#include <linux/syscalls.h>
@@ -248,6 +249,9 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
248249
}
249250
}
250251

252+
/* IMA needs to pass the measurement list to the next kernel. */
253+
ima_add_kexec_buffer(image);
254+
251255
/* Call arch image load handlers */
252256
ldata = arch_kexec_kernel_image_load(image);
253257

security/integrity/ima/ima.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ struct ima_queue_entry {
102102
};
103103
extern struct list_head ima_measurements; /* list of all measurements */
104104

105+
#ifdef CONFIG_KEXEC_FILE
106+
extern void *kexec_buffer;
107+
extern size_t kexec_buffer_size;
108+
#endif
109+
105110
/* Internal IMA function definitions */
106111
int ima_init(void);
107112
int ima_fs_init(void);

security/integrity/ima/ima_init.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/scatterlist.h>
2222
#include <linux/slab.h>
2323
#include <linux/err.h>
24+
#include <linux/kexec.h>
2425

2526
#include "ima.h"
2627

@@ -104,6 +105,29 @@ void __init ima_load_x509(void)
104105
}
105106
#endif
106107

108+
#ifdef CONFIG_KEXEC_FILE
109+
static void ima_load_kexec_buffer(void)
110+
{
111+
int rc;
112+
113+
/* Fetch the buffer from the previous kernel, if any. */
114+
rc = kexec_get_handover_buffer(&kexec_buffer, &kexec_buffer_size);
115+
if (rc == 0) {
116+
/* Demonstrate that buffer handover works. */
117+
pr_err("kexec buffer contents: %s\n", (char *) kexec_buffer);
118+
pr_err("kexec buffer contents after update: %s\n",
119+
(char *) kexec_buffer + 4 * PAGE_SIZE + 10);
120+
121+
kexec_free_handover_buffer();
122+
} else if (rc == -ENOENT)
123+
pr_debug("No kexec buffer from the previous kernel.\n");
124+
else
125+
pr_debug("Error restoring kexec buffer: %d\n", rc);
126+
}
127+
#else
128+
static void ima_load_kexec_buffer(void) { }
129+
#endif
130+
107131
int __init ima_init(void)
108132
{
109133
u8 pcr_i[TPM_DIGEST_SIZE];
@@ -134,5 +158,7 @@ int __init ima_init(void)
134158

135159
ima_init_policy();
136160

161+
ima_load_kexec_buffer();
162+
137163
return ima_fs_init();
138164
}

security/integrity/ima/ima_template.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1717

18+
#include <linux/kexec.h>
19+
#include <linux/reboot.h>
1820
#include "ima.h"
1921
#include "ima_template_lib.h"
2022

@@ -182,6 +184,89 @@ static int template_desc_init_fields(const char *template_fmt,
182184
return 0;
183185
}
184186

187+
#ifdef CONFIG_KEXEC_FILE
188+
void *kexec_buffer = NULL;
189+
size_t kexec_buffer_size = 0;
190+
191+
/* Physical address of the measurement buffer in the next kernel. */
192+
unsigned long kexec_buffer_load_addr = 0;
193+
194+
/*
195+
* Called during reboot. IMA can add here new events that were generated after
196+
* the kexec image was loaded.
197+
*/
198+
static int ima_update_kexec_buffer(struct notifier_block *self,
199+
unsigned long action, void *data)
200+
{
201+
int ret;
202+
203+
if (!kexec_in_progress)
204+
return NOTIFY_OK;
205+
206+
/*
207+
* Add content deep in the buffer to show that we can update
208+
* all of it.
209+
*/
210+
strcpy(kexec_buffer + 4 * PAGE_SIZE + 10,
211+
"Updated kexec buffer contents.");
212+
213+
ret = kexec_update_segment(kexec_buffer, kexec_buffer_size,
214+
kexec_buffer_load_addr, kexec_buffer_size);
215+
if (ret)
216+
pr_err("Error updating kexec buffer: %d\n", ret);
217+
218+
return NOTIFY_OK;
219+
}
220+
221+
struct notifier_block update_buffer_nb = {
222+
.notifier_call = ima_update_kexec_buffer,
223+
};
224+
225+
/*
226+
* Called during kexec_file_load so that IMA can add a segment to the kexec
227+
* image with the measurement event log for the next kernel.
228+
*/
229+
void ima_add_kexec_buffer(struct kimage *image)
230+
{
231+
/* Ask not to checksum the segment, we may have to update it later. */
232+
struct kexec_buf kbuf = { .image = image, .buf_align = PAGE_SIZE,
233+
.buf_min = 0, .buf_max = ULONG_MAX,
234+
.top_down = true, .skip_checksum = true };
235+
bool first_kexec_load = kexec_buffer_load_addr == 0;
236+
int ret;
237+
238+
if (!kexec_can_hand_over_buffer())
239+
return;
240+
241+
if (!first_kexec_load)
242+
kfree(kexec_buffer);
243+
244+
/* Create a relatively big buffer, for testing. */
245+
kexec_buffer_size = kbuf.bufsz = kbuf.memsz = 5 * PAGE_SIZE;
246+
kexec_buffer = kbuf.buffer = kzalloc(kexec_buffer_size, GFP_KERNEL);
247+
if (!kexec_buffer) {
248+
pr_err("Not enough memory for the kexec measurement buffer.\n");
249+
return;
250+
}
251+
252+
/* Add some content for demonstration purposes. */
253+
strcpy(kexec_buffer, "Buffer contents at kexec load time.");
254+
255+
ret = kexec_add_handover_buffer(&kbuf);
256+
if (ret) {
257+
pr_err("Error passing over kexec measurement buffer.\n");
258+
return;
259+
}
260+
kexec_buffer_load_addr = kbuf.mem;
261+
262+
if (first_kexec_load)
263+
register_reboot_notifier(&update_buffer_nb);
264+
265+
pr_debug("kexec measurement buffer for the loaded kernel at 0x%lx.\n",
266+
kexec_buffer_load_addr);
267+
}
268+
#endif /* CONFIG_KEXEC_FILE */
269+
185270
struct ima_template_desc *ima_template_desc_current(void)
186271
{
187272
if (!ima_template)

0 commit comments

Comments
 (0)