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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2892 - (show annotations) (download) (as text)
Tue Aug 11 02:02:02 2009 UTC (14 years, 9 months ago) by kumaneko
Original Path: branches/ccs-patch/security/ccsecurity/util.c
File MIME type: text/x-csrc
File size: 26291 byte(s)


1 /*
2 * security/ccsecurity/util.c
3 *
4 * Copyright (C) 2005-2009 NTT DATA CORPORATION
5 *
6 * Version: 1.7.0-pre 2009/08/08
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 DEFINE_MUTEX(ccs_policy_lock);
16
17 /* Has /sbin/init started? */
18 bool ccs_policy_loaded;
19
20 /* Capability name used by domain policy. */
21 const char *ccs_capability_control_keyword[CCS_MAX_CAPABILITY_INDEX]
22 = {
23 [CCS_INET_STREAM_SOCKET_CREATE] = "inet_tcp_create",
24 [CCS_INET_STREAM_SOCKET_LISTEN] = "inet_tcp_listen",
25 [CCS_INET_STREAM_SOCKET_CONNECT] = "inet_tcp_connect",
26 [CCS_USE_INET_DGRAM_SOCKET] = "use_inet_udp",
27 [CCS_USE_INET_RAW_SOCKET] = "use_inet_ip",
28 [CCS_USE_ROUTE_SOCKET] = "use_route",
29 [CCS_USE_PACKET_SOCKET] = "use_packet",
30 [CCS_SYS_MOUNT] = "SYS_MOUNT",
31 [CCS_SYS_UMOUNT] = "SYS_UMOUNT",
32 [CCS_SYS_REBOOT] = "SYS_REBOOT",
33 [CCS_SYS_CHROOT] = "SYS_CHROOT",
34 [CCS_SYS_KILL] = "SYS_KILL",
35 [CCS_SYS_VHANGUP] = "SYS_VHANGUP",
36 [CCS_SYS_SETTIME] = "SYS_TIME",
37 [CCS_SYS_NICE] = "SYS_NICE",
38 [CCS_SYS_SETHOSTNAME] = "SYS_SETHOSTNAME",
39 [CCS_USE_KERNEL_MODULE] = "use_kernel_module",
40 [CCS_CREATE_FIFO] = "create_fifo",
41 [CCS_CREATE_BLOCK_DEV] = "create_block_dev",
42 [CCS_CREATE_CHAR_DEV] = "create_char_dev",
43 [CCS_CREATE_UNIX_SOCKET] = "create_unix_socket",
44 [CCS_SYS_LINK] = "SYS_LINK",
45 [CCS_SYS_SYMLINK] = "SYS_SYMLINK",
46 [CCS_SYS_RENAME] = "SYS_RENAME",
47 [CCS_SYS_UNLINK] = "SYS_UNLINK",
48 [CCS_SYS_CHMOD] = "SYS_CHMOD",
49 [CCS_SYS_CHOWN] = "SYS_CHOWN",
50 [CCS_SYS_IOCTL] = "SYS_IOCTL",
51 [CCS_SYS_KEXEC_LOAD] = "SYS_KEXEC_LOAD",
52 [CCS_SYS_PIVOT_ROOT] = "SYS_PIVOT_ROOT",
53 [CCS_SYS_PTRACE] = "SYS_PTRACE",
54 [CCS_CONCEAL_MOUNT] = "conceal_mount",
55 };
56
57 /* Profile table. Memory is allocated as needed. */
58 struct ccs_profile *ccs_profile_ptr[CCS_MAX_PROFILES];
59
60 /* Utility functions. */
61
62 /**
63 * ccs_parse_ulong - Parse an "unsigned long" value.
64 *
65 * @result: Pointer to "unsigned long".
66 * @str: Pointer to string to parse.
67 *
68 * Returns value type on success, 0 otherwise.
69 *
70 * The @src is updated to point the first character after the value
71 * on success.
72 */
73 u8 ccs_parse_ulong(unsigned long *result, char **str)
74 {
75 const char *cp = *str;
76 char *ep;
77 int base = 10;
78 if (*cp == '0') {
79 char c = *(cp + 1);
80 if (c == 'x' || c == 'X') {
81 base = 16;
82 cp += 2;
83 } else if (c >= '0' && c <= '7') {
84 base = 8;
85 cp++;
86 }
87 }
88 *result = simple_strtoul(cp, &ep, base);
89 if (cp == ep)
90 return 0;
91 *str = ep;
92 switch (base) {
93 case 16:
94 return CCS_VALUE_TYPE_HEXADECIMAL;
95 case 8:
96 return CCS_VALUE_TYPE_OCTAL;
97 default:
98 return CCS_VALUE_TYPE_DECIMAL;
99 }
100 }
101
102 /**
103 * ccs_print_ulong - Print an "unsigned long" value.
104 *
105 * @buffer: Pointer to buffer.
106 * @buffer_len: Size of @buffer.
107 * @value: An "unsigned long" value.
108 * @type: Type of @value.
109 *
110 * Returns nothing.
111 */
112 void ccs_print_ulong(char *buffer, const int buffer_len,
113 const unsigned long value, const u8 type)
114 {
115 if (type == CCS_VALUE_TYPE_DECIMAL)
116 snprintf(buffer, buffer_len, "%lu", value);
117 else if (type == CCS_VALUE_TYPE_OCTAL)
118 snprintf(buffer, buffer_len, "0%lo", value);
119 else if (type == CCS_VALUE_TYPE_HEXADECIMAL)
120 snprintf(buffer, buffer_len, "0x%lX", value);
121 else
122 snprintf(buffer, buffer_len, "type(%u)", type);
123 }
124
125 bool ccs_parse_number_union(char *data, struct ccs_number_union *num)
126 {
127 u8 type;
128 unsigned long v;
129 memset(num, 0, sizeof(*num));
130 if (data[0] == '@') {
131 if (!ccs_is_correct_path(data, 0, 0, 0))
132 return false;
133 num->group = ccs_get_number_group(data + 1);
134 num->is_group = true;
135 return num->group != NULL;
136 }
137 type = ccs_parse_ulong(&v, &data);
138 if (!type)
139 return false;
140 num->values[0] = v;
141 num->min_type = type;
142 if (!*data) {
143 num->values[1] = v;
144 num->max_type = type;
145 return true;
146 }
147 if (*data++ != '-')
148 return false;
149 type = ccs_parse_ulong(&v, &data);
150 if (!type || *data)
151 return false;
152 num->values[1] = v;
153 num->max_type = type;
154 return true;
155 }
156
157 /**
158 * ccs_is_byte_range - Check whether the string isa \ooo style octal value.
159 *
160 * @str: Pointer to the string.
161 *
162 * Returns true if @str is a \ooo style octal value, false otherwise.
163 */
164 static inline bool ccs_is_byte_range(const char *str)
165 {
166 return *str >= '0' && *str++ <= '3' &&
167 *str >= '0' && *str++ <= '7' &&
168 *str >= '0' && *str <= '7';
169 }
170
171 /**
172 * ccs_is_decimal - Check whether the character is a decimal character.
173 *
174 * @c: The character to check.
175 *
176 * Returns true if @c is a decimal character, false otherwise.
177 */
178 static inline bool ccs_is_decimal(const char c)
179 {
180 return c >= '0' && c <= '9';
181 }
182
183 /**
184 * ccs_is_hexadecimal - Check whether the character is a hexadecimal character.
185 *
186 * @c: The character to check.
187 *
188 * Returns true if @c is a hexadecimal character, false otherwise.
189 */
190 static inline bool ccs_is_hexadecimal(const char c)
191 {
192 return (c >= '0' && c <= '9') ||
193 (c >= 'A' && c <= 'F') ||
194 (c >= 'a' && c <= 'f');
195 }
196
197 /**
198 * ccs_is_alphabet_char - Check whether the character is an alphabet.
199 *
200 * @c: The character to check.
201 *
202 * Returns true if @c is an alphabet character, false otherwise.
203 */
204 static inline bool ccs_is_alphabet_char(const char c)
205 {
206 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
207 }
208
209 /**
210 * ccs_make_byte - Make byte value from three octal characters.
211 *
212 * @c1: The first character.
213 * @c2: The second character.
214 * @c3: The third character.
215 *
216 * Returns byte value.
217 */
218 static inline u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3)
219 {
220 return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
221 }
222
223 /**
224 * ccs_str_starts - Check whether the given string starts with the given keyword.
225 *
226 * @src: Pointer to pointer to the string.
227 * @find: Pointer to the keyword.
228 *
229 * Returns true if @src starts with @find, false otherwise.
230 *
231 * The @src is updated to point the first character after the @find
232 * if @src starts with @find.
233 */
234 bool ccs_str_starts(char **src, const char *find)
235 {
236 const int len = strlen(find);
237 char *tmp = *src;
238 if (strncmp(tmp, find, len))
239 return false;
240 tmp += len;
241 *src = tmp;
242 return true;
243 }
244
245 /**
246 * ccs_normalize_line - Format string.
247 *
248 * @buffer: The line to normalize.
249 *
250 * Leading and trailing whitespaces are removed.
251 * Multiple whitespaces are packed into single space.
252 *
253 * Returns nothing.
254 */
255 void ccs_normalize_line(unsigned char *buffer)
256 {
257 unsigned char *sp = buffer;
258 unsigned char *dp = buffer;
259 bool first = true;
260 while (*sp && (*sp <= ' ' || *sp >= 127))
261 sp++;
262 while (*sp) {
263 if (!first)
264 *dp++ = ' ';
265 first = false;
266 while (*sp > ' ' && *sp < 127)
267 *dp++ = *sp++;
268 while (*sp && (*sp <= ' ' || *sp >= 127))
269 sp++;
270 }
271 *dp = '\0';
272 }
273
274 /**
275 * ccs_tokenize - Tokenize string.
276 *
277 * @buffer: The line to tokenize.
278 * @w: Pointer to "char *".
279 * @size: Sizeof @w .
280 *
281 * Returns true on success, false otherwise.
282 */
283 bool ccs_tokenize(char *buffer, char *w[], size_t size)
284 {
285 int count = size / sizeof(char *);
286 int i;
287 for (i = 0; i < count; i++)
288 w[i] = "";
289 for (i = 0; i < count; i++) {
290 char *cp = strchr(buffer, ' ');
291 if (cp)
292 *cp = '\0';
293 w[i] = buffer;
294 if (!cp)
295 break;
296 buffer = cp + 1;
297 }
298 return i < count || !*buffer;
299 }
300
301 /**
302 * ccs_is_correct_path - Validate a pathname.
303 * @filename: The pathname to check.
304 * @start_type: Should the pathname start with '/'?
305 * 1 = must / -1 = must not / 0 = don't care
306 * @pattern_type: Can the pathname contain a wildcard?
307 * 1 = must / -1 = must not / 0 = don't care
308 * @end_type: Should the pathname end with '/'?
309 * 1 = must / -1 = must not / 0 = don't care
310 *
311 * Check whether the given filename follows the naming rules.
312 * Returns true if @filename follows the naming rules, false otherwise.
313 */
314 bool ccs_is_correct_path(const char *filename, const s8 start_type,
315 const s8 pattern_type, const s8 end_type)
316 {
317 bool contains_pattern = false;
318 unsigned char c;
319 unsigned char d;
320 unsigned char e;
321 const char *original_filename = filename;
322 if (!filename)
323 goto out;
324 c = *filename;
325 if (start_type == 1) { /* Must start with '/' */
326 if (c != '/')
327 goto out;
328 } else if (start_type == -1) { /* Must not start with '/' */
329 if (c == '/')
330 goto out;
331 }
332 if (c)
333 c = *(filename + strlen(filename) - 1);
334 if (end_type == 1) { /* Must end with '/' */
335 if (c != '/')
336 goto out;
337 } else if (end_type == -1) { /* Must not end with '/' */
338 if (c == '/')
339 goto out;
340 }
341 while (1) {
342 c = *filename++;
343 if (!c)
344 break;
345 if (c == '\\') {
346 c = *filename++;
347 switch (c) {
348 case '\\': /* "\\" */
349 continue;
350 case '$': /* "\$" */
351 case '+': /* "\+" */
352 case '?': /* "\?" */
353 case '*': /* "\*" */
354 case '@': /* "\@" */
355 case 'x': /* "\x" */
356 case 'X': /* "\X" */
357 case 'a': /* "\a" */
358 case 'A': /* "\A" */
359 case '-': /* "\-" */
360 if (pattern_type == -1)
361 break; /* Must not contain pattern */
362 contains_pattern = true;
363 continue;
364 case '0': /* "\ooo" */
365 case '1':
366 case '2':
367 case '3':
368 d = *filename++;
369 if (d < '0' || d > '7')
370 break;
371 e = *filename++;
372 if (e < '0' || e > '7')
373 break;
374 c = ccs_make_byte(c, d, e);
375 if (c && (c <= ' ' || c >= 127))
376 continue; /* pattern is not \000 */
377 }
378 goto out;
379 } else if (c <= ' ' || c >= 127) {
380 goto out;
381 }
382 }
383 if (pattern_type == 1) { /* Must contain pattern */
384 if (!contains_pattern)
385 goto out;
386 }
387 return true;
388 out:
389 printk(KERN_DEBUG "Invalid pathname '%s'\n", original_filename);
390 return false;
391 }
392
393 /**
394 * ccs_is_correct_domain - Check whether the given domainname follows the naming rules.
395 * @domainname: The domainname to check.
396 *
397 * Returns true if @domainname follows the naming rules, false otherwise.
398 */
399 bool ccs_is_correct_domain(const unsigned char *domainname)
400 {
401 unsigned char c;
402 unsigned char d;
403 unsigned char e;
404 const char *org_domainname = domainname;
405 if (!domainname || strncmp(domainname, ROOT_NAME, ROOT_NAME_LEN))
406 goto out;
407 domainname += ROOT_NAME_LEN;
408 if (!*domainname)
409 return true;
410 do {
411 if (*domainname++ != ' ')
412 goto out;
413 if (*domainname++ != '/')
414 goto out;
415 while (1) {
416 c = *domainname;
417 if (!c || c == ' ')
418 break;
419 domainname++;
420 if (c == '\\') {
421 c = *domainname++;
422 switch ((c)) {
423 case '\\': /* "\\" */
424 continue;
425 case '0': /* "\ooo" */
426 case '1':
427 case '2':
428 case '3':
429 d = *domainname++;
430 if (d < '0' || d > '7')
431 break;
432 e = *domainname++;
433 if (e < '0' || e > '7')
434 break;
435 c = ccs_make_byte(c, d, e);
436 if (c && (c <= ' ' || c >= 127))
437 /* pattern is not \000 */
438 continue;
439 }
440 goto out;
441 } else if (c < ' ' || c >= 127) {
442 goto out;
443 }
444 }
445 } while (*domainname);
446 return true;
447 out:
448 printk(KERN_DEBUG "Invalid domainname '%s'\n", org_domainname);
449 return false;
450 }
451
452 /**
453 * ccs_is_domain_def - Check whether the given token can be a domainname.
454 *
455 * @buffer: The token to check.
456 *
457 * Returns true if @buffer possibly be a domainname, false otherwise.
458 */
459 bool ccs_is_domain_def(const unsigned char *buffer)
460 {
461 return !strncmp(buffer, ROOT_NAME, ROOT_NAME_LEN);
462 }
463
464 /**
465 * ccs_find_domain - Find a domain by the given name.
466 *
467 * @domainname: The domainname to find.
468 *
469 * Returns pointer to "struct ccs_domain_info" if found, NULL otherwise.
470 *
471 * Caller holds ccs_read_lock().
472 */
473 struct ccs_domain_info *ccs_find_domain(const char *domainname)
474 {
475 struct ccs_domain_info *domain;
476 struct ccs_path_info name;
477 ccs_check_read_lock();
478 name.name = domainname;
479 ccs_fill_path_info(&name);
480 list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
481 if (!domain->is_deleted &&
482 !ccs_pathcmp(&name, domain->domainname))
483 return domain;
484 }
485 return NULL;
486 }
487
488 /**
489 * ccs_path_depth - Evaluate the number of '/' in a string.
490 *
491 * @pathname: The string to evaluate.
492 *
493 * Returns path depth of the string.
494 *
495 * I score 2 for each of the '/' in the @pathname
496 * and score 1 if the @pathname ends with '/'.
497 */
498 static int ccs_path_depth(const char *pathname)
499 {
500 int i = 0;
501 if (pathname) {
502 const char *ep = pathname + strlen(pathname);
503 if (pathname < ep--) {
504 if (*ep != '/')
505 i++;
506 while (pathname <= ep)
507 if (*ep-- == '/')
508 i += 2;
509 }
510 }
511 return i;
512 }
513
514 /**
515 * ccs_const_part_length - Evaluate the initial length without a pattern in a token.
516 *
517 * @filename: The string to evaluate.
518 *
519 * Returns the initial length without a pattern in @filename.
520 */
521 static int ccs_const_part_length(const char *filename)
522 {
523 char c;
524 int len = 0;
525 if (!filename)
526 return 0;
527 while (1) {
528 c = *filename++;
529 if (!c)
530 break;
531 if (c != '\\') {
532 len++;
533 continue;
534 }
535 c = *filename++;
536 switch (c) {
537 case '\\': /* "\\" */
538 len += 2;
539 continue;
540 case '0': /* "\ooo" */
541 case '1':
542 case '2':
543 case '3':
544 c = *filename++;
545 if (c < '0' || c > '7')
546 break;
547 c = *filename++;
548 if (c < '0' || c > '7')
549 break;
550 len += 4;
551 continue;
552 }
553 break;
554 }
555 return len;
556 }
557
558 /**
559 * ccs_fill_path_info - Fill in "struct ccs_path_info" members.
560 *
561 * @ptr: Pointer to "struct ccs_path_info" to fill in.
562 *
563 * The caller sets "struct ccs_path_info"->name.
564 */
565 void ccs_fill_path_info(struct ccs_path_info *ptr)
566 {
567 const char *name = ptr->name;
568 const int len = strlen(name);
569 ptr->total_len = len;
570 ptr->const_len = ccs_const_part_length(name);
571 ptr->is_dir = len && (name[len - 1] == '/');
572 ptr->is_patterned = (ptr->const_len < len);
573 ptr->hash = full_name_hash(name, len);
574 ptr->depth = ccs_path_depth(name);
575 }
576
577 /**
578 * ccs_file_matches_pattern2 - Pattern matching without '/' character
579 * and "\-" pattern.
580 *
581 * @filename: The start of string to check.
582 * @filename_end: The end of string to check.
583 * @pattern: The start of pattern to compare.
584 * @pattern_end: The end of pattern to compare.
585 *
586 * Returns true if @filename matches @pattern, false otherwise.
587 */
588 static bool ccs_file_matches_pattern2(const char *filename,
589 const char *filename_end,
590 const char *pattern,
591 const char *pattern_end)
592 {
593 while (filename < filename_end && pattern < pattern_end) {
594 char c;
595 if (*pattern != '\\') {
596 if (*filename++ != *pattern++)
597 return false;
598 continue;
599 }
600 c = *filename;
601 pattern++;
602 switch (*pattern) {
603 int i;
604 int j;
605 case '?':
606 if (c == '/') {
607 return false;
608 } else if (c == '\\') {
609 if (filename[1] == '\\')
610 filename++;
611 else if (ccs_is_byte_range(filename + 1))
612 filename += 3;
613 else
614 return false;
615 }
616 break;
617 case '\\':
618 if (c != '\\')
619 return false;
620 if (*++filename != '\\')
621 return false;
622 break;
623 case '+':
624 if (!ccs_is_decimal(c))
625 return false;
626 break;
627 case 'x':
628 if (!ccs_is_hexadecimal(c))
629 return false;
630 break;
631 case 'a':
632 if (!ccs_is_alphabet_char(c))
633 return false;
634 break;
635 case '0':
636 case '1':
637 case '2':
638 case '3':
639 if (c == '\\' && ccs_is_byte_range(filename + 1)
640 && strncmp(filename + 1, pattern, 3) == 0) {
641 filename += 3;
642 pattern += 2;
643 break;
644 }
645 return false; /* Not matched. */
646 case '*':
647 case '@':
648 for (i = 0; i <= filename_end - filename; i++) {
649 if (ccs_file_matches_pattern2(filename + i,
650 filename_end,
651 pattern + 1,
652 pattern_end))
653 return true;
654 c = filename[i];
655 if (c == '.' && *pattern == '@')
656 break;
657 if (c != '\\')
658 continue;
659 if (filename[i + 1] == '\\')
660 i++;
661 else if (ccs_is_byte_range(filename + i + 1))
662 i += 3;
663 else
664 break; /* Bad pattern. */
665 }
666 return false; /* Not matched. */
667 default:
668 j = 0;
669 c = *pattern;
670 if (c == '$') {
671 while (ccs_is_decimal(filename[j]))
672 j++;
673 } else if (c == 'X') {
674 while (ccs_is_hexadecimal(filename[j]))
675 j++;
676 } else if (c == 'A') {
677 while (ccs_is_alphabet_char(filename[j]))
678 j++;
679 }
680 for (i = 1; i <= j; i++) {
681 if (ccs_file_matches_pattern2(filename + i,
682 filename_end,
683 pattern + 1,
684 pattern_end))
685 return true;
686 }
687 return false; /* Not matched or bad pattern. */
688 }
689 filename++;
690 pattern++;
691 }
692 while (*pattern == '\\' &&
693 (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
694 pattern += 2;
695 return filename == filename_end && pattern == pattern_end;
696 }
697
698 /**
699 * ccs_file_matches_pattern - Pattern matching without without '/' character.
700 *
701 * @filename: The start of string to check.
702 * @filename_end: The end of string to check.
703 * @pattern: The start of pattern to compare.
704 * @pattern_end: The end of pattern to compare.
705 *
706 * Returns true if @filename matches @pattern, false otherwise.
707 */
708 static bool ccs_file_matches_pattern(const char *filename,
709 const char *filename_end,
710 const char *pattern,
711 const char *pattern_end)
712 {
713 const char *pattern_start = pattern;
714 bool first = true;
715 bool result;
716 while (pattern < pattern_end - 1) {
717 /* Split at "\-" pattern. */
718 if (*pattern++ != '\\' || *pattern++ != '-')
719 continue;
720 result = ccs_file_matches_pattern2(filename, filename_end,
721 pattern_start, pattern - 2);
722 if (first)
723 result = !result;
724 if (result)
725 return false;
726 first = false;
727 pattern_start = pattern;
728 }
729 result = ccs_file_matches_pattern2(filename, filename_end,
730 pattern_start, pattern_end);
731 return first ? result : !result;
732 }
733
734 /**
735 * ccs_path_matches_pattern - Check whether the given filename matches the given pattern.
736 * @filename: The filename to check.
737 * @pattern: The pattern to compare.
738 *
739 * Returns true if matches, false otherwise.
740 *
741 * The following patterns are available.
742 * \\ \ itself.
743 * \ooo Octal representation of a byte.
744 * \* More than or equals to 0 character other than '/'.
745 * \@ More than or equals to 0 character other than '/' or '.'.
746 * \? 1 byte character other than '/'.
747 * \$ More than or equals to 1 decimal digit.
748 * \+ 1 decimal digit.
749 * \X More than or equals to 1 hexadecimal digit.
750 * \x 1 hexadecimal digit.
751 * \A More than or equals to 1 alphabet character.
752 * \a 1 alphabet character.
753 * \- Subtraction operator.
754 */
755 bool ccs_path_matches_pattern(const struct ccs_path_info *filename,
756 const struct ccs_path_info *pattern)
757 {
758 /*
759 if (!filename || !pattern)
760 return false;
761 */
762 const char *f = filename->name;
763 const char *p = pattern->name;
764 const int len = pattern->const_len;
765 /* If @pattern doesn't contain pattern, I can use strcmp(). */
766 if (!pattern->is_patterned)
767 return !ccs_pathcmp(filename, pattern);
768 /* Don't compare if the number of '/' differs. */
769 if (filename->depth != pattern->depth)
770 return false;
771 /* Compare the initial length without patterns. */
772 if (strncmp(f, p, len))
773 return false;
774 f += len;
775 p += len;
776 /* Main loop. Compare each directory component. */
777 while (*f && *p) {
778 const char *f_delimiter = strchr(f, '/');
779 const char *p_delimiter = strchr(p, '/');
780 if (!f_delimiter)
781 f_delimiter = f + strlen(f);
782 if (!p_delimiter)
783 p_delimiter = p + strlen(p);
784 if (!ccs_file_matches_pattern(f, f_delimiter, p, p_delimiter))
785 return false;
786 f = f_delimiter;
787 if (*f)
788 f++;
789 p = p_delimiter;
790 if (*p)
791 p++;
792 }
793 /* Ignore trailing "\*" and "\@" in @pattern. */
794 while (*p == '\\' &&
795 (*(p + 1) == '*' || *(p + 1) == '@'))
796 p += 2;
797 return !*f && !*p;
798 }
799
800 /**
801 * ccs_get_exe - Get ccs_realpath() of current process.
802 *
803 * Returns the ccs_realpath() of current process on success, NULL otherwise.
804 *
805 * This function uses kzalloc(), so the caller must kfree()
806 * if this function didn't return NULL.
807 */
808 const char *ccs_get_exe(void)
809 {
810 struct mm_struct *mm = current->mm;
811 struct vm_area_struct *vma;
812 const char *cp = NULL;
813 if (!mm)
814 return NULL;
815 down_read(&mm->mmap_sem);
816 for (vma = mm->mmap; vma; vma = vma->vm_next) {
817 if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
818 cp = ccs_realpath_from_dentry(vma->vm_file->f_dentry,
819 vma->vm_file->f_vfsmnt);
820 break;
821 }
822 }
823 up_read(&mm->mmap_sem);
824 return cp;
825 }
826
827 /**
828 * ccs_get_msg - Get warning message.
829 *
830 * @is_enforce: Is it enforcing mode?
831 *
832 * Returns "ERROR" or "WARNING".
833 */
834 const char *ccs_get_msg(const bool is_enforce)
835 {
836 if (is_enforce)
837 return "ERROR";
838 else
839 return "WARNING";
840 }
841
842 /**
843 * ccs_can_sleep - Check whether it is permitted to do operations that may sleep.
844 *
845 * Returns true if it is permitted to do operations that may sleep,
846 * false otherwise.
847 *
848 * TOMOYO Linux supports interactive enforcement that lets processes
849 * wait for the administrator's decision.
850 * All hooks but the one for ccs_may_autobind() are inserted where
851 * it is permitted to do operations that may sleep.
852 * Thus, this warning should not happen.
853 */
854 bool ccs_can_sleep(void)
855 {
856 static u8 count = 20;
857 if (likely(!in_interrupt()))
858 return true;
859 if (count) {
860 count--;
861 printk(KERN_ERR "BUG: sleeping function called "
862 "from invalid context.\n");
863 dump_stack();
864 }
865 return false;
866 }
867
868 /**
869 * ccs_check_flags - Check mode for specified functionality.
870 *
871 * @domain: Pointer to "struct ccs_domain_info". NULL for ccs_current_domain().
872 * @index: The functionality to check mode.
873 *
874 * Returns the mode of specified functionality.
875 */
876 unsigned int ccs_check_flags(const struct ccs_domain_info *domain,
877 const u8 index)
878 {
879 u8 profile;
880 if (!domain)
881 domain = ccs_current_domain();
882 profile = domain->profile;
883 return ccs_policy_loaded && index < CCS_MAX_CONTROL_INDEX
884 #if CCS_MAX_PROFILES != 256
885 && profile < CCS_MAX_PROFILES
886 #endif
887 && ccs_profile_ptr[profile] ?
888 ccs_profile_ptr[profile]->value[index] : 0;
889 }
890
891 /**
892 * ccs_check_capability_flags - Check mode for specified capability.
893 *
894 * @domain: Pointer to "struct ccs_domain_info". NULL for ccs_current_domain().
895 * @index: The capability to check mode.
896 *
897 * Returns the mode of specified capability.
898 */
899 static u8 ccs_check_capability_flags(const struct ccs_domain_info *domain,
900 const u8 index)
901 {
902 const u8 profile = domain ? domain->profile :
903 ccs_current_domain()->profile;
904 return ccs_policy_loaded && index < CCS_MAX_CAPABILITY_INDEX
905 #if CCS_MAX_PROFILES != 256
906 && profile < CCS_MAX_PROFILES
907 #endif
908 && ccs_profile_ptr[profile] ?
909 ccs_profile_ptr[profile]->capability_value[index] : 0;
910 }
911
912 /**
913 * ccs_cap2keyword - Convert capability operation to capability name.
914 *
915 * @operation: The capability index.
916 *
917 * Returns the name of the specified capability's name.
918 */
919 const char *ccs_cap2keyword(const u8 operation)
920 {
921 return operation < CCS_MAX_CAPABILITY_INDEX
922 ? ccs_capability_control_keyword[operation] : NULL;
923 }
924
925 /**
926 * ccs_init_request_info - Initialize "struct ccs_request_info" members.
927 *
928 * @r: Pointer to "struct ccs_request_info" to initialize.
929 * @domain: Pointer to "struct ccs_domain_info". NULL for ccs_current_domain().
930 * @index: Index number of functionality.
931 */
932 void ccs_init_request_info(struct ccs_request_info *r,
933 struct ccs_domain_info *domain, const u8 index)
934 {
935 memset(r, 0, sizeof(*r));
936 if (!domain)
937 domain = ccs_current_domain();
938 r->domain = domain;
939 r->profile = domain->profile;
940 if (index < CCS_MAX_CONTROL_INDEX)
941 r->mode = ccs_check_flags(domain, index);
942 else
943 r->mode = ccs_check_capability_flags(domain, index
944 - CCS_MAX_CONTROL_INDEX);
945 }
946
947 /**
948 * ccs_verbose_mode - Check whether TOMOYO is verbose mode.
949 *
950 * @domain: Pointer to "struct ccs_domain_info". NULL for ccs_current_domain().
951 *
952 * Returns true if domain policy violation warning should be printed to
953 * console.
954 */
955 bool ccs_verbose_mode(const struct ccs_domain_info *domain)
956 {
957 return ccs_check_flags(domain, CCS_VERBOSE) != 0;
958 }
959
960 /**
961 * ccs_domain_quota_ok - Check for domain's quota.
962 *
963 * @r: Pointer to "struct ccs_request_info".
964 *
965 * Returns true if the domain is not exceeded quota, false otherwise.
966 *
967 * Caller holds ccs_read_lock().
968 */
969 bool ccs_domain_quota_ok(struct ccs_request_info *r)
970 {
971 unsigned int count = 0;
972 struct ccs_domain_info *domain = r->domain;
973 struct ccs_acl_info *ptr;
974 ccs_check_read_lock();
975 if (r->mode != 1)
976 return false;
977 if (!domain)
978 return true;
979 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
980 if (ptr->type & CCS_ACL_DELETED)
981 continue;
982 switch (ccs_acl_type2(ptr)) {
983 struct ccs_single_path_acl_record *acl1;
984 struct ccs_double_path_acl_record *acl2;
985 u16 perm;
986 case CCS_TYPE_SINGLE_PATH_ACL:
987 acl1 = container_of(ptr,
988 struct ccs_single_path_acl_record,
989 head);
990 perm = acl1->perm;
991 if (perm & (1 << CCS_TYPE_EXECUTE_ACL))
992 count++;
993 if (perm & ((1 << CCS_TYPE_READ_ACL) |
994 (1 << CCS_TYPE_WRITE_ACL)))
995 count++;
996 if (perm & (1 << CCS_TYPE_CREATE_ACL))
997 count++;
998 if (perm & (1 << CCS_TYPE_UNLINK_ACL))
999 count++;
1000 if (perm & (1 << CCS_TYPE_MKDIR_ACL))
1001 count++;
1002 if (perm & (1 << CCS_TYPE_RMDIR_ACL))
1003 count++;
1004 if (perm & (1 << CCS_TYPE_MKFIFO_ACL))
1005 count++;
1006 if (perm & (1 << CCS_TYPE_MKSOCK_ACL))
1007 count++;
1008 if (perm & (1 << CCS_TYPE_MKBLOCK_ACL))
1009 count++;
1010 if (perm & (1 << CCS_TYPE_MKCHAR_ACL))
1011 count++;
1012 if (perm & (1 << CCS_TYPE_TRUNCATE_ACL))
1013 count++;
1014 if (perm & (1 << CCS_TYPE_SYMLINK_ACL))
1015 count++;
1016 if (perm & (1 << CCS_TYPE_REWRITE_ACL))
1017 count++;
1018 break;
1019 case CCS_TYPE_DOUBLE_PATH_ACL:
1020 acl2 = container_of(ptr,
1021 struct ccs_double_path_acl_record,
1022 head);
1023 perm = acl2->perm;
1024 if (perm & (1 << CCS_TYPE_LINK_ACL))
1025 count++;
1026 if (perm & (1 << CCS_TYPE_RENAME_ACL))
1027 count++;
1028 break;
1029 case CCS_TYPE_EXECUTE_HANDLER:
1030 case CCS_TYPE_DENIED_EXECUTE_HANDLER:
1031 break;
1032 default:
1033 count++;
1034 }
1035 }
1036 if (count < ccs_check_flags(domain, CCS_MAX_ACCEPT_ENTRY))
1037 return true;
1038 if (!domain->quota_warned) {
1039 domain->quota_warned = true;
1040 printk(KERN_WARNING "TOMOYO-WARNING: "
1041 "Domain '%s' has so many ACLs to hold. "
1042 "Stopped learning mode.\n", domain->domainname->name);
1043 }
1044 return false;
1045 }

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