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