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
...
...
60
61
61
V7 of this series is available here[9] for reference.
62
V7 of this series is available here[9] for reference.
62
63
63
V8 of this series is available here[10] for reference.
64
V8 of this series is available here[10] for reference.
64
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
65
References:
70
References:
66
-----------
71
-----------
67
72
68
[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
69
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/
...
...
92
[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
93
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/
94
99
95
[10] [PATCH v8 0/7] ima: kexec: measure events between kexec load and execute
100
[10] [PATCH v8 0/7] ima: kexec: measure events between kexec load and execute
96
https://lore.kernel.org/all/20250218225502.747963-1-chenste@linux.microsoft.com/
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.
97
129
98
Change Log v9:
130
Change Log v9:
99
- Incorporated feedback from the community (Stefan Berger, Mimi Zohar,
131
- Incorporated feedback from the community (Stefan Berger, Mimi Zohar,
100
and kernel test robot) on v8 of this series[10].
132
and kernel test robot) on v8 of this series[10].
101
- Rebased the patch series to mainline 6.14.0-rc3.
133
- Rebased the patch series to mainline 6.14.0-rc3.
...
...
215
compilation.
247
compilation.
216
- Used virt_to_page instead of phys_to_page.
248
- Used virt_to_page instead of phys_to_page.
217
- Updated patch descriptions as necessary.
249
- Updated patch descriptions as necessary.
218
250
219
251
220
steven chen (7):
252
steven chen (9):
221
ima: copy only complete measurement records across kexec
253
ima: rename variable the set_file "file" to "ima_kexec_file"
254
ima: define and call ima_alloc_kexec_file_buf()
222
kexec: define functions to map and unmap segments
255
kexec: define functions to map and unmap segments
223
ima: kexec: skip IMA segment validation after kexec soft reboot
256
ima: kexec: skip IMA segment validation after kexec soft reboot
224
ima: kexec: define functions to copy IMA log at soft boot
257
ima: kexec: define functions to copy IMA log at soft boot
225
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
226
ima: make the kexec extra memory configurable
260
ima: make the kexec extra memory configurable
227
ima: measure kexec load and exec events as critical data
261
ima: measure kexec load and exec events as critical data
228
262
229
include/linux/ima.h | 3 +
263
include/linux/ima.h | 3 +
230
include/linux/kexec.h | 9 ++
264
include/linux/kexec.h | 9 ++
231
kernel/kexec_core.c | 54 ++++++++
265
kernel/kexec_core.c | 54 ++++++++
232
kernel/kexec_file.c | 32 +++++
266
kernel/kexec_file.c | 33 ++++-
233
security/integrity/ima/Kconfig | 10 ++
267
security/integrity/ima/Kconfig | 10 ++
234
security/integrity/ima/ima.h | 7 +
268
security/integrity/ima/ima.h | 6 +
235
security/integrity/ima/ima_kexec.c | 210 ++++++++++++++++++++++++-----
269
security/integrity/ima/ima_kexec.c | 193 ++++++++++++++++++++++++-----
236
security/integrity/ima/ima_queue.c | 9 +-
270
security/integrity/ima/ima_queue.c | 5 +
237
8 files changed, 297 insertions(+), 37 deletions(-)
271
8 files changed, 279 insertions(+), 34 deletions(-)
238
272
239
--
273
--
240
2.25.1
274
2.25.1
241
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 only complete measurement records.
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. Copy only complete measurement records if there
20
is enough memory. If there is not enough memory, it will not copy
21
any IMA measurement records, and this situation will result in a
22
failure of remote attestation.
23
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 | 105 ++++++++++++++++++++++-------
20
1 file changed, 35 insertions(+), 11 deletions(-)
30
security/integrity/ima/ima_queue.c | 4 +-
31
3 files changed, 83 insertions(+), 27 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
+/*
96
+ * Copy the measurement list to the allocated memory
97
+ * compare the size of IMA measurement list with the size of the allocated memory
98
+ * if the size of the allocated memory is not less than the size of IMA measurement list
99
+ * copy the measurement list to the allocated memory.
100
+ * else return error
101
+ */
102
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,
103
                 unsigned long segment_size)
58
                 unsigned long segment_size)
104
{
59
{
60
-    struct seq_file ima_kexec_file;
105
    struct ima_queue_entry *qe;
61
    struct ima_queue_entry *qe;
106
-    struct seq_file file;
107
    struct ima_kexec_hdr khdr;
62
    struct ima_kexec_hdr khdr;
108
    int ret = 0;
63
    int ret = 0;
109
+    size_t entry_size = 0;
64
110
65
    /* segment size can't change between kexec load and execute */
111
-    /* segment size can't change between kexec load and execute */
66
-    ima_kexec_file.buf = vmalloc(segment_size);
112
-    file.buf = vmalloc(segment_size);
67
    if (!ima_kexec_file.buf) {
113
-    if (!file.buf) {
114
-        ret = -ENOMEM;
68
-        ret = -ENOMEM;
115
-        goto out;
69
-        goto out;
116
+    if (!ima_kexec_file.buf) {
117
+        pr_err("Kexec file buf not allocated\n");
70
+        pr_err("Kexec file buf not allocated\n");
118
+        return -EINVAL;
71
+        return -EINVAL;
119
    }
72
    }
120
73
121
-    file.file = NULL;
74
-    ima_kexec_file.file = NULL;
122
-    file.size = segment_size;
75
-    ima_kexec_file.size = segment_size;
123
-    file.read_pos = 0;
76
-    ima_kexec_file.read_pos = 0;
124
-    file.count = sizeof(khdr);    /* reserved space */
77
-    ima_kexec_file.count = sizeof(khdr);    /* reserved space */
125
-
78
-
126
    memset(&khdr, 0, sizeof(khdr));
79
    memset(&khdr, 0, sizeof(khdr));
127
    khdr.version = 1;
80
    khdr.version = 1;
128
    /* 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 */
129
    list_for_each_entry_rcu(qe, &ima_measurements, later, true) {
82
@@ -XXX,XX +XXX,XX @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
130
-        if (file.count < file.size) {
83
    *buffer_size = ima_kexec_file.count;
131
+        entry_size += ima_get_binary_runtime_entry_size(qe->entry);
84
    *buffer = ima_kexec_file.buf;
132
+        if (entry_size <= segment_size) {
133
            khdr.count++;
134
-            ima_measurements_show(&file, qe);
135
+            ima_measurements_show(&ima_kexec_file, qe);
136
        } else {
137
            ret = -EINVAL;
138
+            pr_err("IMA log file is too big for Kexec buf\n");
139
            break;
140
        }
141
    }
142
143
    if (ret < 0)
144
        goto out;
145
-
146
    /*
147
     * fill in reserved space with some buffer details
148
     * (eg. version, buffer size, number of measurements)
149
     */
150
-    khdr.buffer_size = file.count;
151
+    khdr.buffer_size = ima_kexec_file.count;
152
    if (ima_canonical_fmt) {
153
        khdr.version = cpu_to_le16(khdr.version);
154
        khdr.count = cpu_to_le64(khdr.count);
155
        khdr.buffer_size = cpu_to_le64(khdr.buffer_size);
156
    }
157
-    memcpy(file.buf, &khdr, sizeof(khdr));
158
+    memcpy(ima_kexec_file.buf, &khdr, sizeof(khdr));
159
160
    print_hex_dump_debug("ima dump: ", DUMP_PREFIX_NONE, 16, 1,
161
-             file.buf, file.count < 100 ? file.count : 100,
162
+             ima_kexec_file.buf, ima_kexec_file.count < 100 ?
163
+             ima_kexec_file.count : 100,
164
             true);
165
166
-    *buffer_size = file.count;
167
-    *buffer = file.buf;
168
+    *buffer_size = ima_kexec_file.count;
169
+    *buffer = ima_kexec_file.buf;
170
+
171
out:
85
out:
172
-    if (ret == -EINVAL)
86
-    if (ret == -EINVAL)
173
-        vfree(file.buf);
87
-        vfree(ima_kexec_file.buf);
174
    return ret;
88
    return ret;
175
}
89
}
176
177
@@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image)
178
179
    /* use more understandable variable names than defined in kbuf */
180
    void *kexec_buffer = NULL;
181
-    size_t kexec_buffer_size;
182
+    size_t kexec_buffer_size = 0;
183
    size_t kexec_segment_size;
184
    int ret;
185
90
186
@@ -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)
187
        return;
92
        return;
188
    }
93
    }
189
94
190
-    ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
191
-                 kexec_segment_size);
192
-    if (!kexec_buffer) {
193
+    ret = ima_alloc_kexec_file_buf(kexec_segment_size);
95
+    ret = ima_alloc_kexec_file_buf(kexec_segment_size);
194
+    if (ret < 0) {
96
+    if (ret < 0) {
195
        pr_err("Not enough memory for the kexec measurement buffer.\n");
97
+        pr_err("Not enough memory for the kexec measurement buffer.\n");
196
        return;
197
    }
198
199
+    ret = ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
200
+                    kexec_segment_size);
201
+    if (ret < 0) {
202
+        pr_err("Failed to dump IMA measurements. Error:%d.\n", ret);
203
+        return;
98
+        return;
204
+    }
99
+    }
205
+
100
+
206
    kbuf.buffer = kexec_buffer;
101
    ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
207
    kbuf.bufsz = kexec_buffer_size;
102
                 kexec_segment_size);
208
    kbuf.memsz = kexec_segment_size;
103
    if (!kexec_buffer) {
209
@@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image)
210
    image->ima_buffer_size = kexec_segment_size;
211
    image->ima_buffer = kexec_buffer;
212
213
+    /*
214
+     * kexec owns kexec_buffer after kexec_add_buffer() is called
215
+     * and it will vfree() that buffer.
216
+     */
217
+    ima_reset_kexec_file(&ima_kexec_file);
218
+
219
    kexec_dprintk("kexec measurement buffer for the loaded kernel at 0x%lx.\n",
220
         kbuf.mem);
221
}
222
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
223
index XXXXXXX..XXXXXXX 100644
224
--- a/security/integrity/ima/ima_queue.c
225
+++ b/security/integrity/ima/ima_queue.c
226
@@ -XXX,XX +XXX,XX @@ static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value,
227
* binary_runtime_measurement list entry, which contains a
228
* couple of variable length fields (e.g template name and data).
229
*/
230
-static int get_binary_runtime_size(struct ima_template_entry *entry)
231
+int ima_get_binary_runtime_entry_size(struct ima_template_entry *entry)
232
{
233
    int size = 0;
234
235
@@ -XXX,XX +XXX,XX @@ static int ima_add_digest_entry(struct ima_template_entry *entry,
236
    if (binary_runtime_size != ULONG_MAX) {
237
        int size;
238
239
-        size = get_binary_runtime_size(entry);
240
+        size = ima_get_binary_runtime_entry_size(entry);
241
        binary_runtime_size = (binary_runtime_size < ULONG_MAX - size) ?
242
         binary_runtime_size + size : ULONG_MAX;
243
    }
244
--
104
--
245
2.25.1
105
2.25.1
diff view generated by jsdifflib
1
The content of memory segments carried over to the new kernel during the
1
Currently, the kernel behavior during kexec load is to fetch the IMA
2
kexec systemcall can be changed at kexec 'execute' stage, but the size of
2
measurements logs and store logs in kernel memory. When a kexec reboot is
3
the memory segments cannot be changed at kexec 'execute' stage.
3
triggered, these stored logs in the kernel memory are carried over to the
4
second kernel. However, the time gap between kexec load and kexec reboot
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.
4
9
5
To copy IMA measurement logs during the kexec operation, IMA needs to
10
To solve this problem, the new design defers reading the IMA measurements
6
allocate memory at the kexec 'load' stage and map the segments to the
11
logs into the kexec buffer to the kexec reboot phase, while still allocating
7
kimage structure. The mapped address will then be used to copy IMA
12
the necessary buffer at kexec load time because it is not appropriate to
8
measurements during the kexec 'execute' stage.
13
allocate memory at the kexec reboot moment.
9
14
10
Currently, the mechanism to map and unmap segments to the kimage
15
The content of memory segments carried over to the new kernel during the
11
structure is not available to subsystems outside of kexec.
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.
12
18
13
Implement kimage_map_segment() to enable IMA to map measurement log list to
19
To copy IMA measurement logs during the kexec operation, IMA allocates
14
the kimage structure during kexec 'load' stage. This function takes a kimage
20
memory at the kexec 'load' stage and map the segments to the kimage
15
pointer, a memory address, and a size, then gathers the
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
16
source pages within the specified address range, creates an array of page
30
source pages within the specified address range, creates an array of page
17
pointers, and maps these to a contiguous virtual address range. The
31
pointers, and maps these to a contiguous virtual address range. The
18
function returns the start virtual address of this range if successful, or NULL on
32
function returns the start virtual address of this range if successful,
19
failure.
33
or NULL on failure.
20
34
21
Implement kimage_unmap_segment() for unmapping segments
35
Implement kimage_unmap_segment() for unmapping segments using vunmap().
22
using vunmap().
23
36
24
From: Tushar Sugandhi <tusharsu@linux.microsoft.com>
37
From: Tushar Sugandhi <tusharsu@linux.microsoft.com>
25
Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
38
Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
26
Cc: Eric Biederman <ebiederm@xmission.com>
39
Cc: Eric Biederman <ebiederm@xmission.com>
27
Cc: Baoquan He <bhe@redhat.com>
40
Cc: Baoquan He <bhe@redhat.com>
28
Cc: Vivek Goyal <vgoyal@redhat.com>
41
Cc: Vivek Goyal <vgoyal@redhat.com>
29
Cc: Dave Young <dyoung@redhat.com>
42
Cc: Dave Young <dyoung@redhat.com>
30
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>
31
---
45
---
32
include/linux/kexec.h | 6 +++++
46
include/linux/kexec.h | 6 +++++
33
kernel/kexec_core.c | 54 +++++++++++++++++++++++++++++++++++++++++++
47
kernel/kexec_core.c | 54 +++++++++++++++++++++++++++++++++++++++++++
34
2 files changed, 60 insertions(+)
48
2 files changed, 60 insertions(+)
35
49
...
...
66
}
80
}
67
81
68
+void *kimage_map_segment(struct kimage *image,
82
+void *kimage_map_segment(struct kimage *image,
69
+             unsigned long addr, unsigned long size)
83
+             unsigned long addr, unsigned long size)
70
+{
84
+{
85
+    unsigned long src_page_addr, dest_page_addr = 0;
71
+    unsigned long eaddr = addr + size;
86
+    unsigned long eaddr = addr + size;
72
+    unsigned long src_page_addr, dest_page_addr;
87
+    kimage_entry_t *ptr, entry;
88
+    struct page **src_pages;
73
+    unsigned int npages;
89
+    unsigned int npages;
74
+    struct page **src_pages;
90
+    void *vaddr = NULL;
75
+    int i;
91
+    int i;
76
+    kimage_entry_t *ptr, entry;
77
+    void *vaddr = NULL;
78
+
92
+
79
+    /*
93
+    /*
80
+     * 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.
81
+     */
95
+     */
82
+    npages = PFN_UP(eaddr) - PFN_DOWN(addr);
96
+    npages = PFN_UP(eaddr) - PFN_DOWN(addr);
...
...
diff view generated by jsdifflib
...
...
11
kexec systemcall can be changed at kexec 'execute' stage, but the size
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
12
and the location of the memory segments cannot be changed at kexec
13
'execute' stage.
13
'execute' stage.
14
14
15
However, during the kexec execute stage, if kexec_calculate_store_digests()
15
However, during the kexec execute stage, if kexec_calculate_store_digests()
16
API is call to update the digest, it does not reuse the same memory segment
16
API is called to update the digest, it does not reuse the same memory
17
allocated during the kexec 'load' stage and the new memory segment required
17
segment allocated during the kexec 'load' stage and the new memory segment
18
cannot be transferred/mapped to the new kernel.
18
required cannot be transferred/mapped to the new kernel.
19
19
20
As a result, digest verification will fail in verify_sha256_digest()
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
21
after a kexec soft reboot into the new kernel. Therefore, the digest
22
calculation/verification of the IMA segment needs to be skipped.
22
calculation/verification of the IMA segment needs to be skipped.
23
23
...
...
37
Cc: Vivek Goyal <vgoyal@redhat.com>
37
Cc: Vivek Goyal <vgoyal@redhat.com>
38
Cc: Dave Young <dyoung@redhat.com>
38
Cc: Dave Young <dyoung@redhat.com>
39
Signed-off-by: steven chen <chenste@linux.microsoft.com>
39
Signed-off-by: steven chen <chenste@linux.microsoft.com>
40
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>
41
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
42
Acked-by: Baoquan He <bhe@redhat.com>
42
---
43
---
43
include/linux/kexec.h | 3 +++
44
include/linux/kexec.h | 3 +++
44
kernel/kexec_file.c | 22 ++++++++++++++++++++++
45
kernel/kexec_file.c | 22 ++++++++++++++++++++++
45
security/integrity/ima/ima_kexec.c | 3 +++
46
security/integrity/ima/ima_kexec.c | 3 +++
46
3 files changed, 28 insertions(+)
47
3 files changed, 28 insertions(+)
...
...
116
    image->ima_buffer_size = kexec_segment_size;
117
    image->ima_buffer_size = kexec_segment_size;
117
    image->ima_buffer = kexec_buffer;
118
    image->ima_buffer = kexec_buffer;
118
+    image->ima_segment_index = image->nr_segments - 1;
119
+    image->ima_segment_index = image->nr_segments - 1;
119
+    image->is_ima_segment_index_set = true;
120
+    image->is_ima_segment_index_set = true;
120
121
121
    /*
122
    kexec_dprintk("kexec measurement buffer for the loaded kernel at 0x%lx.\n",
122
     * kexec owns kexec_buffer after kexec_add_buffer() is called
123
         kbuf.mem);
123
--
124
--
124
2.25.1
125
2.25.1
diff view generated by jsdifflib
1
The IMA log is currently copied to the new kernel during kexec 'load'
1
The IMA log is currently copied to the new kernel during kexec 'load'
2
using ima_dump_measurement_list(). However, the log copied at kexec
2
using ima_dump_measurement_list(). However, the log copied at kexec
3
'load' may result in loss of IMA measurements that only occurred after
3
'load' may result in loss of IMA measurements that only occurred after
4
kexec "load'. Therefore, the log needs to be copied during kexec
4
kexec "load'. Therefore, the log needs to be copied during kexec
5
'execute'. Setup the needed infrastructure to move the IMA log copy from
5
'execute'. Setup the needed infrastructure to move the IMA log copy from
6
kexec 'load' to 'execute'.
6
kexec 'load' to 'execute'.
7
7
...
...
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
kexec '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>
18
Cc: Eric Biederman <ebiederm@xmission.com>
22
Cc: Eric Biederman <ebiederm@xmission.com>
19
Cc: Baoquan He <bhe@redhat.com>
23
Cc: Baoquan He <bhe@redhat.com>
20
Cc: Vivek Goyal <vgoyal@redhat.com>
24
Cc: Vivek Goyal <vgoyal@redhat.com>
...
...
51
+#include <linux/reboot.h>
55
+#include <linux/reboot.h>
52
+#include <asm/page.h>
56
+#include <asm/page.h>
53
#include "ima.h"
57
#include "ima.h"
54
58
55
#ifdef CONFIG_IMA_KEXEC
59
#ifdef CONFIG_IMA_KEXEC
60
+static bool ima_kexec_update_registered;
56
static struct seq_file ima_kexec_file;
61
static struct seq_file ima_kexec_file;
57
+static void *ima_kexec_buffer;
62
+static void *ima_kexec_buffer;
58
+static bool ima_kexec_update_registered;
63
59
64
static void ima_free_kexec_file_buf(struct seq_file *sf)
60
static void ima_reset_kexec_file(struct seq_file *sf)
61
{
65
{
62
@@ -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)
63
    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",
64
         kbuf.mem);
68
         kbuf.mem);
65
}
69
}
...
...
71
+                 unsigned long action, void *data)
75
+                 unsigned long action, void *data)
72
+{
76
+{
73
+    return NOTIFY_OK;
77
+    return NOTIFY_OK;
74
+}
78
+}
75
+
79
+
76
+struct notifier_block update_buffer_nb = {
80
+static struct notifier_block update_buffer_nb = {
77
+    .notifier_call = ima_update_kexec_buffer,
81
+    .notifier_call = ima_update_kexec_buffer,
78
+    .priority = 1,
82
+    .priority = INT_MIN
79
+};
83
+};
80
+
84
+
81
+/*
85
+/*
82
+ * 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
83
+ * 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. Due to
2
result in loss of IMA measurements during kexec soft reboot. Due to
3
missed measurements that only occurred after kexec 'load', this function
3
missed measurements that only occurred after kexec 'load', this function
4
needs to be called during kexec 'execute'.
4
needs to be called during kexec 'execute'.
5
5
6
This patch includes the following changes:
6
Make the kexec_segment_size variable a local static variable within the
7
- 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'.
8
kernel image has been loaded for kexec.
8
9
- 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
10
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()
11
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
12
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.
13
reboot.
13
14
- Make kexec_segment_size variable local static to the file so that it
14
Invoke ima_kexec_post_load() within the kexec_post_load() API only for kexec
15
becomes accessible both during kexec 'load' and 'execute'.
15
soft reboot scenarios, excluding KEXEC_FILE_ON_CRASH.
16
- Move ima_dump_measurement_list() call from ima_add_kexec_buffer()
16
17
to ima_update_kexec_buffer().
17
Register a reboot notifier for the ima_update_kexec_buffer() API within
18
- Copy the measurement list as much as possible.
18
ima_kexec_post_load() to ensure it is called upon receiving a reboot
19
- Remove ima_reset_kexec_file() call from ima_add_kexec_buffer(), now
19
notification.
20
that the buffer is being copied at kexec 'execute', and resetting the
20
21
file at kexec 'load' would corrupt the buffer.
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.
22
26
23
Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
27
Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
24
Cc: Eric Biederman <ebiederm@xmission.com>
28
Cc: Eric Biederman <ebiederm@xmission.com>
25
Cc: Baoquan He <bhe@redhat.com>
29
Cc: Baoquan He <bhe@redhat.com>
26
Cc: Vivek Goyal <vgoyal@redhat.com>
30
Cc: Vivek Goyal <vgoyal@redhat.com>
27
Cc: Dave Young <dyoung@redhat.com>
31
Cc: Dave Young <dyoung@redhat.com>
28
Signed-off-by: steven chen <chenste@linux.microsoft.com>
32
Signed-off-by: steven chen <chenste@linux.microsoft.com>
29
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
33
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
30
---
34
---
31
kernel/kexec_file.c | 10 +++++++
35
kernel/kexec_file.c | 11 +++++++-
32
security/integrity/ima/ima_kexec.c | 48 ++++++++++++++++++------------
36
security/integrity/ima/ima_kexec.c | 43 ++++++++++++++++++++----------
33
2 files changed, 39 insertions(+), 19 deletions(-)
37
2 files changed, 39 insertions(+), 15 deletions(-)
34
38
35
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
36
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
37
--- a/kernel/kexec_file.c
41
--- a/kernel/kexec_file.c
38
+++ b/kernel/kexec_file.c
42
+++ b/kernel/kexec_file.c
39
@@ -XXX,XX +XXX,XX @@ kimage_validate_signature(struct kimage *image)
43
@@ -XXX,XX +XXX,XX @@ kimage_validate_signature(struct kimage *image)
40
}
44
}
41
#endif
45
#endif
42
46
43
+static void kimage_file_post_load(struct kimage *image)
47
+static int kexec_post_load(struct kimage *image, unsigned long flags)
44
+{
48
+{
45
+#ifdef CONFIG_IMA_KEXEC
49
+#ifdef CONFIG_IMA_KEXEC
46
+    ima_kexec_post_load(image);
50
+    if (!(flags & KEXEC_FILE_ON_CRASH))
51
+        ima_kexec_post_load(image);
47
+#endif
52
+#endif
53
+    return machine_kexec_post_load(image);
48
+}
54
+}
49
+
55
+
50
/*
56
/*
51
* 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
52
* data from user space, do error checking, prepare segment list
58
* data from user space, do error checking, prepare segment list
53
@@ -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,
54
60
55
    kimage_terminate(image);
61
    kimage_terminate(image);
56
62
57
+    if (!(flags & KEXEC_FILE_ON_CRASH))
63
-    ret = machine_kexec_post_load(image);
58
+        kimage_file_post_load(image);
64
+    ret = kexec_post_load(image, flags);
59
+
60
    ret = machine_kexec_post_load(image);
61
    if (ret)
65
    if (ret)
62
        goto out;
66
        goto out;
67
63
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
64
index XXXXXXX..XXXXXXX 100644
69
index XXXXXXX..XXXXXXX 100644
65
--- a/security/integrity/ima/ima_kexec.c
70
--- a/security/integrity/ima/ima_kexec.c
66
+++ b/security/integrity/ima/ima_kexec.c
71
+++ b/security/integrity/ima/ima_kexec.c
67
@@ -XXX,XX +XXX,XX @@
72
@@ -XXX,XX +XXX,XX @@
68
#ifdef CONFIG_IMA_KEXEC
73
#ifdef CONFIG_IMA_KEXEC
74
static bool ima_kexec_update_registered;
69
static struct seq_file ima_kexec_file;
75
static struct seq_file ima_kexec_file;
76
+static size_t kexec_segment_size;
70
static void *ima_kexec_buffer;
77
static void *ima_kexec_buffer;
71
+static size_t kexec_segment_size;
78
72
static bool ima_kexec_update_registered;
79
static void ima_free_kexec_file_buf(struct seq_file *sf)
73
74
static void ima_reset_kexec_file(struct seq_file *sf)
75
@@ -XXX,XX +XXX,XX @@ static int ima_alloc_kexec_file_buf(size_t segment_size)
76
* compare the size of IMA measurement list with the size of the allocated memory
77
* if the size of the allocated memory is not less than the size of IMA measurement list
78
* copy the measurement list to the allocated memory.
79
- * else return error
80
+ * else
81
+ * copy the measurement list as much as possible.
82
*/
83
static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
84
                 unsigned long segment_size)
85
@@ -XXX,XX +XXX,XX @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
80
@@ -XXX,XX +XXX,XX @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
86
        }
81
        }
87
    }
82
    }
88
83
89
-    if (ret < 0)
84
-    if (ret < 0)
90
-        goto out;
85
-        goto out;
86
-
91
    /*
87
    /*
92
     * fill in reserved space with some buffer details
88
     * fill in reserved space with some buffer details
93
     * (eg. version, buffer size, number of measurements)
89
     * (eg. version, buffer size, number of measurements)
94
@@ -XXX,XX +XXX,XX @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
90
@@ -XXX,XX +XXX,XX @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
91
95
    *buffer_size = ima_kexec_file.count;
92
    *buffer_size = ima_kexec_file.count;
96
    *buffer = ima_kexec_file.buf;
93
    *buffer = ima_kexec_file.buf;
97
98
-out:
94
-out:
95
+
99
    return ret;
96
    return ret;
100
}
97
}
101
98
102
@@ -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
103
    /* 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;
104
    void *kexec_buffer = NULL;
104
    void *kexec_buffer = NULL;
105
    size_t kexec_buffer_size = 0;
105
-    size_t kexec_buffer_size;
106
-    size_t kexec_segment_size;
106
-    size_t kexec_segment_size;
107
    int ret;
107
    int ret;
108
108
109
    /*
109
    /*
110
@@ -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)
111
        return;
111
        return;
112
    }
112
    }
113
113
114
-    ret = ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
114
-    ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
115
-                    kexec_segment_size);
115
-                 kexec_segment_size);
116
-    if (ret < 0) {
116
-    if (!kexec_buffer) {
117
-        pr_err("Failed to dump IMA measurements. Error:%d.\n", ret);
117
-        pr_err("Not enough memory for the kexec measurement buffer.\n");
118
-        return;
118
-        return;
119
-    }
119
-    }
120
-
120
-
121
    kbuf.buffer = kexec_buffer;
121
    kbuf.buffer = kexec_buffer;
122
    kbuf.bufsz = kexec_buffer_size;
122
    kbuf.bufsz = kexec_buffer_size;
123
    kbuf.memsz = kexec_segment_size;
123
    kbuf.memsz = kexec_segment_size;
124
@@ -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)
125
    image->ima_segment_index = image->nr_segments - 1;
126
    image->is_ima_segment_index_set = true;
127
128
-    /*
129
-     * kexec owns kexec_buffer after kexec_add_buffer() is called
130
-     * and it will vfree() that buffer.
131
-     */
132
-    ima_reset_kexec_file(&ima_kexec_file);
133
-
134
    kexec_dprintk("kexec measurement buffer for the loaded kernel at 0x%lx.\n",
135
         kbuf.mem);
136
}
137
@@ -XXX,XX +XXX,XX @@ void ima_add_kexec_buffer(struct kimage *image)
138
static int ima_update_kexec_buffer(struct notifier_block *self,
125
static int ima_update_kexec_buffer(struct notifier_block *self,
139
                 unsigned long action, void *data)
126
                 unsigned long action, void *data)
140
{
127
{
141
-    return NOTIFY_OK;
128
-    return NOTIFY_OK;
142
+    void *buf = NULL;
143
+    size_t buf_size = 0;
129
+    size_t buf_size = 0;
144
+    int ret = NOTIFY_OK;
130
+    int ret = NOTIFY_OK;
131
+    void *buf = NULL;
145
+
132
+
146
+    if (!kexec_in_progress) {
133
+    if (!kexec_in_progress) {
147
+        pr_info("No kexec in progress.\n");
134
+        pr_info("No kexec in progress.\n");
148
+        return ret;
135
+        return ret;
149
+    }
136
+    }
...
...
165
+    ima_kexec_buffer = NULL;
152
+    ima_kexec_buffer = NULL;
166
+
153
+
167
+    return ret;
154
+    return ret;
168
}
155
}
169
156
170
struct notifier_block update_buffer_nb = {
157
static struct notifier_block update_buffer_nb = {
171
--
158
--
172
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
...
...
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
Reviewed-by: Mimi Zohar <zohar@linux.ibm.com>
18
---
18
---
19
security/integrity/ima/Kconfig | 10 ++++++++++
19
security/integrity/ima/Kconfig | 10 ++++++++++
20
security/integrity/ima/ima_kexec.c | 16 ++++++++++------
20
security/integrity/ima/ima_kexec.c | 16 +++++++++++-----
21
2 files changed, 20 insertions(+), 6 deletions(-)
21
2 files changed, 21 insertions(+), 5 deletions(-)
22
22
23
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
24
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
25
--- a/security/integrity/ima/Kconfig
25
--- a/security/integrity/ima/Kconfig
26
+++ b/security/integrity/ima/Kconfig
26
+++ b/security/integrity/ima/Kconfig
...
...
45
+++ b/security/integrity/ima/ima_kexec.c
45
+++ b/security/integrity/ima/ima_kexec.c
46
@@ -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)
47
                 .buf_min = 0, .buf_max = ULONG_MAX,
47
                 .buf_min = 0, .buf_max = ULONG_MAX,
48
                 .top_down = true };
48
                 .top_down = true };
49
    unsigned long binary_runtime_size;
49
    unsigned long binary_runtime_size;
50
-
51
+    unsigned long extra_memory;
50
+    unsigned long extra_memory;
51
52
    /* use more understandable variable names than defined in kbuf */
52
    /* use more understandable variable names than defined in kbuf */
53
    void *kexec_buffer = NULL;
54
    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)
55
    int ret;
55
    int ret;
56
56
57
    /*
57
    /*
58
-     * Reserve an extra half page of memory for additional measurements
58
-     * Reserve an extra half page of memory for additional measurements
59
-     * added during the kexec load.
59
-     * added during the kexec load.
...
...
62
-    binary_runtime_size = ima_get_binary_runtime_size();
62
-    binary_runtime_size = ima_get_binary_runtime_size();
63
+    if (CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB <= 0)
63
+    if (CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB <= 0)
64
+        extra_memory = PAGE_SIZE / 2;
64
+        extra_memory = PAGE_SIZE / 2;
65
+    else
65
+    else
66
+        extra_memory = CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB * 1024;
66
+        extra_memory = CONFIG_IMA_KEXEC_EXTRA_MEMORY_KB * 1024;
67
+
67
+    binary_runtime_size = ima_get_binary_runtime_size() + extra_memory;
68
+    binary_runtime_size = ima_get_binary_runtime_size() + extra_memory;
68
+
69
+
69
    if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE)
70
    if (binary_runtime_size >= ULONG_MAX - PAGE_SIZE)
70
        kexec_segment_size = ULONG_MAX;
71
        kexec_segment_size = ULONG_MAX;
71
    else
72
    else
...
...
diff view generated by jsdifflib
...
...
35
Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
35
Signed-off-by: Tushar Sugandhi <tusharsu@linux.microsoft.com>
36
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>
37
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
38
---
38
---
39
security/integrity/ima/ima.h | 6 ++++++
39
security/integrity/ima/ima.h | 6 ++++++
40
security/integrity/ima/ima_kexec.c | 20 ++++++++++++++++++++
40
security/integrity/ima/ima_kexec.c | 21 +++++++++++++++++++++
41
security/integrity/ima/ima_queue.c | 5 +++++
41
security/integrity/ima/ima_queue.c | 5 +++++
42
3 files changed, 31 insertions(+)
42
3 files changed, 32 insertions(+)
43
43
44
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
44
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
45
index XXXXXXX..XXXXXXX 100644
45
index XXXXXXX..XXXXXXX 100644
46
--- a/security/integrity/ima/ima.h
46
--- a/security/integrity/ima/ima.h
47
+++ b/security/integrity/ima/ima.h
47
+++ b/security/integrity/ima/ima.h
...
...
66
#include "ima.h"
66
#include "ima.h"
67
67
68
#ifdef CONFIG_IMA_KEXEC
68
#ifdef CONFIG_IMA_KEXEC
69
+#define IMA_KEXEC_EVENT_LEN 256
69
+#define IMA_KEXEC_EVENT_LEN 256
70
+
70
+
71
static bool ima_kexec_update_registered;
71
static struct seq_file ima_kexec_file;
72
static struct seq_file ima_kexec_file;
72
static void *ima_kexec_buffer;
73
static size_t kexec_segment_size;
73
static size_t kexec_segment_size;
74
@@ -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)
75
    ima_reset_kexec_file(sf);
75
    sf->count = 0;
76
}
76
}
77
77
78
+void ima_measure_kexec_event(const char *event_name)
78
+void ima_measure_kexec_event(const char *event_name)
79
+{
79
+{
80
+    char ima_kexec_event[IMA_KEXEC_EVENT_LEN];
80
+    char ima_kexec_event[IMA_KEXEC_EVENT_LEN];
81
+    size_t buf_size = 0;
81
+    size_t buf_size = 0;
82
+    long len;
82
+    long len;
83
+    int n;
83
+
84
+
84
+    buf_size = ima_get_binary_runtime_size();
85
+    buf_size = ima_get_binary_runtime_size();
85
+    len = atomic_long_read(&ima_htable.len);
86
+    len = atomic_long_read(&ima_htable.len);
86
+
87
+
87
+    int n = scnprintf(ima_kexec_event, IMA_KEXEC_EVENT_LEN,
88
+    n = scnprintf(ima_kexec_event, IMA_KEXEC_EVENT_LEN,
88
+                    "kexec_segment_size=%lu;ima_binary_runtime_size=%lu;"
89
+         "kexec_segment_size=%lu;ima_binary_runtime_size=%lu;"
89
+                    "ima_runtime_measurements_count=%ld;",
90
+         "ima_runtime_measurements_count=%ld;",
90
+                    kexec_segment_size, buf_size, len);
91
+         kexec_segment_size, buf_size, len);
91
+
92
+
92
+    ima_measure_critical_data("ima_kexec", event_name, ima_kexec_event, n, false, NULL, 0);
93
+    ima_measure_critical_data("ima_kexec", event_name, ima_kexec_event, n, false, NULL, 0);
93
+}
94
+}
94
+
95
+
95
static int ima_alloc_kexec_file_buf(size_t segment_size)
96
static int ima_alloc_kexec_file_buf(size_t segment_size)
...
...
diff view generated by jsdifflib