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

Subversion リポジトリの参照

Contents of /branches/ccs-patch/security/ccsecurity/util.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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