Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/security/tomoyo/util.c
10814 views
1
/*
2
* security/tomoyo/util.c
3
*
4
* Utility functions for TOMOYO.
5
*
6
* Copyright (C) 2005-2010 NTT DATA CORPORATION
7
*/
8
9
#include <linux/slab.h>
10
#include "common.h"
11
12
/* Lock for protecting policy. */
13
DEFINE_MUTEX(tomoyo_policy_lock);
14
15
/* Has /sbin/init started? */
16
bool tomoyo_policy_loaded;
17
18
/**
19
* tomoyo_parse_ulong - Parse an "unsigned long" value.
20
*
21
* @result: Pointer to "unsigned long".
22
* @str: Pointer to string to parse.
23
*
24
* Returns value type on success, 0 otherwise.
25
*
26
* The @src is updated to point the first character after the value
27
* on success.
28
*/
29
static u8 tomoyo_parse_ulong(unsigned long *result, char **str)
30
{
31
const char *cp = *str;
32
char *ep;
33
int base = 10;
34
if (*cp == '0') {
35
char c = *(cp + 1);
36
if (c == 'x' || c == 'X') {
37
base = 16;
38
cp += 2;
39
} else if (c >= '0' && c <= '7') {
40
base = 8;
41
cp++;
42
}
43
}
44
*result = simple_strtoul(cp, &ep, base);
45
if (cp == ep)
46
return 0;
47
*str = ep;
48
switch (base) {
49
case 16:
50
return TOMOYO_VALUE_TYPE_HEXADECIMAL;
51
case 8:
52
return TOMOYO_VALUE_TYPE_OCTAL;
53
default:
54
return TOMOYO_VALUE_TYPE_DECIMAL;
55
}
56
}
57
58
/**
59
* tomoyo_print_ulong - Print an "unsigned long" value.
60
*
61
* @buffer: Pointer to buffer.
62
* @buffer_len: Size of @buffer.
63
* @value: An "unsigned long" value.
64
* @type: Type of @value.
65
*
66
* Returns nothing.
67
*/
68
void tomoyo_print_ulong(char *buffer, const int buffer_len,
69
const unsigned long value, const u8 type)
70
{
71
if (type == TOMOYO_VALUE_TYPE_DECIMAL)
72
snprintf(buffer, buffer_len, "%lu", value);
73
else if (type == TOMOYO_VALUE_TYPE_OCTAL)
74
snprintf(buffer, buffer_len, "0%lo", value);
75
else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL)
76
snprintf(buffer, buffer_len, "0x%lX", value);
77
else
78
snprintf(buffer, buffer_len, "type(%u)", type);
79
}
80
81
/**
82
* tomoyo_parse_name_union - Parse a tomoyo_name_union.
83
*
84
* @filename: Name or name group.
85
* @ptr: Pointer to "struct tomoyo_name_union".
86
*
87
* Returns true on success, false otherwise.
88
*/
89
bool tomoyo_parse_name_union(const char *filename,
90
struct tomoyo_name_union *ptr)
91
{
92
if (!tomoyo_correct_word(filename))
93
return false;
94
if (filename[0] == '@') {
95
ptr->group = tomoyo_get_group(filename + 1, TOMOYO_PATH_GROUP);
96
ptr->is_group = true;
97
return ptr->group != NULL;
98
}
99
ptr->filename = tomoyo_get_name(filename);
100
ptr->is_group = false;
101
return ptr->filename != NULL;
102
}
103
104
/**
105
* tomoyo_parse_number_union - Parse a tomoyo_number_union.
106
*
107
* @data: Number or number range or number group.
108
* @ptr: Pointer to "struct tomoyo_number_union".
109
*
110
* Returns true on success, false otherwise.
111
*/
112
bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num)
113
{
114
u8 type;
115
unsigned long v;
116
memset(num, 0, sizeof(*num));
117
if (data[0] == '@') {
118
if (!tomoyo_correct_word(data))
119
return false;
120
num->group = tomoyo_get_group(data + 1, TOMOYO_NUMBER_GROUP);
121
num->is_group = true;
122
return num->group != NULL;
123
}
124
type = tomoyo_parse_ulong(&v, &data);
125
if (!type)
126
return false;
127
num->values[0] = v;
128
num->min_type = type;
129
if (!*data) {
130
num->values[1] = v;
131
num->max_type = type;
132
return true;
133
}
134
if (*data++ != '-')
135
return false;
136
type = tomoyo_parse_ulong(&v, &data);
137
if (!type || *data)
138
return false;
139
num->values[1] = v;
140
num->max_type = type;
141
return true;
142
}
143
144
/**
145
* tomoyo_byte_range - Check whether the string is a \ooo style octal value.
146
*
147
* @str: Pointer to the string.
148
*
149
* Returns true if @str is a \ooo style octal value, false otherwise.
150
*
151
* TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
152
* This function verifies that \ooo is in valid range.
153
*/
154
static inline bool tomoyo_byte_range(const char *str)
155
{
156
return *str >= '0' && *str++ <= '3' &&
157
*str >= '0' && *str++ <= '7' &&
158
*str >= '0' && *str <= '7';
159
}
160
161
/**
162
* tomoyo_alphabet_char - Check whether the character is an alphabet.
163
*
164
* @c: The character to check.
165
*
166
* Returns true if @c is an alphabet character, false otherwise.
167
*/
168
static inline bool tomoyo_alphabet_char(const char c)
169
{
170
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
171
}
172
173
/**
174
* tomoyo_make_byte - Make byte value from three octal characters.
175
*
176
* @c1: The first character.
177
* @c2: The second character.
178
* @c3: The third character.
179
*
180
* Returns byte value.
181
*/
182
static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
183
{
184
return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
185
}
186
187
/**
188
* tomoyo_str_starts - Check whether the given string starts with the given keyword.
189
*
190
* @src: Pointer to pointer to the string.
191
* @find: Pointer to the keyword.
192
*
193
* Returns true if @src starts with @find, false otherwise.
194
*
195
* The @src is updated to point the first character after the @find
196
* if @src starts with @find.
197
*/
198
bool tomoyo_str_starts(char **src, const char *find)
199
{
200
const int len = strlen(find);
201
char *tmp = *src;
202
203
if (strncmp(tmp, find, len))
204
return false;
205
tmp += len;
206
*src = tmp;
207
return true;
208
}
209
210
/**
211
* tomoyo_normalize_line - Format string.
212
*
213
* @buffer: The line to normalize.
214
*
215
* Leading and trailing whitespaces are removed.
216
* Multiple whitespaces are packed into single space.
217
*
218
* Returns nothing.
219
*/
220
void tomoyo_normalize_line(unsigned char *buffer)
221
{
222
unsigned char *sp = buffer;
223
unsigned char *dp = buffer;
224
bool first = true;
225
226
while (tomoyo_invalid(*sp))
227
sp++;
228
while (*sp) {
229
if (!first)
230
*dp++ = ' ';
231
first = false;
232
while (tomoyo_valid(*sp))
233
*dp++ = *sp++;
234
while (tomoyo_invalid(*sp))
235
sp++;
236
}
237
*dp = '\0';
238
}
239
240
/**
241
* tomoyo_tokenize - Tokenize string.
242
*
243
* @buffer: The line to tokenize.
244
* @w: Pointer to "char *".
245
* @size: Sizeof @w .
246
*
247
* Returns true on success, false otherwise.
248
*/
249
bool tomoyo_tokenize(char *buffer, char *w[], size_t size)
250
{
251
int count = size / sizeof(char *);
252
int i;
253
for (i = 0; i < count; i++)
254
w[i] = "";
255
for (i = 0; i < count; i++) {
256
char *cp = strchr(buffer, ' ');
257
if (cp)
258
*cp = '\0';
259
w[i] = buffer;
260
if (!cp)
261
break;
262
buffer = cp + 1;
263
}
264
return i < count || !*buffer;
265
}
266
267
/**
268
* tomoyo_correct_word2 - Validate a string.
269
*
270
* @string: The string to check. May be non-'\0'-terminated.
271
* @len: Length of @string.
272
*
273
* Check whether the given string follows the naming rules.
274
* Returns true if @string follows the naming rules, false otherwise.
275
*/
276
static bool tomoyo_correct_word2(const char *string, size_t len)
277
{
278
const char *const start = string;
279
bool in_repetition = false;
280
unsigned char c;
281
unsigned char d;
282
unsigned char e;
283
if (!len)
284
goto out;
285
while (len--) {
286
c = *string++;
287
if (c == '\\') {
288
if (!len--)
289
goto out;
290
c = *string++;
291
switch (c) {
292
case '\\': /* "\\" */
293
continue;
294
case '$': /* "\$" */
295
case '+': /* "\+" */
296
case '?': /* "\?" */
297
case '*': /* "\*" */
298
case '@': /* "\@" */
299
case 'x': /* "\x" */
300
case 'X': /* "\X" */
301
case 'a': /* "\a" */
302
case 'A': /* "\A" */
303
case '-': /* "\-" */
304
continue;
305
case '{': /* "/\{" */
306
if (string - 3 < start || *(string - 3) != '/')
307
break;
308
in_repetition = true;
309
continue;
310
case '}': /* "\}/" */
311
if (*string != '/')
312
break;
313
if (!in_repetition)
314
break;
315
in_repetition = false;
316
continue;
317
case '0': /* "\ooo" */
318
case '1':
319
case '2':
320
case '3':
321
if (!len-- || !len--)
322
break;
323
d = *string++;
324
e = *string++;
325
if (d < '0' || d > '7' || e < '0' || e > '7')
326
break;
327
c = tomoyo_make_byte(c, d, e);
328
if (tomoyo_invalid(c))
329
continue; /* pattern is not \000 */
330
}
331
goto out;
332
} else if (in_repetition && c == '/') {
333
goto out;
334
} else if (tomoyo_invalid(c)) {
335
goto out;
336
}
337
}
338
if (in_repetition)
339
goto out;
340
return true;
341
out:
342
return false;
343
}
344
345
/**
346
* tomoyo_correct_word - Validate a string.
347
*
348
* @string: The string to check.
349
*
350
* Check whether the given string follows the naming rules.
351
* Returns true if @string follows the naming rules, false otherwise.
352
*/
353
bool tomoyo_correct_word(const char *string)
354
{
355
return tomoyo_correct_word2(string, strlen(string));
356
}
357
358
/**
359
* tomoyo_correct_path - Validate a pathname.
360
*
361
* @filename: The pathname to check.
362
*
363
* Check whether the given pathname follows the naming rules.
364
* Returns true if @filename follows the naming rules, false otherwise.
365
*/
366
bool tomoyo_correct_path(const char *filename)
367
{
368
return *filename == '/' && tomoyo_correct_word(filename);
369
}
370
371
/**
372
* tomoyo_correct_domain - Check whether the given domainname follows the naming rules.
373
*
374
* @domainname: The domainname to check.
375
*
376
* Returns true if @domainname follows the naming rules, false otherwise.
377
*/
378
bool tomoyo_correct_domain(const unsigned char *domainname)
379
{
380
if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
381
TOMOYO_ROOT_NAME_LEN))
382
goto out;
383
domainname += TOMOYO_ROOT_NAME_LEN;
384
if (!*domainname)
385
return true;
386
if (*domainname++ != ' ')
387
goto out;
388
while (1) {
389
const unsigned char *cp = strchr(domainname, ' ');
390
if (!cp)
391
break;
392
if (*domainname != '/' ||
393
!tomoyo_correct_word2(domainname, cp - domainname))
394
goto out;
395
domainname = cp + 1;
396
}
397
return tomoyo_correct_path(domainname);
398
out:
399
return false;
400
}
401
402
/**
403
* tomoyo_domain_def - Check whether the given token can be a domainname.
404
*
405
* @buffer: The token to check.
406
*
407
* Returns true if @buffer possibly be a domainname, false otherwise.
408
*/
409
bool tomoyo_domain_def(const unsigned char *buffer)
410
{
411
return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN);
412
}
413
414
/**
415
* tomoyo_find_domain - Find a domain by the given name.
416
*
417
* @domainname: The domainname to find.
418
*
419
* Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
420
*
421
* Caller holds tomoyo_read_lock().
422
*/
423
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
424
{
425
struct tomoyo_domain_info *domain;
426
struct tomoyo_path_info name;
427
428
name.name = domainname;
429
tomoyo_fill_path_info(&name);
430
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
431
if (!domain->is_deleted &&
432
!tomoyo_pathcmp(&name, domain->domainname))
433
return domain;
434
}
435
return NULL;
436
}
437
438
/**
439
* tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
440
*
441
* @filename: The string to evaluate.
442
*
443
* Returns the initial length without a pattern in @filename.
444
*/
445
static int tomoyo_const_part_length(const char *filename)
446
{
447
char c;
448
int len = 0;
449
450
if (!filename)
451
return 0;
452
while ((c = *filename++) != '\0') {
453
if (c != '\\') {
454
len++;
455
continue;
456
}
457
c = *filename++;
458
switch (c) {
459
case '\\': /* "\\" */
460
len += 2;
461
continue;
462
case '0': /* "\ooo" */
463
case '1':
464
case '2':
465
case '3':
466
c = *filename++;
467
if (c < '0' || c > '7')
468
break;
469
c = *filename++;
470
if (c < '0' || c > '7')
471
break;
472
len += 4;
473
continue;
474
}
475
break;
476
}
477
return len;
478
}
479
480
/**
481
* tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
482
*
483
* @ptr: Pointer to "struct tomoyo_path_info" to fill in.
484
*
485
* The caller sets "struct tomoyo_path_info"->name.
486
*/
487
void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
488
{
489
const char *name = ptr->name;
490
const int len = strlen(name);
491
492
ptr->const_len = tomoyo_const_part_length(name);
493
ptr->is_dir = len && (name[len - 1] == '/');
494
ptr->is_patterned = (ptr->const_len < len);
495
ptr->hash = full_name_hash(name, len);
496
}
497
498
/**
499
* tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
500
*
501
* @filename: The start of string to check.
502
* @filename_end: The end of string to check.
503
* @pattern: The start of pattern to compare.
504
* @pattern_end: The end of pattern to compare.
505
*
506
* Returns true if @filename matches @pattern, false otherwise.
507
*/
508
static bool tomoyo_file_matches_pattern2(const char *filename,
509
const char *filename_end,
510
const char *pattern,
511
const char *pattern_end)
512
{
513
while (filename < filename_end && pattern < pattern_end) {
514
char c;
515
if (*pattern != '\\') {
516
if (*filename++ != *pattern++)
517
return false;
518
continue;
519
}
520
c = *filename;
521
pattern++;
522
switch (*pattern) {
523
int i;
524
int j;
525
case '?':
526
if (c == '/') {
527
return false;
528
} else if (c == '\\') {
529
if (filename[1] == '\\')
530
filename++;
531
else if (tomoyo_byte_range(filename + 1))
532
filename += 3;
533
else
534
return false;
535
}
536
break;
537
case '\\':
538
if (c != '\\')
539
return false;
540
if (*++filename != '\\')
541
return false;
542
break;
543
case '+':
544
if (!isdigit(c))
545
return false;
546
break;
547
case 'x':
548
if (!isxdigit(c))
549
return false;
550
break;
551
case 'a':
552
if (!tomoyo_alphabet_char(c))
553
return false;
554
break;
555
case '0':
556
case '1':
557
case '2':
558
case '3':
559
if (c == '\\' && tomoyo_byte_range(filename + 1)
560
&& strncmp(filename + 1, pattern, 3) == 0) {
561
filename += 3;
562
pattern += 2;
563
break;
564
}
565
return false; /* Not matched. */
566
case '*':
567
case '@':
568
for (i = 0; i <= filename_end - filename; i++) {
569
if (tomoyo_file_matches_pattern2(
570
filename + i, filename_end,
571
pattern + 1, pattern_end))
572
return true;
573
c = filename[i];
574
if (c == '.' && *pattern == '@')
575
break;
576
if (c != '\\')
577
continue;
578
if (filename[i + 1] == '\\')
579
i++;
580
else if (tomoyo_byte_range(filename + i + 1))
581
i += 3;
582
else
583
break; /* Bad pattern. */
584
}
585
return false; /* Not matched. */
586
default:
587
j = 0;
588
c = *pattern;
589
if (c == '$') {
590
while (isdigit(filename[j]))
591
j++;
592
} else if (c == 'X') {
593
while (isxdigit(filename[j]))
594
j++;
595
} else if (c == 'A') {
596
while (tomoyo_alphabet_char(filename[j]))
597
j++;
598
}
599
for (i = 1; i <= j; i++) {
600
if (tomoyo_file_matches_pattern2(
601
filename + i, filename_end,
602
pattern + 1, pattern_end))
603
return true;
604
}
605
return false; /* Not matched or bad pattern. */
606
}
607
filename++;
608
pattern++;
609
}
610
while (*pattern == '\\' &&
611
(*(pattern + 1) == '*' || *(pattern + 1) == '@'))
612
pattern += 2;
613
return filename == filename_end && pattern == pattern_end;
614
}
615
616
/**
617
* tomoyo_file_matches_pattern - Pattern matching without '/' character.
618
*
619
* @filename: The start of string to check.
620
* @filename_end: The end of string to check.
621
* @pattern: The start of pattern to compare.
622
* @pattern_end: The end of pattern to compare.
623
*
624
* Returns true if @filename matches @pattern, false otherwise.
625
*/
626
static bool tomoyo_file_matches_pattern(const char *filename,
627
const char *filename_end,
628
const char *pattern,
629
const char *pattern_end)
630
{
631
const char *pattern_start = pattern;
632
bool first = true;
633
bool result;
634
635
while (pattern < pattern_end - 1) {
636
/* Split at "\-" pattern. */
637
if (*pattern++ != '\\' || *pattern++ != '-')
638
continue;
639
result = tomoyo_file_matches_pattern2(filename,
640
filename_end,
641
pattern_start,
642
pattern - 2);
643
if (first)
644
result = !result;
645
if (result)
646
return false;
647
first = false;
648
pattern_start = pattern;
649
}
650
result = tomoyo_file_matches_pattern2(filename, filename_end,
651
pattern_start, pattern_end);
652
return first ? result : !result;
653
}
654
655
/**
656
* tomoyo_path_matches_pattern2 - Do pathname pattern matching.
657
*
658
* @f: The start of string to check.
659
* @p: The start of pattern to compare.
660
*
661
* Returns true if @f matches @p, false otherwise.
662
*/
663
static bool tomoyo_path_matches_pattern2(const char *f, const char *p)
664
{
665
const char *f_delimiter;
666
const char *p_delimiter;
667
668
while (*f && *p) {
669
f_delimiter = strchr(f, '/');
670
if (!f_delimiter)
671
f_delimiter = f + strlen(f);
672
p_delimiter = strchr(p, '/');
673
if (!p_delimiter)
674
p_delimiter = p + strlen(p);
675
if (*p == '\\' && *(p + 1) == '{')
676
goto recursive;
677
if (!tomoyo_file_matches_pattern(f, f_delimiter, p,
678
p_delimiter))
679
return false;
680
f = f_delimiter;
681
if (*f)
682
f++;
683
p = p_delimiter;
684
if (*p)
685
p++;
686
}
687
/* Ignore trailing "\*" and "\@" in @pattern. */
688
while (*p == '\\' &&
689
(*(p + 1) == '*' || *(p + 1) == '@'))
690
p += 2;
691
return !*f && !*p;
692
recursive:
693
/*
694
* The "\{" pattern is permitted only after '/' character.
695
* This guarantees that below "*(p - 1)" is safe.
696
* Also, the "\}" pattern is permitted only before '/' character
697
* so that "\{" + "\}" pair will not break the "\-" operator.
698
*/
699
if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
700
*(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
701
return false; /* Bad pattern. */
702
do {
703
/* Compare current component with pattern. */
704
if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2,
705
p_delimiter - 2))
706
break;
707
/* Proceed to next component. */
708
f = f_delimiter;
709
if (!*f)
710
break;
711
f++;
712
/* Continue comparison. */
713
if (tomoyo_path_matches_pattern2(f, p_delimiter + 1))
714
return true;
715
f_delimiter = strchr(f, '/');
716
} while (f_delimiter);
717
return false; /* Not matched. */
718
}
719
720
/**
721
* tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
722
*
723
* @filename: The filename to check.
724
* @pattern: The pattern to compare.
725
*
726
* Returns true if matches, false otherwise.
727
*
728
* The following patterns are available.
729
* \\ \ itself.
730
* \ooo Octal representation of a byte.
731
* \* Zero or more repetitions of characters other than '/'.
732
* \@ Zero or more repetitions of characters other than '/' or '.'.
733
* \? 1 byte character other than '/'.
734
* \$ One or more repetitions of decimal digits.
735
* \+ 1 decimal digit.
736
* \X One or more repetitions of hexadecimal digits.
737
* \x 1 hexadecimal digit.
738
* \A One or more repetitions of alphabet characters.
739
* \a 1 alphabet character.
740
*
741
* \- Subtraction operator.
742
*
743
* /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
744
* /dir/dir/dir/ ).
745
*/
746
bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
747
const struct tomoyo_path_info *pattern)
748
{
749
const char *f = filename->name;
750
const char *p = pattern->name;
751
const int len = pattern->const_len;
752
753
/* If @pattern doesn't contain pattern, I can use strcmp(). */
754
if (!pattern->is_patterned)
755
return !tomoyo_pathcmp(filename, pattern);
756
/* Don't compare directory and non-directory. */
757
if (filename->is_dir != pattern->is_dir)
758
return false;
759
/* Compare the initial length without patterns. */
760
if (strncmp(f, p, len))
761
return false;
762
f += len;
763
p += len;
764
return tomoyo_path_matches_pattern2(f, p);
765
}
766
767
/**
768
* tomoyo_get_exe - Get tomoyo_realpath() of current process.
769
*
770
* Returns the tomoyo_realpath() of current process on success, NULL otherwise.
771
*
772
* This function uses kzalloc(), so the caller must call kfree()
773
* if this function didn't return NULL.
774
*/
775
const char *tomoyo_get_exe(void)
776
{
777
struct mm_struct *mm = current->mm;
778
struct vm_area_struct *vma;
779
const char *cp = NULL;
780
781
if (!mm)
782
return NULL;
783
down_read(&mm->mmap_sem);
784
for (vma = mm->mmap; vma; vma = vma->vm_next) {
785
if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
786
cp = tomoyo_realpath_from_path(&vma->vm_file->f_path);
787
break;
788
}
789
}
790
up_read(&mm->mmap_sem);
791
return cp;
792
}
793
794
/**
795
* tomoyo_get_mode - Get MAC mode.
796
*
797
* @profile: Profile number.
798
* @index: Index number of functionality.
799
*
800
* Returns mode.
801
*/
802
int tomoyo_get_mode(const u8 profile, const u8 index)
803
{
804
u8 mode;
805
const u8 category = TOMOYO_MAC_CATEGORY_FILE;
806
if (!tomoyo_policy_loaded)
807
return TOMOYO_CONFIG_DISABLED;
808
mode = tomoyo_profile(profile)->config[index];
809
if (mode == TOMOYO_CONFIG_USE_DEFAULT)
810
mode = tomoyo_profile(profile)->config[category];
811
if (mode == TOMOYO_CONFIG_USE_DEFAULT)
812
mode = tomoyo_profile(profile)->default_config;
813
return mode & 3;
814
}
815
816
/**
817
* tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members.
818
*
819
* @r: Pointer to "struct tomoyo_request_info" to initialize.
820
* @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain().
821
* @index: Index number of functionality.
822
*
823
* Returns mode.
824
*/
825
int tomoyo_init_request_info(struct tomoyo_request_info *r,
826
struct tomoyo_domain_info *domain, const u8 index)
827
{
828
u8 profile;
829
memset(r, 0, sizeof(*r));
830
if (!domain)
831
domain = tomoyo_domain();
832
r->domain = domain;
833
profile = domain->profile;
834
r->profile = profile;
835
r->type = index;
836
r->mode = tomoyo_get_mode(profile, index);
837
return r->mode;
838
}
839
840
/**
841
* tomoyo_last_word - Get last component of a line.
842
*
843
* @line: A line.
844
*
845
* Returns the last word of a line.
846
*/
847
const char *tomoyo_last_word(const char *name)
848
{
849
const char *cp = strrchr(name, ' ');
850
if (cp)
851
return cp + 1;
852
return name;
853
}
854
855
/**
856
* tomoyo_warn_log - Print warning or error message on console.
857
*
858
* @r: Pointer to "struct tomoyo_request_info".
859
* @fmt: The printf()'s format string, followed by parameters.
860
*/
861
void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...)
862
{
863
va_list args;
864
char *buffer;
865
const struct tomoyo_domain_info * const domain = r->domain;
866
const struct tomoyo_profile *profile = tomoyo_profile(domain->profile);
867
switch (r->mode) {
868
case TOMOYO_CONFIG_ENFORCING:
869
if (!profile->enforcing->enforcing_verbose)
870
return;
871
break;
872
case TOMOYO_CONFIG_PERMISSIVE:
873
if (!profile->permissive->permissive_verbose)
874
return;
875
break;
876
case TOMOYO_CONFIG_LEARNING:
877
if (!profile->learning->learning_verbose)
878
return;
879
break;
880
}
881
buffer = kmalloc(4096, GFP_NOFS);
882
if (!buffer)
883
return;
884
va_start(args, fmt);
885
vsnprintf(buffer, 4095, fmt, args);
886
va_end(args);
887
buffer[4095] = '\0';
888
printk(KERN_WARNING "%s: Access %s denied for %s\n",
889
r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING", buffer,
890
tomoyo_last_word(domain->domainname->name));
891
kfree(buffer);
892
}
893
894
/**
895
* tomoyo_domain_quota_is_ok - Check for domain's quota.
896
*
897
* @r: Pointer to "struct tomoyo_request_info".
898
*
899
* Returns true if the domain is not exceeded quota, false otherwise.
900
*
901
* Caller holds tomoyo_read_lock().
902
*/
903
bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
904
{
905
unsigned int count = 0;
906
struct tomoyo_domain_info *domain = r->domain;
907
struct tomoyo_acl_info *ptr;
908
909
if (r->mode != TOMOYO_CONFIG_LEARNING)
910
return false;
911
if (!domain)
912
return true;
913
list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
914
if (ptr->is_deleted)
915
continue;
916
switch (ptr->type) {
917
u16 perm;
918
u8 i;
919
case TOMOYO_TYPE_PATH_ACL:
920
perm = container_of(ptr, struct tomoyo_path_acl, head)
921
->perm;
922
for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++)
923
if (perm & (1 << i))
924
count++;
925
if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
926
count -= 2;
927
break;
928
case TOMOYO_TYPE_PATH2_ACL:
929
perm = container_of(ptr, struct tomoyo_path2_acl, head)
930
->perm;
931
for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++)
932
if (perm & (1 << i))
933
count++;
934
break;
935
case TOMOYO_TYPE_PATH_NUMBER_ACL:
936
perm = container_of(ptr, struct tomoyo_path_number_acl,
937
head)->perm;
938
for (i = 0; i < TOMOYO_MAX_PATH_NUMBER_OPERATION; i++)
939
if (perm & (1 << i))
940
count++;
941
break;
942
case TOMOYO_TYPE_MKDEV_ACL:
943
perm = container_of(ptr, struct tomoyo_mkdev_acl,
944
head)->perm;
945
for (i = 0; i < TOMOYO_MAX_MKDEV_OPERATION; i++)
946
if (perm & (1 << i))
947
count++;
948
break;
949
default:
950
count++;
951
}
952
}
953
if (count < tomoyo_profile(domain->profile)->learning->
954
learning_max_entry)
955
return true;
956
if (!domain->quota_warned) {
957
domain->quota_warned = true;
958
printk(KERN_WARNING "TOMOYO-WARNING: "
959
"Domain '%s' has so many ACLs to hold. "
960
"Stopped learning mode.\n", domain->domainname->name);
961
}
962
return false;
963
}
964
965