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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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