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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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