aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMimi Zohar <zohar@linux.vnet.ibm.com>2016-12-19 19:22:48 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-12-20 12:48:44 -0500
commit7b8589cc29e7c35dcfd2d5138979f17b48f90110 (patch)
tree034068b5b20ee7e55247197c5df5d94e6aeadee6
parentab6b1d1fc4aae6b8bd6fb1422405568094c9b40f (diff)
ima: on soft reboot, save the measurement list
The TPM PCRs are only reset on a hard reboot. In order to validate a TPM's quote after a soft reboot (eg. kexec -e), the IMA measurement list of the running kernel must be saved and restored on boot. This patch uses the kexec buffer passing mechanism to pass the serialized IMA binary_runtime_measurements to the next kernel. Link: http://lkml.kernel.org/r/1480554346-29071-7-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> Acked-by: Dmitry Kasatkin <dmitry.kasatkin@gmail.com> Cc: Andreas Steffen <andreas.steffen@strongswan.org> 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>
-rw-r--r--include/linux/ima.h12
-rw-r--r--kernel/kexec_file.c4
-rw-r--r--security/integrity/ima/ima.h1
-rw-r--r--security/integrity/ima/ima_fs.c2
-rw-r--r--security/integrity/ima/ima_kexec.c117
5 files changed, 135 insertions, 1 deletions
diff --git a/include/linux/ima.h b/include/linux/ima.h
index 0eb7c2e7f0d6..7f6952f8d6aa 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -11,6 +11,7 @@
11#define _LINUX_IMA_H 11#define _LINUX_IMA_H
12 12
13#include <linux/fs.h> 13#include <linux/fs.h>
14#include <linux/kexec.h>
14struct linux_binprm; 15struct linux_binprm;
15 16
16#ifdef CONFIG_IMA 17#ifdef CONFIG_IMA
@@ -23,6 +24,10 @@ extern int ima_post_read_file(struct file *file, void *buf, loff_t size,
23 enum kernel_read_file_id id); 24 enum kernel_read_file_id id);
24extern void ima_post_path_mknod(struct dentry *dentry); 25extern void ima_post_path_mknod(struct dentry *dentry);
25 26
27#ifdef CONFIG_IMA_KEXEC
28extern void ima_add_kexec_buffer(struct kimage *image);
29#endif
30
26#else 31#else
27static inline int ima_bprm_check(struct linux_binprm *bprm) 32static inline int ima_bprm_check(struct linux_binprm *bprm)
28{ 33{
@@ -62,6 +67,13 @@ static inline void ima_post_path_mknod(struct dentry *dentry)
62 67
63#endif /* CONFIG_IMA */ 68#endif /* CONFIG_IMA */
64 69
70#ifndef CONFIG_IMA_KEXEC
71struct kimage;
72
73static inline void ima_add_kexec_buffer(struct kimage *image)
74{}
75#endif
76
65#ifdef CONFIG_IMA_APPRAISE 77#ifdef CONFIG_IMA_APPRAISE
66extern void ima_inode_post_setattr(struct dentry *dentry); 78extern void ima_inode_post_setattr(struct dentry *dentry);
67extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, 79extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index 0c2df7f73792..b56a558e406d 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -19,6 +19,7 @@
19#include <linux/mutex.h> 19#include <linux/mutex.h>
20#include <linux/list.h> 20#include <linux/list.h>
21#include <linux/fs.h> 21#include <linux/fs.h>
22#include <linux/ima.h>
22#include <crypto/hash.h> 23#include <crypto/hash.h>
23#include <crypto/sha.h> 24#include <crypto/sha.h>
24#include <linux/syscalls.h> 25#include <linux/syscalls.h>
@@ -132,6 +133,9 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
132 return ret; 133 return ret;
133 image->kernel_buf_len = size; 134 image->kernel_buf_len = size;
134 135
136 /* IMA needs to pass the measurement list to the next kernel. */
137 ima_add_kexec_buffer(image);
138
135 /* Call arch image probe handlers */ 139 /* Call arch image probe handlers */
136 ret = arch_kexec_kernel_image_probe(image, image->kernel_buf, 140 ret = arch_kexec_kernel_image_probe(image, image->kernel_buf,
137 image->kernel_buf_len); 141 image->kernel_buf_len);
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index ea1dcc452911..139dec67dcbf 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -143,6 +143,7 @@ void ima_print_digest(struct seq_file *m, u8 *digest, u32 size);
143struct ima_template_desc *ima_template_desc_current(void); 143struct ima_template_desc *ima_template_desc_current(void);
144int ima_restore_measurement_entry(struct ima_template_entry *entry); 144int ima_restore_measurement_entry(struct ima_template_entry *entry);
145int ima_restore_measurement_list(loff_t bufsize, void *buf); 145int ima_restore_measurement_list(loff_t bufsize, void *buf);
146int ima_measurements_show(struct seq_file *m, void *v);
146unsigned long ima_get_binary_runtime_size(void); 147unsigned long ima_get_binary_runtime_size(void);
147int ima_init_template(void); 148int ima_init_template(void);
148 149
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 3df46906492d..10bea0125fa1 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -116,7 +116,7 @@ void ima_putc(struct seq_file *m, void *data, int datalen)
116 * [eventdata length] 116 * [eventdata length]
117 * eventdata[n]=template specific data 117 * eventdata[n]=template specific data
118 */ 118 */
119static int ima_measurements_show(struct seq_file *m, void *v) 119int ima_measurements_show(struct seq_file *m, void *v)
120{ 120{
121 /* the list never shrinks, so we don't need a lock here */ 121 /* the list never shrinks, so we don't need a lock here */
122 struct ima_queue_entry *qe = v; 122 struct ima_queue_entry *qe = v;
diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c
index 36afd0fe9747..2c4824ac1ce1 100644
--- a/security/integrity/ima/ima_kexec.c
+++ b/security/integrity/ima/ima_kexec.c
@@ -10,8 +10,125 @@
10 * the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version. 11 * (at your option) any later version.
12 */ 12 */
13#include <linux/seq_file.h>
14#include <linux/vmalloc.h>
15#include <linux/kexec.h>
13#include "ima.h" 16#include "ima.h"
14 17
18#ifdef CONFIG_IMA_KEXEC
19static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
20 unsigned long segment_size)
21{
22 struct ima_queue_entry *qe;
23 struct seq_file file;
24 struct ima_kexec_hdr khdr = {
25 .version = 1, .buffer_size = 0, .count = 0};
26 int ret = 0;
27
28 /* segment size can't change between kexec load and execute */
29 file.buf = vmalloc(segment_size);
30 if (!file.buf) {
31 ret = -ENOMEM;
32 goto out;
33 }
34
35 file.size = segment_size;
36 file.read_pos = 0;
37 file.count = sizeof(khdr); /* reserved space */
38
39 list_for_each_entry_rcu(qe, &ima_measurements, later) {
40 if (file.count < file.size) {
41 khdr.count++;
42 ima_measurements_show(&file, qe);
43 } else {
44 ret = -EINVAL;
45 break;
46 }
47 }
48
49 if (ret < 0)
50 goto out;
51
52 /*
53 * fill in reserved space with some buffer details
54 * (eg. version, buffer size, number of measurements)
55 */
56 khdr.buffer_size = file.count;
57 memcpy(file.buf, &khdr, sizeof(khdr));
58 print_hex_dump(KERN_DEBUG, "ima dump: ", DUMP_PREFIX_NONE,
59 16, 1, file.buf,
60 file.count < 100 ? file.count : 100, true);
61
62 *buffer_size = file.count;
63 *buffer = file.buf;
64out:
65 if (ret == -EINVAL)
66 vfree(file.buf);
67 return ret;
68}
69
70/*
71 * Called during kexec_file_load so that IMA can add a segment to the kexec
72 * image for the measurement list for the next kernel.
73 *
74 * This function assumes that kexec_mutex is held.
75 */
76void ima_add_kexec_buffer(struct kimage *image)
77{
78 struct kexec_buf kbuf = { .image = image, .buf_align = PAGE_SIZE,
79 .buf_min = 0, .buf_max = ULONG_MAX,
80 .top_down = true };
81 unsigned long binary_runtime_size;
82
83 /* use more understandable variable names than defined in kbuf */
84 void *kexec_buffer = NULL;
85 size_t kexec_buffer_size;
86 size_t kexec_segment_size;
87 int ret;
88
89 /*
90 * Reserve an extra half page of memory for additional measurements
91 * added during the kexec load.
92 */
93 binary_runtime_size = ima_get_binary_runtime_size();
94 if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE)
95 kexec_segment_size = ULONG_MAX;
96 else
97 kexec_segment_size = ALIGN(ima_get_binary_runtime_size() +
98 PAGE_SIZE / 2, PAGE_SIZE);
99 if ((kexec_segment_size == ULONG_MAX) ||
100 ((kexec_segment_size >> PAGE_SHIFT) > totalram_pages / 2)) {
101 pr_err("Binary measurement list too large.\n");
102 return;
103 }
104
105 ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
106 kexec_segment_size);
107 if (!kexec_buffer) {
108 pr_err("Not enough memory for the kexec measurement buffer.\n");
109 return;
110 }
111
112 kbuf.buffer = kexec_buffer;
113 kbuf.bufsz = kexec_buffer_size;
114 kbuf.memsz = kexec_segment_size;
115 ret = kexec_add_buffer(&kbuf);
116 if (ret) {
117 pr_err("Error passing over kexec measurement buffer.\n");
118 return;
119 }
120
121 ret = arch_ima_add_kexec_buffer(image, kbuf.mem, kexec_segment_size);
122 if (ret) {
123 pr_err("Error passing over kexec measurement buffer.\n");
124 return;
125 }
126
127 pr_debug("kexec measurement buffer for the loaded kernel at 0x%lx.\n",
128 kbuf.mem);
129}
130#endif /* IMA_KEXEC */
131
15/* 132/*
16 * Restore the measurement list from the previous kernel. 133 * Restore the measurement list from the previous kernel.
17 */ 134 */