Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/security/tomoyo/condition.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* security/tomoyo/condition.c
4
*
5
* Copyright (C) 2005-2011 NTT DATA CORPORATION
6
*/
7
8
#include "common.h"
9
#include <linux/slab.h>
10
11
/* List of "struct tomoyo_condition". */
12
LIST_HEAD(tomoyo_condition_list);
13
14
/**
15
* tomoyo_argv - Check argv[] in "struct linux_binbrm".
16
*
17
* @index: Index number of @arg_ptr.
18
* @arg_ptr: Contents of argv[@index].
19
* @argc: Length of @argv.
20
* @argv: Pointer to "struct tomoyo_argv".
21
* @checked: Set to true if @argv[@index] was found.
22
*
23
* Returns true on success, false otherwise.
24
*/
25
static bool tomoyo_argv(const unsigned int index, const char *arg_ptr,
26
const int argc, const struct tomoyo_argv *argv,
27
u8 *checked)
28
{
29
int i;
30
struct tomoyo_path_info arg;
31
32
arg.name = arg_ptr;
33
for (i = 0; i < argc; argv++, checked++, i++) {
34
bool result;
35
36
if (index != argv->index)
37
continue;
38
*checked = 1;
39
tomoyo_fill_path_info(&arg);
40
result = tomoyo_path_matches_pattern(&arg, argv->value);
41
if (argv->is_not)
42
result = !result;
43
if (!result)
44
return false;
45
}
46
return true;
47
}
48
49
/**
50
* tomoyo_envp - Check envp[] in "struct linux_binbrm".
51
*
52
* @env_name: The name of environment variable.
53
* @env_value: The value of environment variable.
54
* @envc: Length of @envp.
55
* @envp: Pointer to "struct tomoyo_envp".
56
* @checked: Set to true if @envp[@env_name] was found.
57
*
58
* Returns true on success, false otherwise.
59
*/
60
static bool tomoyo_envp(const char *env_name, const char *env_value,
61
const int envc, const struct tomoyo_envp *envp,
62
u8 *checked)
63
{
64
int i;
65
struct tomoyo_path_info name;
66
struct tomoyo_path_info value;
67
68
name.name = env_name;
69
tomoyo_fill_path_info(&name);
70
value.name = env_value;
71
tomoyo_fill_path_info(&value);
72
for (i = 0; i < envc; envp++, checked++, i++) {
73
bool result;
74
75
if (!tomoyo_path_matches_pattern(&name, envp->name))
76
continue;
77
*checked = 1;
78
if (envp->value) {
79
result = tomoyo_path_matches_pattern(&value,
80
envp->value);
81
if (envp->is_not)
82
result = !result;
83
} else {
84
result = true;
85
if (!envp->is_not)
86
result = !result;
87
}
88
if (!result)
89
return false;
90
}
91
return true;
92
}
93
94
/**
95
* tomoyo_scan_bprm - Scan "struct linux_binprm".
96
*
97
* @ee: Pointer to "struct tomoyo_execve".
98
* @argc: Length of @argc.
99
* @argv: Pointer to "struct tomoyo_argv".
100
* @envc: Length of @envp.
101
* @envp: Pointer to "struct tomoyo_envp".
102
*
103
* Returns true on success, false otherwise.
104
*/
105
static bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
106
const u16 argc, const struct tomoyo_argv *argv,
107
const u16 envc, const struct tomoyo_envp *envp)
108
{
109
struct linux_binprm *bprm = ee->bprm;
110
struct tomoyo_page_dump *dump = &ee->dump;
111
char *arg_ptr = ee->tmp;
112
int arg_len = 0;
113
unsigned long pos = bprm->p;
114
int offset = pos % PAGE_SIZE;
115
int argv_count = bprm->argc;
116
int envp_count = bprm->envc;
117
bool result = true;
118
u8 local_checked[32];
119
u8 *checked;
120
121
if (argc + envc <= sizeof(local_checked)) {
122
checked = local_checked;
123
memset(local_checked, 0, sizeof(local_checked));
124
} else {
125
checked = kzalloc(argc + envc, GFP_NOFS);
126
if (!checked)
127
return false;
128
}
129
while (argv_count || envp_count) {
130
if (!tomoyo_dump_page(bprm, pos, dump)) {
131
result = false;
132
goto out;
133
}
134
pos += PAGE_SIZE - offset;
135
while (offset < PAGE_SIZE) {
136
/* Read. */
137
const char *kaddr = dump->data;
138
const unsigned char c = kaddr[offset++];
139
140
if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
141
if (c == '\\') {
142
arg_ptr[arg_len++] = '\\';
143
arg_ptr[arg_len++] = '\\';
144
} else if (c > ' ' && c < 127) {
145
arg_ptr[arg_len++] = c;
146
} else {
147
arg_ptr[arg_len++] = '\\';
148
arg_ptr[arg_len++] = (c >> 6) + '0';
149
arg_ptr[arg_len++] =
150
((c >> 3) & 7) + '0';
151
arg_ptr[arg_len++] = (c & 7) + '0';
152
}
153
} else {
154
arg_ptr[arg_len] = '\0';
155
}
156
if (c)
157
continue;
158
/* Check. */
159
if (argv_count) {
160
if (!tomoyo_argv(bprm->argc - argv_count,
161
arg_ptr, argc, argv,
162
checked)) {
163
result = false;
164
break;
165
}
166
argv_count--;
167
} else if (envp_count) {
168
char *cp = strchr(arg_ptr, '=');
169
170
if (cp) {
171
*cp = '\0';
172
if (!tomoyo_envp(arg_ptr, cp + 1,
173
envc, envp,
174
checked + argc)) {
175
result = false;
176
break;
177
}
178
}
179
envp_count--;
180
} else {
181
break;
182
}
183
arg_len = 0;
184
}
185
offset = 0;
186
if (!result)
187
break;
188
}
189
out:
190
if (result) {
191
int i;
192
193
/* Check not-yet-checked entries. */
194
for (i = 0; i < argc; i++) {
195
if (checked[i])
196
continue;
197
/*
198
* Return true only if all unchecked indexes in
199
* bprm->argv[] are not matched.
200
*/
201
if (argv[i].is_not)
202
continue;
203
result = false;
204
break;
205
}
206
for (i = 0; i < envc; envp++, i++) {
207
if (checked[argc + i])
208
continue;
209
/*
210
* Return true only if all unchecked environ variables
211
* in bprm->envp[] are either undefined or not matched.
212
*/
213
if ((!envp->value && !envp->is_not) ||
214
(envp->value && envp->is_not))
215
continue;
216
result = false;
217
break;
218
}
219
}
220
if (checked != local_checked)
221
kfree(checked);
222
return result;
223
}
224
225
/**
226
* tomoyo_scan_exec_realpath - Check "exec.realpath" parameter of "struct tomoyo_condition".
227
*
228
* @file: Pointer to "struct file".
229
* @ptr: Pointer to "struct tomoyo_name_union".
230
* @match: True if "exec.realpath=", false if "exec.realpath!=".
231
*
232
* Returns true on success, false otherwise.
233
*/
234
static bool tomoyo_scan_exec_realpath(struct file *file,
235
const struct tomoyo_name_union *ptr,
236
const bool match)
237
{
238
bool result;
239
struct tomoyo_path_info exe;
240
241
if (!file)
242
return false;
243
exe.name = tomoyo_realpath_from_path(&file->f_path);
244
if (!exe.name)
245
return false;
246
tomoyo_fill_path_info(&exe);
247
result = tomoyo_compare_name_union(&exe, ptr);
248
kfree(exe.name);
249
return result == match;
250
}
251
252
/**
253
* tomoyo_get_dqword - tomoyo_get_name() for a quoted string.
254
*
255
* @start: String to save.
256
*
257
* Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
258
*/
259
static const struct tomoyo_path_info *tomoyo_get_dqword(char *start)
260
{
261
char *cp = start + strlen(start) - 1;
262
263
if (cp == start || *start++ != '"' || *cp != '"')
264
return NULL;
265
*cp = '\0';
266
if (*start && !tomoyo_correct_word(start))
267
return NULL;
268
return tomoyo_get_name(start);
269
}
270
271
/**
272
* tomoyo_parse_name_union_quoted - Parse a quoted word.
273
*
274
* @param: Pointer to "struct tomoyo_acl_param".
275
* @ptr: Pointer to "struct tomoyo_name_union".
276
*
277
* Returns true on success, false otherwise.
278
*/
279
static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param,
280
struct tomoyo_name_union *ptr)
281
{
282
char *filename = param->data;
283
284
if (*filename == '@')
285
return tomoyo_parse_name_union(param, ptr);
286
ptr->filename = tomoyo_get_dqword(filename);
287
return ptr->filename != NULL;
288
}
289
290
/**
291
* tomoyo_parse_argv - Parse an argv[] condition part.
292
*
293
* @left: Lefthand value.
294
* @right: Righthand value.
295
* @argv: Pointer to "struct tomoyo_argv".
296
*
297
* Returns true on success, false otherwise.
298
*/
299
static bool tomoyo_parse_argv(char *left, char *right,
300
struct tomoyo_argv *argv)
301
{
302
if (tomoyo_parse_ulong(&argv->index, &left) !=
303
TOMOYO_VALUE_TYPE_DECIMAL || *left++ != ']' || *left)
304
return false;
305
argv->value = tomoyo_get_dqword(right);
306
return argv->value != NULL;
307
}
308
309
/**
310
* tomoyo_parse_envp - Parse an envp[] condition part.
311
*
312
* @left: Lefthand value.
313
* @right: Righthand value.
314
* @envp: Pointer to "struct tomoyo_envp".
315
*
316
* Returns true on success, false otherwise.
317
*/
318
static bool tomoyo_parse_envp(char *left, char *right,
319
struct tomoyo_envp *envp)
320
{
321
const struct tomoyo_path_info *name;
322
const struct tomoyo_path_info *value;
323
char *cp = left + strlen(left) - 1;
324
325
if (*cp-- != ']' || *cp != '"')
326
goto out;
327
*cp = '\0';
328
if (!tomoyo_correct_word(left))
329
goto out;
330
name = tomoyo_get_name(left);
331
if (!name)
332
goto out;
333
if (!strcmp(right, "NULL")) {
334
value = NULL;
335
} else {
336
value = tomoyo_get_dqword(right);
337
if (!value) {
338
tomoyo_put_name(name);
339
goto out;
340
}
341
}
342
envp->name = name;
343
envp->value = value;
344
return true;
345
out:
346
return false;
347
}
348
349
/**
350
* tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry.
351
*
352
* @a: Pointer to "struct tomoyo_condition".
353
* @b: Pointer to "struct tomoyo_condition".
354
*
355
* Returns true if @a == @b, false otherwise.
356
*/
357
static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
358
const struct tomoyo_condition *b)
359
{
360
return a->size == b->size && a->condc == b->condc &&
361
a->numbers_count == b->numbers_count &&
362
a->names_count == b->names_count &&
363
a->argc == b->argc && a->envc == b->envc &&
364
a->grant_log == b->grant_log && a->transit == b->transit &&
365
!memcmp(a + 1, b + 1, a->size - sizeof(*a));
366
}
367
368
/**
369
* tomoyo_condition_type - Get condition type.
370
*
371
* @word: Keyword string.
372
*
373
* Returns one of values in "enum tomoyo_conditions_index" on success,
374
* TOMOYO_MAX_CONDITION_KEYWORD otherwise.
375
*/
376
static u8 tomoyo_condition_type(const char *word)
377
{
378
u8 i;
379
380
for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) {
381
if (!strcmp(word, tomoyo_condition_keyword[i]))
382
break;
383
}
384
return i;
385
}
386
387
/* Define this to enable debug mode. */
388
/* #define DEBUG_CONDITION */
389
390
#ifdef DEBUG_CONDITION
391
#define dprintk printk
392
#else
393
#define dprintk(...) do { } while (0)
394
#endif
395
396
/**
397
* tomoyo_commit_condition - Commit "struct tomoyo_condition".
398
*
399
* @entry: Pointer to "struct tomoyo_condition".
400
*
401
* Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
402
*
403
* This function merges duplicated entries. This function returns NULL if
404
* @entry is not duplicated but memory quota for policy has exceeded.
405
*/
406
static struct tomoyo_condition *tomoyo_commit_condition
407
(struct tomoyo_condition *entry)
408
{
409
struct tomoyo_condition *ptr;
410
bool found = false;
411
412
if (mutex_lock_interruptible(&tomoyo_policy_lock)) {
413
dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
414
ptr = NULL;
415
found = true;
416
goto out;
417
}
418
list_for_each_entry(ptr, &tomoyo_condition_list, head.list) {
419
if (!tomoyo_same_condition(ptr, entry) ||
420
atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS)
421
continue;
422
/* Same entry found. Share this entry. */
423
atomic_inc(&ptr->head.users);
424
found = true;
425
break;
426
}
427
if (!found) {
428
if (tomoyo_memory_ok(entry)) {
429
atomic_set(&entry->head.users, 1);
430
list_add(&entry->head.list, &tomoyo_condition_list);
431
} else {
432
found = true;
433
ptr = NULL;
434
}
435
}
436
mutex_unlock(&tomoyo_policy_lock);
437
out:
438
if (found) {
439
tomoyo_del_condition(&entry->head.list);
440
kfree(entry);
441
entry = ptr;
442
}
443
return entry;
444
}
445
446
/**
447
* tomoyo_get_transit_preference - Parse domain transition preference for execve().
448
*
449
* @param: Pointer to "struct tomoyo_acl_param".
450
* @e: Pointer to "struct tomoyo_condition".
451
*
452
* Returns the condition string part.
453
*/
454
static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param,
455
struct tomoyo_condition *e)
456
{
457
char * const pos = param->data;
458
bool flag;
459
460
if (*pos == '<') {
461
e->transit = tomoyo_get_domainname(param);
462
goto done;
463
}
464
{
465
char *cp = strchr(pos, ' ');
466
467
if (cp)
468
*cp = '\0';
469
flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") ||
470
!strcmp(pos, "initialize") || !strcmp(pos, "reset") ||
471
!strcmp(pos, "child") || !strcmp(pos, "parent");
472
if (cp)
473
*cp = ' ';
474
}
475
if (!flag)
476
return pos;
477
e->transit = tomoyo_get_name(tomoyo_read_token(param));
478
done:
479
if (e->transit)
480
return param->data;
481
/*
482
* Return a bad read-only condition string that will let
483
* tomoyo_get_condition() return NULL.
484
*/
485
return "/";
486
}
487
488
/**
489
* tomoyo_get_condition - Parse condition part.
490
*
491
* @param: Pointer to "struct tomoyo_acl_param".
492
*
493
* Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
494
*/
495
struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
496
{
497
struct tomoyo_condition *entry = NULL;
498
struct tomoyo_condition_element *condp = NULL;
499
struct tomoyo_number_union *numbers_p = NULL;
500
struct tomoyo_name_union *names_p = NULL;
501
struct tomoyo_argv *argv = NULL;
502
struct tomoyo_envp *envp = NULL;
503
struct tomoyo_condition e = { };
504
char * const start_of_string =
505
tomoyo_get_transit_preference(param, &e);
506
char * const end_of_string = start_of_string + strlen(start_of_string);
507
char *pos;
508
509
rerun:
510
pos = start_of_string;
511
while (1) {
512
u8 left = -1;
513
u8 right = -1;
514
char *left_word = pos;
515
char *cp;
516
char *right_word;
517
bool is_not;
518
519
if (!*left_word)
520
break;
521
/*
522
* Since left-hand condition does not allow use of "path_group"
523
* or "number_group" and environment variable's names do not
524
* accept '=', it is guaranteed that the original line consists
525
* of one or more repetition of $left$operator$right blocks
526
* where "$left is free from '=' and ' '" and "$operator is
527
* either '=' or '!='" and "$right is free from ' '".
528
* Therefore, we can reconstruct the original line at the end
529
* of dry run even if we overwrite $operator with '\0'.
530
*/
531
cp = strchr(pos, ' ');
532
if (cp) {
533
*cp = '\0'; /* Will restore later. */
534
pos = cp + 1;
535
} else {
536
pos = "";
537
}
538
right_word = strchr(left_word, '=');
539
if (!right_word || right_word == left_word)
540
goto out;
541
is_not = *(right_word - 1) == '!';
542
if (is_not)
543
*(right_word++ - 1) = '\0'; /* Will restore later. */
544
else if (*(right_word + 1) != '=')
545
*right_word++ = '\0'; /* Will restore later. */
546
else
547
goto out;
548
dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
549
is_not ? "!" : "", right_word);
550
if (!strcmp(left_word, "grant_log")) {
551
if (entry) {
552
if (is_not ||
553
entry->grant_log != TOMOYO_GRANTLOG_AUTO)
554
goto out;
555
else if (!strcmp(right_word, "yes"))
556
entry->grant_log = TOMOYO_GRANTLOG_YES;
557
else if (!strcmp(right_word, "no"))
558
entry->grant_log = TOMOYO_GRANTLOG_NO;
559
else
560
goto out;
561
}
562
continue;
563
}
564
if (!strncmp(left_word, "exec.argv[", 10)) {
565
if (!argv) {
566
e.argc++;
567
e.condc++;
568
} else {
569
e.argc--;
570
e.condc--;
571
left = TOMOYO_ARGV_ENTRY;
572
argv->is_not = is_not;
573
if (!tomoyo_parse_argv(left_word + 10,
574
right_word, argv++))
575
goto out;
576
}
577
goto store_value;
578
}
579
if (!strncmp(left_word, "exec.envp[\"", 11)) {
580
if (!envp) {
581
e.envc++;
582
e.condc++;
583
} else {
584
e.envc--;
585
e.condc--;
586
left = TOMOYO_ENVP_ENTRY;
587
envp->is_not = is_not;
588
if (!tomoyo_parse_envp(left_word + 11,
589
right_word, envp++))
590
goto out;
591
}
592
goto store_value;
593
}
594
left = tomoyo_condition_type(left_word);
595
dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
596
left);
597
if (left == TOMOYO_MAX_CONDITION_KEYWORD) {
598
if (!numbers_p) {
599
e.numbers_count++;
600
} else {
601
e.numbers_count--;
602
left = TOMOYO_NUMBER_UNION;
603
param->data = left_word;
604
if (*left_word == '@' ||
605
!tomoyo_parse_number_union(param,
606
numbers_p++))
607
goto out;
608
}
609
}
610
if (!condp)
611
e.condc++;
612
else
613
e.condc--;
614
if (left == TOMOYO_EXEC_REALPATH ||
615
left == TOMOYO_SYMLINK_TARGET) {
616
if (!names_p) {
617
e.names_count++;
618
} else {
619
e.names_count--;
620
right = TOMOYO_NAME_UNION;
621
param->data = right_word;
622
if (!tomoyo_parse_name_union_quoted(param,
623
names_p++))
624
goto out;
625
}
626
goto store_value;
627
}
628
right = tomoyo_condition_type(right_word);
629
if (right == TOMOYO_MAX_CONDITION_KEYWORD) {
630
if (!numbers_p) {
631
e.numbers_count++;
632
} else {
633
e.numbers_count--;
634
right = TOMOYO_NUMBER_UNION;
635
param->data = right_word;
636
if (!tomoyo_parse_number_union(param,
637
numbers_p++))
638
goto out;
639
}
640
}
641
store_value:
642
if (!condp) {
643
dprintk(KERN_WARNING "%u: dry_run left=%u right=%u match=%u\n",
644
__LINE__, left, right, !is_not);
645
continue;
646
}
647
condp->left = left;
648
condp->right = right;
649
condp->equals = !is_not;
650
dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
651
__LINE__, condp->left, condp->right,
652
condp->equals);
653
condp++;
654
}
655
dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n",
656
__LINE__, e.condc, e.numbers_count, e.names_count, e.argc,
657
e.envc);
658
if (entry) {
659
BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc |
660
e.condc);
661
return tomoyo_commit_condition(entry);
662
}
663
e.size = sizeof(*entry)
664
+ e.condc * sizeof(struct tomoyo_condition_element)
665
+ e.numbers_count * sizeof(struct tomoyo_number_union)
666
+ e.names_count * sizeof(struct tomoyo_name_union)
667
+ e.argc * sizeof(struct tomoyo_argv)
668
+ e.envc * sizeof(struct tomoyo_envp);
669
entry = kzalloc(e.size, GFP_NOFS);
670
if (!entry)
671
goto out2;
672
*entry = e;
673
e.transit = NULL;
674
condp = (struct tomoyo_condition_element *) (entry + 1);
675
numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
676
names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count);
677
argv = (struct tomoyo_argv *) (names_p + e.names_count);
678
envp = (struct tomoyo_envp *) (argv + e.argc);
679
{
680
bool flag = false;
681
682
for (pos = start_of_string; pos < end_of_string; pos++) {
683
if (*pos)
684
continue;
685
if (flag) /* Restore " ". */
686
*pos = ' ';
687
else if (*(pos + 1) == '=') /* Restore "!=". */
688
*pos = '!';
689
else /* Restore "=". */
690
*pos = '=';
691
flag = !flag;
692
}
693
}
694
goto rerun;
695
out:
696
dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
697
if (entry) {
698
tomoyo_del_condition(&entry->head.list);
699
kfree(entry);
700
}
701
out2:
702
tomoyo_put_name(e.transit);
703
return NULL;
704
}
705
706
/**
707
* tomoyo_get_attributes - Revalidate "struct inode".
708
*
709
* @obj: Pointer to "struct tomoyo_obj_info".
710
*
711
* Returns nothing.
712
*/
713
void tomoyo_get_attributes(struct tomoyo_obj_info *obj)
714
{
715
u8 i;
716
struct dentry *dentry = NULL;
717
718
for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
719
struct inode *inode;
720
721
switch (i) {
722
case TOMOYO_PATH1:
723
dentry = obj->path1.dentry;
724
if (!dentry)
725
continue;
726
break;
727
case TOMOYO_PATH2:
728
dentry = obj->path2.dentry;
729
if (!dentry)
730
continue;
731
break;
732
default:
733
if (!dentry)
734
continue;
735
dentry = dget_parent(dentry);
736
break;
737
}
738
inode = d_backing_inode(dentry);
739
if (inode) {
740
struct tomoyo_mini_stat *stat = &obj->stat[i];
741
742
stat->uid = inode->i_uid;
743
stat->gid = inode->i_gid;
744
stat->ino = inode->i_ino;
745
stat->mode = inode->i_mode;
746
stat->dev = inode->i_sb->s_dev;
747
stat->rdev = inode->i_rdev;
748
obj->stat_valid[i] = true;
749
}
750
if (i & 1) /* TOMOYO_PATH1_PARENT or TOMOYO_PATH2_PARENT */
751
dput(dentry);
752
}
753
}
754
755
/**
756
* tomoyo_condition - Check condition part.
757
*
758
* @r: Pointer to "struct tomoyo_request_info".
759
* @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
760
*
761
* Returns true on success, false otherwise.
762
*
763
* Caller holds tomoyo_read_lock().
764
*/
765
bool tomoyo_condition(struct tomoyo_request_info *r,
766
const struct tomoyo_condition *cond)
767
{
768
u32 i;
769
unsigned long min_v[2] = { 0, 0 };
770
unsigned long max_v[2] = { 0, 0 };
771
const struct tomoyo_condition_element *condp;
772
const struct tomoyo_number_union *numbers_p;
773
const struct tomoyo_name_union *names_p;
774
const struct tomoyo_argv *argv;
775
const struct tomoyo_envp *envp;
776
struct tomoyo_obj_info *obj;
777
u16 condc;
778
u16 argc;
779
u16 envc;
780
struct linux_binprm *bprm = NULL;
781
782
if (!cond)
783
return true;
784
condc = cond->condc;
785
argc = cond->argc;
786
envc = cond->envc;
787
obj = r->obj;
788
if (r->ee)
789
bprm = r->ee->bprm;
790
if (!bprm && (argc || envc))
791
return false;
792
condp = (struct tomoyo_condition_element *) (cond + 1);
793
numbers_p = (const struct tomoyo_number_union *) (condp + condc);
794
names_p = (const struct tomoyo_name_union *)
795
(numbers_p + cond->numbers_count);
796
argv = (const struct tomoyo_argv *) (names_p + cond->names_count);
797
envp = (const struct tomoyo_envp *) (argv + argc);
798
for (i = 0; i < condc; i++) {
799
const bool match = condp->equals;
800
const u8 left = condp->left;
801
const u8 right = condp->right;
802
bool is_bitop[2] = { false, false };
803
u8 j;
804
805
condp++;
806
/* Check argv[] and envp[] later. */
807
if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY)
808
continue;
809
/* Check string expressions. */
810
if (right == TOMOYO_NAME_UNION) {
811
const struct tomoyo_name_union *ptr = names_p++;
812
struct tomoyo_path_info *symlink;
813
struct tomoyo_execve *ee;
814
struct file *file;
815
816
switch (left) {
817
case TOMOYO_SYMLINK_TARGET:
818
symlink = obj ? obj->symlink_target : NULL;
819
if (!symlink ||
820
!tomoyo_compare_name_union(symlink, ptr)
821
== match)
822
goto out;
823
break;
824
case TOMOYO_EXEC_REALPATH:
825
ee = r->ee;
826
file = ee ? ee->bprm->file : NULL;
827
if (!tomoyo_scan_exec_realpath(file, ptr,
828
match))
829
goto out;
830
break;
831
}
832
continue;
833
}
834
/* Check numeric or bit-op expressions. */
835
for (j = 0; j < 2; j++) {
836
const u8 index = j ? right : left;
837
unsigned long value = 0;
838
839
switch (index) {
840
case TOMOYO_TASK_UID:
841
value = from_kuid(&init_user_ns, current_uid());
842
break;
843
case TOMOYO_TASK_EUID:
844
value = from_kuid(&init_user_ns, current_euid());
845
break;
846
case TOMOYO_TASK_SUID:
847
value = from_kuid(&init_user_ns, current_suid());
848
break;
849
case TOMOYO_TASK_FSUID:
850
value = from_kuid(&init_user_ns, current_fsuid());
851
break;
852
case TOMOYO_TASK_GID:
853
value = from_kgid(&init_user_ns, current_gid());
854
break;
855
case TOMOYO_TASK_EGID:
856
value = from_kgid(&init_user_ns, current_egid());
857
break;
858
case TOMOYO_TASK_SGID:
859
value = from_kgid(&init_user_ns, current_sgid());
860
break;
861
case TOMOYO_TASK_FSGID:
862
value = from_kgid(&init_user_ns, current_fsgid());
863
break;
864
case TOMOYO_TASK_PID:
865
value = tomoyo_sys_getpid();
866
break;
867
case TOMOYO_TASK_PPID:
868
value = tomoyo_sys_getppid();
869
break;
870
case TOMOYO_TYPE_IS_SOCKET:
871
value = S_IFSOCK;
872
break;
873
case TOMOYO_TYPE_IS_SYMLINK:
874
value = S_IFLNK;
875
break;
876
case TOMOYO_TYPE_IS_FILE:
877
value = S_IFREG;
878
break;
879
case TOMOYO_TYPE_IS_BLOCK_DEV:
880
value = S_IFBLK;
881
break;
882
case TOMOYO_TYPE_IS_DIRECTORY:
883
value = S_IFDIR;
884
break;
885
case TOMOYO_TYPE_IS_CHAR_DEV:
886
value = S_IFCHR;
887
break;
888
case TOMOYO_TYPE_IS_FIFO:
889
value = S_IFIFO;
890
break;
891
case TOMOYO_MODE_SETUID:
892
value = S_ISUID;
893
break;
894
case TOMOYO_MODE_SETGID:
895
value = S_ISGID;
896
break;
897
case TOMOYO_MODE_STICKY:
898
value = S_ISVTX;
899
break;
900
case TOMOYO_MODE_OWNER_READ:
901
value = 0400;
902
break;
903
case TOMOYO_MODE_OWNER_WRITE:
904
value = 0200;
905
break;
906
case TOMOYO_MODE_OWNER_EXECUTE:
907
value = 0100;
908
break;
909
case TOMOYO_MODE_GROUP_READ:
910
value = 0040;
911
break;
912
case TOMOYO_MODE_GROUP_WRITE:
913
value = 0020;
914
break;
915
case TOMOYO_MODE_GROUP_EXECUTE:
916
value = 0010;
917
break;
918
case TOMOYO_MODE_OTHERS_READ:
919
value = 0004;
920
break;
921
case TOMOYO_MODE_OTHERS_WRITE:
922
value = 0002;
923
break;
924
case TOMOYO_MODE_OTHERS_EXECUTE:
925
value = 0001;
926
break;
927
case TOMOYO_EXEC_ARGC:
928
if (!bprm)
929
goto out;
930
value = bprm->argc;
931
break;
932
case TOMOYO_EXEC_ENVC:
933
if (!bprm)
934
goto out;
935
value = bprm->envc;
936
break;
937
case TOMOYO_NUMBER_UNION:
938
/* Fetch values later. */
939
break;
940
default:
941
if (!obj)
942
goto out;
943
if (!obj->validate_done) {
944
tomoyo_get_attributes(obj);
945
obj->validate_done = true;
946
}
947
{
948
u8 stat_index;
949
struct tomoyo_mini_stat *stat;
950
951
switch (index) {
952
case TOMOYO_PATH1_UID:
953
case TOMOYO_PATH1_GID:
954
case TOMOYO_PATH1_INO:
955
case TOMOYO_PATH1_MAJOR:
956
case TOMOYO_PATH1_MINOR:
957
case TOMOYO_PATH1_TYPE:
958
case TOMOYO_PATH1_DEV_MAJOR:
959
case TOMOYO_PATH1_DEV_MINOR:
960
case TOMOYO_PATH1_PERM:
961
stat_index = TOMOYO_PATH1;
962
break;
963
case TOMOYO_PATH2_UID:
964
case TOMOYO_PATH2_GID:
965
case TOMOYO_PATH2_INO:
966
case TOMOYO_PATH2_MAJOR:
967
case TOMOYO_PATH2_MINOR:
968
case TOMOYO_PATH2_TYPE:
969
case TOMOYO_PATH2_DEV_MAJOR:
970
case TOMOYO_PATH2_DEV_MINOR:
971
case TOMOYO_PATH2_PERM:
972
stat_index = TOMOYO_PATH2;
973
break;
974
case TOMOYO_PATH1_PARENT_UID:
975
case TOMOYO_PATH1_PARENT_GID:
976
case TOMOYO_PATH1_PARENT_INO:
977
case TOMOYO_PATH1_PARENT_PERM:
978
stat_index =
979
TOMOYO_PATH1_PARENT;
980
break;
981
case TOMOYO_PATH2_PARENT_UID:
982
case TOMOYO_PATH2_PARENT_GID:
983
case TOMOYO_PATH2_PARENT_INO:
984
case TOMOYO_PATH2_PARENT_PERM:
985
stat_index =
986
TOMOYO_PATH2_PARENT;
987
break;
988
default:
989
goto out;
990
}
991
if (!obj->stat_valid[stat_index])
992
goto out;
993
stat = &obj->stat[stat_index];
994
switch (index) {
995
case TOMOYO_PATH1_UID:
996
case TOMOYO_PATH2_UID:
997
case TOMOYO_PATH1_PARENT_UID:
998
case TOMOYO_PATH2_PARENT_UID:
999
value = from_kuid(&init_user_ns, stat->uid);
1000
break;
1001
case TOMOYO_PATH1_GID:
1002
case TOMOYO_PATH2_GID:
1003
case TOMOYO_PATH1_PARENT_GID:
1004
case TOMOYO_PATH2_PARENT_GID:
1005
value = from_kgid(&init_user_ns, stat->gid);
1006
break;
1007
case TOMOYO_PATH1_INO:
1008
case TOMOYO_PATH2_INO:
1009
case TOMOYO_PATH1_PARENT_INO:
1010
case TOMOYO_PATH2_PARENT_INO:
1011
value = stat->ino;
1012
break;
1013
case TOMOYO_PATH1_MAJOR:
1014
case TOMOYO_PATH2_MAJOR:
1015
value = MAJOR(stat->dev);
1016
break;
1017
case TOMOYO_PATH1_MINOR:
1018
case TOMOYO_PATH2_MINOR:
1019
value = MINOR(stat->dev);
1020
break;
1021
case TOMOYO_PATH1_TYPE:
1022
case TOMOYO_PATH2_TYPE:
1023
value = stat->mode & S_IFMT;
1024
break;
1025
case TOMOYO_PATH1_DEV_MAJOR:
1026
case TOMOYO_PATH2_DEV_MAJOR:
1027
value = MAJOR(stat->rdev);
1028
break;
1029
case TOMOYO_PATH1_DEV_MINOR:
1030
case TOMOYO_PATH2_DEV_MINOR:
1031
value = MINOR(stat->rdev);
1032
break;
1033
case TOMOYO_PATH1_PERM:
1034
case TOMOYO_PATH2_PERM:
1035
case TOMOYO_PATH1_PARENT_PERM:
1036
case TOMOYO_PATH2_PARENT_PERM:
1037
value = stat->mode & S_IALLUGO;
1038
break;
1039
}
1040
}
1041
break;
1042
}
1043
max_v[j] = value;
1044
min_v[j] = value;
1045
switch (index) {
1046
case TOMOYO_MODE_SETUID:
1047
case TOMOYO_MODE_SETGID:
1048
case TOMOYO_MODE_STICKY:
1049
case TOMOYO_MODE_OWNER_READ:
1050
case TOMOYO_MODE_OWNER_WRITE:
1051
case TOMOYO_MODE_OWNER_EXECUTE:
1052
case TOMOYO_MODE_GROUP_READ:
1053
case TOMOYO_MODE_GROUP_WRITE:
1054
case TOMOYO_MODE_GROUP_EXECUTE:
1055
case TOMOYO_MODE_OTHERS_READ:
1056
case TOMOYO_MODE_OTHERS_WRITE:
1057
case TOMOYO_MODE_OTHERS_EXECUTE:
1058
is_bitop[j] = true;
1059
}
1060
}
1061
if (left == TOMOYO_NUMBER_UNION) {
1062
/* Fetch values now. */
1063
const struct tomoyo_number_union *ptr = numbers_p++;
1064
1065
min_v[0] = ptr->values[0];
1066
max_v[0] = ptr->values[1];
1067
}
1068
if (right == TOMOYO_NUMBER_UNION) {
1069
/* Fetch values now. */
1070
const struct tomoyo_number_union *ptr = numbers_p++;
1071
1072
if (ptr->group) {
1073
if (tomoyo_number_matches_group(min_v[0],
1074
max_v[0],
1075
ptr->group)
1076
== match)
1077
continue;
1078
} else {
1079
if ((min_v[0] <= ptr->values[1] &&
1080
max_v[0] >= ptr->values[0]) == match)
1081
continue;
1082
}
1083
goto out;
1084
}
1085
/*
1086
* Bit operation is valid only when counterpart value
1087
* represents permission.
1088
*/
1089
if (is_bitop[0] && is_bitop[1]) {
1090
goto out;
1091
} else if (is_bitop[0]) {
1092
switch (right) {
1093
case TOMOYO_PATH1_PERM:
1094
case TOMOYO_PATH1_PARENT_PERM:
1095
case TOMOYO_PATH2_PERM:
1096
case TOMOYO_PATH2_PARENT_PERM:
1097
if (!(max_v[0] & max_v[1]) == !match)
1098
continue;
1099
}
1100
goto out;
1101
} else if (is_bitop[1]) {
1102
switch (left) {
1103
case TOMOYO_PATH1_PERM:
1104
case TOMOYO_PATH1_PARENT_PERM:
1105
case TOMOYO_PATH2_PERM:
1106
case TOMOYO_PATH2_PARENT_PERM:
1107
if (!(max_v[0] & max_v[1]) == !match)
1108
continue;
1109
}
1110
goto out;
1111
}
1112
/* Normal value range comparison. */
1113
if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
1114
continue;
1115
out:
1116
return false;
1117
}
1118
/* Check argv[] and envp[] now. */
1119
if (r->ee && (argc || envc))
1120
return tomoyo_scan_bprm(r->ee, argc, argv, envc, envp);
1121
return true;
1122
}
1123
1124