オープンソース・ソフトウェアの開発とダウンロード

Subversion リポジトリの参照

Contents of /trunk/1.8.x/ccs-patch/security/ccsecurity/util.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3949 - (show annotations) (download) (as text)
Sun Sep 5 11:50:03 2010 UTC (13 years, 9 months ago) by kumaneko
File MIME type: text/x-csrc
File size: 27584 byte(s)


1 /*
2 * security/ccsecurity/util.c
3 *
4 * Copyright (C) 2005-2010 NTT DATA CORPORATION
5 *
6 * Version: 1.8.0-pre 2010/09/01
7 *
8 * This file is applicable to both 2.4.30 and 2.6.11 and later.
9 * See README.ccs for ChangeLog.
10 *
11 */
12
13 #include "internal.h"
14
15 /* Lock for protecting policy. */
16 DEFINE_MUTEX(ccs_policy_lock);
17
18 /* Has /sbin/init started? */
19 bool ccs_policy_loaded;
20
21 /* Index table for searching parent category. */
22 const u8 ccs_index2category[CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX] = {
23 [CCS_MAC_FILE_EXECUTE] = CCS_MAC_CATEGORY_FILE,
24 [CCS_MAC_FILE_OPEN] = CCS_MAC_CATEGORY_FILE,
25 [CCS_MAC_FILE_CREATE] = CCS_MAC_CATEGORY_FILE,
26 [CCS_MAC_FILE_UNLINK] = CCS_MAC_CATEGORY_FILE,
27 [CCS_MAC_FILE_MKDIR] = CCS_MAC_CATEGORY_FILE,
28 [CCS_MAC_FILE_RMDIR] = CCS_MAC_CATEGORY_FILE,
29 [CCS_MAC_FILE_MKFIFO] = CCS_MAC_CATEGORY_FILE,
30 [CCS_MAC_FILE_MKSOCK] = CCS_MAC_CATEGORY_FILE,
31 [CCS_MAC_FILE_TRUNCATE] = CCS_MAC_CATEGORY_FILE,
32 [CCS_MAC_FILE_SYMLINK] = CCS_MAC_CATEGORY_FILE,
33 [CCS_MAC_FILE_MKBLOCK] = CCS_MAC_CATEGORY_FILE,
34 [CCS_MAC_FILE_MKCHAR] = CCS_MAC_CATEGORY_FILE,
35 [CCS_MAC_FILE_LINK] = CCS_MAC_CATEGORY_FILE,
36 [CCS_MAC_FILE_RENAME] = CCS_MAC_CATEGORY_FILE,
37 [CCS_MAC_FILE_CHMOD] = CCS_MAC_CATEGORY_FILE,
38 [CCS_MAC_FILE_CHOWN] = CCS_MAC_CATEGORY_FILE,
39 [CCS_MAC_FILE_CHGRP] = CCS_MAC_CATEGORY_FILE,
40 [CCS_MAC_FILE_IOCTL] = CCS_MAC_CATEGORY_FILE,
41 [CCS_MAC_FILE_CHROOT] = CCS_MAC_CATEGORY_FILE,
42 [CCS_MAC_FILE_MOUNT] = CCS_MAC_CATEGORY_FILE,
43 [CCS_MAC_FILE_UMOUNT] = CCS_MAC_CATEGORY_FILE,
44 [CCS_MAC_FILE_PIVOT_ROOT] = CCS_MAC_CATEGORY_FILE,
45 [CCS_MAC_ENVIRON] = CCS_MAC_CATEGORY_MISC,
46 [CCS_MAC_NETWORK_INET_STREAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
47 [CCS_MAC_NETWORK_INET_STREAM_LISTEN] = CCS_MAC_CATEGORY_NETWORK,
48 [CCS_MAC_NETWORK_INET_STREAM_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
49 [CCS_MAC_NETWORK_INET_STREAM_ACCEPT] = CCS_MAC_CATEGORY_NETWORK,
50 [CCS_MAC_NETWORK_INET_DGRAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
51 [CCS_MAC_NETWORK_INET_DGRAM_SEND] = CCS_MAC_CATEGORY_NETWORK,
52 [CCS_MAC_NETWORK_INET_DGRAM_RECV] = CCS_MAC_CATEGORY_NETWORK,
53 [CCS_MAC_NETWORK_INET_RAW_BIND] = CCS_MAC_CATEGORY_NETWORK,
54 [CCS_MAC_NETWORK_INET_RAW_SEND] = CCS_MAC_CATEGORY_NETWORK,
55 [CCS_MAC_NETWORK_INET_RAW_RECV] = CCS_MAC_CATEGORY_NETWORK,
56 [CCS_MAC_NETWORK_UNIX_STREAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
57 [CCS_MAC_NETWORK_UNIX_STREAM_LISTEN] = CCS_MAC_CATEGORY_NETWORK,
58 [CCS_MAC_NETWORK_UNIX_STREAM_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
59 [CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT] = CCS_MAC_CATEGORY_NETWORK,
60 [CCS_MAC_NETWORK_UNIX_DGRAM_BIND] = CCS_MAC_CATEGORY_NETWORK,
61 [CCS_MAC_NETWORK_UNIX_DGRAM_SEND] = CCS_MAC_CATEGORY_NETWORK,
62 [CCS_MAC_NETWORK_UNIX_DGRAM_RECV] = CCS_MAC_CATEGORY_NETWORK,
63 [CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND] = CCS_MAC_CATEGORY_NETWORK,
64 [CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = CCS_MAC_CATEGORY_NETWORK,
65 [CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
66 [CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT] = CCS_MAC_CATEGORY_NETWORK,
67 [CCS_MAC_SIGNAL] = CCS_MAC_CATEGORY_IPC,
68 [CCS_MAX_MAC_INDEX + CCS_USE_ROUTE_SOCKET]
69 = CCS_MAC_CATEGORY_CAPABILITY,
70 [CCS_MAX_MAC_INDEX + CCS_USE_PACKET_SOCKET]
71 = CCS_MAC_CATEGORY_CAPABILITY,
72 [CCS_MAX_MAC_INDEX + CCS_SYS_REBOOT]
73 = CCS_MAC_CATEGORY_CAPABILITY,
74 [CCS_MAX_MAC_INDEX + CCS_SYS_VHANGUP]
75 = CCS_MAC_CATEGORY_CAPABILITY,
76 [CCS_MAX_MAC_INDEX + CCS_SYS_SETTIME]
77 = CCS_MAC_CATEGORY_CAPABILITY,
78 [CCS_MAX_MAC_INDEX + CCS_SYS_NICE]
79 = CCS_MAC_CATEGORY_CAPABILITY,
80 [CCS_MAX_MAC_INDEX + CCS_SYS_SETHOSTNAME]
81 = CCS_MAC_CATEGORY_CAPABILITY,
82 [CCS_MAX_MAC_INDEX + CCS_USE_KERNEL_MODULE]
83 = CCS_MAC_CATEGORY_CAPABILITY,
84 [CCS_MAX_MAC_INDEX + CCS_SYS_KEXEC_LOAD]
85 = CCS_MAC_CATEGORY_CAPABILITY,
86 [CCS_MAX_MAC_INDEX + CCS_SYS_PTRACE]
87 = CCS_MAC_CATEGORY_CAPABILITY,
88 };
89
90 /* Utility functions. */
91
92 bool ccs_permstr(const char *string, const char *keyword)
93 {
94 const char *cp = strstr(string, keyword);
95 if (cp)
96 return cp == string || *(cp - 1) == '/';
97 return false;
98 }
99
100 /**
101 * ccs_parse_ulong - Parse an "unsigned long" value.
102 *
103 * @result: Pointer to "unsigned long".
104 * @str: Pointer to string to parse.
105 *
106 * Returns value type on success, 0 otherwise.
107 *
108 * The @src is updated to point the first character after the value
109 * on success.
110 */
111 u8 ccs_parse_ulong(unsigned long *result, char **str)
112 {
113 const char *cp = *str;
114 char *ep;
115 int base = 10;
116 if (*cp == '0') {
117 char c = *(cp + 1);
118 if (c == 'x' || c == 'X') {
119 base = 16;
120 cp += 2;
121 } else if (c >= '0' && c <= '7') {
122 base = 8;
123 cp++;
124 }
125 }
126 *result = simple_strtoul(cp, &ep, base);
127 if (cp == ep)
128 return 0;
129 *str = ep;
130 switch (base) {
131 case 16:
132 return CCS_VALUE_TYPE_HEXADECIMAL;
133 case 8:
134 return CCS_VALUE_TYPE_OCTAL;
135 default:
136 return CCS_VALUE_TYPE_DECIMAL;
137 }
138 }
139
140 /**
141 * ccs_print_ulong - Print an "unsigned long" value.
142 *
143 * @buffer: Pointer to buffer.
144 * @buffer_len: Size of @buffer.
145 * @value: An "unsigned long" value.
146 * @type: Type of @value.
147 *
148 * Returns nothing.
149 */
150 void ccs_print_ulong(char *buffer, const int buffer_len,
151 const unsigned long value, const u8 type)
152 {
153 if (type == CCS_VALUE_TYPE_DECIMAL)
154 snprintf(buffer, buffer_len, "%lu", value);
155 else if (type == CCS_VALUE_TYPE_OCTAL)
156 snprintf(buffer, buffer_len, "0%lo", value);
157 else
158 snprintf(buffer, buffer_len, "0x%lX", value);
159 }
160
161 /**
162 * ccs_parse_name_union - Parse a ccs_name_union.
163 *
164 * @filename: Name or name group.
165 * @ptr: Pointer to "struct ccs_name_union".
166 *
167 * Returns true on success, false otherwise.
168 */
169 bool ccs_parse_name_union(const char *filename, struct ccs_name_union *ptr)
170 {
171 if (!ccs_correct_word(filename))
172 return false;
173 if (filename[0] == '@') {
174 ptr->group = ccs_get_group(filename + 1, CCS_PATH_GROUP);
175 ptr->is_group = true;
176 return ptr->group != NULL;
177 }
178 ptr->filename = ccs_get_name(filename);
179 ptr->is_group = false;
180 return ptr->filename != NULL;
181 }
182
183 /**
184 * ccs_parse_number_union - Parse a ccs_number_union.
185 *
186 * @data: Number or number range or number group.
187 * @ptr: Pointer to "struct ccs_number_union".
188 *
189 * Returns true on success, false otherwise.
190 */
191 bool ccs_parse_number_union(char *data, struct ccs_number_union *num)
192 {
193 u8 type;
194 unsigned long v;
195 memset(num, 0, sizeof(*num));
196 if (!data[0])
197 return false;
198 if (data[0] == '@') {
199 if (!ccs_correct_word(data))
200 return false;
201 num->group = ccs_get_group(data + 1, CCS_NUMBER_GROUP);
202 num->is_group = true;
203 return num->group != NULL;
204 }
205 type = ccs_parse_ulong(&v, &data);
206 if (!type)
207 return false;
208 num->values[0] = v;
209 num->value_type[0] = type;
210 if (!*data) {
211 num->values[1] = v;
212 num->value_type[1] = type;
213 return true;
214 }
215 if (*data++ != '-')
216 return false;
217 type = ccs_parse_ulong(&v, &data);
218 if (!type || *data)
219 return false;
220 num->values[1] = v;
221 num->value_type[1] = type;
222 return true;
223 }
224
225 /**
226 * ccs_byte_range - Check whether the string is a \ooo style octal value.
227 *
228 * @str: Pointer to the string.
229 *
230 * Returns true if @str is a \ooo style octal value, false otherwise.
231 */
232 static bool ccs_byte_range(const char *str)
233 {
234 return *str >= '0' && *str++ <= '3' &&
235 *str >= '0' && *str++ <= '7' &&
236 *str >= '0' && *str <= '7';
237 }
238
239 /**
240 * ccs_decimal - Check whether the character is a decimal character.
241 *
242 * @c: The character to check.
243 *
244 * Returns true if @c is a decimal character, false otherwise.
245 */
246 static bool ccs_decimal(const char c)
247 {
248 return c >= '0' && c <= '9';
249 }
250
251 /**
252 * ccs_hexadecimal - Check whether the character is a hexadecimal character.
253 *
254 * @c: The character to check.
255 *
256 * Returns true if @c is a hexadecimal character, false otherwise.
257 */
258 static bool ccs_hexadecimal(const char c)
259 {
260 return (c >= '0' && c <= '9') ||
261 (c >= 'A' && c <= 'F') ||
262 (c >= 'a' && c <= 'f');
263 }
264
265 /**
266 * ccs_alphabet_char - Check whether the character is an alphabet.
267 *
268 * @c: The character to check.
269 *
270 * Returns true if @c is an alphabet character, false otherwise.
271 */
272 static bool ccs_alphabet_char(const char c)
273 {
274 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
275 }
276
277 /**
278 * ccs_make_byte - Make byte value from three octal characters.
279 *
280 * @c1: The first character.
281 * @c2: The second character.
282 * @c3: The third character.
283 *
284 * Returns byte value.
285 */
286 static u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3)
287 {
288 return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
289 }
290
291 /**
292 * ccs_str_starts - Check whether the given string starts with the given keyword.
293 *
294 * @src: Pointer to pointer to the string.
295 * @find: Pointer to the keyword.
296 *
297 * Returns true if @src starts with @find, false otherwise.
298 *
299 * The @src is updated to point the first character after the @find
300 * if @src starts with @find.
301 */
302 bool ccs_str_starts(char **src, const char *find)
303 {
304 const int len = strlen(find);
305 char *tmp = *src;
306 if (strncmp(tmp, find, len))
307 return false;
308 tmp += len;
309 *src = tmp;
310 return true;
311 }
312
313 /**
314 * ccs_normalize_line - Format string.
315 *
316 * @buffer: The line to normalize.
317 *
318 * Leading and trailing whitespaces are removed.
319 * Multiple whitespaces are packed into single space.
320 *
321 * Returns nothing.
322 */
323 void ccs_normalize_line(unsigned char *buffer)
324 {
325 unsigned char *sp = buffer;
326 unsigned char *dp = buffer;
327 bool first = true;
328 while (*sp && (*sp <= ' ' || *sp >= 127))
329 sp++;
330 while (*sp) {
331 if (!first)
332 *dp++ = ' ';
333 first = false;
334 while (*sp > ' ' && *sp < 127)
335 *dp++ = *sp++;
336 while (*sp && (*sp <= ' ' || *sp >= 127))
337 sp++;
338 }
339 *dp = '\0';
340 }
341
342 /**
343 * ccs_tokenize - Tokenize string.
344 *
345 * @buffer: The line to tokenize.
346 * @w: Pointer to "char *".
347 * @size: Sizeof @w .
348 *
349 * Returns true on success, false otherwise.
350 */
351 bool ccs_tokenize(char *buffer, char *w[], size_t size)
352 {
353 int count = size / sizeof(char *);
354 int i;
355 for (i = 0; i < count; i++)
356 w[i] = "";
357 for (i = 0; i < count; i++) {
358 char *cp = strchr(buffer, ' ');
359 if (cp)
360 *cp = '\0';
361 w[i] = buffer;
362 if (!cp)
363 break;
364 buffer = cp + 1;
365 }
366 return i < count || !*buffer;
367 }
368
369 /**
370 * ccs_correct_word2 - Validate a string.
371 *
372 * @string: The string to check. Maybe non-'\0'-terminated.
373 * @len: Length of @string.
374 *
375 * Check whether the given string follows the naming rules.
376 * Returns true if @string follows the naming rules, false otherwise.
377 */
378 static bool ccs_correct_word2(const char *string, size_t len)
379 {
380 const char *const start = string;
381 bool in_repetition = false;
382 unsigned char c;
383 unsigned char d;
384 unsigned char e;
385 if (!len)
386 goto out;
387 while (len--) {
388 c = *string++;
389 if (c == '\\') {
390 if (!len--)
391 goto out;
392 c = *string++;
393 switch (c) {
394 case '\\': /* "\\" */
395 continue;
396 case '$': /* "\$" */
397 case '+': /* "\+" */
398 case '?': /* "\?" */
399 case '*': /* "\*" */
400 case '@': /* "\@" */
401 case 'x': /* "\x" */
402 case 'X': /* "\X" */
403 case 'a': /* "\a" */
404 case 'A': /* "\A" */
405 case '-': /* "\-" */
406 continue;
407 case '{': /* "/\{" */
408 if (string - 3 < start || *(string - 3) != '/')
409 break;
410 in_repetition = true;
411 continue;
412 case '}': /* "\}/" */
413 if (*string != '/')
414 break;
415 if (!in_repetition)
416 break;
417 in_repetition = false;
418 continue;
419 case '0': /* "\ooo" */
420 case '1':
421 case '2':
422 case '3':
423 if (!len-- || !len--)
424 break;
425 d = *string++;
426 e = *string++;
427 if (d < '0' || d > '7' || e < '0' || e > '7')
428 break;
429 c = ccs_make_byte(c, d, e);
430 if (c <= ' ' || c >= 127)
431 continue;
432 }
433 goto out;
434 } else if (in_repetition && c == '/') {
435 goto out;
436 } else if (c <= ' ' || c >= 127) {
437 goto out;
438 }
439 }
440 if (in_repetition)
441 goto out;
442 return true;
443 out:
444 return false;
445 }
446
447 /**
448 * ccs_correct_word - Validate a string.
449 *
450 * @string: The string to check.
451 *
452 * Check whether the given string follows the naming rules.
453 * Returns true if @string follows the naming rules, false otherwise.
454 */
455 bool ccs_correct_word(const char *string)
456 {
457 return ccs_correct_word2(string, strlen(string));
458 }
459
460 /**
461 * ccs_correct_path - Validate a pathname.
462 *
463 * @filename: The pathname to check.
464 *
465 * Check whether the given pathname follows the naming rules.
466 * Returns true if @filename follows the naming rules, false otherwise.
467 */
468 bool ccs_correct_path(const char *filename)
469 {
470 return *filename == '/' && ccs_correct_word(filename);
471 }
472
473 /**
474 * ccs_correct_domain - Check whether the given domainname follows the naming rules.
475 *
476 * @domainname: The domainname to check.
477 *
478 * Returns true if @domainname follows the naming rules, false otherwise.
479 */
480 bool ccs_correct_domain(const unsigned char *domainname)
481 {
482 if (!domainname || strncmp(domainname, CCS_ROOT_NAME,
483 CCS_ROOT_NAME_LEN))
484 goto out;
485 domainname += CCS_ROOT_NAME_LEN;
486 if (!*domainname)
487 return true;
488 if (*domainname++ != ' ')
489 goto out;
490 while (1) {
491 const unsigned char *cp = strchr(domainname, ' ');
492 if (!cp)
493 break;
494 if (*domainname != '/' ||
495 !ccs_correct_word2(domainname, cp - domainname - 1))
496 goto out;
497 domainname = cp + 1;
498 }
499 return ccs_correct_path(domainname);
500 out:
501 return false;
502 }
503
504 /**
505 * ccs_domain_def - Check whether the given token can be a domainname.
506 *
507 * @buffer: The token to check.
508 *
509 * Returns true if @buffer possibly be a domainname, false otherwise.
510 */
511 bool ccs_domain_def(const unsigned char *buffer)
512 {
513 return !strncmp(buffer, CCS_ROOT_NAME, CCS_ROOT_NAME_LEN);
514 }
515
516 /**
517 * ccs_find_domain - Find a domain by the given name.
518 *
519 * @domainname: The domainname to find.
520 *
521 * Returns pointer to "struct ccs_domain_info" if found, NULL otherwise.
522 *
523 * Caller holds ccs_read_lock().
524 */
525 struct ccs_domain_info *ccs_find_domain(const char *domainname)
526 {
527 struct ccs_domain_info *domain;
528 struct ccs_path_info name;
529 name.name = domainname;
530 ccs_fill_path_info(&name);
531 list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
532 if (!domain->is_deleted &&
533 !ccs_pathcmp(&name, domain->domainname))
534 return domain;
535 }
536 return NULL;
537 }
538
539 /**
540 * ccs_const_part_length - Evaluate the initial length without a pattern in a token.
541 *
542 * @filename: The string to evaluate.
543 *
544 * Returns the initial length without a pattern in @filename.
545 */
546 static int ccs_const_part_length(const char *filename)
547 {
548 char c;
549 int len = 0;
550 if (!filename)
551 return 0;
552 while (1) {
553 c = *filename++;
554 if (!c)
555 break;
556 if (c != '\\') {
557 len++;
558 continue;
559 }
560 c = *filename++;
561 switch (c) {
562 case '\\': /* "\\" */
563 len += 2;
564 continue;
565 case '0': /* "\ooo" */
566 case '1':
567 case '2':
568 case '3':
569 c = *filename++;
570 if (c < '0' || c > '7')
571 break;
572 c = *filename++;
573 if (c < '0' || c > '7')
574 break;
575 len += 4;
576 continue;
577 }
578 break;
579 }
580 return len;
581 }
582
583 /**
584 * ccs_fill_path_info - Fill in "struct ccs_path_info" members.
585 *
586 * @ptr: Pointer to "struct ccs_path_info" to fill in.
587 *
588 * The caller sets "struct ccs_path_info"->name.
589 */
590 void ccs_fill_path_info(struct ccs_path_info *ptr)
591 {
592 const char *name = ptr->name;
593 const int len = strlen(name);
594 ptr->total_len = len;
595 ptr->const_len = ccs_const_part_length(name);
596 ptr->is_dir = len && (name[len - 1] == '/');
597 ptr->is_patterned = (ptr->const_len < len);
598 ptr->hash = full_name_hash(name, len);
599 }
600
601 /**
602 * ccs_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
603 *
604 * @filename: The start of string to check.
605 * @filename_end: The end of string to check.
606 * @pattern: The start of pattern to compare.
607 * @pattern_end: The end of pattern to compare.
608 *
609 * Returns true if @filename matches @pattern, false otherwise.
610 */
611 static bool ccs_file_matches_pattern2(const char *filename,
612 const char *filename_end,
613 const char *pattern,
614 const char *pattern_end)
615 {
616 while (filename < filename_end && pattern < pattern_end) {
617 char c;
618 if (*pattern != '\\') {
619 if (*filename++ != *pattern++)
620 return false;
621 continue;
622 }
623 c = *filename;
624 pattern++;
625 switch (*pattern) {
626 int i;
627 int j;
628 case '?':
629 if (c == '/') {
630 return false;
631 } else if (c == '\\') {
632 if (filename[1] == '\\')
633 filename++;
634 else if (ccs_byte_range(filename + 1))
635 filename += 3;
636 else
637 return false;
638 }
639 break;
640 case '\\':
641 if (c != '\\')
642 return false;
643 if (*++filename != '\\')
644 return false;
645 break;
646 case '+':
647 if (!ccs_decimal(c))
648 return false;
649 break;
650 case 'x':
651 if (!ccs_hexadecimal(c))
652 return false;
653 break;
654 case 'a':
655 if (!ccs_alphabet_char(c))
656 return false;
657 break;
658 case '0':
659 case '1':
660 case '2':
661 case '3':
662 if (c == '\\' && ccs_byte_range(filename + 1)
663 && !strncmp(filename + 1, pattern, 3)) {
664 filename += 3;
665 pattern += 2;
666 break;
667 }
668 return false; /* Not matched. */
669 case '*':
670 case '@':
671 for (i = 0; i <= filename_end - filename; i++) {
672 if (ccs_file_matches_pattern2(filename + i,
673 filename_end,
674 pattern + 1,
675 pattern_end))
676 return true;
677 c = filename[i];
678 if (c == '.' && *pattern == '@')
679 break;
680 if (c != '\\')
681 continue;
682 if (filename[i + 1] == '\\')
683 i++;
684 else if (ccs_byte_range(filename + i + 1))
685 i += 3;
686 else
687 break; /* Bad pattern. */
688 }
689 return false; /* Not matched. */
690 default:
691 j = 0;
692 c = *pattern;
693 if (c == '$') {
694 while (ccs_decimal(filename[j]))
695 j++;
696 } else if (c == 'X') {
697 while (ccs_hexadecimal(filename[j]))
698 j++;
699 } else if (c == 'A') {
700 while (ccs_alphabet_char(filename[j]))
701 j++;
702 }
703 for (i = 1; i <= j; i++) {
704 if (ccs_file_matches_pattern2(filename + i,
705 filename_end,
706 pattern + 1,
707 pattern_end))
708 return true;
709 }
710 return false; /* Not matched or bad pattern. */
711 }
712 filename++;
713 pattern++;
714 }
715 while (*pattern == '\\' &&
716 (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
717 pattern += 2;
718 return filename == filename_end && pattern == pattern_end;
719 }
720
721 /**
722 * ccs_file_matches_pattern - Pattern matching without '/' character.
723 *
724 * @filename: The start of string to check.
725 * @filename_end: The end of string to check.
726 * @pattern: The start of pattern to compare.
727 * @pattern_end: The end of pattern to compare.
728 *
729 * Returns true if @filename matches @pattern, false otherwise.
730 */
731 static bool ccs_file_matches_pattern(const char *filename,
732 const char *filename_end,
733 const char *pattern,
734 const char *pattern_end)
735 {
736 const char *pattern_start = pattern;
737 bool first = true;
738 bool result;
739 while (pattern < pattern_end - 1) {
740 /* Split at "\-" pattern. */
741 if (*pattern++ != '\\' || *pattern++ != '-')
742 continue;
743 result = ccs_file_matches_pattern2(filename, filename_end,
744 pattern_start, pattern - 2);
745 if (first)
746 result = !result;
747 if (result)
748 return false;
749 first = false;
750 pattern_start = pattern;
751 }
752 result = ccs_file_matches_pattern2(filename, filename_end,
753 pattern_start, pattern_end);
754 return first ? result : !result;
755 }
756
757 /**
758 * ccs_path_matches_pattern2 - Do pathname pattern matching.
759 *
760 * @f: The start of string to check.
761 * @p: The start of pattern to compare.
762 *
763 * Returns true if @f matches @p, false otherwise.
764 */
765 static bool ccs_path_matches_pattern2(const char *f, const char *p)
766 {
767 const char *f_delimiter;
768 const char *p_delimiter;
769 while (*f && *p) {
770 f_delimiter = strchr(f, '/');
771 if (!f_delimiter)
772 f_delimiter = f + strlen(f);
773 p_delimiter = strchr(p, '/');
774 if (!p_delimiter)
775 p_delimiter = p + strlen(p);
776 if (*p == '\\' && *(p + 1) == '{')
777 goto recursive;
778 if (!ccs_file_matches_pattern(f, f_delimiter, p, p_delimiter))
779 return false;
780 f = f_delimiter;
781 if (*f)
782 f++;
783 p = p_delimiter;
784 if (*p)
785 p++;
786 }
787 /* Ignore trailing "\*" and "\@" in @pattern. */
788 while (*p == '\\' &&
789 (*(p + 1) == '*' || *(p + 1) == '@'))
790 p += 2;
791 return !*f && !*p;
792 recursive:
793 /*
794 * The "\{" pattern is permitted only after '/' character.
795 * This guarantees that below "*(p - 1)" is safe.
796 * Also, the "\}" pattern is permitted only before '/' character
797 * so that "\{" + "\}" pair will not break the "\-" operator.
798 */
799 if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
800 *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
801 return false; /* Bad pattern. */
802 do {
803 /* Compare current component with pattern. */
804 if (!ccs_file_matches_pattern(f, f_delimiter, p + 2,
805 p_delimiter - 2))
806 break;
807 /* Proceed to next component. */
808 f = f_delimiter;
809 if (!*f)
810 break;
811 f++;
812 /* Continue comparison. */
813 if (ccs_path_matches_pattern2(f, p_delimiter + 1))
814 return true;
815 f_delimiter = strchr(f, '/');
816 } while (f_delimiter);
817 return false; /* Not matched. */
818 }
819
820 /**
821 * ccs_path_matches_pattern - Check whether the given filename matches the given pattern.
822 *
823 * @filename: The filename to check.
824 * @pattern: The pattern to compare.
825 *
826 * Returns true if matches, false otherwise.
827 *
828 * The following patterns are available.
829 * \\ \ itself.
830 * \ooo Octal representation of a byte.
831 * \* Zero or more repetitions of characters other than '/'.
832 * \@ Zero or more repetitions of characters other than '/' or '.'.
833 * \? 1 byte character other than '/'.
834 * \$ One or more repetitions of decimal digits.
835 * \+ 1 decimal digit.
836 * \X One or more repetitions of hexadecimal digits.
837 * \x 1 hexadecimal digit.
838 * \A One or more repetitions of alphabet characters.
839 * \a 1 alphabet character.
840 *
841 * \- Subtraction operator.
842 *
843 * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
844 * /dir/dir/dir/ ).
845 */
846 bool ccs_path_matches_pattern(const struct ccs_path_info *filename,
847 const struct ccs_path_info *pattern)
848 {
849 const char *f = filename->name;
850 const char *p = pattern->name;
851 const int len = pattern->const_len;
852 /* If @pattern doesn't contain pattern, I can use strcmp(). */
853 if (!pattern->is_patterned)
854 return !ccs_pathcmp(filename, pattern);
855 /* Don't compare directory and non-directory. */
856 if (filename->is_dir != pattern->is_dir)
857 return false;
858 /* Compare the initial length without patterns. */
859 if (strncmp(f, p, len))
860 return false;
861 f += len;
862 p += len;
863 return ccs_path_matches_pattern2(f, p);
864 }
865
866 /**
867 * ccs_get_exe - Get ccs_realpath() of current process.
868 *
869 * Returns the ccs_realpath() of current process on success, NULL otherwise.
870 *
871 * This function uses kzalloc(), so the caller must kfree()
872 * if this function didn't return NULL.
873 */
874 const char *ccs_get_exe(void)
875 {
876 struct mm_struct *mm = current->mm;
877 struct vm_area_struct *vma;
878 const char *cp = NULL;
879 if (!mm)
880 return NULL;
881 down_read(&mm->mmap_sem);
882 for (vma = mm->mmap; vma; vma = vma->vm_next) {
883 if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
884 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
885 struct path path = { vma->vm_file->f_vfsmnt,
886 vma->vm_file->f_dentry };
887 cp = ccs_realpath_from_path(&path);
888 #else
889 cp = ccs_realpath_from_path(&vma->vm_file->f_path);
890 #endif
891 break;
892 }
893 }
894 up_read(&mm->mmap_sem);
895 return cp;
896 }
897
898 /**
899 * ccs_get_config - Get config.
900 *
901 * @profile: Profile number.
902 * @index: Index number of functionality.
903 *
904 * Returns config.
905 */
906 u8 ccs_get_config(const u8 profile, const u8 index)
907 {
908 u8 config;
909 const struct ccs_profile *p;
910 if (!ccs_policy_loaded)
911 return CCS_CONFIG_DISABLED;
912 p = ccs_profile(profile);
913 config = p->config[index];
914 if (config == CCS_CONFIG_USE_DEFAULT)
915 config = p->config[ccs_index2category[index]
916 + CCS_MAX_MAC_INDEX
917 + CCS_MAX_CAPABILITY_INDEX];
918 if (config == CCS_CONFIG_USE_DEFAULT)
919 config = p->default_config;
920 return config;
921 }
922
923 /**
924 * ccs_init_request_info - Initialize "struct ccs_request_info" members.
925 *
926 * @r: Pointer to "struct ccs_request_info" to initialize.
927 * @index: Index number of functionality.
928 *
929 * Returns mode.
930 */
931 int ccs_init_request_info(struct ccs_request_info *r, const u8 index)
932 {
933 u8 i;
934 const char *buf;
935 for (i = 0; i < 255; i++) {
936 struct ccs_domain_info *domain = ccs_current_domain();
937 const u8 profile = domain->profile;
938 memset(r, 0, sizeof(*r));
939 r->profile = profile;
940 r->type = index;
941 r->mode = ccs_get_mode(profile, index);
942 r->param_type = CCS_TYPE_AUTO_TASK_ACL;
943 ccs_check_acl(r, NULL);
944 if (!r->granted)
945 return r->mode;
946 buf = container_of(r->matched_acl, typeof(struct ccs_task_acl),
947 head)->domainname->name;
948 if (!ccs_assign_domain(buf, profile, domain->group, true))
949 break;
950 }
951 printk(KERN_WARNING "ERROR: Unable to transit to '%s' domain.\n",
952 buf);
953 force_sig(SIGKILL, current);
954 return CCS_CONFIG_DISABLED;
955 }
956
957 /**
958 * ccs_last_word - Get last component of a domainname.
959 *
960 * @name: Domainname to check.
961 *
962 * Returns the last word of @name.
963 */
964 const char *ccs_last_word(const char *name)
965 {
966 const char *cp = strrchr(name, ' ');
967 if (cp)
968 return cp + 1;
969 return name;
970 }
971
972 /**
973 * ccs_warn_log - Print warning or error message on console.
974 *
975 * @r: Pointer to "struct ccs_request_info".
976 * @fmt: The printf()'s format string, followed by parameters.
977 */
978 void ccs_warn_log(struct ccs_request_info *r, const char *fmt, ...)
979 {
980 va_list args;
981 char *buffer;
982 const struct ccs_domain_info * const domain = ccs_current_domain();
983 if (!(ccs_get_config(domain->profile, r->type) & CCS_CONFIG_VERBOSE))
984 return;
985 buffer = kmalloc(4096, CCS_GFP_FLAGS);
986 if (!buffer)
987 return;
988 va_start(args, fmt);
989 vsnprintf(buffer, 4095, fmt, args);
990 va_end(args);
991 buffer[4095] = '\0';
992 printk(KERN_WARNING "%s: Access %s denied for %s\n",
993 r->mode == CCS_CONFIG_ENFORCING ? "ERROR" : "WARNING", buffer,
994 ccs_last_word(domain->domainname->name));
995 kfree(buffer);
996 }
997
998 /**
999 * ccs_domain_quota_ok - Check for domain's quota.
1000 *
1001 * @r: Pointer to "struct ccs_request_info".
1002 *
1003 * Returns true if the domain is not exceeded quota, false otherwise.
1004 *
1005 * Caller holds ccs_read_lock().
1006 */
1007 bool ccs_domain_quota_ok(struct ccs_request_info *r)
1008 {
1009 unsigned int count = 0;
1010 struct ccs_domain_info * const domain = ccs_current_domain();
1011 struct ccs_acl_info *ptr;
1012 if (r->mode != CCS_CONFIG_LEARNING)
1013 return false;
1014 if (!domain)
1015 return true;
1016 list_for_each_entry_rcu(ptr, &domain->acl_info_list[0], list) {
1017 u16 perm;
1018 u8 i;
1019 if (ptr->is_deleted)
1020 continue;
1021 switch (ptr->type) {
1022 case CCS_TYPE_PATH_ACL:
1023 perm = container_of(ptr, struct ccs_path_acl,
1024 head)->perm;
1025 break;
1026 case CCS_TYPE_PATH2_ACL:
1027 perm = container_of(ptr, struct ccs_path2_acl,
1028 head)->perm;
1029 break;
1030 case CCS_TYPE_PATH_NUMBER_ACL:
1031 perm = container_of(ptr, struct ccs_path_number_acl,
1032 head)->perm;
1033 break;
1034 case CCS_TYPE_MKDEV_ACL:
1035 perm = container_of(ptr, struct ccs_mkdev_acl,
1036 head)->perm;
1037 break;
1038 case CCS_TYPE_INET_ACL:
1039 perm = container_of(ptr, struct ccs_inet_acl,
1040 head)->perm;
1041 break;
1042 case CCS_TYPE_UNIX_ACL:
1043 perm = container_of(ptr, struct ccs_unix_acl,
1044 head)->perm;
1045 break;
1046 default:
1047 perm = 1;
1048 }
1049 for (i = 0; i < 16; i++)
1050 if (perm & (1 << i))
1051 count++;
1052 }
1053 if (count < ccs_profile(domain->profile)->preference.
1054 learning_max_entry)
1055 return true;
1056 if (!domain->flags[CCS_DIF_QUOTA_WARNED]) {
1057 domain->flags[CCS_DIF_QUOTA_WARNED] = true;
1058 /* r->granted = false; */
1059 ccs_write_log(r, CCS_KEYWORD_QUOTA_EXCEEDED "\n");
1060 printk(KERN_WARNING "WARNING: "
1061 "Domain '%s' has so many ACLs to hold. "
1062 "Stopped learning mode.\n", domain->domainname->name);
1063 }
1064 return false;
1065 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26