1 | The current kernel behavior is IMA measurements snapshot is taken at | 1 | The current kernel behavior is IMA measurements snapshot is taken at |
---|---|---|---|
2 | kexec 'load' and not at kexec 'execute'. IMA log is then carried | 2 | kexec 'load' and not at kexec 'execute'. IMA log is then carried |
3 | over to the new kernel after kexec 'execute'. | 3 | over to the new kernel after kexec 'execute'. |
4 | 4 | ||
5 | New events can be measured during/after the IMA log snapshot at kexec | 5 | Currently, the kernel behavior during kexec load is to fetch the IMA |
6 | 'load' and before the system boots to the new kernel. In this scenario, | 6 | measurements log from TPM PCRs and store it in a buffer. When a kexec |
7 | the TPM PCRs are extended with these events, but they are not carried | 7 | reboot is triggered, this stored log buffer is carried over to the second |
8 | over to the new kernel after kexec soft reboot since the snapshot is | 8 | kernel. However, the time gap between kexec load and kexec reboot can be |
9 | already taken. This results in mismatch between TPM PCR quotes and the | 9 | very long. During this time window, new events extended into TPM PCRs miss |
10 | actual IMA measurements list after kexec soft reboot, which in turn | 10 | the chance to be carried over to the second kernel. This results in |
11 | results in remote attestation failure. | 11 | mismatch between TPM PCR quotes and the actual IMA measurements list after |
12 | kexec soft reboot, which in turn results in remote attestation failure. | ||
12 | 13 | ||
13 | To solve this problem - | 14 | To solve this problem - |
14 | - allocate the necessary buffer at kexec 'load' time, | 15 | - allocate the necessary buffer at kexec 'load' time, |
15 | - populate the buffer with the IMA measurements at kexec 'execute' time, | 16 | - populate the buffer with the IMA measurements at kexec 'execute' time, |
16 | - and measure two new IMA events 'kexec_load' and 'kexec_execute' as | 17 | - and measure two new IMA events 'kexec_load' and 'kexec_execute' as |
... | ... | ||
32 | - introducing a new Kconfig option to configure the extra memory to be | 33 | - introducing a new Kconfig option to configure the extra memory to be |
33 | allocated for passing IMA log from the current Kernel to the next, | 34 | allocated for passing IMA log from the current Kernel to the next, |
34 | 35 | ||
35 | - introducing two new events to be measured by IMA during kexec, to | 36 | - introducing two new events to be measured by IMA during kexec, to |
36 | help diagnose if the IMA log was copied fully or partially, from the | 37 | help diagnose if the IMA log was copied fully or partially, from the |
37 | current Kernel to the next, | 38 | current Kernel to the next, |
38 | 39 | ||
39 | - excluding IMA segment while calculating and storing digest in function | 40 | - excluding IMA segment while calculating and storing digest in function |
40 | kexec_calculate_store_digests(), since IMA segment can be modified | 41 | kexec_calculate_store_digests(), since IMA segment can be modified |
41 | after the digest is computed during kexec 'load'. This will ensure | 42 | after the digest is computed during kexec 'load'. This will ensure |
42 | that the segment is not added to the 'purgatory_sha_regions', and thus | 43 | that the segment is not added to the 'purgatory_sha_regions', and thus |
... | ... | ||
56 | 57 | ||
57 | V5 of this series is available here[7] for reference. | 58 | V5 of this series is available here[7] for reference. |
58 | 59 | ||
59 | V6 of this series is available here[8] for reference. | 60 | V6 of this series is available here[8] for reference. |
60 | 61 | ||
62 | V7 of this series is available here[9] for reference. | ||
63 | |||
64 | V8 of this series is available here[10] for reference. | ||
65 | |||
66 | V9 of this series is available here[11] for reference. | ||
67 | |||
68 | V10 of this series is available here[12] for reference. | ||
69 | |||
61 | References: | 70 | References: |
62 | ----------- | 71 | ----------- |
63 | 72 | ||
64 | [1] [PATHC v2 5/9] ima: on soft reboot, save the measurement list | 73 | [1] [PATHC v2 5/9] ima: on soft reboot, save the measurement list |
65 | https://lore.kernel.org/lkml/1472596811-9596-6-git-send-email-zohar@linux.vnet.ibm.com/ | 74 | https://lore.kernel.org/lkml/1472596811-9596-6-git-send-email-zohar@linux.vnet.ibm.com/ |
... | ... | ||
85 | [8] [PATCH v6 0/7] ima: kexec: measure events between kexec load and execute | 94 | [8] [PATCH v6 0/7] ima: kexec: measure events between kexec load and execute |
86 | https://lore.kernel.org/all/20250124225547.22684-1-chenste@linux.microsoft.com/ | 95 | https://lore.kernel.org/all/20250124225547.22684-1-chenste@linux.microsoft.com/ |
87 | 96 | ||
88 | [9] [PATCH v7 0/7] ima: kexec: measure events between kexec load and execute | 97 | [9] [PATCH v7 0/7] ima: kexec: measure events between kexec load and execute |
89 | https://lore.kernel.org/all/20250203232033.64123-1-chenste@linux.microsoft.com/ | 98 | https://lore.kernel.org/all/20250203232033.64123-1-chenste@linux.microsoft.com/ |
99 | |||
100 | [10] [PATCH v8 0/7] ima: kexec: measure events between kexec load and execute | ||
101 | https://lore.kernel.org/all/20250218225502.747963-1-chenste@linux.microsoft.com/ | ||
102 | |||
103 | [11] [PATCH v9 0/7] ima: kexec: measure events between kexec load and execute | ||
104 | https://lore.kernel.org/all/20250304190351.96975-1-chenste@linux.microsoft.com/ | ||
105 | |||
106 | [12] [PATCH v10 0/8] ima: kexec: measure events between kexec load and execute | ||
107 | https://lore.kernel.org/all/20250318010448.954-1-chenste@linux.microsoft.com/ | ||
108 | |||
109 | Change Log v11: | ||
110 | - Incorporated feedback from the community (Mimi Zohar and Baoquan He) on | ||
111 | v10 of this series[12]. | ||
112 | - [PATCH V10 2/8] was splited into two [PATCH V11 2/9] and [PATCH V11 7/9]. | ||
113 | Per Mimi comment on [PATCH V10 2/8]. | ||
114 | - Verified all the patches are bisect-safe by booting into each | ||
115 | patch and verifying multiple kexec 'load' operations work, | ||
116 | and also verifying kexec soft reboot works, and IMA log gets | ||
117 | carried over for each patch. | ||
118 | - Updated patch descriptions as necessary. | ||
119 | |||
120 | Change Log v10: | ||
121 | - Incorporated feedback from the community (Mimi Zohar, Baoquan He, and | ||
122 | kernel test robot) on v9 of this series[11]. | ||
123 | - [PATCH V9 1/7] was splited into two [PATCH V10 1/8] and [PATCH V10 2/8]. | ||
124 | Per Mimi comment on [PATCH V9 1/7]. | ||
125 | - Verified all the patches are bisect-safe by booting into each | ||
126 | patch and verifying multiple kexec 'load' operations work, | ||
127 | and also verifying kexec soft reboot works, and IMA log gets | ||
128 | carried over for each patch. | ||
129 | |||
130 | Change Log v9: | ||
131 | - Incorporated feedback from the community (Stefan Berger, Mimi Zohar, | ||
132 | and kernel test robot) on v8 of this series[10]. | ||
133 | - Rebased the patch series to mainline 6.14.0-rc3. | ||
134 | - Verified all the patches are bisect-safe by booting into each | ||
135 | patch and verifying multiple kexec 'load' operations work, | ||
136 | and also verifying kexec soft reboot works, and IMA log gets | ||
137 | carried over for each patch. | ||
90 | 138 | ||
91 | Change Log v8: | 139 | Change Log v8: |
92 | - Incorporated feedback from the community (Stefan Berger, Mimi Zohar) | 140 | - Incorporated feedback from the community (Stefan Berger, Mimi Zohar) |
93 | on v7 of this series[9]. | 141 | on v7 of this series[9]. |
94 | - Rebased the patch series to mainline 6.14.0-rc1. | 142 | - Rebased the patch series to mainline 6.14.0-rc1. |
... | ... | ||
198 | - Refactored patches to ensure no warnings during individual patch | 246 | - Refactored patches to ensure no warnings during individual patch |
199 | compilation. | 247 | compilation. |
200 | - Used virt_to_page instead of phys_to_page. | 248 | - Used virt_to_page instead of phys_to_page. |
201 | - Updated patch descriptions as necessary. | 249 | - Updated patch descriptions as necessary. |
202 | 250 | ||
203 | steven chen (7): | 251 | |
204 | ima: define and call ima_alloc_kexec_file_buf | 252 | steven chen (9): |
253 | ima: rename variable the set_file "file" to "ima_kexec_file" | ||
254 | ima: define and call ima_alloc_kexec_file_buf() | ||
205 | kexec: define functions to map and unmap segments | 255 | kexec: define functions to map and unmap segments |
206 | ima: kexec: skip IMA segment validation after kexec soft reboot | 256 | ima: kexec: skip IMA segment validation after kexec soft reboot |
207 | ima: kexec: define functions to copy IMA log at soft boot | 257 | ima: kexec: define functions to copy IMA log at soft boot |
208 | ima: kexec: move IMA log copy from kexec load to execute | 258 | ima: kexec: move IMA log copy from kexec load to execute |
259 | ima: verify if the segment size has changed | ||
209 | ima: make the kexec extra memory configurable | 260 | ima: make the kexec extra memory configurable |
210 | ima: measure kexec load and exec events as critical data | 261 | ima: measure kexec load and exec events as critical data |
211 | 262 | ||
212 | include/linux/ima.h | 3 + | 263 | include/linux/ima.h | 3 + |
213 | include/linux/kexec.h | 8 ++ | 264 | include/linux/kexec.h | 9 ++ |
214 | kernel/kexec_core.c | 54 ++++++++ | 265 | kernel/kexec_core.c | 54 ++++++++ |
215 | kernel/kexec_file.c | 30 +++++ | 266 | kernel/kexec_file.c | 33 ++++- |
216 | security/integrity/ima/Kconfig | 10 ++ | 267 | security/integrity/ima/Kconfig | 10 ++ |
217 | security/integrity/ima/ima.h | 7 + | 268 | security/integrity/ima/ima.h | 6 + |
218 | security/integrity/ima/ima_kexec.c | 203 ++++++++++++++++++++++++----- | 269 | security/integrity/ima/ima_kexec.c | 193 ++++++++++++++++++++++++----- |
219 | security/integrity/ima/ima_queue.c | 9 +- | 270 | security/integrity/ima/ima_queue.c | 5 + |
220 | 8 files changed, 287 insertions(+), 37 deletions(-) | 271 | 8 files changed, 279 insertions(+), 34 deletions(-) |
221 | 272 | ||
222 | -- | 273 | -- |
223 | 2.25.1 | 274 | 2.25.1 |
224 | 275 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | The current kernel behavior is IMA measurements snapshot is taken at | ||
2 | kexec 'load' and not at kexec 'execute'. IMA log is then carried | ||
3 | over to the new kernel after kexec 'execute'. However, the time gap | ||
4 | between kexec load and kexec reboot can be very long. During this | ||
5 | time window, new events extended into TPM PCRs miss the chance | ||
6 | to be carried over to the second kernel. | ||
7 | |||
8 | To address the above, the following approach is proposed: | ||
9 | - Allocate the necessary buffer during the kexec load phase. | ||
10 | - Populate this buffer with the IMA measurements during | ||
11 | the kexec execute phase. | ||
1 | 12 | ||
13 | In the current implementation, a local variable "file" of type seq_file | ||
14 | is used in the API ima_dump_measurement_list() to store the IMA measurements | ||
15 | to be carried over across kexec system call. To make this buffer accessible | ||
16 | at kexec 'execute' time, rename it to "ima_kexec_file" before making it | ||
17 | a file variable to better reflect its purpose. | ||
18 | |||
19 | Renaming the local variable "file" of type seq_file defined in the | ||
20 | ima_dump_measurement_list function to "ima_kexec_file" will improve code | ||
21 | readability and maintainability by making the variable's role more explicit. | ||
22 | |||
23 | Suggested-by: Mimi Zohar <zohar@linux.ibm.com> | ||
24 | Signed-off-by: steven chen <chenste@linux.microsoft.com> | ||
25 | Reviewed-by: Stefan Berger <stefanb@linux.ibm.com> | ||
26 | --- | ||
27 | security/integrity/ima/ima_kexec.c | 31 +++++++++++++++--------------- | ||
28 | 1 file changed, 16 insertions(+), 15 deletions(-) | ||
29 | |||
30 | diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c | ||
31 | index XXXXXXX..XXXXXXX 100644 | ||
32 | --- a/security/integrity/ima/ima_kexec.c | ||
33 | +++ b/security/integrity/ima/ima_kexec.c | ||
34 | @@ -XXX,XX +XXX,XX @@ | ||
35 | static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, | ||
36 | unsigned long segment_size) | ||
37 | { | ||
38 | + struct seq_file ima_kexec_file; | ||
39 | struct ima_queue_entry *qe; | ||
40 | - struct seq_file file; | ||
41 | struct ima_kexec_hdr khdr; | ||
42 | int ret = 0; | ||
43 | |||
44 | /* segment size can't change between kexec load and execute */ | ||
45 | - file.buf = vmalloc(segment_size); | ||
46 | - if (!file.buf) { | ||
47 | + ima_kexec_file.buf = vmalloc(segment_size); | ||
48 | + if (!ima_kexec_file.buf) { | ||
49 | ret = -ENOMEM; | ||
50 | goto out; | ||
51 | } | ||
52 | |||
53 | - file.file = NULL; | ||
54 | - file.size = segment_size; | ||
55 | - file.read_pos = 0; | ||
56 | - file.count = sizeof(khdr); /* reserved space */ | ||
57 | + ima_kexec_file.file = NULL; | ||
58 | + ima_kexec_file.size = segment_size; | ||
59 | + ima_kexec_file.read_pos = 0; | ||
60 | + ima_kexec_file.count = sizeof(khdr); /* reserved space */ | ||
61 | |||
62 | memset(&khdr, 0, sizeof(khdr)); | ||
63 | khdr.version = 1; | ||
64 | /* This is an append-only list, no need to hold the RCU read lock */ | ||
65 | list_for_each_entry_rcu(qe, &ima_measurements, later, true) { | ||
66 | - if (file.count < file.size) { | ||
67 | + if (ima_kexec_file.count < ima_kexec_file.size) { | ||
68 | khdr.count++; | ||
69 | - ima_measurements_show(&file, qe); | ||
70 | + ima_measurements_show(&ima_kexec_file, qe); | ||
71 | } else { | ||
72 | ret = -EINVAL; | ||
73 | break; | ||
74 | @@ -XXX,XX +XXX,XX @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, | ||
75 | * fill in reserved space with some buffer details | ||
76 | * (eg. version, buffer size, number of measurements) | ||
77 | */ | ||
78 | - khdr.buffer_size = file.count; | ||
79 | + khdr.buffer_size = ima_kexec_file.count; | ||
80 | if (ima_canonical_fmt) { | ||
81 | khdr.version = cpu_to_le16(khdr.version); | ||
82 | khdr.count = cpu_to_le64(khdr.count); | ||
83 | khdr.buffer_size = cpu_to_le64(khdr.buffer_size); | ||
84 | } | ||
85 | - memcpy(file.buf, &khdr, sizeof(khdr)); | ||
86 | + memcpy(ima_kexec_file.buf, &khdr, sizeof(khdr)); | ||
87 | |||
88 | print_hex_dump_debug("ima dump: ", DUMP_PREFIX_NONE, 16, 1, | ||
89 | - file.buf, file.count < 100 ? file.count : 100, | ||
90 | + ima_kexec_file.buf, ima_kexec_file.count < 100 ? | ||
91 | + ima_kexec_file.count : 100, | ||
92 | true); | ||
93 | |||
94 | - *buffer_size = file.count; | ||
95 | - *buffer = file.buf; | ||
96 | + *buffer_size = ima_kexec_file.count; | ||
97 | + *buffer = ima_kexec_file.buf; | ||
98 | out: | ||
99 | if (ret == -EINVAL) | ||
100 | - vfree(file.buf); | ||
101 | + vfree(ima_kexec_file.buf); | ||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | -- | ||
106 | 2.25.1 | diff view generated by jsdifflib |
1 | In the current implementation, the ima_dump_measurement_list() API is | ||
---|---|---|---|
2 | called during the kexec "load" phase, where a buffer is allocated and | ||
3 | the measurement records are copied. Due to this, new events added after | ||
4 | kexec load but before kexec execute are not carried over to the new kernel | ||
5 | during kexec operation | ||
6 | |||
7 | To allow the buffer allocation and population to be separated into distinct | ||
8 | steps, make the function local seq_file "ima_kexec_file" to a file variable. | ||
9 | |||
1 | Carrying the IMA measurement list across kexec requires allocating a | 10 | Carrying the IMA measurement list across kexec requires allocating a |
2 | buffer and copying the measurement records. Separate allocating the | 11 | buffer and copying the measurement records. Separate allocating the |
3 | buffer and copying the measurement records into separate functions in | 12 | buffer and copying the measurement records into separate functions in |
4 | order to allocate the buffer at kexec 'load' and copy the measurements | 13 | order to allocate the buffer at kexec 'load' and copy the measurements |
5 | at kexec 'execute'. | 14 | at kexec 'execute'. |
6 | 15 | ||
7 | This patch includes the following changes: | ||
8 | - Refactor ima_dump_measurement_list() to move the memory allocation | ||
9 | to a separate function ima_alloc_kexec_file_buf() which allocates | ||
10 | buffer of size 'kexec_segment_size' at kexec 'load'. | ||
11 | - Make the local variable ima_kexec_file in ima_dump_measurement_list() | ||
12 | a local static to the file, so that it can be accessed from | ||
13 | ima_alloc_kexec_file_buf(). Compare actual memory required to ensure | ||
14 | there is enough memory for the entire measurement record. | ||
15 | - Copy as many measurement events as possible. | ||
16 | - Make necessary changes to the function ima_add_kexec_buffer() to call | ||
17 | the above two functions. | ||
18 | - Compared the memory size allocated with memory size of the entire | ||
19 | measurement record. If there is not enough memory, it will copy as many | ||
20 | IMA measurement records as possible, and this situation will result | ||
21 | in a failure of remote attestation. | ||
22 | |||
23 | Author: Tushar Sugandhi <tusharsu@linux.microsoft.com> | ||
24 | Suggested-by: Mimi Zohar <zohar@linux.ibm.com> | ||
25 | Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> | 16 | Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> |
26 | Signed-off-by: steven chen <chenste@linux.microsoft.com> | 17 | Signed-off-by: steven chen <chenste@linux.microsoft.com> |
27 | --- | 18 | --- |
28 | security/integrity/ima/ima.h | 1 + | 19 | security/integrity/ima/ima_kexec.c | 46 +++++++++++++++++++++++------- |
29 | security/integrity/ima/ima_kexec.c | 102 +++++++++++++++++++++-------- | 20 | 1 file changed, 35 insertions(+), 11 deletions(-) |
30 | security/integrity/ima/ima_queue.c | 4 +- | ||
31 | 3 files changed, 77 insertions(+), 30 deletions(-) | ||
32 | 21 | ||
33 | diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h | ||
34 | index XXXXXXX..XXXXXXX 100644 | ||
35 | --- a/security/integrity/ima/ima.h | ||
36 | +++ b/security/integrity/ima/ima.h | ||
37 | @@ -XXX,XX +XXX,XX @@ bool ima_template_has_modsig(const struct ima_template_desc *ima_template); | ||
38 | int ima_restore_measurement_entry(struct ima_template_entry *entry); | ||
39 | int ima_restore_measurement_list(loff_t bufsize, void *buf); | ||
40 | int ima_measurements_show(struct seq_file *m, void *v); | ||
41 | +int ima_get_binary_runtime_entry_size(struct ima_template_entry *entry); | ||
42 | unsigned long ima_get_binary_runtime_size(void); | ||
43 | int ima_init_template(void); | ||
44 | void ima_init_template_list(void); | ||
45 | diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c | 22 | diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c |
46 | index XXXXXXX..XXXXXXX 100644 | 23 | index XXXXXXX..XXXXXXX 100644 |
47 | --- a/security/integrity/ima/ima_kexec.c | 24 | --- a/security/integrity/ima/ima_kexec.c |
48 | +++ b/security/integrity/ima/ima_kexec.c | 25 | +++ b/security/integrity/ima/ima_kexec.c |
49 | @@ -XXX,XX +XXX,XX @@ | 26 | @@ -XXX,XX +XXX,XX @@ |
50 | #include "ima.h" | 27 | #include "ima.h" |
51 | 28 | ||
52 | #ifdef CONFIG_IMA_KEXEC | 29 | #ifdef CONFIG_IMA_KEXEC |
53 | +static struct seq_file ima_kexec_file; | 30 | +static struct seq_file ima_kexec_file; |
54 | + | 31 | + |
55 | +static void ima_reset_kexec_file(struct seq_file *sf) | 32 | +static void ima_free_kexec_file_buf(struct seq_file *sf) |
56 | +{ | 33 | +{ |
34 | + vfree(sf->buf); | ||
57 | + sf->buf = NULL; | 35 | + sf->buf = NULL; |
58 | + sf->size = 0; | 36 | + sf->size = 0; |
59 | + sf->read_pos = 0; | 37 | + sf->read_pos = 0; |
60 | + sf->count = 0; | 38 | + sf->count = 0; |
61 | +} | 39 | +} |
62 | + | 40 | + |
63 | +static void ima_free_kexec_file_buf(struct seq_file *sf) | ||
64 | +{ | ||
65 | + vfree(sf->buf); | ||
66 | + ima_reset_kexec_file(sf); | ||
67 | +} | ||
68 | + | ||
69 | +static int ima_alloc_kexec_file_buf(size_t segment_size) | 41 | +static int ima_alloc_kexec_file_buf(size_t segment_size) |
70 | +{ | 42 | +{ |
71 | + /* | ||
72 | + * kexec 'load' may be called multiple times. | ||
73 | + * Free and realloc the buffer only if the segment_size is | ||
74 | + * changed from the previous kexec 'load' call. | ||
75 | + */ | ||
76 | + if (ima_kexec_file.buf && ima_kexec_file.size == segment_size) | ||
77 | + goto out; | ||
78 | + | ||
79 | + ima_free_kexec_file_buf(&ima_kexec_file); | 43 | + ima_free_kexec_file_buf(&ima_kexec_file); |
80 | + | 44 | + |
81 | + /* segment size can't change between kexec load and execute */ | 45 | + /* segment size can't change between kexec load and execute */ |
82 | + ima_kexec_file.buf = vmalloc(segment_size); | 46 | + ima_kexec_file.buf = vmalloc(segment_size); |
83 | + if (!ima_kexec_file.buf) | 47 | + if (!ima_kexec_file.buf) |
84 | + return -ENOMEM; | 48 | + return -ENOMEM; |
85 | + | 49 | + |
86 | + ima_kexec_file.size = segment_size; | 50 | + ima_kexec_file.size = segment_size; |
87 | + | ||
88 | +out: | ||
89 | + ima_kexec_file.read_pos = 0; | 51 | + ima_kexec_file.read_pos = 0; |
90 | + ima_kexec_file.count = sizeof(struct ima_kexec_hdr); /* reserved space */ | 52 | + ima_kexec_file.count = sizeof(struct ima_kexec_hdr); /* reserved space */ |
91 | + | 53 | + |
92 | + return 0; | 54 | + return 0; |
93 | +} | 55 | +} |
94 | + | 56 | + |
95 | static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, | 57 | static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, |
96 | unsigned long segment_size) | 58 | unsigned long segment_size) |
97 | { | 59 | { |
60 | - struct seq_file ima_kexec_file; | ||
98 | struct ima_queue_entry *qe; | 61 | struct ima_queue_entry *qe; |
99 | - struct seq_file file; | ||
100 | struct ima_kexec_hdr khdr; | 62 | struct ima_kexec_hdr khdr; |
101 | int ret = 0; | 63 | int ret = 0; |
102 | + size_t entry_size = 0; | 64 | |
103 | 65 | /* segment size can't change between kexec load and execute */ | |
104 | - /* segment size can't change between kexec load and execute */ | 66 | - ima_kexec_file.buf = vmalloc(segment_size); |
105 | - file.buf = vmalloc(segment_size); | 67 | if (!ima_kexec_file.buf) { |
106 | - if (!file.buf) { | ||
107 | - ret = -ENOMEM; | 68 | - ret = -ENOMEM; |
108 | - goto out; | 69 | - goto out; |
109 | + if (!ima_kexec_file.buf) { | ||
110 | + pr_err("Kexec file buf not allocated\n"); | 70 | + pr_err("Kexec file buf not allocated\n"); |
111 | + return -EINVAL; | 71 | + return -EINVAL; |
112 | } | 72 | } |
113 | 73 | ||
114 | - file.file = NULL; | 74 | - ima_kexec_file.file = NULL; |
115 | - file.size = segment_size; | 75 | - ima_kexec_file.size = segment_size; |
116 | - file.read_pos = 0; | 76 | - ima_kexec_file.read_pos = 0; |
117 | - file.count = sizeof(khdr); /* reserved space */ | 77 | - ima_kexec_file.count = sizeof(khdr); /* reserved space */ |
118 | - | 78 | - |
119 | memset(&khdr, 0, sizeof(khdr)); | 79 | memset(&khdr, 0, sizeof(khdr)); |
120 | khdr.version = 1; | 80 | khdr.version = 1; |
121 | /* This is an append-only list, no need to hold the RCU read lock */ | 81 | /* This is an append-only list, no need to hold the RCU read lock */ |
122 | + /* Copy as many IMA measurements list records as possible */ | 82 | @@ -XXX,XX +XXX,XX @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, |
123 | list_for_each_entry_rcu(qe, &ima_measurements, later, true) { | 83 | *buffer_size = ima_kexec_file.count; |
124 | - if (file.count < file.size) { | 84 | *buffer = ima_kexec_file.buf; |
125 | + entry_size += ima_get_binary_runtime_entry_size(qe->entry); | 85 | out: |
126 | + if (entry_size <= segment_size) { | ||
127 | khdr.count++; | ||
128 | - ima_measurements_show(&file, qe); | ||
129 | + ima_measurements_show(&ima_kexec_file, qe); | ||
130 | } else { | ||
131 | ret = -EINVAL; | ||
132 | + pr_err("IMA log file is too big for Kexec buf\n"); | ||
133 | break; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | - if (ret < 0) | ||
138 | - goto out; | ||
139 | - | ||
140 | /* | ||
141 | * fill in reserved space with some buffer details | ||
142 | * (eg. version, buffer size, number of measurements) | ||
143 | */ | ||
144 | - khdr.buffer_size = file.count; | ||
145 | + khdr.buffer_size = ima_kexec_file.count; | ||
146 | if (ima_canonical_fmt) { | ||
147 | khdr.version = cpu_to_le16(khdr.version); | ||
148 | khdr.count = cpu_to_le64(khdr.count); | ||
149 | khdr.buffer_size = cpu_to_le64(khdr.buffer_size); | ||
150 | } | ||
151 | - memcpy(file.buf, &khdr, sizeof(khdr)); | ||
152 | + memcpy(ima_kexec_file.buf, &khdr, sizeof(khdr)); | ||
153 | |||
154 | print_hex_dump_debug("ima dump: ", DUMP_PREFIX_NONE, 16, 1, | ||
155 | - file.buf, file.count < 100 ? file.count : 100, | ||
156 | + ima_kexec_file.buf, ima_kexec_file.count < 100 ? | ||
157 | + ima_kexec_file.count : 100, | ||
158 | true); | ||
159 | |||
160 | - *buffer_size = file.count; | ||
161 | - *buffer = file.buf; | ||
162 | -out: | ||
163 | - if (ret == -EINVAL) | 86 | - if (ret == -EINVAL) |
164 | - vfree(file.buf); | 87 | - vfree(ima_kexec_file.buf); |
165 | + *buffer_size = ima_kexec_file.count; | ||
166 | + *buffer = ima_kexec_file.buf; | ||
167 | + | ||
168 | return ret; | 88 | return ret; |
169 | } | 89 | } |
170 | |||
171 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) | ||
172 | |||
173 | /* use more understandable variable names than defined in kbuf */ | ||
174 | void *kexec_buffer = NULL; | ||
175 | - size_t kexec_buffer_size; | ||
176 | + size_t kexec_buffer_size = 0; | ||
177 | size_t kexec_segment_size; | ||
178 | int ret; | ||
179 | 90 | ||
180 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) | 91 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) |
181 | return; | 92 | return; |
182 | } | 93 | } |
183 | 94 | ||
184 | - ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer, | ||
185 | - kexec_segment_size); | ||
186 | - if (!kexec_buffer) { | ||
187 | + ret = ima_alloc_kexec_file_buf(kexec_segment_size); | 95 | + ret = ima_alloc_kexec_file_buf(kexec_segment_size); |
188 | + if (ret < 0) { | 96 | + if (ret < 0) { |
189 | pr_err("Not enough memory for the kexec measurement buffer.\n"); | 97 | + pr_err("Not enough memory for the kexec measurement buffer.\n"); |
190 | return; | ||
191 | } | ||
192 | |||
193 | + ret = ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer, | ||
194 | + kexec_segment_size); | ||
195 | + if (ret < 0) { | ||
196 | + pr_err("Failed to dump IMA measurements. Error:%d.\n", ret); | ||
197 | + return; | 98 | + return; |
198 | + } | 99 | + } |
199 | + | 100 | + |
200 | kbuf.buffer = kexec_buffer; | 101 | ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer, |
201 | kbuf.bufsz = kexec_buffer_size; | 102 | kexec_segment_size); |
202 | kbuf.memsz = kexec_segment_size; | 103 | if (!kexec_buffer) { |
203 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) | ||
204 | image->ima_buffer_size = kexec_segment_size; | ||
205 | image->ima_buffer = kexec_buffer; | ||
206 | |||
207 | + /* | ||
208 | + * kexec owns kexec_buffer after kexec_add_buffer() is called | ||
209 | + * and it will vfree() that buffer. | ||
210 | + */ | ||
211 | + ima_reset_kexec_file(&ima_kexec_file); | ||
212 | + | ||
213 | kexec_dprintk("kexec measurement buffer for the loaded kernel at 0x%lx.\n", | ||
214 | kbuf.mem); | ||
215 | } | ||
216 | diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c | ||
217 | index XXXXXXX..XXXXXXX 100644 | ||
218 | --- a/security/integrity/ima/ima_queue.c | ||
219 | +++ b/security/integrity/ima/ima_queue.c | ||
220 | @@ -XXX,XX +XXX,XX @@ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value, | ||
221 | * binary_runtime_measurement list entry, which contains a | ||
222 | * couple of variable length fields (e.g template name and data). | ||
223 | */ | ||
224 | -static int get_binary_runtime_size(struct ima_template_entry *entry) | ||
225 | +int ima_get_binary_runtime_entry_size(struct ima_template_entry *entry) | ||
226 | { | ||
227 | int size = 0; | ||
228 | |||
229 | @@ -XXX,XX +XXX,XX @@ static int ima_add_digest_entry(struct ima_template_entry *entry, | ||
230 | if (binary_runtime_size != ULONG_MAX) { | ||
231 | int size; | ||
232 | |||
233 | - size = get_binary_runtime_size(entry); | ||
234 | + size = ima_get_binary_runtime_entry_size(entry); | ||
235 | binary_runtime_size = (binary_runtime_size < ULONG_MAX - size) ? | ||
236 | binary_runtime_size + size : ULONG_MAX; | ||
237 | } | ||
238 | -- | 104 | -- |
239 | 2.25.1 | 105 | 2.25.1 | diff view generated by jsdifflib |
1 | Currently, the mechanism to map and unmap segments to the kimage | 1 | Currently, the kernel behavior during kexec load is to fetch the IMA |
---|---|---|---|
2 | structure is not available to the subsystems outside of kexec. This | 2 | measurements logs and store logs in kernel memory. When a kexec reboot is |
3 | functionality is needed when IMA is allocating the memory segments | 3 | triggered, these stored logs in the kernel memory are carried over to the |
4 | during kexec 'load' operation. Implement functions to map and unmap | 4 | second kernel. However, the time gap between kexec load and kexec reboot |
5 | segments to kimage. | 5 | can be very long. During this time window, new events extended into TPM |
6 | PCRs miss the chance to be carried over to the second kernel. This results | ||
7 | in a mismatch between TPM PCR quotes and the actual IMA measurements list | ||
8 | after kexec reboot, leading to remote attestation failure. | ||
6 | 9 | ||
7 | Implement kimage_map_segment() to enable mapping of IMA buffer source | 10 | To solve this problem, the new design defers reading the IMA measurements |
8 | pages to the kimage structure post kexec 'load'. This function, | 11 | logs into the kexec buffer to the kexec reboot phase, while still allocating |
9 | accepting a kimage pointer, an address, and a size, will gather the | 12 | the necessary buffer at kexec load time because it is not appropriate to |
10 | source pages within the specified address range, create an array of page | 13 | allocate memory at the kexec reboot moment. |
11 | pointers, and map these to a contiguous virtual address range. The | ||
12 | function returns the start of this range if successful, or NULL if | ||
13 | unsuccessful. | ||
14 | 14 | ||
15 | Implement kimage_unmap_segment() for unmapping segments | 15 | The content of memory segments carried over to the new kernel during the |
16 | using vunmap(). | 16 | kexec system call can be changed at the kexec 'execute' stage, but the size |
17 | of the memory segments cannot be changed at the kexec 'execute' stage. | ||
18 | |||
19 | To copy IMA measurement logs during the kexec operation, IMA allocates | ||
20 | memory at the kexec 'load' stage and map the segments to the kimage | ||
21 | structure. The mapped address will then be used to copy IMA measurements | ||
22 | during the kexec 'execute' stage. | ||
23 | |||
24 | Currently, the mechanism to map and unmap segments to the kimage structure | ||
25 | is not available to subsystems outside of kexec. | ||
26 | |||
27 | Implement kimage_map_segment() to enable IMA to map the measurement log | ||
28 | list to the kimage structure during the kexec 'load' stage. This function | ||
29 | takes a kimage pointer, a memory address, and a size, then gathers the | ||
30 | source pages within the specified address range, creates an array of page | ||
31 | pointers, and maps these to a contiguous virtual address range. The | ||
32 | function returns the start virtual address of this range if successful, | ||
33 | or NULL on failure. | ||
34 | |||
35 | Implement kimage_unmap_segment() for unmapping segments using vunmap(). | ||
17 | 36 | ||
18 | From: Tushar Sugandhi <tusharsu@linux.microsoft.com> | 37 | From: Tushar Sugandhi <tusharsu@linux.microsoft.com> |
19 | Author: Tushar Sugandhi <tusharsu@linux.microsoft.com> | ||
20 | Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> | 38 | Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> |
39 | Cc: Eric Biederman <ebiederm@xmission.com> | ||
40 | Cc: Baoquan He <bhe@redhat.com> | ||
41 | Cc: Vivek Goyal <vgoyal@redhat.com> | ||
42 | Cc: Dave Young <dyoung@redhat.com> | ||
21 | Signed-off-by: steven chen <chenste@linux.microsoft.com> | 43 | Signed-off-by: steven chen <chenste@linux.microsoft.com> |
44 | Acked-by: Baoquan He <bhe@redhat.com> | ||
22 | --- | 45 | --- |
23 | include/linux/kexec.h | 5 ++++ | 46 | include/linux/kexec.h | 6 +++++ |
24 | kernel/kexec_core.c | 54 +++++++++++++++++++++++++++++++++++++++++++ | 47 | kernel/kexec_core.c | 54 +++++++++++++++++++++++++++++++++++++++++++ |
25 | 2 files changed, 59 insertions(+) | 48 | 2 files changed, 60 insertions(+) |
26 | 49 | ||
27 | diff --git a/include/linux/kexec.h b/include/linux/kexec.h | 50 | diff --git a/include/linux/kexec.h b/include/linux/kexec.h |
28 | index XXXXXXX..XXXXXXX 100644 | 51 | index XXXXXXX..XXXXXXX 100644 |
29 | --- a/include/linux/kexec.h | 52 | --- a/include/linux/kexec.h |
30 | +++ b/include/linux/kexec.h | 53 | +++ b/include/linux/kexec.h |
... | ... | ||
35 | +extern void *kimage_map_segment(struct kimage *image, unsigned long addr, unsigned long size); | 58 | +extern void *kimage_map_segment(struct kimage *image, unsigned long addr, unsigned long size); |
36 | +extern void kimage_unmap_segment(void *buffer); | 59 | +extern void kimage_unmap_segment(void *buffer); |
37 | #else /* !CONFIG_KEXEC_CORE */ | 60 | #else /* !CONFIG_KEXEC_CORE */ |
38 | struct pt_regs; | 61 | struct pt_regs; |
39 | struct task_struct; | 62 | struct task_struct; |
40 | @@ -XXX,XX +XXX,XX @@ static inline void __crash_kexec(struct pt_regs *regs) { } | 63 | +struct kimage; |
64 | static inline void __crash_kexec(struct pt_regs *regs) { } | ||
41 | static inline void crash_kexec(struct pt_regs *regs) { } | 65 | static inline void crash_kexec(struct pt_regs *regs) { } |
42 | static inline int kexec_should_crash(struct task_struct *p) { return 0; } | 66 | static inline int kexec_should_crash(struct task_struct *p) { return 0; } |
43 | static inline int kexec_crash_loaded(void) { return 0; } | 67 | static inline int kexec_crash_loaded(void) { return 0; } |
44 | +static inline void *kimage_map_segment(struct kimage *image, unsigned long addr, unsigned long size) | 68 | +static inline void *kimage_map_segment(struct kimage *image, unsigned long addr, unsigned long size) |
45 | +{ return NULL; } | 69 | +{ return NULL; } |
... | ... | ||
56 | } | 80 | } |
57 | 81 | ||
58 | +void *kimage_map_segment(struct kimage *image, | 82 | +void *kimage_map_segment(struct kimage *image, |
59 | + unsigned long addr, unsigned long size) | 83 | + unsigned long addr, unsigned long size) |
60 | +{ | 84 | +{ |
85 | + unsigned long src_page_addr, dest_page_addr = 0; | ||
61 | + unsigned long eaddr = addr + size; | 86 | + unsigned long eaddr = addr + size; |
62 | + unsigned long src_page_addr, dest_page_addr; | 87 | + kimage_entry_t *ptr, entry; |
88 | + struct page **src_pages; | ||
63 | + unsigned int npages; | 89 | + unsigned int npages; |
64 | + struct page **src_pages; | 90 | + void *vaddr = NULL; |
65 | + int i; | 91 | + int i; |
66 | + kimage_entry_t *ptr, entry; | ||
67 | + void *vaddr = NULL; | ||
68 | + | 92 | + |
69 | + /* | 93 | + /* |
70 | + * Collect the source pages and map them in a contiguous VA range. | 94 | + * Collect the source pages and map them in a contiguous VA range. |
71 | + */ | 95 | + */ |
72 | + npages = PFN_UP(eaddr) - PFN_DOWN(addr); | 96 | + npages = PFN_UP(eaddr) - PFN_DOWN(addr); |
... | ... | diff view generated by jsdifflib |
1 | kexec_calculate_store_digests() calculates and stores the digest of the | 1 | The kexec_calculate_store_digests() function calculates and stores the |
---|---|---|---|
2 | segment at kexec_file_load syscall where the IMA segment is also | 2 | digest of the segment during the kexec_file_load syscall, where the |
3 | allocated. With this series, the IMA segment will be updated with the | 3 | IMA segment is also allocated. |
4 | measurement log at kexec execute stage when soft reboot is initiated. | 4 | |
5 | Therefore, it may fail digest verification in verify_sha256_digest() | 5 | With this series, the IMA segment will be updated with the measurement |
6 | after kexec soft reboot into the new kernel. Therefore, the digest | 6 | log at the kexec execute stage when a soft reboot is initiated. |
7 | Therefore, the digests should be updated for the IMA segment in the | ||
8 | normal case. | ||
9 | |||
10 | The content of memory segments carried over to the new kernel during the | ||
11 | kexec systemcall can be changed at kexec 'execute' stage, but the size | ||
12 | and the location of the memory segments cannot be changed at kexec | ||
13 | 'execute' stage. | ||
14 | |||
15 | However, during the kexec execute stage, if kexec_calculate_store_digests() | ||
16 | API is called to update the digest, it does not reuse the same memory | ||
17 | segment allocated during the kexec 'load' stage and the new memory segment | ||
18 | required cannot be transferred/mapped to the new kernel. | ||
19 | |||
20 | As a result, digest verification will fail in verify_sha256_digest() | ||
21 | after a kexec soft reboot into the new kernel. Therefore, the digest | ||
7 | calculation/verification of the IMA segment needs to be skipped. | 22 | calculation/verification of the IMA segment needs to be skipped. |
8 | 23 | ||
9 | Skip the calculating and storing digest of the IMA segment in | 24 | To address this, skip the calculation and storage of the digest for the |
10 | kexec_calculate_store_digests() so that it is not added to the | 25 | IMA segment in kexec_calculate_store_digests() so that it is not added |
11 | 'purgatory_sha_regions'. | 26 | to the purgatory_sha_regions. |
12 | 27 | ||
13 | Since verify_sha256_digest() only verifies 'purgatory_sha_regions', | 28 | Since verify_sha256_digest() only verifies 'purgatory_sha_regions', |
14 | no change is needed in verify_sha256_digest() in this context. | 29 | no change is needed in verify_sha256_digest() in this context. |
15 | 30 | ||
16 | With this change, the IMA segment is not included in the digest | 31 | With this change, the IMA segment is not included in the digest |
17 | calculation, storage, and verification. | 32 | calculation, storage, and verification. |
18 | 33 | ||
19 | Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> | 34 | Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> |
35 | Cc: Eric Biederman <ebiederm@xmission.com> | ||
36 | Cc: Baoquan He <bhe@redhat.com> | ||
37 | Cc: Vivek Goyal <vgoyal@redhat.com> | ||
38 | Cc: Dave Young <dyoung@redhat.com> | ||
20 | Signed-off-by: steven chen <chenste@linux.microsoft.com> | 39 | Signed-off-by: steven chen <chenste@linux.microsoft.com> |
21 | Reviewed-by: Stefan Berger <stefanb@linux.ibm.com> | 40 | Reviewed-by: Stefan Berger <stefanb@linux.ibm.com> |
41 | Reviewed-by: Mimi Zohar <zohar@linux.ibm.com> | ||
42 | Acked-by: Baoquan He <bhe@redhat.com> | ||
22 | --- | 43 | --- |
23 | include/linux/kexec.h | 3 +++ | 44 | include/linux/kexec.h | 3 +++ |
24 | kernel/kexec_file.c | 22 ++++++++++++++++++++++ | 45 | kernel/kexec_file.c | 22 ++++++++++++++++++++++ |
25 | security/integrity/ima/ima_kexec.c | 3 +++ | 46 | security/integrity/ima/ima_kexec.c | 3 +++ |
26 | 3 files changed, 28 insertions(+) | 47 | 3 files changed, 28 insertions(+) |
... | ... | ||
96 | image->ima_buffer_size = kexec_segment_size; | 117 | image->ima_buffer_size = kexec_segment_size; |
97 | image->ima_buffer = kexec_buffer; | 118 | image->ima_buffer = kexec_buffer; |
98 | + image->ima_segment_index = image->nr_segments - 1; | 119 | + image->ima_segment_index = image->nr_segments - 1; |
99 | + image->is_ima_segment_index_set = true; | 120 | + image->is_ima_segment_index_set = true; |
100 | 121 | ||
101 | /* | 122 | kexec_dprintk("kexec measurement buffer for the loaded kernel at 0x%lx.\n", |
102 | * kexec owns kexec_buffer after kexec_add_buffer() is called | 123 | kbuf.mem); |
103 | -- | 124 | -- |
104 | 2.25.1 | 125 | 2.25.1 | diff view generated by jsdifflib |
1 | IMA log is copied to the new Kernel during kexec 'load' using | 1 | The IMA log is currently copied to the new kernel during kexec 'load' |
---|---|---|---|
2 | ima_dump_measurement_list(). The log copy at kexec 'load' may result in | 2 | using ima_dump_measurement_list(). However, the log copied at kexec |
3 | loss of IMA measurements during kexec soft reboot. It needs to be copied | 3 | 'load' may result in loss of IMA measurements that only occurred after |
4 | over during kexec 'execute'. Setup the needed infrastructure to move the | 4 | kexec "load'. Therefore, the log needs to be copied during kexec |
5 | IMA log copy from kexec 'load' to 'execute'. | 5 | 'execute'. Setup the needed infrastructure to move the IMA log copy from |
6 | kexec 'load' to 'execute'. | ||
6 | 7 | ||
7 | Define a new IMA hook ima_update_kexec_buffer() as a stub function. | 8 | Define a new IMA hook ima_update_kexec_buffer() as a stub function. |
8 | It will be used to call ima_dump_measurement_list() during kexec | 9 | It will be used to call ima_dump_measurement_list() during kexec 'execute'. |
9 | 'execute'. | ||
10 | 10 | ||
11 | Implement ima_kexec_post_load() function to be invoked after the new | 11 | Implement ima_kexec_post_load() function to be invoked after the new |
12 | Kernel image has been loaded for kexec. ima_kexec_post_load() maps the | 12 | Kernel image has been loaded for kexec. ima_kexec_post_load() maps the |
13 | IMA buffer to a segment in the newly loaded Kernel. It also registers | 13 | IMA buffer to a segment in the newly loaded Kernel. It also registers |
14 | the reboot notifier_block to trigger ima_update_kexec_buffer() at | 14 | the reboot notifier_block to trigger ima_update_kexec_buffer() at |
15 | exec 'execute'. | 15 | kexec 'execute'. |
16 | |||
17 | Set the priority of register_reboot_notifier to INT_MIN to ensure that the | ||
18 | IMA log copy operation will happen at the end of the operation chain, which | ||
19 | is crucial for maintaining the integrity of the logs | ||
16 | 20 | ||
17 | Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> | 21 | Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> |
22 | Cc: Eric Biederman <ebiederm@xmission.com> | ||
23 | Cc: Baoquan He <bhe@redhat.com> | ||
24 | Cc: Vivek Goyal <vgoyal@redhat.com> | ||
25 | Cc: Dave Young <dyoung@redhat.com> | ||
18 | Signed-off-by: steven chen <chenste@linux.microsoft.com> | 26 | Signed-off-by: steven chen <chenste@linux.microsoft.com> |
27 | Reviewed-by: Stefan Berger <stefanb@linux.ibm.com> | ||
19 | --- | 28 | --- |
20 | include/linux/ima.h | 3 ++ | 29 | include/linux/ima.h | 3 ++ |
21 | security/integrity/ima/ima_kexec.c | 46 ++++++++++++++++++++++++++++++ | 30 | security/integrity/ima/ima_kexec.c | 47 ++++++++++++++++++++++++++++++ |
22 | 2 files changed, 49 insertions(+) | 31 | 2 files changed, 50 insertions(+) |
23 | 32 | ||
24 | diff --git a/include/linux/ima.h b/include/linux/ima.h | 33 | diff --git a/include/linux/ima.h b/include/linux/ima.h |
25 | index XXXXXXX..XXXXXXX 100644 | 34 | index XXXXXXX..XXXXXXX 100644 |
26 | --- a/include/linux/ima.h | 35 | --- a/include/linux/ima.h |
27 | +++ b/include/linux/ima.h | 36 | +++ b/include/linux/ima.h |
... | ... | ||
46 | +#include <linux/reboot.h> | 55 | +#include <linux/reboot.h> |
47 | +#include <asm/page.h> | 56 | +#include <asm/page.h> |
48 | #include "ima.h" | 57 | #include "ima.h" |
49 | 58 | ||
50 | #ifdef CONFIG_IMA_KEXEC | 59 | #ifdef CONFIG_IMA_KEXEC |
60 | +static bool ima_kexec_update_registered; | ||
51 | static struct seq_file ima_kexec_file; | 61 | static struct seq_file ima_kexec_file; |
52 | +static void *ima_kexec_buffer; | 62 | +static void *ima_kexec_buffer; |
53 | +static bool ima_kexec_update_registered; | 63 | |
54 | 64 | static void ima_free_kexec_file_buf(struct seq_file *sf) | |
55 | static void ima_reset_kexec_file(struct seq_file *sf) | ||
56 | { | 65 | { |
57 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) | 66 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) |
58 | kexec_dprintk("kexec measurement buffer for the loaded kernel at 0x%lx.\n", | 67 | kexec_dprintk("kexec measurement buffer for the loaded kernel at 0x%lx.\n", |
59 | kbuf.mem); | 68 | kbuf.mem); |
60 | } | 69 | } |
... | ... | ||
66 | + unsigned long action, void *data) | 75 | + unsigned long action, void *data) |
67 | +{ | 76 | +{ |
68 | + return NOTIFY_OK; | 77 | + return NOTIFY_OK; |
69 | +} | 78 | +} |
70 | + | 79 | + |
71 | +struct notifier_block update_buffer_nb = { | 80 | +static struct notifier_block update_buffer_nb = { |
72 | + .notifier_call = ima_update_kexec_buffer, | 81 | + .notifier_call = ima_update_kexec_buffer, |
82 | + .priority = INT_MIN | ||
73 | +}; | 83 | +}; |
74 | + | 84 | + |
75 | +/* | 85 | +/* |
76 | + * Create a mapping for the source pages that contain the IMA buffer | 86 | + * Create a mapping for the source pages that contain the IMA buffer |
77 | + * so we can update it later. | 87 | + * so we can update it later. |
... | ... | diff view generated by jsdifflib |
1 | ima_dump_measurement_list() is called during kexec 'load', which may | 1 | ima_dump_measurement_list() is called during kexec 'load', which may |
---|---|---|---|
2 | result in loss of IMA measurements during kexec soft reboot. It needs | 2 | result in loss of IMA measurements during kexec soft reboot. Due to |
3 | to be called during kexec 'execute'. | 3 | missed measurements that only occurred after kexec 'load', this function |
4 | needs to be called during kexec 'execute'. | ||
4 | 5 | ||
5 | This patch includes the following changes: | 6 | Make the kexec_segment_size variable a local static variable within the |
6 | - Implement kimage_file_post_load() function to be invoked after the new | 7 | file, so it can be accessed during both kexec 'load' and 'execute'. |
7 | Kernel image has been loaded for kexec. | 8 | |
8 | - Call kimage_file_post_load() from kexec_file_load() syscall only for | 9 | Implement the kexec_post_load() function to be invoked after the new kernel |
9 | kexec soft reboot scenarios and not for KEXEC_FILE_ON_CRASH. It will | 10 | image has been loaded for kexec. Instead of calling machine_kexec_post_load() |
10 | map the IMA segment, and register reboot notifier for the function | 11 | directly from the kexec_file_load() syscall, call kexec_post_load(), which in |
11 | ima_update_kexec_buffer() which would copy the IMA log at kexec soft | 12 | turn calls machine_kexec_post_load() to maintain the original image processing. |
12 | reboot. | 13 | |
13 | - Make kexec_segment_size variable local static to the file, for it to be | 14 | Invoke ima_kexec_post_load() within the kexec_post_load() API only for kexec |
14 | accessible both during kexec 'load' and 'execute'. | 15 | soft reboot scenarios, excluding KEXEC_FILE_ON_CRASH. |
15 | - Move ima_dump_measurement_list() call from ima_add_kexec_buffer() | 16 | |
16 | to ima_update_kexec_buffer(). | 17 | Register a reboot notifier for the ima_update_kexec_buffer() API within |
17 | - Remove ima_reset_kexec_file() call from ima_add_kexec_buffer(), now | 18 | ima_kexec_post_load() to ensure it is called upon receiving a reboot |
18 | that the buffer is being copied at kexec 'execute', and resetting the | 19 | notification. |
19 | file at kexec 'load' will corrupt the buffer. | 20 | |
21 | Move the ima_dump_measurement_list() call from ima_add_kexec_buffer() to | ||
22 | ima_update_kexec_buffer() to copy the IMA log at the kexec 'execute' stage. | ||
23 | |||
24 | When there is insufficient memory to copy all the measurement logs, copy as | ||
25 | much of the measurement list as possible. | ||
20 | 26 | ||
21 | Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> | 27 | Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> |
28 | Cc: Eric Biederman <ebiederm@xmission.com> | ||
29 | Cc: Baoquan He <bhe@redhat.com> | ||
30 | Cc: Vivek Goyal <vgoyal@redhat.com> | ||
31 | Cc: Dave Young <dyoung@redhat.com> | ||
22 | Signed-off-by: steven chen <chenste@linux.microsoft.com> | 32 | Signed-off-by: steven chen <chenste@linux.microsoft.com> |
33 | Reviewed-by: Stefan Berger <stefanb@linux.ibm.com> | ||
23 | --- | 34 | --- |
24 | kernel/kexec_file.c | 8 ++++++ | 35 | kernel/kexec_file.c | 11 +++++++- |
25 | security/integrity/ima/ima_kexec.c | 43 +++++++++++++++++++----------- | 36 | security/integrity/ima/ima_kexec.c | 43 ++++++++++++++++++++---------- |
26 | 2 files changed, 36 insertions(+), 15 deletions(-) | 37 | 2 files changed, 39 insertions(+), 15 deletions(-) |
27 | 38 | ||
28 | diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c | 39 | diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c |
29 | index XXXXXXX..XXXXXXX 100644 | 40 | index XXXXXXX..XXXXXXX 100644 |
30 | --- a/kernel/kexec_file.c | 41 | --- a/kernel/kexec_file.c |
31 | +++ b/kernel/kexec_file.c | 42 | +++ b/kernel/kexec_file.c |
32 | @@ -XXX,XX +XXX,XX @@ kimage_validate_signature(struct kimage *image) | 43 | @@ -XXX,XX +XXX,XX @@ kimage_validate_signature(struct kimage *image) |
33 | } | 44 | } |
34 | #endif | 45 | #endif |
35 | 46 | ||
36 | +static void kimage_file_post_load(struct kimage *image) | 47 | +static int kexec_post_load(struct kimage *image, unsigned long flags) |
37 | +{ | 48 | +{ |
38 | + ima_kexec_post_load(image); | 49 | +#ifdef CONFIG_IMA_KEXEC |
50 | + if (!(flags & KEXEC_FILE_ON_CRASH)) | ||
51 | + ima_kexec_post_load(image); | ||
52 | +#endif | ||
53 | + return machine_kexec_post_load(image); | ||
39 | +} | 54 | +} |
40 | + | 55 | + |
41 | /* | 56 | /* |
42 | * In file mode list of segments is prepared by kernel. Copy relevant | 57 | * In file mode list of segments is prepared by kernel. Copy relevant |
43 | * data from user space, do error checking, prepare segment list | 58 | * data from user space, do error checking, prepare segment list |
44 | @@ -XXX,XX +XXX,XX @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, | 59 | @@ -XXX,XX +XXX,XX @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, |
45 | 60 | ||
46 | kimage_terminate(image); | 61 | kimage_terminate(image); |
47 | 62 | ||
48 | + if (!(flags & KEXEC_FILE_ON_CRASH)) | 63 | - ret = machine_kexec_post_load(image); |
49 | + kimage_file_post_load(image); | 64 | + ret = kexec_post_load(image, flags); |
50 | + | ||
51 | ret = machine_kexec_post_load(image); | ||
52 | if (ret) | 65 | if (ret) |
53 | goto out; | 66 | goto out; |
67 | |||
54 | diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c | 68 | diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c |
55 | index XXXXXXX..XXXXXXX 100644 | 69 | index XXXXXXX..XXXXXXX 100644 |
56 | --- a/security/integrity/ima/ima_kexec.c | 70 | --- a/security/integrity/ima/ima_kexec.c |
57 | +++ b/security/integrity/ima/ima_kexec.c | 71 | +++ b/security/integrity/ima/ima_kexec.c |
58 | @@ -XXX,XX +XXX,XX @@ | 72 | @@ -XXX,XX +XXX,XX @@ |
59 | #ifdef CONFIG_IMA_KEXEC | 73 | #ifdef CONFIG_IMA_KEXEC |
74 | static bool ima_kexec_update_registered; | ||
60 | static struct seq_file ima_kexec_file; | 75 | static struct seq_file ima_kexec_file; |
76 | +static size_t kexec_segment_size; | ||
61 | static void *ima_kexec_buffer; | 77 | static void *ima_kexec_buffer; |
62 | +static size_t kexec_segment_size; | 78 | |
63 | static bool ima_kexec_update_registered; | 79 | static void ima_free_kexec_file_buf(struct seq_file *sf) |
64 | 80 | @@ -XXX,XX +XXX,XX @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, | |
65 | static void ima_reset_kexec_file(struct seq_file *sf) | 81 | } |
82 | } | ||
83 | |||
84 | - if (ret < 0) | ||
85 | - goto out; | ||
86 | - | ||
87 | /* | ||
88 | * fill in reserved space with some buffer details | ||
89 | * (eg. version, buffer size, number of measurements) | ||
90 | @@ -XXX,XX +XXX,XX @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer, | ||
91 | |||
92 | *buffer_size = ima_kexec_file.count; | ||
93 | *buffer = ima_kexec_file.buf; | ||
94 | -out: | ||
95 | + | ||
96 | return ret; | ||
97 | } | ||
98 | |||
66 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) | 99 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) |
100 | unsigned long binary_runtime_size; | ||
101 | |||
67 | /* use more understandable variable names than defined in kbuf */ | 102 | /* use more understandable variable names than defined in kbuf */ |
103 | + size_t kexec_buffer_size = 0; | ||
68 | void *kexec_buffer = NULL; | 104 | void *kexec_buffer = NULL; |
69 | size_t kexec_buffer_size = 0; | 105 | - size_t kexec_buffer_size; |
70 | - size_t kexec_segment_size; | 106 | - size_t kexec_segment_size; |
71 | int ret; | 107 | int ret; |
72 | 108 | ||
73 | /* | 109 | /* |
74 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) | 110 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) |
75 | return; | 111 | return; |
76 | } | 112 | } |
77 | 113 | ||
78 | - ret = ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer, | 114 | - ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer, |
79 | - kexec_segment_size); | 115 | - kexec_segment_size); |
80 | - if (ret < 0) { | 116 | - if (!kexec_buffer) { |
81 | - pr_err("Failed to dump IMA measurements. Error:%d.\n", ret); | 117 | - pr_err("Not enough memory for the kexec measurement buffer.\n"); |
82 | - return; | 118 | - return; |
83 | - } | 119 | - } |
84 | - | 120 | - |
85 | kbuf.buffer = kexec_buffer; | 121 | kbuf.buffer = kexec_buffer; |
86 | kbuf.bufsz = kexec_buffer_size; | 122 | kbuf.bufsz = kexec_buffer_size; |
87 | kbuf.memsz = kexec_segment_size; | 123 | kbuf.memsz = kexec_segment_size; |
88 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) | 124 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) |
89 | image->ima_segment_index = image->nr_segments - 1; | ||
90 | image->is_ima_segment_index_set = true; | ||
91 | |||
92 | - /* | ||
93 | - * kexec owns kexec_buffer after kexec_add_buffer() is called | ||
94 | - * and it will vfree() that buffer. | ||
95 | - */ | ||
96 | - ima_reset_kexec_file(&ima_kexec_file); | ||
97 | - | ||
98 | kexec_dprintk("kexec measurement buffer for the loaded kernel at 0x%lx.\n", | ||
99 | kbuf.mem); | ||
100 | } | ||
101 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) | ||
102 | static int ima_update_kexec_buffer(struct notifier_block *self, | 125 | static int ima_update_kexec_buffer(struct notifier_block *self, |
103 | unsigned long action, void *data) | 126 | unsigned long action, void *data) |
104 | { | 127 | { |
105 | - return NOTIFY_OK; | 128 | - return NOTIFY_OK; |
106 | + void *buf = NULL; | ||
107 | + size_t buf_size = 0; | 129 | + size_t buf_size = 0; |
108 | + int ret = NOTIFY_OK; | 130 | + int ret = NOTIFY_OK; |
131 | + void *buf = NULL; | ||
109 | + | 132 | + |
110 | + if (!kexec_in_progress) { | 133 | + if (!kexec_in_progress) { |
111 | + pr_info("No kexec in progress.\n"); | 134 | + pr_info("No kexec in progress.\n"); |
112 | + return ret; | 135 | + return ret; |
113 | + } | 136 | + } |
114 | + | 137 | + |
115 | + if (!ima_kexec_buffer) { | 138 | + if (!ima_kexec_buffer) { |
116 | + pr_err("Kexec buffer not set.\n"); | 139 | + pr_err("Kexec buffer not set.\n"); |
117 | + return ret; | 140 | + return ret; |
118 | + } | 141 | + } |
119 | + | 142 | + |
120 | + ret = ima_dump_measurement_list(&buf_size, &buf, | 143 | + ret = ima_dump_measurement_list(&buf_size, &buf, kexec_segment_size); |
121 | + kexec_segment_size); | ||
122 | + | 144 | + |
123 | + if (ret) | 145 | + if (ret) |
124 | + pr_err("Dump measurements failed. Error:%d\n", ret); | 146 | + pr_err("Dump measurements failed. Error:%d\n", ret); |
125 | + | 147 | + |
126 | + if (buf_size != 0) | 148 | + if (buf_size != 0) |
... | ... | ||
130 | + ima_kexec_buffer = NULL; | 152 | + ima_kexec_buffer = NULL; |
131 | + | 153 | + |
132 | + return ret; | 154 | + return ret; |
133 | } | 155 | } |
134 | 156 | ||
135 | struct notifier_block update_buffer_nb = { | 157 | static struct notifier_block update_buffer_nb = { |
136 | -- | 158 | -- |
137 | 2.25.1 | 159 | 2.25.1 | diff view generated by jsdifflib |
New patch | |||
---|---|---|---|
1 | kexec 'load' may be called multiple times. Free and realloc the buffer | ||
2 | only if the segment_size is changed from the previous kexec 'load' call. | ||
1 | 3 | ||
4 | Signed-off-by: steven chen <chenste@linux.microsoft.com> | ||
5 | --- | ||
6 | security/integrity/ima/ima_kexec.c | 10 ++++++++++ | ||
7 | 1 file changed, 10 insertions(+) | ||
8 | |||
9 | diff --git a/security/integrity/ima/ima_kexec.c b/security/integrity/ima/ima_kexec.c | ||
10 | index XXXXXXX..XXXXXXX 100644 | ||
11 | --- a/security/integrity/ima/ima_kexec.c | ||
12 | +++ b/security/integrity/ima/ima_kexec.c | ||
13 | @@ -XXX,XX +XXX,XX @@ static void ima_free_kexec_file_buf(struct seq_file *sf) | ||
14 | |||
15 | static int ima_alloc_kexec_file_buf(size_t segment_size) | ||
16 | { | ||
17 | + /* | ||
18 | + * kexec 'load' may be called multiple times. | ||
19 | + * Free and realloc the buffer only if the segment_size is | ||
20 | + * changed from the previous kexec 'load' call. | ||
21 | + */ | ||
22 | + if (ima_kexec_file.buf && ima_kexec_file.size == segment_size) | ||
23 | + goto out; | ||
24 | + | ||
25 | ima_free_kexec_file_buf(&ima_kexec_file); | ||
26 | |||
27 | /* segment size can't change between kexec load and execute */ | ||
28 | @@ -XXX,XX +XXX,XX @@ static int ima_alloc_kexec_file_buf(size_t segment_size) | ||
29 | return -ENOMEM; | ||
30 | |||
31 | ima_kexec_file.size = segment_size; | ||
32 | + | ||
33 | +out: | ||
34 | ima_kexec_file.read_pos = 0; | ||
35 | ima_kexec_file.count = sizeof(struct ima_kexec_hdr); /* reserved space */ | ||
36 | |||
37 | -- | ||
38 | 2.25.1 | diff view generated by jsdifflib |
... | ... | ||
---|---|---|---|
12 | 12 | ||
13 | Suggested-by: Stefan Berger <stefanb@linux.ibm.com> | 13 | Suggested-by: Stefan Berger <stefanb@linux.ibm.com> |
14 | Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> | 14 | Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> |
15 | Signed-off-by: steven chen <chenste@linux.microsoft.com> | 15 | Signed-off-by: steven chen <chenste@linux.microsoft.com> |
16 | Reviewed-by: Stefan Berger <stefanb@linux.ibm.com> | 16 | Reviewed-by: Stefan Berger <stefanb@linux.ibm.com> |
17 | Reviewed-by: Mimi Zohar <zohar@linux.ibm.com> | ||
17 | --- | 18 | --- |
18 | security/integrity/ima/Kconfig | 10 ++++++++++ | 19 | security/integrity/ima/Kconfig | 10 ++++++++++ |
19 | security/integrity/ima/ima_kexec.c | 16 ++++++++++------ | 20 | security/integrity/ima/ima_kexec.c | 16 +++++++++++----- |
20 | 2 files changed, 20 insertions(+), 6 deletions(-) | 21 | 2 files changed, 21 insertions(+), 5 deletions(-) |
21 | 22 | ||
22 | diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig | 23 | diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig |
23 | index XXXXXXX..XXXXXXX 100644 | 24 | index XXXXXXX..XXXXXXX 100644 |
24 | --- a/security/integrity/ima/Kconfig | 25 | --- a/security/integrity/ima/Kconfig |
25 | +++ b/security/integrity/ima/Kconfig | 26 | +++ b/security/integrity/ima/Kconfig |
... | ... | ||
44 | +++ b/security/integrity/ima/ima_kexec.c | 45 | +++ b/security/integrity/ima/ima_kexec.c |
45 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) | 46 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) |
46 | .buf_min = 0, .buf_max = ULONG_MAX, | 47 | .buf_min = 0, .buf_max = ULONG_MAX, |
47 | .top_down = true }; | 48 | .top_down = true }; |
48 | unsigned long binary_runtime_size; | 49 | unsigned long binary_runtime_size; |
49 | - | ||
50 | + unsigned long extra_memory; | 50 | + unsigned long extra_memory; |
51 | |||
51 | /* use more understandable variable names than defined in kbuf */ | 52 | /* use more understandable variable names than defined in kbuf */ |
52 | void *kexec_buffer = NULL; | ||
53 | size_t kexec_buffer_size = 0; | 53 | size_t kexec_buffer_size = 0; |
54 | @@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image) | ||
54 | int ret; | 55 | int ret; |
55 | 56 | ||
56 | /* | 57 | /* |
57 | - * Reserve an extra half page of memory for additional measurements | 58 | - * Reserve an extra half page of memory for additional measurements |
58 | - * added during the kexec load. | 59 | - * added during the kexec load. |
... | ... | ||
61 | - binary_runtime_size = ima_get_binary_runtime_size(); | 62 | - binary_runtime_size = ima_get_binary_runtime_size(); |
62 | + if (CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB <= 0) | 63 | + if (CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB <= 0) |
63 | + extra_memory = PAGE_SIZE / 2; | 64 | + extra_memory = PAGE_SIZE / 2; |
64 | + else | 65 | + else |
65 | + extra_memory = CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB * 1024; | 66 | + extra_memory = CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB * 1024; |
67 | + | ||
66 | + binary_runtime_size = ima_get_binary_runtime_size() + extra_memory; | 68 | + binary_runtime_size = ima_get_binary_runtime_size() + extra_memory; |
67 | + | 69 | + |
68 | if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE) | 70 | if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE) |
69 | kexec_segment_size = ULONG_MAX; | 71 | kexec_segment_size = ULONG_MAX; |
70 | else | 72 | else |
... | ... | diff view generated by jsdifflib |
... | ... | ||
---|---|---|---|
15 | reboot, and not a cold-boot. And the absence of 'kexec_execute' event | 15 | reboot, and not a cold-boot. And the absence of 'kexec_execute' event |
16 | after kexec soft reboot implies missing events in that window which | 16 | after kexec soft reboot implies missing events in that window which |
17 | results in inconsistency with TPM PCR quotes, necessitating a cold boot | 17 | results in inconsistency with TPM PCR quotes, necessitating a cold boot |
18 | for a successful remote attestation. | 18 | for a successful remote attestation. |
19 | 19 | ||
20 | The 'kexec_load' event IMA log can be found using the following command: | 20 | These critical data events are displayed as hex encoded ascii in the |
21 | sudo cat /sys/kernel/security/integrity/ima/ascii_runtime_measurements | | 21 | ascii_runtime_measurement_list. Verifying the critical data hash requires |
22 | grep kexec_load | 22 | calculating the hash of the decoded ascii string. |
23 | 23 | ||
24 | The 'kexec_load' event IMA log can be found using the following command: | 24 | For example, to verify the 'kexec_load' data hash: |
25 | sudo cat /sys/kernel/security/integrity/ima/ascii_runtime_measurements | | 25 | |
26 | grep kexec_execute | 26 | sudo cat /sys/kernel/security/integrity/ima/ascii_runtime_measurements |
27 | | grep kexec_load | cut -d' ' -f 6 | xxd -r -p | sha256sum | ||
28 | |||
29 | |||
30 | To verify the 'kexec_execute' data hash: | ||
31 | |||
32 | sudo cat /sys/kernel/security/integrity/ima/ascii_runtime_measurements | ||
33 | | grep kexec_execute | cut -d' ' -f 6 | xxd -r -p | sha256sum | ||
27 | 34 | ||
28 | Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> | 35 | Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com> |
29 | Signed-off-by: steven chen <chenste@linux.microsoft.com> | 36 | Signed-off-by: steven chen <chenste@linux.microsoft.com> |
37 | Reviewed-by: Stefan Berger <stefanb@linux.ibm.com> | ||
30 | --- | 38 | --- |
31 | security/integrity/ima/ima.h | 6 ++++++ | 39 | security/integrity/ima/ima.h | 6 ++++++ |
32 | security/integrity/ima/ima_kexec.c | 21 +++++++++++++++++++++ | 40 | security/integrity/ima/ima_kexec.c | 21 +++++++++++++++++++++ |
33 | security/integrity/ima/ima_queue.c | 5 +++++ | 41 | security/integrity/ima/ima_queue.c | 5 +++++ |
34 | 3 files changed, 32 insertions(+) | 42 | 3 files changed, 32 insertions(+) |
... | ... | ||
58 | #include "ima.h" | 66 | #include "ima.h" |
59 | 67 | ||
60 | #ifdef CONFIG_IMA_KEXEC | 68 | #ifdef CONFIG_IMA_KEXEC |
61 | +#define IMA_KEXEC_EVENT_LEN 256 | 69 | +#define IMA_KEXEC_EVENT_LEN 256 |
62 | + | 70 | + |
71 | static bool ima_kexec_update_registered; | ||
63 | static struct seq_file ima_kexec_file; | 72 | static struct seq_file ima_kexec_file; |
64 | static void *ima_kexec_buffer; | ||
65 | static size_t kexec_segment_size; | 73 | static size_t kexec_segment_size; |
66 | @@ -XXX,XX +XXX,XX @@ static void ima_free_kexec_file_buf(struct seq_file *sf) | 74 | @@ -XXX,XX +XXX,XX @@ static void ima_free_kexec_file_buf(struct seq_file *sf) |
67 | ima_reset_kexec_file(sf); | 75 | sf->count = 0; |
68 | } | 76 | } |
69 | 77 | ||
70 | +void ima_measure_kexec_event(const char *event_name) | 78 | +void ima_measure_kexec_event(const char *event_name) |
71 | +{ | 79 | +{ |
72 | + char ima_kexec_event[IMA_KEXEC_EVENT_LEN]; | 80 | + char ima_kexec_event[IMA_KEXEC_EVENT_LEN]; |
73 | + size_t buf_size = 0; | 81 | + size_t buf_size = 0; |
74 | + long len; | 82 | + long len; |
83 | + int n; | ||
75 | + | 84 | + |
76 | + buf_size = ima_get_binary_runtime_size(); | 85 | + buf_size = ima_get_binary_runtime_size(); |
77 | + len = atomic_long_read(&ima_htable.len); | 86 | + len = atomic_long_read(&ima_htable.len); |
78 | + | 87 | + |
79 | + scnprintf(ima_kexec_event, IMA_KEXEC_EVENT_LEN, | 88 | + n = scnprintf(ima_kexec_event, IMA_KEXEC_EVENT_LEN, |
80 | + "kexec_segment_size=%lu;ima_binary_runtime_size=%lu;" | 89 | + "kexec_segment_size=%lu;ima_binary_runtime_size=%lu;" |
81 | + "ima_runtime_measurements_count=%ld;", | 90 | + "ima_runtime_measurements_count=%ld;", |
82 | + kexec_segment_size, buf_size, len); | 91 | + kexec_segment_size, buf_size, len); |
83 | + | 92 | + |
84 | + ima_measure_critical_data("ima_kexec", event_name, ima_kexec_event, | 93 | + ima_measure_critical_data("ima_kexec", event_name, ima_kexec_event, n, false, NULL, 0); |
85 | + strlen(ima_kexec_event), false, NULL, 0); | ||
86 | +} | 94 | +} |
87 | + | 95 | + |
88 | static int ima_alloc_kexec_file_buf(size_t segment_size) | 96 | static int ima_alloc_kexec_file_buf(size_t segment_size) |
89 | { | 97 | { |
90 | /* | 98 | /* |
... | ... | diff view generated by jsdifflib |