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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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