Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/security/tomoyo/file.c
10814 views
1
/*
2
* security/tomoyo/file.c
3
*
4
* Pathname restriction functions.
5
*
6
* Copyright (C) 2005-2010 NTT DATA CORPORATION
7
*/
8
9
#include "common.h"
10
#include <linux/slab.h>
11
12
/* Keyword array for operations with one pathname. */
13
const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
14
[TOMOYO_TYPE_READ_WRITE] = "read/write",
15
[TOMOYO_TYPE_EXECUTE] = "execute",
16
[TOMOYO_TYPE_READ] = "read",
17
[TOMOYO_TYPE_WRITE] = "write",
18
[TOMOYO_TYPE_UNLINK] = "unlink",
19
[TOMOYO_TYPE_RMDIR] = "rmdir",
20
[TOMOYO_TYPE_TRUNCATE] = "truncate",
21
[TOMOYO_TYPE_SYMLINK] = "symlink",
22
[TOMOYO_TYPE_REWRITE] = "rewrite",
23
[TOMOYO_TYPE_CHROOT] = "chroot",
24
[TOMOYO_TYPE_UMOUNT] = "unmount",
25
};
26
27
/* Keyword array for operations with one pathname and three numbers. */
28
const char *tomoyo_mkdev_keyword[TOMOYO_MAX_MKDEV_OPERATION] = {
29
[TOMOYO_TYPE_MKBLOCK] = "mkblock",
30
[TOMOYO_TYPE_MKCHAR] = "mkchar",
31
};
32
33
/* Keyword array for operations with two pathnames. */
34
const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
35
[TOMOYO_TYPE_LINK] = "link",
36
[TOMOYO_TYPE_RENAME] = "rename",
37
[TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
38
};
39
40
/* Keyword array for operations with one pathname and one number. */
41
const char *tomoyo_path_number_keyword[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
42
[TOMOYO_TYPE_CREATE] = "create",
43
[TOMOYO_TYPE_MKDIR] = "mkdir",
44
[TOMOYO_TYPE_MKFIFO] = "mkfifo",
45
[TOMOYO_TYPE_MKSOCK] = "mksock",
46
[TOMOYO_TYPE_IOCTL] = "ioctl",
47
[TOMOYO_TYPE_CHMOD] = "chmod",
48
[TOMOYO_TYPE_CHOWN] = "chown",
49
[TOMOYO_TYPE_CHGRP] = "chgrp",
50
};
51
52
static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
53
[TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN,
54
[TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE,
55
[TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN,
56
[TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN,
57
[TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK,
58
[TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR,
59
[TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE,
60
[TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK,
61
[TOMOYO_TYPE_REWRITE] = TOMOYO_MAC_FILE_REWRITE,
62
[TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT,
63
[TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT,
64
};
65
66
static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
67
[TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
68
[TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR,
69
};
70
71
static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
72
[TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK,
73
[TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME,
74
[TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
75
};
76
77
static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
78
[TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
79
[TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR,
80
[TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
81
[TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
82
[TOMOYO_TYPE_IOCTL] = TOMOYO_MAC_FILE_IOCTL,
83
[TOMOYO_TYPE_CHMOD] = TOMOYO_MAC_FILE_CHMOD,
84
[TOMOYO_TYPE_CHOWN] = TOMOYO_MAC_FILE_CHOWN,
85
[TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP,
86
};
87
88
void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
89
{
90
if (!ptr)
91
return;
92
if (ptr->is_group)
93
tomoyo_put_group(ptr->group);
94
else
95
tomoyo_put_name(ptr->filename);
96
}
97
98
const struct tomoyo_path_info *
99
tomoyo_compare_name_union(const struct tomoyo_path_info *name,
100
const struct tomoyo_name_union *ptr)
101
{
102
if (ptr->is_group)
103
return tomoyo_path_matches_group(name, ptr->group);
104
if (tomoyo_path_matches_pattern(name, ptr->filename))
105
return ptr->filename;
106
return NULL;
107
}
108
109
void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
110
{
111
if (ptr && ptr->is_group)
112
tomoyo_put_group(ptr->group);
113
}
114
115
bool tomoyo_compare_number_union(const unsigned long value,
116
const struct tomoyo_number_union *ptr)
117
{
118
if (ptr->is_group)
119
return tomoyo_number_matches_group(value, value, ptr->group);
120
return value >= ptr->values[0] && value <= ptr->values[1];
121
}
122
123
static void tomoyo_add_slash(struct tomoyo_path_info *buf)
124
{
125
if (buf->is_dir)
126
return;
127
/*
128
* This is OK because tomoyo_encode() reserves space for appending "/".
129
*/
130
strcat((char *) buf->name, "/");
131
tomoyo_fill_path_info(buf);
132
}
133
134
/**
135
* tomoyo_strendswith - Check whether the token ends with the given token.
136
*
137
* @name: The token to check.
138
* @tail: The token to find.
139
*
140
* Returns true if @name ends with @tail, false otherwise.
141
*/
142
static bool tomoyo_strendswith(const char *name, const char *tail)
143
{
144
int len;
145
146
if (!name || !tail)
147
return false;
148
len = strlen(name) - strlen(tail);
149
return len >= 0 && !strcmp(name + len, tail);
150
}
151
152
/**
153
* tomoyo_get_realpath - Get realpath.
154
*
155
* @buf: Pointer to "struct tomoyo_path_info".
156
* @path: Pointer to "struct path".
157
*
158
* Returns true on success, false otherwise.
159
*/
160
static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
161
{
162
buf->name = tomoyo_realpath_from_path(path);
163
if (buf->name) {
164
tomoyo_fill_path_info(buf);
165
return true;
166
}
167
return false;
168
}
169
170
/**
171
* tomoyo_audit_path_log - Audit path request log.
172
*
173
* @r: Pointer to "struct tomoyo_request_info".
174
*
175
* Returns 0 on success, negative value otherwise.
176
*/
177
static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
178
{
179
const char *operation = tomoyo_path_keyword[r->param.path.operation];
180
const struct tomoyo_path_info *filename = r->param.path.filename;
181
if (r->granted)
182
return 0;
183
tomoyo_warn_log(r, "%s %s", operation, filename->name);
184
return tomoyo_supervisor(r, "allow_%s %s\n", operation,
185
tomoyo_pattern(filename));
186
}
187
188
/**
189
* tomoyo_audit_path2_log - Audit path/path request log.
190
*
191
* @r: Pointer to "struct tomoyo_request_info".
192
*
193
* Returns 0 on success, negative value otherwise.
194
*/
195
static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
196
{
197
const char *operation = tomoyo_path2_keyword[r->param.path2.operation];
198
const struct tomoyo_path_info *filename1 = r->param.path2.filename1;
199
const struct tomoyo_path_info *filename2 = r->param.path2.filename2;
200
if (r->granted)
201
return 0;
202
tomoyo_warn_log(r, "%s %s %s", operation, filename1->name,
203
filename2->name);
204
return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
205
tomoyo_pattern(filename1),
206
tomoyo_pattern(filename2));
207
}
208
209
/**
210
* tomoyo_audit_mkdev_log - Audit path/number/number/number request log.
211
*
212
* @r: Pointer to "struct tomoyo_request_info".
213
*
214
* Returns 0 on success, negative value otherwise.
215
*/
216
static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
217
{
218
const char *operation = tomoyo_mkdev_keyword[r->param.mkdev.operation];
219
const struct tomoyo_path_info *filename = r->param.mkdev.filename;
220
const unsigned int major = r->param.mkdev.major;
221
const unsigned int minor = r->param.mkdev.minor;
222
const unsigned int mode = r->param.mkdev.mode;
223
if (r->granted)
224
return 0;
225
tomoyo_warn_log(r, "%s %s 0%o %u %u", operation, filename->name, mode,
226
major, minor);
227
return tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", operation,
228
tomoyo_pattern(filename), mode, major, minor);
229
}
230
231
/**
232
* tomoyo_audit_path_number_log - Audit path/number request log.
233
*
234
* @r: Pointer to "struct tomoyo_request_info".
235
* @error: Error code.
236
*
237
* Returns 0 on success, negative value otherwise.
238
*/
239
static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
240
{
241
const u8 type = r->param.path_number.operation;
242
u8 radix;
243
const struct tomoyo_path_info *filename = r->param.path_number.filename;
244
const char *operation = tomoyo_path_number_keyword[type];
245
char buffer[64];
246
if (r->granted)
247
return 0;
248
switch (type) {
249
case TOMOYO_TYPE_CREATE:
250
case TOMOYO_TYPE_MKDIR:
251
case TOMOYO_TYPE_MKFIFO:
252
case TOMOYO_TYPE_MKSOCK:
253
case TOMOYO_TYPE_CHMOD:
254
radix = TOMOYO_VALUE_TYPE_OCTAL;
255
break;
256
case TOMOYO_TYPE_IOCTL:
257
radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
258
break;
259
default:
260
radix = TOMOYO_VALUE_TYPE_DECIMAL;
261
break;
262
}
263
tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
264
radix);
265
tomoyo_warn_log(r, "%s %s %s", operation, filename->name, buffer);
266
return tomoyo_supervisor(r, "allow_%s %s %s\n", operation,
267
tomoyo_pattern(filename), buffer);
268
}
269
270
static bool tomoyo_same_globally_readable(const struct tomoyo_acl_head *a,
271
const struct tomoyo_acl_head *b)
272
{
273
return container_of(a, struct tomoyo_readable_file,
274
head)->filename ==
275
container_of(b, struct tomoyo_readable_file,
276
head)->filename;
277
}
278
279
/**
280
* tomoyo_update_globally_readable_entry - Update "struct tomoyo_readable_file" list.
281
*
282
* @filename: Filename unconditionally permitted to open() for reading.
283
* @is_delete: True if it is a delete request.
284
*
285
* Returns 0 on success, negative value otherwise.
286
*
287
* Caller holds tomoyo_read_lock().
288
*/
289
static int tomoyo_update_globally_readable_entry(const char *filename,
290
const bool is_delete)
291
{
292
struct tomoyo_readable_file e = { };
293
int error;
294
295
if (!tomoyo_correct_word(filename))
296
return -EINVAL;
297
e.filename = tomoyo_get_name(filename);
298
if (!e.filename)
299
return -ENOMEM;
300
error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
301
&tomoyo_policy_list
302
[TOMOYO_ID_GLOBALLY_READABLE],
303
tomoyo_same_globally_readable);
304
tomoyo_put_name(e.filename);
305
return error;
306
}
307
308
/**
309
* tomoyo_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
310
*
311
* @filename: The filename to check.
312
*
313
* Returns true if any domain can open @filename for reading, false otherwise.
314
*
315
* Caller holds tomoyo_read_lock().
316
*/
317
static bool tomoyo_globally_readable_file(const struct tomoyo_path_info *
318
filename)
319
{
320
struct tomoyo_readable_file *ptr;
321
bool found = false;
322
323
list_for_each_entry_rcu(ptr, &tomoyo_policy_list
324
[TOMOYO_ID_GLOBALLY_READABLE], head.list) {
325
if (!ptr->head.is_deleted &&
326
tomoyo_path_matches_pattern(filename, ptr->filename)) {
327
found = true;
328
break;
329
}
330
}
331
return found;
332
}
333
334
/**
335
* tomoyo_write_globally_readable - Write "struct tomoyo_readable_file" list.
336
*
337
* @data: String to parse.
338
* @is_delete: True if it is a delete request.
339
*
340
* Returns 0 on success, negative value otherwise.
341
*
342
* Caller holds tomoyo_read_lock().
343
*/
344
int tomoyo_write_globally_readable(char *data, const bool is_delete)
345
{
346
return tomoyo_update_globally_readable_entry(data, is_delete);
347
}
348
349
static bool tomoyo_same_pattern(const struct tomoyo_acl_head *a,
350
const struct tomoyo_acl_head *b)
351
{
352
return container_of(a, struct tomoyo_no_pattern, head)->pattern ==
353
container_of(b, struct tomoyo_no_pattern, head)->pattern;
354
}
355
356
/**
357
* tomoyo_update_file_pattern_entry - Update "struct tomoyo_no_pattern" list.
358
*
359
* @pattern: Pathname pattern.
360
* @is_delete: True if it is a delete request.
361
*
362
* Returns 0 on success, negative value otherwise.
363
*
364
* Caller holds tomoyo_read_lock().
365
*/
366
static int tomoyo_update_file_pattern_entry(const char *pattern,
367
const bool is_delete)
368
{
369
struct tomoyo_no_pattern e = { };
370
int error;
371
372
if (!tomoyo_correct_word(pattern))
373
return -EINVAL;
374
e.pattern = tomoyo_get_name(pattern);
375
if (!e.pattern)
376
return -ENOMEM;
377
error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
378
&tomoyo_policy_list[TOMOYO_ID_PATTERN],
379
tomoyo_same_pattern);
380
tomoyo_put_name(e.pattern);
381
return error;
382
}
383
384
/**
385
* tomoyo_pattern - Get patterned pathname.
386
*
387
* @filename: The filename to find patterned pathname.
388
*
389
* Returns pointer to pathname pattern if matched, @filename otherwise.
390
*
391
* Caller holds tomoyo_read_lock().
392
*/
393
const char *tomoyo_pattern(const struct tomoyo_path_info *filename)
394
{
395
struct tomoyo_no_pattern *ptr;
396
const struct tomoyo_path_info *pattern = NULL;
397
398
list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_PATTERN],
399
head.list) {
400
if (ptr->head.is_deleted)
401
continue;
402
if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
403
continue;
404
pattern = ptr->pattern;
405
if (tomoyo_strendswith(pattern->name, "/\\*")) {
406
/* Do nothing. Try to find the better match. */
407
} else {
408
/* This would be the better match. Use this. */
409
break;
410
}
411
}
412
if (pattern)
413
filename = pattern;
414
return filename->name;
415
}
416
417
/**
418
* tomoyo_write_pattern - Write "struct tomoyo_no_pattern" list.
419
*
420
* @data: String to parse.
421
* @is_delete: True if it is a delete request.
422
*
423
* Returns 0 on success, negative value otherwise.
424
*
425
* Caller holds tomoyo_read_lock().
426
*/
427
int tomoyo_write_pattern(char *data, const bool is_delete)
428
{
429
return tomoyo_update_file_pattern_entry(data, is_delete);
430
}
431
432
static bool tomoyo_same_no_rewrite(const struct tomoyo_acl_head *a,
433
const struct tomoyo_acl_head *b)
434
{
435
return container_of(a, struct tomoyo_no_rewrite, head)->pattern
436
== container_of(b, struct tomoyo_no_rewrite, head)
437
->pattern;
438
}
439
440
/**
441
* tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite" list.
442
*
443
* @pattern: Pathname pattern that are not rewritable by default.
444
* @is_delete: True if it is a delete request.
445
*
446
* Returns 0 on success, negative value otherwise.
447
*
448
* Caller holds tomoyo_read_lock().
449
*/
450
static int tomoyo_update_no_rewrite_entry(const char *pattern,
451
const bool is_delete)
452
{
453
struct tomoyo_no_rewrite e = { };
454
int error;
455
456
if (!tomoyo_correct_word(pattern))
457
return -EINVAL;
458
e.pattern = tomoyo_get_name(pattern);
459
if (!e.pattern)
460
return -ENOMEM;
461
error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
462
&tomoyo_policy_list[TOMOYO_ID_NO_REWRITE],
463
tomoyo_same_no_rewrite);
464
tomoyo_put_name(e.pattern);
465
return error;
466
}
467
468
/**
469
* tomoyo_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
470
*
471
* @filename: Filename to check.
472
*
473
* Returns true if @filename is specified by "deny_rewrite" directive,
474
* false otherwise.
475
*
476
* Caller holds tomoyo_read_lock().
477
*/
478
static bool tomoyo_no_rewrite_file(const struct tomoyo_path_info *filename)
479
{
480
struct tomoyo_no_rewrite *ptr;
481
bool found = false;
482
483
list_for_each_entry_rcu(ptr, &tomoyo_policy_list[TOMOYO_ID_NO_REWRITE],
484
head.list) {
485
if (ptr->head.is_deleted)
486
continue;
487
if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
488
continue;
489
found = true;
490
break;
491
}
492
return found;
493
}
494
495
/**
496
* tomoyo_write_no_rewrite - Write "struct tomoyo_no_rewrite" list.
497
*
498
* @data: String to parse.
499
* @is_delete: True if it is a delete request.
500
*
501
* Returns 0 on success, negative value otherwise.
502
*
503
* Caller holds tomoyo_read_lock().
504
*/
505
int tomoyo_write_no_rewrite(char *data, const bool is_delete)
506
{
507
return tomoyo_update_no_rewrite_entry(data, is_delete);
508
}
509
510
static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
511
const struct tomoyo_acl_info *ptr)
512
{
513
const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
514
head);
515
if (acl->perm & (1 << r->param.path.operation)) {
516
r->param.path.matched_path =
517
tomoyo_compare_name_union(r->param.path.filename,
518
&acl->name);
519
return r->param.path.matched_path != NULL;
520
}
521
return false;
522
}
523
524
static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
525
const struct tomoyo_acl_info *ptr)
526
{
527
const struct tomoyo_path_number_acl *acl =
528
container_of(ptr, typeof(*acl), head);
529
return (acl->perm & (1 << r->param.path_number.operation)) &&
530
tomoyo_compare_number_union(r->param.path_number.number,
531
&acl->number) &&
532
tomoyo_compare_name_union(r->param.path_number.filename,
533
&acl->name);
534
}
535
536
static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
537
const struct tomoyo_acl_info *ptr)
538
{
539
const struct tomoyo_path2_acl *acl =
540
container_of(ptr, typeof(*acl), head);
541
return (acl->perm & (1 << r->param.path2.operation)) &&
542
tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
543
&& tomoyo_compare_name_union(r->param.path2.filename2,
544
&acl->name2);
545
}
546
547
static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
548
const struct tomoyo_acl_info *ptr)
549
{
550
const struct tomoyo_mkdev_acl *acl =
551
container_of(ptr, typeof(*acl), head);
552
return (acl->perm & (1 << r->param.mkdev.operation)) &&
553
tomoyo_compare_number_union(r->param.mkdev.mode,
554
&acl->mode) &&
555
tomoyo_compare_number_union(r->param.mkdev.major,
556
&acl->major) &&
557
tomoyo_compare_number_union(r->param.mkdev.minor,
558
&acl->minor) &&
559
tomoyo_compare_name_union(r->param.mkdev.filename,
560
&acl->name);
561
}
562
563
static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
564
const struct tomoyo_acl_info *b)
565
{
566
const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
567
const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
568
return tomoyo_same_acl_head(&p1->head, &p2->head) &&
569
tomoyo_same_name_union(&p1->name, &p2->name);
570
}
571
572
static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
573
struct tomoyo_acl_info *b,
574
const bool is_delete)
575
{
576
u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
577
->perm;
578
u16 perm = *a_perm;
579
const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
580
if (is_delete) {
581
perm &= ~b_perm;
582
if ((perm & TOMOYO_RW_MASK) != TOMOYO_RW_MASK)
583
perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
584
else if (!(perm & (1 << TOMOYO_TYPE_READ_WRITE)))
585
perm &= ~TOMOYO_RW_MASK;
586
} else {
587
perm |= b_perm;
588
if ((perm & TOMOYO_RW_MASK) == TOMOYO_RW_MASK)
589
perm |= (1 << TOMOYO_TYPE_READ_WRITE);
590
else if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
591
perm |= TOMOYO_RW_MASK;
592
}
593
*a_perm = perm;
594
return !perm;
595
}
596
597
/**
598
* tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
599
*
600
* @type: Type of operation.
601
* @filename: Filename.
602
* @domain: Pointer to "struct tomoyo_domain_info".
603
* @is_delete: True if it is a delete request.
604
*
605
* Returns 0 on success, negative value otherwise.
606
*
607
* Caller holds tomoyo_read_lock().
608
*/
609
static int tomoyo_update_path_acl(const u8 type, const char *filename,
610
struct tomoyo_domain_info * const domain,
611
const bool is_delete)
612
{
613
struct tomoyo_path_acl e = {
614
.head.type = TOMOYO_TYPE_PATH_ACL,
615
.perm = 1 << type
616
};
617
int error;
618
if (e.perm == (1 << TOMOYO_TYPE_READ_WRITE))
619
e.perm |= TOMOYO_RW_MASK;
620
if (!tomoyo_parse_name_union(filename, &e.name))
621
return -EINVAL;
622
error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
623
tomoyo_same_path_acl,
624
tomoyo_merge_path_acl);
625
tomoyo_put_name_union(&e.name);
626
return error;
627
}
628
629
static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
630
const struct tomoyo_acl_info *b)
631
{
632
const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1),
633
head);
634
const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2),
635
head);
636
return tomoyo_same_acl_head(&p1->head, &p2->head)
637
&& tomoyo_same_name_union(&p1->name, &p2->name)
638
&& tomoyo_same_number_union(&p1->mode, &p2->mode)
639
&& tomoyo_same_number_union(&p1->major, &p2->major)
640
&& tomoyo_same_number_union(&p1->minor, &p2->minor);
641
}
642
643
static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
644
struct tomoyo_acl_info *b,
645
const bool is_delete)
646
{
647
u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
648
head)->perm;
649
u8 perm = *a_perm;
650
const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
651
->perm;
652
if (is_delete)
653
perm &= ~b_perm;
654
else
655
perm |= b_perm;
656
*a_perm = perm;
657
return !perm;
658
}
659
660
/**
661
* tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
662
*
663
* @type: Type of operation.
664
* @filename: Filename.
665
* @mode: Create mode.
666
* @major: Device major number.
667
* @minor: Device minor number.
668
* @domain: Pointer to "struct tomoyo_domain_info".
669
* @is_delete: True if it is a delete request.
670
*
671
* Returns 0 on success, negative value otherwise.
672
*
673
* Caller holds tomoyo_read_lock().
674
*/
675
static int tomoyo_update_mkdev_acl(const u8 type, const char *filename,
676
char *mode, char *major, char *minor,
677
struct tomoyo_domain_info * const
678
domain, const bool is_delete)
679
{
680
struct tomoyo_mkdev_acl e = {
681
.head.type = TOMOYO_TYPE_MKDEV_ACL,
682
.perm = 1 << type
683
};
684
int error = is_delete ? -ENOENT : -ENOMEM;
685
if (!tomoyo_parse_name_union(filename, &e.name) ||
686
!tomoyo_parse_number_union(mode, &e.mode) ||
687
!tomoyo_parse_number_union(major, &e.major) ||
688
!tomoyo_parse_number_union(minor, &e.minor))
689
goto out;
690
error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
691
tomoyo_same_mkdev_acl,
692
tomoyo_merge_mkdev_acl);
693
out:
694
tomoyo_put_name_union(&e.name);
695
tomoyo_put_number_union(&e.mode);
696
tomoyo_put_number_union(&e.major);
697
tomoyo_put_number_union(&e.minor);
698
return error;
699
}
700
701
static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
702
const struct tomoyo_acl_info *b)
703
{
704
const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
705
const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
706
return tomoyo_same_acl_head(&p1->head, &p2->head)
707
&& tomoyo_same_name_union(&p1->name1, &p2->name1)
708
&& tomoyo_same_name_union(&p1->name2, &p2->name2);
709
}
710
711
static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
712
struct tomoyo_acl_info *b,
713
const bool is_delete)
714
{
715
u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
716
->perm;
717
u8 perm = *a_perm;
718
const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
719
if (is_delete)
720
perm &= ~b_perm;
721
else
722
perm |= b_perm;
723
*a_perm = perm;
724
return !perm;
725
}
726
727
/**
728
* tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
729
*
730
* @type: Type of operation.
731
* @filename1: First filename.
732
* @filename2: Second filename.
733
* @domain: Pointer to "struct tomoyo_domain_info".
734
* @is_delete: True if it is a delete request.
735
*
736
* Returns 0 on success, negative value otherwise.
737
*
738
* Caller holds tomoyo_read_lock().
739
*/
740
static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
741
const char *filename2,
742
struct tomoyo_domain_info * const domain,
743
const bool is_delete)
744
{
745
struct tomoyo_path2_acl e = {
746
.head.type = TOMOYO_TYPE_PATH2_ACL,
747
.perm = 1 << type
748
};
749
int error = is_delete ? -ENOENT : -ENOMEM;
750
if (!tomoyo_parse_name_union(filename1, &e.name1) ||
751
!tomoyo_parse_name_union(filename2, &e.name2))
752
goto out;
753
error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
754
tomoyo_same_path2_acl,
755
tomoyo_merge_path2_acl);
756
out:
757
tomoyo_put_name_union(&e.name1);
758
tomoyo_put_name_union(&e.name2);
759
return error;
760
}
761
762
/**
763
* tomoyo_path_permission - Check permission for single path operation.
764
*
765
* @r: Pointer to "struct tomoyo_request_info".
766
* @operation: Type of operation.
767
* @filename: Filename to check.
768
*
769
* Returns 0 on success, negative value otherwise.
770
*
771
* Caller holds tomoyo_read_lock().
772
*/
773
int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
774
const struct tomoyo_path_info *filename)
775
{
776
int error;
777
778
next:
779
r->type = tomoyo_p2mac[operation];
780
r->mode = tomoyo_get_mode(r->profile, r->type);
781
if (r->mode == TOMOYO_CONFIG_DISABLED)
782
return 0;
783
r->param_type = TOMOYO_TYPE_PATH_ACL;
784
r->param.path.filename = filename;
785
r->param.path.operation = operation;
786
do {
787
tomoyo_check_acl(r, tomoyo_check_path_acl);
788
if (!r->granted && operation == TOMOYO_TYPE_READ &&
789
!r->domain->ignore_global_allow_read &&
790
tomoyo_globally_readable_file(filename))
791
r->granted = true;
792
error = tomoyo_audit_path_log(r);
793
/*
794
* Do not retry for execute request, for alias may have
795
* changed.
796
*/
797
} while (error == TOMOYO_RETRY_REQUEST &&
798
operation != TOMOYO_TYPE_EXECUTE);
799
/*
800
* Since "allow_truncate" doesn't imply "allow_rewrite" permission,
801
* we need to check "allow_rewrite" permission if the filename is
802
* specified by "deny_rewrite" keyword.
803
*/
804
if (!error && operation == TOMOYO_TYPE_TRUNCATE &&
805
tomoyo_no_rewrite_file(filename)) {
806
operation = TOMOYO_TYPE_REWRITE;
807
goto next;
808
}
809
return error;
810
}
811
812
static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
813
const struct tomoyo_acl_info *b)
814
{
815
const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
816
head);
817
const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
818
head);
819
return tomoyo_same_acl_head(&p1->head, &p2->head)
820
&& tomoyo_same_name_union(&p1->name, &p2->name)
821
&& tomoyo_same_number_union(&p1->number, &p2->number);
822
}
823
824
static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
825
struct tomoyo_acl_info *b,
826
const bool is_delete)
827
{
828
u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
829
head)->perm;
830
u8 perm = *a_perm;
831
const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
832
->perm;
833
if (is_delete)
834
perm &= ~b_perm;
835
else
836
perm |= b_perm;
837
*a_perm = perm;
838
return !perm;
839
}
840
841
/**
842
* tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
843
*
844
* @type: Type of operation.
845
* @filename: Filename.
846
* @number: Number.
847
* @domain: Pointer to "struct tomoyo_domain_info".
848
* @is_delete: True if it is a delete request.
849
*
850
* Returns 0 on success, negative value otherwise.
851
*/
852
static int tomoyo_update_path_number_acl(const u8 type, const char *filename,
853
char *number,
854
struct tomoyo_domain_info * const
855
domain,
856
const bool is_delete)
857
{
858
struct tomoyo_path_number_acl e = {
859
.head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
860
.perm = 1 << type
861
};
862
int error = is_delete ? -ENOENT : -ENOMEM;
863
if (!tomoyo_parse_name_union(filename, &e.name))
864
return -EINVAL;
865
if (!tomoyo_parse_number_union(number, &e.number))
866
goto out;
867
error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
868
tomoyo_same_path_number_acl,
869
tomoyo_merge_path_number_acl);
870
out:
871
tomoyo_put_name_union(&e.name);
872
tomoyo_put_number_union(&e.number);
873
return error;
874
}
875
876
/**
877
* tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
878
*
879
* @type: Type of operation.
880
* @path: Pointer to "struct path".
881
* @number: Number.
882
*
883
* Returns 0 on success, negative value otherwise.
884
*/
885
int tomoyo_path_number_perm(const u8 type, struct path *path,
886
unsigned long number)
887
{
888
struct tomoyo_request_info r;
889
int error = -ENOMEM;
890
struct tomoyo_path_info buf;
891
int idx;
892
893
if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
894
== TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry)
895
return 0;
896
idx = tomoyo_read_lock();
897
if (!tomoyo_get_realpath(&buf, path))
898
goto out;
899
if (type == TOMOYO_TYPE_MKDIR)
900
tomoyo_add_slash(&buf);
901
r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
902
r.param.path_number.operation = type;
903
r.param.path_number.filename = &buf;
904
r.param.path_number.number = number;
905
do {
906
tomoyo_check_acl(&r, tomoyo_check_path_number_acl);
907
error = tomoyo_audit_path_number_log(&r);
908
} while (error == TOMOYO_RETRY_REQUEST);
909
kfree(buf.name);
910
out:
911
tomoyo_read_unlock(idx);
912
if (r.mode != TOMOYO_CONFIG_ENFORCING)
913
error = 0;
914
return error;
915
}
916
917
/**
918
* tomoyo_check_open_permission - Check permission for "read" and "write".
919
*
920
* @domain: Pointer to "struct tomoyo_domain_info".
921
* @path: Pointer to "struct path".
922
* @flag: Flags for open().
923
*
924
* Returns 0 on success, negative value otherwise.
925
*/
926
int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
927
struct path *path, const int flag)
928
{
929
const u8 acc_mode = ACC_MODE(flag);
930
int error = 0;
931
struct tomoyo_path_info buf;
932
struct tomoyo_request_info r;
933
int idx;
934
935
if (!path->mnt ||
936
(path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)))
937
return 0;
938
buf.name = NULL;
939
r.mode = TOMOYO_CONFIG_DISABLED;
940
idx = tomoyo_read_lock();
941
/*
942
* If the filename is specified by "deny_rewrite" keyword,
943
* we need to check "allow_rewrite" permission when the filename is not
944
* opened for append mode or the filename is truncated at open time.
945
*/
946
if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND)
947
&& tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE)
948
!= TOMOYO_CONFIG_DISABLED) {
949
if (!tomoyo_get_realpath(&buf, path)) {
950
error = -ENOMEM;
951
goto out;
952
}
953
if (tomoyo_no_rewrite_file(&buf))
954
error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE,
955
&buf);
956
}
957
if (!error && acc_mode &&
958
tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
959
!= TOMOYO_CONFIG_DISABLED) {
960
u8 operation;
961
if (!buf.name && !tomoyo_get_realpath(&buf, path)) {
962
error = -ENOMEM;
963
goto out;
964
}
965
if (acc_mode == (MAY_READ | MAY_WRITE))
966
operation = TOMOYO_TYPE_READ_WRITE;
967
else if (acc_mode == MAY_READ)
968
operation = TOMOYO_TYPE_READ;
969
else
970
operation = TOMOYO_TYPE_WRITE;
971
error = tomoyo_path_permission(&r, operation, &buf);
972
}
973
out:
974
kfree(buf.name);
975
tomoyo_read_unlock(idx);
976
if (r.mode != TOMOYO_CONFIG_ENFORCING)
977
error = 0;
978
return error;
979
}
980
981
/**
982
* tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount".
983
*
984
* @operation: Type of operation.
985
* @path: Pointer to "struct path".
986
*
987
* Returns 0 on success, negative value otherwise.
988
*/
989
int tomoyo_path_perm(const u8 operation, struct path *path)
990
{
991
int error = -ENOMEM;
992
struct tomoyo_path_info buf;
993
struct tomoyo_request_info r;
994
int idx;
995
996
if (!path->mnt)
997
return 0;
998
if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
999
== TOMOYO_CONFIG_DISABLED)
1000
return 0;
1001
buf.name = NULL;
1002
idx = tomoyo_read_lock();
1003
if (!tomoyo_get_realpath(&buf, path))
1004
goto out;
1005
switch (operation) {
1006
case TOMOYO_TYPE_REWRITE:
1007
if (!tomoyo_no_rewrite_file(&buf)) {
1008
error = 0;
1009
goto out;
1010
}
1011
break;
1012
case TOMOYO_TYPE_RMDIR:
1013
case TOMOYO_TYPE_CHROOT:
1014
tomoyo_add_slash(&buf);
1015
break;
1016
}
1017
error = tomoyo_path_permission(&r, operation, &buf);
1018
out:
1019
kfree(buf.name);
1020
tomoyo_read_unlock(idx);
1021
if (r.mode != TOMOYO_CONFIG_ENFORCING)
1022
error = 0;
1023
return error;
1024
}
1025
1026
/**
1027
* tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".
1028
*
1029
* @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
1030
* @path: Pointer to "struct path".
1031
* @mode: Create mode.
1032
* @dev: Device number.
1033
*
1034
* Returns 0 on success, negative value otherwise.
1035
*/
1036
int tomoyo_mkdev_perm(const u8 operation, struct path *path,
1037
const unsigned int mode, unsigned int dev)
1038
{
1039
struct tomoyo_request_info r;
1040
int error = -ENOMEM;
1041
struct tomoyo_path_info buf;
1042
int idx;
1043
1044
if (!path->mnt ||
1045
tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
1046
== TOMOYO_CONFIG_DISABLED)
1047
return 0;
1048
idx = tomoyo_read_lock();
1049
error = -ENOMEM;
1050
if (tomoyo_get_realpath(&buf, path)) {
1051
dev = new_decode_dev(dev);
1052
r.param_type = TOMOYO_TYPE_MKDEV_ACL;
1053
r.param.mkdev.filename = &buf;
1054
r.param.mkdev.operation = operation;
1055
r.param.mkdev.mode = mode;
1056
r.param.mkdev.major = MAJOR(dev);
1057
r.param.mkdev.minor = MINOR(dev);
1058
tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
1059
error = tomoyo_audit_mkdev_log(&r);
1060
kfree(buf.name);
1061
}
1062
tomoyo_read_unlock(idx);
1063
if (r.mode != TOMOYO_CONFIG_ENFORCING)
1064
error = 0;
1065
return error;
1066
}
1067
1068
/**
1069
* tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root".
1070
*
1071
* @operation: Type of operation.
1072
* @path1: Pointer to "struct path".
1073
* @path2: Pointer to "struct path".
1074
*
1075
* Returns 0 on success, negative value otherwise.
1076
*/
1077
int tomoyo_path2_perm(const u8 operation, struct path *path1,
1078
struct path *path2)
1079
{
1080
int error = -ENOMEM;
1081
struct tomoyo_path_info buf1;
1082
struct tomoyo_path_info buf2;
1083
struct tomoyo_request_info r;
1084
int idx;
1085
1086
if (!path1->mnt || !path2->mnt ||
1087
tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
1088
== TOMOYO_CONFIG_DISABLED)
1089
return 0;
1090
buf1.name = NULL;
1091
buf2.name = NULL;
1092
idx = tomoyo_read_lock();
1093
if (!tomoyo_get_realpath(&buf1, path1) ||
1094
!tomoyo_get_realpath(&buf2, path2))
1095
goto out;
1096
switch (operation) {
1097
struct dentry *dentry;
1098
case TOMOYO_TYPE_RENAME:
1099
case TOMOYO_TYPE_LINK:
1100
dentry = path1->dentry;
1101
if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
1102
break;
1103
/* fall through */
1104
case TOMOYO_TYPE_PIVOT_ROOT:
1105
tomoyo_add_slash(&buf1);
1106
tomoyo_add_slash(&buf2);
1107
break;
1108
}
1109
r.param_type = TOMOYO_TYPE_PATH2_ACL;
1110
r.param.path2.operation = operation;
1111
r.param.path2.filename1 = &buf1;
1112
r.param.path2.filename2 = &buf2;
1113
do {
1114
tomoyo_check_acl(&r, tomoyo_check_path2_acl);
1115
error = tomoyo_audit_path2_log(&r);
1116
} while (error == TOMOYO_RETRY_REQUEST);
1117
out:
1118
kfree(buf1.name);
1119
kfree(buf2.name);
1120
tomoyo_read_unlock(idx);
1121
if (r.mode != TOMOYO_CONFIG_ENFORCING)
1122
error = 0;
1123
return error;
1124
}
1125
1126
/**
1127
* tomoyo_write_file - Update file related list.
1128
*
1129
* @data: String to parse.
1130
* @domain: Pointer to "struct tomoyo_domain_info".
1131
* @is_delete: True if it is a delete request.
1132
*
1133
* Returns 0 on success, negative value otherwise.
1134
*
1135
* Caller holds tomoyo_read_lock().
1136
*/
1137
int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
1138
const bool is_delete)
1139
{
1140
char *w[5];
1141
u8 type;
1142
if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
1143
return -EINVAL;
1144
if (strncmp(w[0], "allow_", 6))
1145
goto out;
1146
w[0] += 6;
1147
for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
1148
if (strcmp(w[0], tomoyo_path_keyword[type]))
1149
continue;
1150
return tomoyo_update_path_acl(type, w[1], domain, is_delete);
1151
}
1152
if (!w[2][0])
1153
goto out;
1154
for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
1155
if (strcmp(w[0], tomoyo_path2_keyword[type]))
1156
continue;
1157
return tomoyo_update_path2_acl(type, w[1], w[2], domain,
1158
is_delete);
1159
}
1160
for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) {
1161
if (strcmp(w[0], tomoyo_path_number_keyword[type]))
1162
continue;
1163
return tomoyo_update_path_number_acl(type, w[1], w[2], domain,
1164
is_delete);
1165
}
1166
if (!w[3][0] || !w[4][0])
1167
goto out;
1168
for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) {
1169
if (strcmp(w[0], tomoyo_mkdev_keyword[type]))
1170
continue;
1171
return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3],
1172
w[4], domain, is_delete);
1173
}
1174
out:
1175
return -EINVAL;
1176
}
1177
1178