Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/security/tomoyo/util.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* security/tomoyo/util.c
4
*
5
* Copyright (C) 2005-2011 NTT DATA CORPORATION
6
*/
7
8
#include <linux/slab.h>
9
#include <linux/rculist.h>
10
11
#include "common.h"
12
13
/* Lock for protecting policy. */
14
DEFINE_MUTEX(tomoyo_policy_lock);
15
16
/* Has /sbin/init started? */
17
bool tomoyo_policy_loaded;
18
19
/*
20
* Mapping table from "enum tomoyo_mac_index" to
21
* "enum tomoyo_mac_category_index".
22
*/
23
const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = {
24
/* CONFIG::file group */
25
[TOMOYO_MAC_FILE_EXECUTE] = TOMOYO_MAC_CATEGORY_FILE,
26
[TOMOYO_MAC_FILE_OPEN] = TOMOYO_MAC_CATEGORY_FILE,
27
[TOMOYO_MAC_FILE_CREATE] = TOMOYO_MAC_CATEGORY_FILE,
28
[TOMOYO_MAC_FILE_UNLINK] = TOMOYO_MAC_CATEGORY_FILE,
29
[TOMOYO_MAC_FILE_GETATTR] = TOMOYO_MAC_CATEGORY_FILE,
30
[TOMOYO_MAC_FILE_MKDIR] = TOMOYO_MAC_CATEGORY_FILE,
31
[TOMOYO_MAC_FILE_RMDIR] = TOMOYO_MAC_CATEGORY_FILE,
32
[TOMOYO_MAC_FILE_MKFIFO] = TOMOYO_MAC_CATEGORY_FILE,
33
[TOMOYO_MAC_FILE_MKSOCK] = TOMOYO_MAC_CATEGORY_FILE,
34
[TOMOYO_MAC_FILE_TRUNCATE] = TOMOYO_MAC_CATEGORY_FILE,
35
[TOMOYO_MAC_FILE_SYMLINK] = TOMOYO_MAC_CATEGORY_FILE,
36
[TOMOYO_MAC_FILE_MKBLOCK] = TOMOYO_MAC_CATEGORY_FILE,
37
[TOMOYO_MAC_FILE_MKCHAR] = TOMOYO_MAC_CATEGORY_FILE,
38
[TOMOYO_MAC_FILE_LINK] = TOMOYO_MAC_CATEGORY_FILE,
39
[TOMOYO_MAC_FILE_RENAME] = TOMOYO_MAC_CATEGORY_FILE,
40
[TOMOYO_MAC_FILE_CHMOD] = TOMOYO_MAC_CATEGORY_FILE,
41
[TOMOYO_MAC_FILE_CHOWN] = TOMOYO_MAC_CATEGORY_FILE,
42
[TOMOYO_MAC_FILE_CHGRP] = TOMOYO_MAC_CATEGORY_FILE,
43
[TOMOYO_MAC_FILE_IOCTL] = TOMOYO_MAC_CATEGORY_FILE,
44
[TOMOYO_MAC_FILE_CHROOT] = TOMOYO_MAC_CATEGORY_FILE,
45
[TOMOYO_MAC_FILE_MOUNT] = TOMOYO_MAC_CATEGORY_FILE,
46
[TOMOYO_MAC_FILE_UMOUNT] = TOMOYO_MAC_CATEGORY_FILE,
47
[TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE,
48
/* CONFIG::network group */
49
[TOMOYO_MAC_NETWORK_INET_STREAM_BIND] =
50
TOMOYO_MAC_CATEGORY_NETWORK,
51
[TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN] =
52
TOMOYO_MAC_CATEGORY_NETWORK,
53
[TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT] =
54
TOMOYO_MAC_CATEGORY_NETWORK,
55
[TOMOYO_MAC_NETWORK_INET_DGRAM_BIND] =
56
TOMOYO_MAC_CATEGORY_NETWORK,
57
[TOMOYO_MAC_NETWORK_INET_DGRAM_SEND] =
58
TOMOYO_MAC_CATEGORY_NETWORK,
59
[TOMOYO_MAC_NETWORK_INET_RAW_BIND] =
60
TOMOYO_MAC_CATEGORY_NETWORK,
61
[TOMOYO_MAC_NETWORK_INET_RAW_SEND] =
62
TOMOYO_MAC_CATEGORY_NETWORK,
63
[TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND] =
64
TOMOYO_MAC_CATEGORY_NETWORK,
65
[TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN] =
66
TOMOYO_MAC_CATEGORY_NETWORK,
67
[TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT] =
68
TOMOYO_MAC_CATEGORY_NETWORK,
69
[TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND] =
70
TOMOYO_MAC_CATEGORY_NETWORK,
71
[TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND] =
72
TOMOYO_MAC_CATEGORY_NETWORK,
73
[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND] =
74
TOMOYO_MAC_CATEGORY_NETWORK,
75
[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] =
76
TOMOYO_MAC_CATEGORY_NETWORK,
77
[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] =
78
TOMOYO_MAC_CATEGORY_NETWORK,
79
/* CONFIG::misc group */
80
[TOMOYO_MAC_ENVIRON] = TOMOYO_MAC_CATEGORY_MISC,
81
};
82
83
/**
84
* tomoyo_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss.
85
*
86
* @time64: Seconds since 1970/01/01 00:00:00.
87
* @stamp: Pointer to "struct tomoyo_time".
88
*
89
* Returns nothing.
90
*/
91
void tomoyo_convert_time(time64_t time64, struct tomoyo_time *stamp)
92
{
93
struct tm tm;
94
95
time64_to_tm(time64, 0, &tm);
96
stamp->sec = tm.tm_sec;
97
stamp->min = tm.tm_min;
98
stamp->hour = tm.tm_hour;
99
stamp->day = tm.tm_mday;
100
stamp->month = tm.tm_mon + 1;
101
stamp->year = tm.tm_year + 1900;
102
}
103
104
/**
105
* tomoyo_permstr - Find permission keywords.
106
*
107
* @string: String representation for permissions in foo/bar/buz format.
108
* @keyword: Keyword to find from @string/
109
*
110
* Returns true if @keyword was found in @string, false otherwise.
111
*
112
* This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2.
113
*/
114
bool tomoyo_permstr(const char *string, const char *keyword)
115
{
116
const char *cp = strstr(string, keyword);
117
118
if (cp)
119
return cp == string || *(cp - 1) == '/';
120
return false;
121
}
122
123
/**
124
* tomoyo_read_token - Read a word from a line.
125
*
126
* @param: Pointer to "struct tomoyo_acl_param".
127
*
128
* Returns a word on success, "" otherwise.
129
*
130
* To allow the caller to skip NULL check, this function returns "" rather than
131
* NULL if there is no more words to read.
132
*/
133
char *tomoyo_read_token(struct tomoyo_acl_param *param)
134
{
135
char *pos = param->data;
136
char *del = strchr(pos, ' ');
137
138
if (del)
139
*del++ = '\0';
140
else
141
del = pos + strlen(pos);
142
param->data = del;
143
return pos;
144
}
145
146
static bool tomoyo_correct_path2(const char *filename, const size_t len);
147
148
/**
149
* tomoyo_get_domainname - Read a domainname from a line.
150
*
151
* @param: Pointer to "struct tomoyo_acl_param".
152
*
153
* Returns a domainname on success, NULL otherwise.
154
*/
155
const struct tomoyo_path_info *tomoyo_get_domainname
156
(struct tomoyo_acl_param *param)
157
{
158
char *start = param->data;
159
char *pos = start;
160
161
while (*pos) {
162
if (*pos++ != ' ' ||
163
tomoyo_correct_path2(pos, strchrnul(pos, ' ') - pos))
164
continue;
165
*(pos - 1) = '\0';
166
break;
167
}
168
param->data = pos;
169
if (tomoyo_correct_domain(start))
170
return tomoyo_get_name(start);
171
return NULL;
172
}
173
174
/**
175
* tomoyo_parse_ulong - Parse an "unsigned long" value.
176
*
177
* @result: Pointer to "unsigned long".
178
* @str: Pointer to string to parse.
179
*
180
* Returns one of values in "enum tomoyo_value_type".
181
*
182
* The @src is updated to point the first character after the value
183
* on success.
184
*/
185
u8 tomoyo_parse_ulong(unsigned long *result, char **str)
186
{
187
const char *cp = *str;
188
char *ep;
189
int base = 10;
190
191
if (*cp == '0') {
192
char c = *(cp + 1);
193
194
if (c == 'x' || c == 'X') {
195
base = 16;
196
cp += 2;
197
} else if (c >= '0' && c <= '7') {
198
base = 8;
199
cp++;
200
}
201
}
202
*result = simple_strtoul(cp, &ep, base);
203
if (cp == ep)
204
return TOMOYO_VALUE_TYPE_INVALID;
205
*str = ep;
206
switch (base) {
207
case 16:
208
return TOMOYO_VALUE_TYPE_HEXADECIMAL;
209
case 8:
210
return TOMOYO_VALUE_TYPE_OCTAL;
211
default:
212
return TOMOYO_VALUE_TYPE_DECIMAL;
213
}
214
}
215
216
/**
217
* tomoyo_print_ulong - Print an "unsigned long" value.
218
*
219
* @buffer: Pointer to buffer.
220
* @buffer_len: Size of @buffer.
221
* @value: An "unsigned long" value.
222
* @type: Type of @value.
223
*
224
* Returns nothing.
225
*/
226
void tomoyo_print_ulong(char *buffer, const int buffer_len,
227
const unsigned long value, const u8 type)
228
{
229
if (type == TOMOYO_VALUE_TYPE_DECIMAL)
230
snprintf(buffer, buffer_len, "%lu", value);
231
else if (type == TOMOYO_VALUE_TYPE_OCTAL)
232
snprintf(buffer, buffer_len, "0%lo", value);
233
else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL)
234
snprintf(buffer, buffer_len, "0x%lX", value);
235
else
236
snprintf(buffer, buffer_len, "type(%u)", type);
237
}
238
239
/**
240
* tomoyo_parse_name_union - Parse a tomoyo_name_union.
241
*
242
* @param: Pointer to "struct tomoyo_acl_param".
243
* @ptr: Pointer to "struct tomoyo_name_union".
244
*
245
* Returns true on success, false otherwise.
246
*/
247
bool tomoyo_parse_name_union(struct tomoyo_acl_param *param,
248
struct tomoyo_name_union *ptr)
249
{
250
char *filename;
251
252
if (param->data[0] == '@') {
253
param->data++;
254
ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP);
255
return ptr->group != NULL;
256
}
257
filename = tomoyo_read_token(param);
258
if (!tomoyo_correct_word(filename))
259
return false;
260
ptr->filename = tomoyo_get_name(filename);
261
return ptr->filename != NULL;
262
}
263
264
/**
265
* tomoyo_parse_number_union - Parse a tomoyo_number_union.
266
*
267
* @param: Pointer to "struct tomoyo_acl_param".
268
* @ptr: Pointer to "struct tomoyo_number_union".
269
*
270
* Returns true on success, false otherwise.
271
*/
272
bool tomoyo_parse_number_union(struct tomoyo_acl_param *param,
273
struct tomoyo_number_union *ptr)
274
{
275
char *data;
276
u8 type;
277
unsigned long v;
278
279
memset(ptr, 0, sizeof(*ptr));
280
if (param->data[0] == '@') {
281
param->data++;
282
ptr->group = tomoyo_get_group(param, TOMOYO_NUMBER_GROUP);
283
return ptr->group != NULL;
284
}
285
data = tomoyo_read_token(param);
286
type = tomoyo_parse_ulong(&v, &data);
287
if (type == TOMOYO_VALUE_TYPE_INVALID)
288
return false;
289
ptr->values[0] = v;
290
ptr->value_type[0] = type;
291
if (!*data) {
292
ptr->values[1] = v;
293
ptr->value_type[1] = type;
294
return true;
295
}
296
if (*data++ != '-')
297
return false;
298
type = tomoyo_parse_ulong(&v, &data);
299
if (type == TOMOYO_VALUE_TYPE_INVALID || *data || ptr->values[0] > v)
300
return false;
301
ptr->values[1] = v;
302
ptr->value_type[1] = type;
303
return true;
304
}
305
306
/**
307
* tomoyo_byte_range - Check whether the string is a \ooo style octal value.
308
*
309
* @str: Pointer to the string.
310
*
311
* Returns true if @str is a \ooo style octal value, false otherwise.
312
*
313
* TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
314
* This function verifies that \ooo is in valid range.
315
*/
316
static inline bool tomoyo_byte_range(const char *str)
317
{
318
return *str >= '0' && *str++ <= '3' &&
319
*str >= '0' && *str++ <= '7' &&
320
*str >= '0' && *str <= '7';
321
}
322
323
/**
324
* tomoyo_alphabet_char - Check whether the character is an alphabet.
325
*
326
* @c: The character to check.
327
*
328
* Returns true if @c is an alphabet character, false otherwise.
329
*/
330
static inline bool tomoyo_alphabet_char(const char c)
331
{
332
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
333
}
334
335
/**
336
* tomoyo_make_byte - Make byte value from three octal characters.
337
*
338
* @c1: The first character.
339
* @c2: The second character.
340
* @c3: The third character.
341
*
342
* Returns byte value.
343
*/
344
static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
345
{
346
return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
347
}
348
349
/**
350
* tomoyo_valid - Check whether the character is a valid char.
351
*
352
* @c: The character to check.
353
*
354
* Returns true if @c is a valid character, false otherwise.
355
*/
356
static inline bool tomoyo_valid(const unsigned char c)
357
{
358
return c > ' ' && c < 127;
359
}
360
361
/**
362
* tomoyo_invalid - Check whether the character is an invalid char.
363
*
364
* @c: The character to check.
365
*
366
* Returns true if @c is an invalid character, false otherwise.
367
*/
368
static inline bool tomoyo_invalid(const unsigned char c)
369
{
370
return c && (c <= ' ' || c >= 127);
371
}
372
373
/**
374
* tomoyo_str_starts - Check whether the given string starts with the given keyword.
375
*
376
* @src: Pointer to pointer to the string.
377
* @find: Pointer to the keyword.
378
*
379
* Returns true if @src starts with @find, false otherwise.
380
*
381
* The @src is updated to point the first character after the @find
382
* if @src starts with @find.
383
*/
384
bool tomoyo_str_starts(char **src, const char *find)
385
{
386
const int len = strlen(find);
387
char *tmp = *src;
388
389
if (strncmp(tmp, find, len))
390
return false;
391
tmp += len;
392
*src = tmp;
393
return true;
394
}
395
396
/**
397
* tomoyo_normalize_line - Format string.
398
*
399
* @buffer: The line to normalize.
400
*
401
* Leading and trailing whitespaces are removed.
402
* Multiple whitespaces are packed into single space.
403
*
404
* Returns nothing.
405
*/
406
void tomoyo_normalize_line(unsigned char *buffer)
407
{
408
unsigned char *sp = buffer;
409
unsigned char *dp = buffer;
410
bool first = true;
411
412
while (tomoyo_invalid(*sp))
413
sp++;
414
while (*sp) {
415
if (!first)
416
*dp++ = ' ';
417
first = false;
418
while (tomoyo_valid(*sp))
419
*dp++ = *sp++;
420
while (tomoyo_invalid(*sp))
421
sp++;
422
}
423
*dp = '\0';
424
}
425
426
/**
427
* tomoyo_correct_word2 - Validate a string.
428
*
429
* @string: The string to check. Maybe non-'\0'-terminated.
430
* @len: Length of @string.
431
*
432
* Check whether the given string follows the naming rules.
433
* Returns true if @string follows the naming rules, false otherwise.
434
*/
435
static bool tomoyo_correct_word2(const char *string, size_t len)
436
{
437
u8 recursion = 20;
438
const char *const start = string;
439
bool in_repetition = false;
440
441
if (!len)
442
goto out;
443
while (len--) {
444
unsigned char c = *string++;
445
446
if (c == '\\') {
447
if (!len--)
448
goto out;
449
c = *string++;
450
if (c >= '0' && c <= '3') {
451
unsigned char d;
452
unsigned char e;
453
454
if (!len-- || !len--)
455
goto out;
456
d = *string++;
457
e = *string++;
458
if (d < '0' || d > '7' || e < '0' || e > '7')
459
goto out;
460
c = tomoyo_make_byte(c, d, e);
461
if (c <= ' ' || c >= 127)
462
continue;
463
goto out;
464
}
465
switch (c) {
466
case '\\': /* "\\" */
467
case '+': /* "\+" */
468
case '?': /* "\?" */
469
case 'x': /* "\x" */
470
case 'a': /* "\a" */
471
case '-': /* "\-" */
472
continue;
473
}
474
if (!recursion--)
475
goto out;
476
switch (c) {
477
case '*': /* "\*" */
478
case '@': /* "\@" */
479
case '$': /* "\$" */
480
case 'X': /* "\X" */
481
case 'A': /* "\A" */
482
continue;
483
case '{': /* "/\{" */
484
if (string - 3 < start || *(string - 3) != '/')
485
goto out;
486
in_repetition = true;
487
continue;
488
case '}': /* "\}/" */
489
if (*string != '/')
490
goto out;
491
if (!in_repetition)
492
goto out;
493
in_repetition = false;
494
continue;
495
}
496
goto out;
497
} else if (in_repetition && c == '/') {
498
goto out;
499
} else if (c <= ' ' || c >= 127) {
500
goto out;
501
}
502
}
503
if (in_repetition)
504
goto out;
505
return true;
506
out:
507
return false;
508
}
509
510
/**
511
* tomoyo_correct_word - Validate a string.
512
*
513
* @string: The string to check.
514
*
515
* Check whether the given string follows the naming rules.
516
* Returns true if @string follows the naming rules, false otherwise.
517
*/
518
bool tomoyo_correct_word(const char *string)
519
{
520
return tomoyo_correct_word2(string, strlen(string));
521
}
522
523
/**
524
* tomoyo_correct_path2 - Check whether the given pathname follows the naming rules.
525
*
526
* @filename: The pathname to check.
527
* @len: Length of @filename.
528
*
529
* Returns true if @filename follows the naming rules, false otherwise.
530
*/
531
static bool tomoyo_correct_path2(const char *filename, const size_t len)
532
{
533
const char *cp1 = memchr(filename, '/', len);
534
const char *cp2 = memchr(filename, '.', len);
535
536
return cp1 && (!cp2 || (cp1 < cp2)) && tomoyo_correct_word2(filename, len);
537
}
538
539
/**
540
* tomoyo_correct_path - Validate a pathname.
541
*
542
* @filename: The pathname to check.
543
*
544
* Check whether the given pathname follows the naming rules.
545
* Returns true if @filename follows the naming rules, false otherwise.
546
*/
547
bool tomoyo_correct_path(const char *filename)
548
{
549
return tomoyo_correct_path2(filename, strlen(filename));
550
}
551
552
/**
553
* tomoyo_correct_domain - Check whether the given domainname follows the naming rules.
554
*
555
* @domainname: The domainname to check.
556
*
557
* Returns true if @domainname follows the naming rules, false otherwise.
558
*/
559
bool tomoyo_correct_domain(const unsigned char *domainname)
560
{
561
if (!domainname || !tomoyo_domain_def(domainname))
562
return false;
563
domainname = strchr(domainname, ' ');
564
if (!domainname++)
565
return true;
566
while (1) {
567
const unsigned char *cp = strchr(domainname, ' ');
568
569
if (!cp)
570
break;
571
if (!tomoyo_correct_path2(domainname, cp - domainname))
572
return false;
573
domainname = cp + 1;
574
}
575
return tomoyo_correct_path(domainname);
576
}
577
578
/**
579
* tomoyo_domain_def - Check whether the given token can be a domainname.
580
*
581
* @buffer: The token to check.
582
*
583
* Returns true if @buffer possibly be a domainname, false otherwise.
584
*/
585
bool tomoyo_domain_def(const unsigned char *buffer)
586
{
587
const unsigned char *cp;
588
int len;
589
590
if (*buffer != '<')
591
return false;
592
cp = strchr(buffer, ' ');
593
if (!cp)
594
len = strlen(buffer);
595
else
596
len = cp - buffer;
597
if (buffer[len - 1] != '>' ||
598
!tomoyo_correct_word2(buffer + 1, len - 2))
599
return false;
600
return true;
601
}
602
603
/**
604
* tomoyo_find_domain - Find a domain by the given name.
605
*
606
* @domainname: The domainname to find.
607
*
608
* Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
609
*
610
* Caller holds tomoyo_read_lock().
611
*/
612
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
613
{
614
struct tomoyo_domain_info *domain;
615
struct tomoyo_path_info name;
616
617
name.name = domainname;
618
tomoyo_fill_path_info(&name);
619
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list,
620
srcu_read_lock_held(&tomoyo_ss)) {
621
if (!domain->is_deleted &&
622
!tomoyo_pathcmp(&name, domain->domainname))
623
return domain;
624
}
625
return NULL;
626
}
627
628
/**
629
* tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
630
*
631
* @filename: The string to evaluate.
632
*
633
* Returns the initial length without a pattern in @filename.
634
*/
635
static int tomoyo_const_part_length(const char *filename)
636
{
637
char c;
638
int len = 0;
639
640
if (!filename)
641
return 0;
642
while ((c = *filename++) != '\0') {
643
if (c != '\\') {
644
len++;
645
continue;
646
}
647
c = *filename++;
648
switch (c) {
649
case '\\': /* "\\" */
650
len += 2;
651
continue;
652
case '0': /* "\ooo" */
653
case '1':
654
case '2':
655
case '3':
656
c = *filename++;
657
if (c < '0' || c > '7')
658
break;
659
c = *filename++;
660
if (c < '0' || c > '7')
661
break;
662
len += 4;
663
continue;
664
}
665
break;
666
}
667
return len;
668
}
669
670
/**
671
* tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
672
*
673
* @ptr: Pointer to "struct tomoyo_path_info" to fill in.
674
*
675
* The caller sets "struct tomoyo_path_info"->name.
676
*/
677
void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
678
{
679
const char *name = ptr->name;
680
const int len = strlen(name);
681
682
ptr->const_len = tomoyo_const_part_length(name);
683
ptr->is_dir = len && (name[len - 1] == '/');
684
ptr->is_patterned = (ptr->const_len < len);
685
ptr->hash = full_name_hash(NULL, name, len);
686
}
687
688
/**
689
* tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
690
*
691
* @filename: The start of string to check.
692
* @filename_end: The end of string to check.
693
* @pattern: The start of pattern to compare.
694
* @pattern_end: The end of pattern to compare.
695
*
696
* Returns true if @filename matches @pattern, false otherwise.
697
*/
698
static bool tomoyo_file_matches_pattern2(const char *filename,
699
const char *filename_end,
700
const char *pattern,
701
const char *pattern_end)
702
{
703
while (filename < filename_end && pattern < pattern_end) {
704
char c;
705
int i;
706
int j;
707
708
if (*pattern != '\\') {
709
if (*filename++ != *pattern++)
710
return false;
711
continue;
712
}
713
c = *filename;
714
pattern++;
715
switch (*pattern) {
716
case '?':
717
if (c == '/') {
718
return false;
719
} else if (c == '\\') {
720
if (filename[1] == '\\')
721
filename++;
722
else if (tomoyo_byte_range(filename + 1))
723
filename += 3;
724
else
725
return false;
726
}
727
break;
728
case '\\':
729
if (c != '\\')
730
return false;
731
if (*++filename != '\\')
732
return false;
733
break;
734
case '+':
735
if (!isdigit(c))
736
return false;
737
break;
738
case 'x':
739
if (!isxdigit(c))
740
return false;
741
break;
742
case 'a':
743
if (!tomoyo_alphabet_char(c))
744
return false;
745
break;
746
case '0':
747
case '1':
748
case '2':
749
case '3':
750
if (c == '\\' && tomoyo_byte_range(filename + 1)
751
&& strncmp(filename + 1, pattern, 3) == 0) {
752
filename += 3;
753
pattern += 2;
754
break;
755
}
756
return false; /* Not matched. */
757
case '*':
758
case '@':
759
for (i = 0; i <= filename_end - filename; i++) {
760
if (tomoyo_file_matches_pattern2(
761
filename + i, filename_end,
762
pattern + 1, pattern_end))
763
return true;
764
c = filename[i];
765
if (c == '.' && *pattern == '@')
766
break;
767
if (c != '\\')
768
continue;
769
if (filename[i + 1] == '\\')
770
i++;
771
else if (tomoyo_byte_range(filename + i + 1))
772
i += 3;
773
else
774
break; /* Bad pattern. */
775
}
776
return false; /* Not matched. */
777
default:
778
j = 0;
779
c = *pattern;
780
if (c == '$') {
781
while (isdigit(filename[j]))
782
j++;
783
} else if (c == 'X') {
784
while (isxdigit(filename[j]))
785
j++;
786
} else if (c == 'A') {
787
while (tomoyo_alphabet_char(filename[j]))
788
j++;
789
}
790
for (i = 1; i <= j; i++) {
791
if (tomoyo_file_matches_pattern2(
792
filename + i, filename_end,
793
pattern + 1, pattern_end))
794
return true;
795
}
796
return false; /* Not matched or bad pattern. */
797
}
798
filename++;
799
pattern++;
800
}
801
while (*pattern == '\\' &&
802
(*(pattern + 1) == '*' || *(pattern + 1) == '@'))
803
pattern += 2;
804
return filename == filename_end && pattern == pattern_end;
805
}
806
807
/**
808
* tomoyo_file_matches_pattern - Pattern matching without '/' character.
809
*
810
* @filename: The start of string to check.
811
* @filename_end: The end of string to check.
812
* @pattern: The start of pattern to compare.
813
* @pattern_end: The end of pattern to compare.
814
*
815
* Returns true if @filename matches @pattern, false otherwise.
816
*/
817
static bool tomoyo_file_matches_pattern(const char *filename,
818
const char *filename_end,
819
const char *pattern,
820
const char *pattern_end)
821
{
822
const char *pattern_start = pattern;
823
bool first = true;
824
bool result;
825
826
while (pattern < pattern_end - 1) {
827
/* Split at "\-" pattern. */
828
if (*pattern++ != '\\' || *pattern++ != '-')
829
continue;
830
result = tomoyo_file_matches_pattern2(filename,
831
filename_end,
832
pattern_start,
833
pattern - 2);
834
if (first)
835
result = !result;
836
if (result)
837
return false;
838
first = false;
839
pattern_start = pattern;
840
}
841
result = tomoyo_file_matches_pattern2(filename, filename_end,
842
pattern_start, pattern_end);
843
return first ? result : !result;
844
}
845
846
/**
847
* tomoyo_path_matches_pattern2 - Do pathname pattern matching.
848
*
849
* @f: The start of string to check.
850
* @p: The start of pattern to compare.
851
*
852
* Returns true if @f matches @p, false otherwise.
853
*/
854
static bool tomoyo_path_matches_pattern2(const char *f, const char *p)
855
{
856
const char *f_delimiter;
857
const char *p_delimiter;
858
859
while (*f && *p) {
860
f_delimiter = strchr(f, '/');
861
if (!f_delimiter)
862
f_delimiter = f + strlen(f);
863
p_delimiter = strchr(p, '/');
864
if (!p_delimiter)
865
p_delimiter = p + strlen(p);
866
if (*p == '\\' && *(p + 1) == '{')
867
goto recursive;
868
if (!tomoyo_file_matches_pattern(f, f_delimiter, p,
869
p_delimiter))
870
return false;
871
f = f_delimiter;
872
if (*f)
873
f++;
874
p = p_delimiter;
875
if (*p)
876
p++;
877
}
878
/* Ignore trailing "\*" and "\@" in @pattern. */
879
while (*p == '\\' &&
880
(*(p + 1) == '*' || *(p + 1) == '@'))
881
p += 2;
882
return !*f && !*p;
883
recursive:
884
/*
885
* The "\{" pattern is permitted only after '/' character.
886
* This guarantees that below "*(p - 1)" is safe.
887
* Also, the "\}" pattern is permitted only before '/' character
888
* so that "\{" + "\}" pair will not break the "\-" operator.
889
*/
890
if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
891
*(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
892
return false; /* Bad pattern. */
893
do {
894
/* Compare current component with pattern. */
895
if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2,
896
p_delimiter - 2))
897
break;
898
/* Proceed to next component. */
899
f = f_delimiter;
900
if (!*f)
901
break;
902
f++;
903
/* Continue comparison. */
904
if (tomoyo_path_matches_pattern2(f, p_delimiter + 1))
905
return true;
906
f_delimiter = strchr(f, '/');
907
} while (f_delimiter);
908
return false; /* Not matched. */
909
}
910
911
/**
912
* tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
913
*
914
* @filename: The filename to check.
915
* @pattern: The pattern to compare.
916
*
917
* Returns true if matches, false otherwise.
918
*
919
* The following patterns are available.
920
* \\ \ itself.
921
* \ooo Octal representation of a byte.
922
* \* Zero or more repetitions of characters other than '/'.
923
* \@ Zero or more repetitions of characters other than '/' or '.'.
924
* \? 1 byte character other than '/'.
925
* \$ One or more repetitions of decimal digits.
926
* \+ 1 decimal digit.
927
* \X One or more repetitions of hexadecimal digits.
928
* \x 1 hexadecimal digit.
929
* \A One or more repetitions of alphabet characters.
930
* \a 1 alphabet character.
931
*
932
* \- Subtraction operator.
933
*
934
* /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
935
* /dir/dir/dir/ ).
936
*/
937
bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
938
const struct tomoyo_path_info *pattern)
939
{
940
const char *f = filename->name;
941
const char *p = pattern->name;
942
const int len = pattern->const_len;
943
944
/* If @pattern doesn't contain pattern, I can use strcmp(). */
945
if (!pattern->is_patterned)
946
return !tomoyo_pathcmp(filename, pattern);
947
/* Don't compare directory and non-directory. */
948
if (filename->is_dir != pattern->is_dir)
949
return false;
950
/* Compare the initial length without patterns. */
951
if (strncmp(f, p, len))
952
return false;
953
f += len;
954
p += len;
955
return tomoyo_path_matches_pattern2(f, p);
956
}
957
958
/**
959
* tomoyo_get_exe - Get tomoyo_realpath() of current process.
960
*
961
* Returns the tomoyo_realpath() of current process on success, NULL otherwise.
962
*
963
* This function uses kzalloc(), so the caller must call kfree()
964
* if this function didn't return NULL.
965
*/
966
const char *tomoyo_get_exe(void)
967
{
968
struct file *exe_file;
969
const char *cp;
970
struct mm_struct *mm = current->mm;
971
972
if (!mm)
973
return NULL;
974
exe_file = get_mm_exe_file(mm);
975
if (!exe_file)
976
return NULL;
977
978
cp = tomoyo_realpath_from_path(&exe_file->f_path);
979
fput(exe_file);
980
return cp;
981
}
982
983
/**
984
* tomoyo_get_mode - Get MAC mode.
985
*
986
* @ns: Pointer to "struct tomoyo_policy_namespace".
987
* @profile: Profile number.
988
* @index: Index number of functionality.
989
*
990
* Returns mode.
991
*/
992
int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
993
const u8 index)
994
{
995
u8 mode;
996
struct tomoyo_profile *p;
997
998
if (!tomoyo_policy_loaded)
999
return TOMOYO_CONFIG_DISABLED;
1000
p = tomoyo_profile(ns, profile);
1001
mode = p->config[index];
1002
if (mode == TOMOYO_CONFIG_USE_DEFAULT)
1003
mode = p->config[tomoyo_index2category[index]
1004
+ TOMOYO_MAX_MAC_INDEX];
1005
if (mode == TOMOYO_CONFIG_USE_DEFAULT)
1006
mode = p->default_config;
1007
return mode & 3;
1008
}
1009
1010
/**
1011
* tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members.
1012
*
1013
* @r: Pointer to "struct tomoyo_request_info" to initialize.
1014
* @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain().
1015
* @index: Index number of functionality.
1016
*
1017
* Returns mode.
1018
*/
1019
int tomoyo_init_request_info(struct tomoyo_request_info *r,
1020
struct tomoyo_domain_info *domain, const u8 index)
1021
{
1022
u8 profile;
1023
1024
memset(r, 0, sizeof(*r));
1025
if (!domain)
1026
domain = tomoyo_domain();
1027
r->domain = domain;
1028
profile = domain->profile;
1029
r->profile = profile;
1030
r->type = index;
1031
r->mode = tomoyo_get_mode(domain->ns, profile, index);
1032
return r->mode;
1033
}
1034
1035
/**
1036
* tomoyo_domain_quota_is_ok - Check for domain's quota.
1037
*
1038
* @r: Pointer to "struct tomoyo_request_info".
1039
*
1040
* Returns true if the domain is not exceeded quota, false otherwise.
1041
*
1042
* Caller holds tomoyo_read_lock().
1043
*/
1044
bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
1045
{
1046
unsigned int count = 0;
1047
struct tomoyo_domain_info *domain = r->domain;
1048
struct tomoyo_acl_info *ptr;
1049
1050
if (r->mode != TOMOYO_CONFIG_LEARNING)
1051
return false;
1052
if (!domain)
1053
return true;
1054
if (READ_ONCE(domain->flags[TOMOYO_DIF_QUOTA_WARNED]))
1055
return false;
1056
list_for_each_entry_rcu(ptr, &domain->acl_info_list, list,
1057
srcu_read_lock_held(&tomoyo_ss)) {
1058
u16 perm;
1059
1060
if (ptr->is_deleted)
1061
continue;
1062
/*
1063
* Reading perm bitmap might race with tomoyo_merge_*() because
1064
* caller does not hold tomoyo_policy_lock mutex. But exceeding
1065
* max_learning_entry parameter by a few entries does not harm.
1066
*/
1067
switch (ptr->type) {
1068
case TOMOYO_TYPE_PATH_ACL:
1069
perm = data_race(container_of(ptr, struct tomoyo_path_acl, head)->perm);
1070
break;
1071
case TOMOYO_TYPE_PATH2_ACL:
1072
perm = data_race(container_of(ptr, struct tomoyo_path2_acl, head)->perm);
1073
break;
1074
case TOMOYO_TYPE_PATH_NUMBER_ACL:
1075
perm = data_race(container_of(ptr, struct tomoyo_path_number_acl, head)
1076
->perm);
1077
break;
1078
case TOMOYO_TYPE_MKDEV_ACL:
1079
perm = data_race(container_of(ptr, struct tomoyo_mkdev_acl, head)->perm);
1080
break;
1081
case TOMOYO_TYPE_INET_ACL:
1082
perm = data_race(container_of(ptr, struct tomoyo_inet_acl, head)->perm);
1083
break;
1084
case TOMOYO_TYPE_UNIX_ACL:
1085
perm = data_race(container_of(ptr, struct tomoyo_unix_acl, head)->perm);
1086
break;
1087
case TOMOYO_TYPE_MANUAL_TASK_ACL:
1088
perm = 0;
1089
break;
1090
default:
1091
perm = 1;
1092
}
1093
count += hweight16(perm);
1094
}
1095
if (count < tomoyo_profile(domain->ns, domain->profile)->
1096
pref[TOMOYO_PREF_MAX_LEARNING_ENTRY])
1097
return true;
1098
WRITE_ONCE(domain->flags[TOMOYO_DIF_QUOTA_WARNED], true);
1099
/* r->granted = false; */
1100
tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]);
1101
#ifndef CONFIG_SECURITY_TOMOYO_INSECURE_BUILTIN_SETTING
1102
pr_warn("WARNING: Domain '%s' has too many ACLs to hold. Stopped learning mode.\n",
1103
domain->domainname->name);
1104
#endif
1105
return false;
1106
}
1107
1108