Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/security/ipe/hooks.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
4
*/
5
6
#include <linux/fs.h>
7
#include <linux/fs_struct.h>
8
#include <linux/types.h>
9
#include <linux/binfmts.h>
10
#include <linux/mman.h>
11
#include <linux/blk_types.h>
12
13
#include "ipe.h"
14
#include "hooks.h"
15
#include "eval.h"
16
#include "digest.h"
17
18
/**
19
* ipe_bprm_check_security() - ipe security hook function for bprm check.
20
* @bprm: Supplies a pointer to a linux_binprm structure to source the file
21
* being evaluated.
22
*
23
* This LSM hook is called when a binary is loaded through the exec
24
* family of system calls.
25
*
26
* Return:
27
* * %0 - Success
28
* * %-EACCES - Did not pass IPE policy
29
*/
30
int ipe_bprm_check_security(struct linux_binprm *bprm)
31
{
32
struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;
33
34
ipe_build_eval_ctx(&ctx, bprm->file, IPE_OP_EXEC, IPE_HOOK_BPRM_CHECK);
35
return ipe_evaluate_event(&ctx);
36
}
37
38
/**
39
* ipe_mmap_file() - ipe security hook function for mmap check.
40
* @f: File being mmap'd. Can be NULL in the case of anonymous memory.
41
* @reqprot: The requested protection on the mmap, passed from usermode.
42
* @prot: The effective protection on the mmap, resolved from reqprot and
43
* system configuration.
44
* @flags: Unused.
45
*
46
* This hook is called when a file is loaded through the mmap
47
* family of system calls.
48
*
49
* Return:
50
* * %0 - Success
51
* * %-EACCES - Did not pass IPE policy
52
*/
53
int ipe_mmap_file(struct file *f, unsigned long reqprot __always_unused,
54
unsigned long prot, unsigned long flags)
55
{
56
struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;
57
58
if (prot & PROT_EXEC) {
59
ipe_build_eval_ctx(&ctx, f, IPE_OP_EXEC, IPE_HOOK_MMAP);
60
return ipe_evaluate_event(&ctx);
61
}
62
63
return 0;
64
}
65
66
/**
67
* ipe_file_mprotect() - ipe security hook function for mprotect check.
68
* @vma: Existing virtual memory area created by mmap or similar.
69
* @reqprot: The requested protection on the mmap, passed from usermode.
70
* @prot: The effective protection on the mmap, resolved from reqprot and
71
* system configuration.
72
*
73
* This LSM hook is called when a mmap'd region of memory is changing
74
* its protections via mprotect.
75
*
76
* Return:
77
* * %0 - Success
78
* * %-EACCES - Did not pass IPE policy
79
*/
80
int ipe_file_mprotect(struct vm_area_struct *vma,
81
unsigned long reqprot __always_unused,
82
unsigned long prot)
83
{
84
struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;
85
86
/* Already Executable */
87
if (vma->vm_flags & VM_EXEC)
88
return 0;
89
90
if (prot & PROT_EXEC) {
91
ipe_build_eval_ctx(&ctx, vma->vm_file, IPE_OP_EXEC, IPE_HOOK_MPROTECT);
92
return ipe_evaluate_event(&ctx);
93
}
94
95
return 0;
96
}
97
98
/**
99
* ipe_kernel_read_file() - ipe security hook function for kernel read.
100
* @file: Supplies a pointer to the file structure being read in from disk.
101
* @id: Supplies the enumeration identifying the purpose of the read.
102
* @contents: Unused.
103
*
104
* This LSM hook is called when a file is read from disk in the kernel.
105
*
106
* Return:
107
* * %0 - Success
108
* * %-EACCES - Did not pass IPE policy
109
*/
110
int ipe_kernel_read_file(struct file *file, enum kernel_read_file_id id,
111
bool contents)
112
{
113
struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;
114
enum ipe_op_type op;
115
116
switch (id) {
117
case READING_FIRMWARE:
118
op = IPE_OP_FIRMWARE;
119
break;
120
case READING_MODULE:
121
op = IPE_OP_KERNEL_MODULE;
122
break;
123
case READING_KEXEC_INITRAMFS:
124
op = IPE_OP_KEXEC_INITRAMFS;
125
break;
126
case READING_KEXEC_IMAGE:
127
op = IPE_OP_KEXEC_IMAGE;
128
break;
129
case READING_POLICY:
130
op = IPE_OP_POLICY;
131
break;
132
case READING_X509_CERTIFICATE:
133
op = IPE_OP_X509;
134
break;
135
default:
136
op = IPE_OP_INVALID;
137
WARN(1, "no rule setup for kernel_read_file enum %d", id);
138
}
139
140
ipe_build_eval_ctx(&ctx, file, op, IPE_HOOK_KERNEL_READ);
141
return ipe_evaluate_event(&ctx);
142
}
143
144
/**
145
* ipe_kernel_load_data() - ipe security hook function for kernel load data.
146
* @id: Supplies the enumeration identifying the purpose of the load.
147
* @contents: Unused.
148
*
149
* This LSM hook is called when a data buffer provided by userspace is loading
150
* into the kernel.
151
*
152
* Return:
153
* * %0 - Success
154
* * %-EACCES - Did not pass IPE policy
155
*/
156
int ipe_kernel_load_data(enum kernel_load_data_id id, bool contents)
157
{
158
struct ipe_eval_ctx ctx = IPE_EVAL_CTX_INIT;
159
enum ipe_op_type op;
160
161
switch (id) {
162
case LOADING_FIRMWARE:
163
op = IPE_OP_FIRMWARE;
164
break;
165
case LOADING_MODULE:
166
op = IPE_OP_KERNEL_MODULE;
167
break;
168
case LOADING_KEXEC_INITRAMFS:
169
op = IPE_OP_KEXEC_INITRAMFS;
170
break;
171
case LOADING_KEXEC_IMAGE:
172
op = IPE_OP_KEXEC_IMAGE;
173
break;
174
case LOADING_POLICY:
175
op = IPE_OP_POLICY;
176
break;
177
case LOADING_X509_CERTIFICATE:
178
op = IPE_OP_X509;
179
break;
180
default:
181
op = IPE_OP_INVALID;
182
WARN(1, "no rule setup for kernel_load_data enum %d", id);
183
}
184
185
ipe_build_eval_ctx(&ctx, NULL, op, IPE_HOOK_KERNEL_LOAD);
186
return ipe_evaluate_event(&ctx);
187
}
188
189
/**
190
* ipe_unpack_initramfs() - Mark the current rootfs as initramfs.
191
*/
192
void ipe_unpack_initramfs(void)
193
{
194
ipe_sb(current->fs->root.mnt->mnt_sb)->initramfs = true;
195
}
196
197
#ifdef CONFIG_IPE_PROP_DM_VERITY
198
/**
199
* ipe_bdev_free_security() - Free IPE's LSM blob of block_devices.
200
* @bdev: Supplies a pointer to a block_device that contains the structure
201
* to free.
202
*/
203
void ipe_bdev_free_security(struct block_device *bdev)
204
{
205
struct ipe_bdev *blob = ipe_bdev(bdev);
206
207
ipe_digest_free(blob->root_hash);
208
}
209
210
#ifdef CONFIG_IPE_PROP_DM_VERITY_SIGNATURE
211
static void ipe_set_dmverity_signature(struct ipe_bdev *blob,
212
const void *value,
213
size_t size)
214
{
215
blob->dm_verity_signed = size > 0 && value;
216
}
217
#else
218
static inline void ipe_set_dmverity_signature(struct ipe_bdev *blob,
219
const void *value,
220
size_t size)
221
{
222
}
223
#endif /* CONFIG_IPE_PROP_DM_VERITY_SIGNATURE */
224
225
/**
226
* ipe_bdev_setintegrity() - Save integrity data from a bdev to IPE's LSM blob.
227
* @bdev: Supplies a pointer to a block_device that contains the LSM blob.
228
* @type: Supplies the integrity type.
229
* @value: Supplies the value to store.
230
* @size: The size of @value.
231
*
232
* This hook is currently used to save dm-verity's root hash or the existence
233
* of a validated signed dm-verity root hash into LSM blob.
234
*
235
* Return: %0 on success. If an error occurs, the function will return the
236
* -errno.
237
*/
238
int ipe_bdev_setintegrity(struct block_device *bdev, enum lsm_integrity_type type,
239
const void *value, size_t size)
240
{
241
const struct dm_verity_digest *digest = NULL;
242
struct ipe_bdev *blob = ipe_bdev(bdev);
243
struct digest_info *info = NULL;
244
245
if (type == LSM_INT_DMVERITY_SIG_VALID) {
246
ipe_set_dmverity_signature(blob, value, size);
247
248
return 0;
249
}
250
251
if (type != LSM_INT_DMVERITY_ROOTHASH)
252
return -EINVAL;
253
254
if (!value) {
255
ipe_digest_free(blob->root_hash);
256
blob->root_hash = NULL;
257
258
return 0;
259
}
260
digest = value;
261
262
info = kzalloc(sizeof(*info), GFP_KERNEL);
263
if (!info)
264
return -ENOMEM;
265
266
info->digest = kmemdup(digest->digest, digest->digest_len, GFP_KERNEL);
267
if (!info->digest)
268
goto err;
269
270
info->alg = kstrdup(digest->alg, GFP_KERNEL);
271
if (!info->alg)
272
goto err;
273
274
info->digest_len = digest->digest_len;
275
276
ipe_digest_free(blob->root_hash);
277
blob->root_hash = info;
278
279
return 0;
280
err:
281
ipe_digest_free(info);
282
283
return -ENOMEM;
284
}
285
#endif /* CONFIG_IPE_PROP_DM_VERITY */
286
287
#ifdef CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG
288
/**
289
* ipe_inode_setintegrity() - save integrity data from a inode to IPE's LSM blob.
290
* @inode: The inode to source the security blob from.
291
* @type: Supplies the integrity type.
292
* @value: The value to be stored.
293
* @size: The size of @value.
294
*
295
* This hook is currently used to save the existence of a validated fs-verity
296
* builtin signature into LSM blob.
297
*
298
* Return: %0 on success. If an error occurs, the function will return the
299
* -errno.
300
*/
301
int ipe_inode_setintegrity(const struct inode *inode,
302
enum lsm_integrity_type type,
303
const void *value, size_t size)
304
{
305
struct ipe_inode *inode_sec = ipe_inode(inode);
306
307
if (type == LSM_INT_FSVERITY_BUILTINSIG_VALID) {
308
inode_sec->fs_verity_signed = size > 0 && value;
309
return 0;
310
}
311
312
return -EINVAL;
313
}
314
#endif /* CONFIG_CONFIG_IPE_PROP_FS_VERITY_BUILTIN_SIG */
315
316