Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/security/ipe/policy_fs.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* Copyright (C) 2020-2024 Microsoft Corporation. All rights reserved.
4
*/
5
#include <linux/fs.h>
6
#include <linux/namei.h>
7
#include <linux/types.h>
8
#include <linux/dcache.h>
9
#include <linux/security.h>
10
11
#include "ipe.h"
12
#include "policy.h"
13
#include "eval.h"
14
#include "fs.h"
15
#include "audit.h"
16
17
#define MAX_VERSION_SIZE ARRAY_SIZE("65535.65535.65535")
18
19
/**
20
* struct ipefs_file - defines a file in securityfs.
21
*
22
* @name: file name inside the policy subdirectory
23
* @access: file permissions
24
* @fops: &file_operations specific to this file
25
*/
26
struct ipefs_file {
27
const char *name;
28
umode_t access;
29
const struct file_operations *fops;
30
};
31
32
/**
33
* read_pkcs7() - Read handler for "ipe/policies/$name/pkcs7".
34
* @f: Supplies a file structure representing the securityfs node.
35
* @data: Supplies a buffer passed to the write syscall.
36
* @len: Supplies the length of @data.
37
* @offset: unused.
38
*
39
* @data will be populated with the pkcs7 blob representing the policy
40
* on success. If the policy is unsigned (like the boot policy), this
41
* will return -ENOENT.
42
*
43
* Return:
44
* * Length of buffer written - Success
45
* * %-ENOENT - Policy initializing/deleted or is unsigned
46
*/
47
static ssize_t read_pkcs7(struct file *f, char __user *data,
48
size_t len, loff_t *offset)
49
{
50
const struct ipe_policy *p = NULL;
51
struct inode *root = NULL;
52
int rc = 0;
53
54
root = d_inode(f->f_path.dentry->d_parent);
55
56
inode_lock_shared(root);
57
p = (struct ipe_policy *)root->i_private;
58
if (!p) {
59
rc = -ENOENT;
60
goto out;
61
}
62
63
if (!p->pkcs7) {
64
rc = -ENOENT;
65
goto out;
66
}
67
68
rc = simple_read_from_buffer(data, len, offset, p->pkcs7, p->pkcs7len);
69
70
out:
71
inode_unlock_shared(root);
72
73
return rc;
74
}
75
76
/**
77
* read_policy() - Read handler for "ipe/policies/$name/policy".
78
* @f: Supplies a file structure representing the securityfs node.
79
* @data: Supplies a buffer passed to the write syscall.
80
* @len: Supplies the length of @data.
81
* @offset: unused.
82
*
83
* @data will be populated with the plain-text version of the policy
84
* on success.
85
*
86
* Return:
87
* * Length of buffer written - Success
88
* * %-ENOENT - Policy initializing/deleted
89
*/
90
static ssize_t read_policy(struct file *f, char __user *data,
91
size_t len, loff_t *offset)
92
{
93
const struct ipe_policy *p = NULL;
94
struct inode *root = NULL;
95
int rc = 0;
96
97
root = d_inode(f->f_path.dentry->d_parent);
98
99
inode_lock_shared(root);
100
p = (struct ipe_policy *)root->i_private;
101
if (!p) {
102
rc = -ENOENT;
103
goto out;
104
}
105
106
rc = simple_read_from_buffer(data, len, offset, p->text, p->textlen);
107
108
out:
109
inode_unlock_shared(root);
110
111
return rc;
112
}
113
114
/**
115
* read_name() - Read handler for "ipe/policies/$name/name".
116
* @f: Supplies a file structure representing the securityfs node.
117
* @data: Supplies a buffer passed to the write syscall.
118
* @len: Supplies the length of @data.
119
* @offset: unused.
120
*
121
* @data will be populated with the policy_name attribute on success.
122
*
123
* Return:
124
* * Length of buffer written - Success
125
* * %-ENOENT - Policy initializing/deleted
126
*/
127
static ssize_t read_name(struct file *f, char __user *data,
128
size_t len, loff_t *offset)
129
{
130
const struct ipe_policy *p = NULL;
131
struct inode *root = NULL;
132
int rc = 0;
133
134
root = d_inode(f->f_path.dentry->d_parent);
135
136
inode_lock_shared(root);
137
p = (struct ipe_policy *)root->i_private;
138
if (!p) {
139
rc = -ENOENT;
140
goto out;
141
}
142
143
rc = simple_read_from_buffer(data, len, offset, p->parsed->name,
144
strlen(p->parsed->name));
145
146
out:
147
inode_unlock_shared(root);
148
149
return rc;
150
}
151
152
/**
153
* read_version() - Read handler for "ipe/policies/$name/version".
154
* @f: Supplies a file structure representing the securityfs node.
155
* @data: Supplies a buffer passed to the write syscall.
156
* @len: Supplies the length of @data.
157
* @offset: unused.
158
*
159
* @data will be populated with the version string on success.
160
*
161
* Return:
162
* * Length of buffer written - Success
163
* * %-ENOENT - Policy initializing/deleted
164
*/
165
static ssize_t read_version(struct file *f, char __user *data,
166
size_t len, loff_t *offset)
167
{
168
char buffer[MAX_VERSION_SIZE] = { 0 };
169
const struct ipe_policy *p = NULL;
170
struct inode *root = NULL;
171
size_t strsize = 0;
172
ssize_t rc = 0;
173
174
root = d_inode(f->f_path.dentry->d_parent);
175
176
inode_lock_shared(root);
177
p = (struct ipe_policy *)root->i_private;
178
if (!p) {
179
rc = -ENOENT;
180
goto out;
181
}
182
183
strsize = scnprintf(buffer, ARRAY_SIZE(buffer), "%hu.%hu.%hu",
184
p->parsed->version.major, p->parsed->version.minor,
185
p->parsed->version.rev);
186
187
rc = simple_read_from_buffer(data, len, offset, buffer, strsize);
188
189
out:
190
inode_unlock_shared(root);
191
192
return rc;
193
}
194
195
/**
196
* setactive() - Write handler for "ipe/policies/$name/active".
197
* @f: Supplies a file structure representing the securityfs node.
198
* @data: Supplies a buffer passed to the write syscall.
199
* @len: Supplies the length of @data.
200
* @offset: unused.
201
*
202
* Return:
203
* * Length of buffer written - Success
204
* * %-EPERM - Insufficient permission
205
* * %-EINVAL - Invalid input
206
* * %-ENOENT - Policy initializing/deleted
207
*/
208
static ssize_t setactive(struct file *f, const char __user *data,
209
size_t len, loff_t *offset)
210
{
211
const struct ipe_policy *p = NULL;
212
struct inode *root = NULL;
213
bool value = false;
214
int rc = 0;
215
216
if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN))
217
return -EPERM;
218
219
rc = kstrtobool_from_user(data, len, &value);
220
if (rc)
221
return rc;
222
223
if (!value)
224
return -EINVAL;
225
226
root = d_inode(f->f_path.dentry->d_parent);
227
inode_lock(root);
228
229
p = (struct ipe_policy *)root->i_private;
230
if (!p) {
231
rc = -ENOENT;
232
goto out;
233
}
234
235
rc = ipe_set_active_pol(p);
236
237
out:
238
inode_unlock(root);
239
return (rc < 0) ? rc : len;
240
}
241
242
/**
243
* getactive() - Read handler for "ipe/policies/$name/active".
244
* @f: Supplies a file structure representing the securityfs node.
245
* @data: Supplies a buffer passed to the write syscall.
246
* @len: Supplies the length of @data.
247
* @offset: unused.
248
*
249
* @data will be populated with the 1 or 0 depending on if the
250
* corresponding policy is active.
251
*
252
* Return:
253
* * Length of buffer written - Success
254
* * %-ENOENT - Policy initializing/deleted
255
*/
256
static ssize_t getactive(struct file *f, char __user *data,
257
size_t len, loff_t *offset)
258
{
259
const struct ipe_policy *p = NULL;
260
struct inode *root = NULL;
261
const char *str;
262
int rc = 0;
263
264
root = d_inode(f->f_path.dentry->d_parent);
265
266
inode_lock_shared(root);
267
p = (struct ipe_policy *)root->i_private;
268
if (!p) {
269
inode_unlock_shared(root);
270
return -ENOENT;
271
}
272
inode_unlock_shared(root);
273
274
str = (p == rcu_access_pointer(ipe_active_policy)) ? "1" : "0";
275
rc = simple_read_from_buffer(data, len, offset, str, 1);
276
277
return rc;
278
}
279
280
/**
281
* update_policy() - Write handler for "ipe/policies/$name/update".
282
* @f: Supplies a file structure representing the securityfs node.
283
* @data: Supplies a buffer passed to the write syscall.
284
* @len: Supplies the length of @data.
285
* @offset: unused.
286
*
287
* On success this updates the policy represented by $name,
288
* in-place.
289
*
290
* Return:
291
* * Length of buffer written - Success
292
* * %-EPERM - Insufficient permission
293
* * %-ENOMEM - Out of memory (OOM)
294
* * %-ENOENT - Policy was deleted while updating
295
* * %-EINVAL - Policy name mismatch
296
* * %-ESTALE - Policy version too old
297
*/
298
static ssize_t update_policy(struct file *f, const char __user *data,
299
size_t len, loff_t *offset)
300
{
301
struct inode *root = NULL;
302
char *copy = NULL;
303
int rc = 0;
304
305
if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN)) {
306
rc = -EPERM;
307
goto out;
308
}
309
310
copy = memdup_user(data, len);
311
if (IS_ERR(copy)) {
312
rc = PTR_ERR(copy);
313
copy = NULL;
314
goto out;
315
}
316
317
root = d_inode(f->f_path.dentry->d_parent);
318
inode_lock(root);
319
rc = ipe_update_policy(root, NULL, 0, copy, len);
320
inode_unlock(root);
321
322
out:
323
kfree(copy);
324
if (rc) {
325
ipe_audit_policy_load(ERR_PTR(rc));
326
return rc;
327
}
328
329
return len;
330
}
331
332
/**
333
* delete_policy() - write handler for "ipe/policies/$name/delete".
334
* @f: Supplies a file structure representing the securityfs node.
335
* @data: Supplies a buffer passed to the write syscall.
336
* @len: Supplies the length of @data.
337
* @offset: unused.
338
*
339
* On success this deletes the policy represented by $name.
340
*
341
* Return:
342
* * Length of buffer written - Success
343
* * %-EPERM - Insufficient permission/deleting active policy
344
* * %-EINVAL - Invalid input
345
* * %-ENOENT - Policy initializing/deleted
346
*/
347
static ssize_t delete_policy(struct file *f, const char __user *data,
348
size_t len, loff_t *offset)
349
{
350
struct ipe_policy *ap = NULL;
351
struct ipe_policy *p = NULL;
352
struct inode *root = NULL;
353
bool value = false;
354
int rc = 0;
355
356
if (!file_ns_capable(f, &init_user_ns, CAP_MAC_ADMIN))
357
return -EPERM;
358
359
rc = kstrtobool_from_user(data, len, &value);
360
if (rc)
361
return rc;
362
363
if (!value)
364
return -EINVAL;
365
366
root = d_inode(f->f_path.dentry->d_parent);
367
inode_lock(root);
368
p = (struct ipe_policy *)root->i_private;
369
if (!p) {
370
inode_unlock(root);
371
return -ENOENT;
372
}
373
374
mutex_lock(&ipe_policy_lock);
375
ap = rcu_dereference_protected(ipe_active_policy,
376
lockdep_is_held(&ipe_policy_lock));
377
if (p == ap) {
378
mutex_unlock(&ipe_policy_lock);
379
inode_unlock(root);
380
return -EPERM;
381
}
382
mutex_unlock(&ipe_policy_lock);
383
384
root->i_private = NULL;
385
inode_unlock(root);
386
387
synchronize_rcu();
388
ipe_free_policy(p);
389
390
return len;
391
}
392
393
static const struct file_operations content_fops = {
394
.read = read_policy,
395
};
396
397
static const struct file_operations pkcs7_fops = {
398
.read = read_pkcs7,
399
};
400
401
static const struct file_operations name_fops = {
402
.read = read_name,
403
};
404
405
static const struct file_operations ver_fops = {
406
.read = read_version,
407
};
408
409
static const struct file_operations active_fops = {
410
.write = setactive,
411
.read = getactive,
412
};
413
414
static const struct file_operations update_fops = {
415
.write = update_policy,
416
};
417
418
static const struct file_operations delete_fops = {
419
.write = delete_policy,
420
};
421
422
/*
423
* policy_subdir - files under a policy subdirectory
424
*/
425
static const struct ipefs_file policy_subdir[] = {
426
{ "pkcs7", 0444, &pkcs7_fops },
427
{ "policy", 0444, &content_fops },
428
{ "name", 0444, &name_fops },
429
{ "version", 0444, &ver_fops },
430
{ "active", 0600, &active_fops },
431
{ "update", 0200, &update_fops },
432
{ "delete", 0200, &delete_fops },
433
};
434
435
/**
436
* ipe_del_policyfs_node() - Delete a securityfs entry for @p.
437
* @p: Supplies a pointer to the policy to delete a securityfs entry for.
438
*/
439
void ipe_del_policyfs_node(struct ipe_policy *p)
440
{
441
securityfs_remove(p->policyfs);
442
p->policyfs = NULL;
443
}
444
445
/**
446
* ipe_new_policyfs_node() - Create a securityfs entry for @p.
447
* @p: Supplies a pointer to the policy to create a securityfs entry for.
448
*
449
* Return: %0 on success. If an error occurs, the function will return
450
* the -errno.
451
*/
452
int ipe_new_policyfs_node(struct ipe_policy *p)
453
{
454
const struct ipefs_file *f = NULL;
455
struct dentry *policyfs = NULL;
456
struct inode *root = NULL;
457
struct dentry *d = NULL;
458
size_t i = 0;
459
int rc = 0;
460
461
if (p->policyfs)
462
return 0;
463
464
policyfs = securityfs_create_dir(p->parsed->name, policy_root);
465
if (IS_ERR(policyfs))
466
return PTR_ERR(policyfs);
467
468
root = d_inode(policyfs);
469
470
for (i = 0; i < ARRAY_SIZE(policy_subdir); ++i) {
471
f = &policy_subdir[i];
472
473
d = securityfs_create_file(f->name, f->access, policyfs,
474
NULL, f->fops);
475
if (IS_ERR(d)) {
476
rc = PTR_ERR(d);
477
goto err;
478
}
479
}
480
481
inode_lock(root);
482
p->policyfs = policyfs;
483
root->i_private = p;
484
inode_unlock(root);
485
486
return 0;
487
err:
488
securityfs_remove(policyfs);
489
return rc;
490
}
491
492