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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2037 - (show annotations) (download) (as text)
Mon Jan 5 05:56:56 2009 UTC (15 years, 4 months ago) by kumaneko
Original Path: trunk/1.6.x/ccs-patch/fs/ccs_common.c
File MIME type: text/x-csrc
File size: 88484 byte(s)


1 /*
2 * fs/ccs_common.c
3 *
4 * Common functions for SAKURA and TOMOYO.
5 *
6 * Copyright (C) 2005-2009 NTT DATA CORPORATION
7 *
8 * Version: 1.6.6-pre 2009/01/05
9 *
10 * This file is applicable to both 2.4.30 and 2.6.11 and later.
11 * See README.ccs for ChangeLog.
12 *
13 */
14
15 #include <linux/version.h>
16 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
17 #define __KERNEL_SYSCALLS__
18 #endif
19 #include <linux/string.h>
20 #include <linux/mm.h>
21 #include <linux/utime.h>
22 #include <linux/file.h>
23 #include <linux/module.h>
24 #include <linux/slab.h>
25 #include <asm/uaccess.h>
26 #include <stdarg.h>
27 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
28 #include <linux/namei.h>
29 #include <linux/mount.h>
30 static const int ccs_lookup_flags = LOOKUP_FOLLOW;
31 #else
32 static const int ccs_lookup_flags = LOOKUP_FOLLOW | LOOKUP_POSITIVE;
33 #endif
34 #include <linux/realpath.h>
35 #include <linux/ccs_common.h>
36 #include <linux/ccs_proc.h>
37 #include <linux/tomoyo.h>
38 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
39 #include <linux/unistd.h>
40 #endif
41
42 /* To support PID namespace. */
43 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
44 #define find_task_by_pid find_task_by_vpid
45 #endif
46
47 /* Set default specified by the kernel config. */
48 #ifdef CONFIG_TOMOYO
49 #define MAX_ACCEPT_ENTRY (CONFIG_TOMOYO_MAX_ACCEPT_ENTRY)
50 #define MAX_GRANT_LOG (CONFIG_TOMOYO_MAX_GRANT_LOG)
51 #define MAX_REJECT_LOG (CONFIG_TOMOYO_MAX_REJECT_LOG)
52 #else
53 #define MAX_ACCEPT_ENTRY 0
54 #define MAX_GRANT_LOG 0
55 #define MAX_REJECT_LOG 0
56 #endif
57
58 /* Has /sbin/init started? */
59 bool ccs_sbin_init_started;
60
61 /* Log level for SAKURA's printk(). */
62 const char *ccs_log_level = KERN_DEBUG;
63
64 /* String table for functionality that takes 4 modes. */
65 static const char *ccs_mode_4[4] = {
66 "disabled", "learning", "permissive", "enforcing"
67 };
68 /* String table for functionality that takes 2 modes. */
69 static const char *ccs_mode_2[4] = {
70 "disabled", "enabled", "enabled", "enabled"
71 };
72
73 /* Table for profile. */
74 static struct {
75 const char *keyword;
76 unsigned int current_value;
77 const unsigned int max_value;
78 } ccs_control_array[CCS_MAX_CONTROL_INDEX] = {
79 [CCS_TOMOYO_MAC_FOR_FILE] = { "MAC_FOR_FILE", 0, 3 },
80 [CCS_TOMOYO_MAC_FOR_ARGV0] = { "MAC_FOR_ARGV0", 0, 3 },
81 [CCS_TOMOYO_MAC_FOR_ENV] = { "MAC_FOR_ENV", 0, 3 },
82 [CCS_TOMOYO_MAC_FOR_NETWORK] = { "MAC_FOR_NETWORK", 0, 3 },
83 [CCS_TOMOYO_MAC_FOR_SIGNAL] = { "MAC_FOR_SIGNAL", 0, 3 },
84 [CCS_SAKURA_DENY_CONCEAL_MOUNT] = { "DENY_CONCEAL_MOUNT", 0, 3 },
85 [CCS_SAKURA_RESTRICT_CHROOT] = { "RESTRICT_CHROOT", 0, 3 },
86 [CCS_SAKURA_RESTRICT_MOUNT] = { "RESTRICT_MOUNT", 0, 3 },
87 [CCS_SAKURA_RESTRICT_UNMOUNT] = { "RESTRICT_UNMOUNT", 0, 3 },
88 [CCS_SAKURA_RESTRICT_PIVOT_ROOT] = { "RESTRICT_PIVOT_ROOT", 0, 3 },
89 [CCS_SAKURA_RESTRICT_AUTOBIND] = { "RESTRICT_AUTOBIND", 0, 1 },
90 [CCS_TOMOYO_MAX_ACCEPT_ENTRY]
91 = { "MAX_ACCEPT_ENTRY", MAX_ACCEPT_ENTRY, INT_MAX },
92 [CCS_TOMOYO_MAX_GRANT_LOG]
93 = { "MAX_GRANT_LOG", MAX_GRANT_LOG, INT_MAX },
94 [CCS_TOMOYO_MAX_REJECT_LOG]
95 = { "MAX_REJECT_LOG", MAX_REJECT_LOG, INT_MAX },
96 [CCS_TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 },
97 [CCS_SLEEP_PERIOD]
98 = { "SLEEP_PERIOD", 0, 3000 }, /* in 0.1 second */
99 };
100
101 #ifdef CONFIG_TOMOYO
102 /* Capability name used by domain policy. */
103 static const char *ccs_capability_control_keyword[TOMOYO_MAX_CAPABILITY_INDEX]
104 = {
105 [TOMOYO_INET_STREAM_SOCKET_CREATE] = "inet_tcp_create",
106 [TOMOYO_INET_STREAM_SOCKET_LISTEN] = "inet_tcp_listen",
107 [TOMOYO_INET_STREAM_SOCKET_CONNECT] = "inet_tcp_connect",
108 [TOMOYO_USE_INET_DGRAM_SOCKET] = "use_inet_udp",
109 [TOMOYO_USE_INET_RAW_SOCKET] = "use_inet_ip",
110 [TOMOYO_USE_ROUTE_SOCKET] = "use_route",
111 [TOMOYO_USE_PACKET_SOCKET] = "use_packet",
112 [TOMOYO_SYS_MOUNT] = "SYS_MOUNT",
113 [TOMOYO_SYS_UMOUNT] = "SYS_UMOUNT",
114 [TOMOYO_SYS_REBOOT] = "SYS_REBOOT",
115 [TOMOYO_SYS_CHROOT] = "SYS_CHROOT",
116 [TOMOYO_SYS_KILL] = "SYS_KILL",
117 [TOMOYO_SYS_VHANGUP] = "SYS_VHANGUP",
118 [TOMOYO_SYS_SETTIME] = "SYS_TIME",
119 [TOMOYO_SYS_NICE] = "SYS_NICE",
120 [TOMOYO_SYS_SETHOSTNAME] = "SYS_SETHOSTNAME",
121 [TOMOYO_USE_KERNEL_MODULE] = "use_kernel_module",
122 [TOMOYO_CREATE_FIFO] = "create_fifo",
123 [TOMOYO_CREATE_BLOCK_DEV] = "create_block_dev",
124 [TOMOYO_CREATE_CHAR_DEV] = "create_char_dev",
125 [TOMOYO_CREATE_UNIX_SOCKET] = "create_unix_socket",
126 [TOMOYO_SYS_LINK] = "SYS_LINK",
127 [TOMOYO_SYS_SYMLINK] = "SYS_SYMLINK",
128 [TOMOYO_SYS_RENAME] = "SYS_RENAME",
129 [TOMOYO_SYS_UNLINK] = "SYS_UNLINK",
130 [TOMOYO_SYS_CHMOD] = "SYS_CHMOD",
131 [TOMOYO_SYS_CHOWN] = "SYS_CHOWN",
132 [TOMOYO_SYS_IOCTL] = "SYS_IOCTL",
133 [TOMOYO_SYS_KEXEC_LOAD] = "SYS_KEXEC_LOAD",
134 [TOMOYO_SYS_PIVOT_ROOT] = "SYS_PIVOT_ROOT",
135 [TOMOYO_SYS_PTRACE] = "SYS_PTRACE",
136 };
137 #endif
138
139 /* Profile table. Memory is allocated as needed. */
140 static struct ccs_profile {
141 unsigned int value[CCS_MAX_CONTROL_INDEX];
142 const struct ccs_path_info *comment;
143 #ifdef CONFIG_TOMOYO
144 unsigned char capability_value[TOMOYO_MAX_CAPABILITY_INDEX];
145 #endif
146 } *ccs_profile_ptr[MAX_PROFILES];
147
148 /* Permit policy management by non-root user? */
149 static bool ccs_manage_by_non_root;
150
151 /* Utility functions. */
152
153 #ifdef CONFIG_TOMOYO
154 /**
155 * ccs_quiet_setup - Set TOMOYO_VERBOSE=0 by default.
156 *
157 * @str: Unused.
158 *
159 * Returns 0.
160 */
161 static int __init ccs_quiet_setup(char *str)
162 {
163 ccs_control_array[CCS_TOMOYO_VERBOSE].current_value = 0;
164 return 0;
165 }
166
167 __setup("TOMOYO_QUIET", ccs_quiet_setup);
168 #endif
169
170 /**
171 * ccs_is_byte_range - Check whether the string isa \ooo style octal value.
172 *
173 * @str: Pointer to the string.
174 *
175 * Returns true if @str is a \ooo style octal value, false otherwise.
176 */
177 static inline bool ccs_is_byte_range(const char *str)
178 {
179 return *str >= '0' && *str++ <= '3' &&
180 *str >= '0' && *str++ <= '7' &&
181 *str >= '0' && *str <= '7';
182 }
183
184 /**
185 * ccs_is_decimal - Check whether the character is a decimal character.
186 *
187 * @c: The character to check.
188 *
189 * Returns true if @c is a decimal character, false otherwise.
190 */
191 static inline bool ccs_is_decimal(const char c)
192 {
193 return c >= '0' && c <= '9';
194 }
195
196 /**
197 * ccs_is_hexadecimal - Check whether the character is a hexadecimal character.
198 *
199 * @c: The character to check.
200 *
201 * Returns true if @c is a hexadecimal character, false otherwise.
202 */
203 static inline bool ccs_is_hexadecimal(const char c)
204 {
205 return (c >= '0' && c <= '9') ||
206 (c >= 'A' && c <= 'F') ||
207 (c >= 'a' && c <= 'f');
208 }
209
210 /**
211 * ccs_is_alphabet_char - Check whether the character is an alphabet.
212 *
213 * @c: The character to check.
214 *
215 * Returns true if @c is an alphabet character, false otherwise.
216 */
217 static inline bool ccs_is_alphabet_char(const char c)
218 {
219 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
220 }
221
222 /**
223 * ccs_make_byte - Make byte value from three octal characters.
224 *
225 * @c1: The first character.
226 * @c2: The second character.
227 * @c3: The third character.
228 *
229 * Returns byte value.
230 */
231 static inline u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3)
232 {
233 return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
234 }
235
236 /**
237 * ccs_str_starts - Check whether the given string starts with the given keyword.
238 *
239 * @src: Pointer to pointer to the string.
240 * @find: Pointer to the keyword.
241 *
242 * Returns true if @src starts with @find, false otherwise.
243 *
244 * The @src is updated to point the first character after the @find
245 * if @src starts with @find.
246 */
247 static bool ccs_str_starts(char **src, const char *find)
248 {
249 const int len = strlen(find);
250 char *tmp = *src;
251 if (strncmp(tmp, find, len))
252 return false;
253 tmp += len;
254 *src = tmp;
255 return true;
256 }
257
258 /**
259 * ccs_normalize_line - Format string.
260 *
261 * @buffer: The line to normalize.
262 *
263 * Leading and trailing whitespaces are removed.
264 * Multiple whitespaces are packed into single space.
265 *
266 * Returns nothing.
267 */
268 static void ccs_normalize_line(unsigned char *buffer)
269 {
270 unsigned char *sp = buffer;
271 unsigned char *dp = buffer;
272 bool first = true;
273 while (*sp && (*sp <= ' ' || *sp >= 127))
274 sp++;
275 while (*sp) {
276 if (!first)
277 *dp++ = ' ';
278 first = false;
279 while (*sp > ' ' && *sp < 127)
280 *dp++ = *sp++;
281 while (*sp && (*sp <= ' ' || *sp >= 127))
282 sp++;
283 }
284 *dp = '\0';
285 }
286
287 /**
288 * ccs_is_correct_path - Validate a pathname.
289 * @filename: The pathname to check.
290 * @start_type: Should the pathname start with '/'?
291 * 1 = must / -1 = must not / 0 = don't care
292 * @pattern_type: Can the pathname contain a wildcard?
293 * 1 = must / -1 = must not / 0 = don't care
294 * @end_type: Should the pathname end with '/'?
295 * 1 = must / -1 = must not / 0 = don't care
296 * @function: The name of function calling me.
297 *
298 * Check whether the given filename follows the naming rules.
299 * Returns true if @filename follows the naming rules, false otherwise.
300 */
301 bool ccs_is_correct_path(const char *filename, const s8 start_type,
302 const s8 pattern_type, const s8 end_type,
303 const char *function)
304 {
305 bool contains_pattern = false;
306 unsigned char c;
307 unsigned char d;
308 unsigned char e;
309 const char *original_filename = filename;
310 if (!filename)
311 goto out;
312 c = *filename;
313 if (start_type == 1) { /* Must start with '/' */
314 if (c != '/')
315 goto out;
316 } else if (start_type == -1) { /* Must not start with '/' */
317 if (c == '/')
318 goto out;
319 }
320 if (c)
321 c = *(filename + strlen(filename) - 1);
322 if (end_type == 1) { /* Must end with '/' */
323 if (c != '/')
324 goto out;
325 } else if (end_type == -1) { /* Must not end with '/' */
326 if (c == '/')
327 goto out;
328 }
329 while (1) {
330 c = *filename++;
331 if (!c)
332 break;
333 if (c == '\\') {
334 c = *filename++;
335 switch (c) {
336 case '\\': /* "\\" */
337 continue;
338 case '$': /* "\$" */
339 case '+': /* "\+" */
340 case '?': /* "\?" */
341 case '*': /* "\*" */
342 case '@': /* "\@" */
343 case 'x': /* "\x" */
344 case 'X': /* "\X" */
345 case 'a': /* "\a" */
346 case 'A': /* "\A" */
347 case '-': /* "\-" */
348 if (pattern_type == -1)
349 break; /* Must not contain pattern */
350 contains_pattern = true;
351 continue;
352 case '0': /* "\ooo" */
353 case '1':
354 case '2':
355 case '3':
356 d = *filename++;
357 if (d < '0' || d > '7')
358 break;
359 e = *filename++;
360 if (e < '0' || e > '7')
361 break;
362 c = ccs_make_byte(c, d, e);
363 if (c && (c <= ' ' || c >= 127))
364 continue; /* pattern is not \000 */
365 }
366 goto out;
367 } else if (c <= ' ' || c >= 127) {
368 goto out;
369 }
370 }
371 if (pattern_type == 1) { /* Must contain pattern */
372 if (!contains_pattern)
373 goto out;
374 }
375 return true;
376 out:
377 printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function,
378 original_filename);
379 return false;
380 }
381
382 /**
383 * ccs_is_correct_domain - Check whether the given domainname follows the naming rules.
384 * @domainname: The domainname to check.
385 * @function: The name of function calling me.
386 *
387 * Returns true if @domainname follows the naming rules, false otherwise.
388 */
389 bool ccs_is_correct_domain(const unsigned char *domainname,
390 const char *function)
391 {
392 unsigned char c;
393 unsigned char d;
394 unsigned char e;
395 const char *org_domainname = domainname;
396 if (!domainname || strncmp(domainname, ROOT_NAME, ROOT_NAME_LEN))
397 goto out;
398 domainname += ROOT_NAME_LEN;
399 if (!*domainname)
400 return true;
401 do {
402 if (*domainname++ != ' ')
403 goto out;
404 if (*domainname++ != '/')
405 goto out;
406 while (1) {
407 c = *domainname;
408 if (!c || c == ' ')
409 break;
410 domainname++;
411 if (c == '\\') {
412 c = *domainname++;
413 switch ((c)) {
414 case '\\': /* "\\" */
415 continue;
416 case '0': /* "\ooo" */
417 case '1':
418 case '2':
419 case '3':
420 d = *domainname++;
421 if (d < '0' || d > '7')
422 break;
423 e = *domainname++;
424 if (e < '0' || e > '7')
425 break;
426 c = ccs_make_byte(c, d, e);
427 if (c && (c <= ' ' || c >= 127))
428 /* pattern is not \000 */
429 continue;
430 }
431 goto out;
432 } else if (c < ' ' || c >= 127) {
433 goto out;
434 }
435 }
436 } while (*domainname);
437 return true;
438 out:
439 printk(KERN_DEBUG "%s: Invalid domainname '%s'\n", function,
440 org_domainname);
441 return false;
442 }
443
444 /**
445 * ccs_is_domain_def - Check whether the given token can be a domainname.
446 *
447 * @buffer: The token to check.
448 *
449 * Returns true if @buffer possibly be a domainname, false otherwise.
450 */
451 bool ccs_is_domain_def(const unsigned char *buffer)
452 {
453 return !strncmp(buffer, ROOT_NAME, ROOT_NAME_LEN);
454 }
455
456 /**
457 * ccs_find_domain - Find a domain by the given name.
458 *
459 * @domainname: The domainname to find.
460 *
461 * Returns pointer to "struct domain_info" if found, NULL otherwise.
462 */
463 struct domain_info *ccs_find_domain(const char *domainname)
464 {
465 struct domain_info *domain;
466 struct ccs_path_info name;
467 name.name = domainname;
468 ccs_fill_path_info(&name);
469 list1_for_each_entry(domain, &ccs_domain_list, list) {
470 if (!domain->is_deleted &&
471 !ccs_pathcmp(&name, domain->domainname))
472 return domain;
473 }
474 return NULL;
475 }
476
477 /**
478 * ccs_path_depth - Evaluate the number of '/' in a string.
479 *
480 * @pathname: The string to evaluate.
481 *
482 * Returns path depth of the string.
483 *
484 * I score 2 for each of the '/' in the @pathname
485 * and score 1 if the @pathname ends with '/'.
486 */
487 static int ccs_path_depth(const char *pathname)
488 {
489 int i = 0;
490 if (pathname) {
491 const char *ep = pathname + strlen(pathname);
492 if (pathname < ep--) {
493 if (*ep != '/')
494 i++;
495 while (pathname <= ep)
496 if (*ep-- == '/')
497 i += 2;
498 }
499 }
500 return i;
501 }
502
503 /**
504 * ccs_const_part_length - Evaluate the initial length without a pattern in a token.
505 *
506 * @filename: The string to evaluate.
507 *
508 * Returns the initial length without a pattern in @filename.
509 */
510 static int ccs_const_part_length(const char *filename)
511 {
512 char c;
513 int len = 0;
514 if (!filename)
515 return 0;
516 while (1) {
517 c = *filename++;
518 if (!c)
519 break;
520 if (c != '\\') {
521 len++;
522 continue;
523 }
524 c = *filename++;
525 switch (c) {
526 case '\\': /* "\\" */
527 len += 2;
528 continue;
529 case '0': /* "\ooo" */
530 case '1':
531 case '2':
532 case '3':
533 c = *filename++;
534 if (c < '0' || c > '7')
535 break;
536 c = *filename++;
537 if (c < '0' || c > '7')
538 break;
539 len += 4;
540 continue;
541 }
542 break;
543 }
544 return len;
545 }
546
547 /**
548 * ccs_fill_path_info - Fill in "struct ccs_path_info" members.
549 *
550 * @ptr: Pointer to "struct ccs_path_info" to fill in.
551 *
552 * The caller sets "struct ccs_path_info"->name.
553 */
554 void ccs_fill_path_info(struct ccs_path_info *ptr)
555 {
556 const char *name = ptr->name;
557 const int len = strlen(name);
558 ptr->total_len = len;
559 ptr->const_len = ccs_const_part_length(name);
560 ptr->is_dir = len && (name[len - 1] == '/');
561 ptr->is_patterned = (ptr->const_len < len);
562 ptr->hash = full_name_hash(name, len);
563 ptr->depth = ccs_path_depth(name);
564 }
565
566 /**
567 * ccs_file_matches_to_pattern2 - Pattern matching without '/' character
568 * and "\-" pattern.
569 *
570 * @filename: The start of string to check.
571 * @filename_end: The end of string to check.
572 * @pattern: The start of pattern to compare.
573 * @pattern_end: The end of pattern to compare.
574 *
575 * Returns true if @filename matches @pattern, false otherwise.
576 */
577 static bool ccs_file_matches_to_pattern2(const char *filename,
578 const char *filename_end,
579 const char *pattern,
580 const char *pattern_end)
581 {
582 while (filename < filename_end && pattern < pattern_end) {
583 char c;
584 if (*pattern != '\\') {
585 if (*filename++ != *pattern++)
586 return false;
587 continue;
588 }
589 c = *filename;
590 pattern++;
591 switch (*pattern) {
592 int i;
593 int j;
594 case '?':
595 if (c == '/') {
596 return false;
597 } else if (c == '\\') {
598 if (filename[1] == '\\')
599 filename++;
600 else if (ccs_is_byte_range(filename + 1))
601 filename += 3;
602 else
603 return false;
604 }
605 break;
606 case '\\':
607 if (c != '\\')
608 return false;
609 if (*++filename != '\\')
610 return false;
611 break;
612 case '+':
613 if (!ccs_is_decimal(c))
614 return false;
615 break;
616 case 'x':
617 if (!ccs_is_hexadecimal(c))
618 return false;
619 break;
620 case 'a':
621 if (!ccs_is_alphabet_char(c))
622 return false;
623 break;
624 case '0':
625 case '1':
626 case '2':
627 case '3':
628 if (c == '\\' && ccs_is_byte_range(filename + 1)
629 && strncmp(filename + 1, pattern, 3) == 0) {
630 filename += 3;
631 pattern += 2;
632 break;
633 }
634 return false; /* Not matched. */
635 case '*':
636 case '@':
637 for (i = 0; i <= filename_end - filename; i++) {
638 if (ccs_file_matches_to_pattern2(filename + i,
639 filename_end,
640 pattern + 1,
641 pattern_end))
642 return true;
643 c = filename[i];
644 if (c == '.' && *pattern == '@')
645 break;
646 if (c != '\\')
647 continue;
648 if (filename[i + 1] == '\\')
649 i++;
650 else if (ccs_is_byte_range(filename + i + 1))
651 i += 3;
652 else
653 break; /* Bad pattern. */
654 }
655 return false; /* Not matched. */
656 default:
657 j = 0;
658 c = *pattern;
659 if (c == '$') {
660 while (ccs_is_decimal(filename[j]))
661 j++;
662 } else if (c == 'X') {
663 while (ccs_is_hexadecimal(filename[j]))
664 j++;
665 } else if (c == 'A') {
666 while (ccs_is_alphabet_char(filename[j]))
667 j++;
668 }
669 for (i = 1; i <= j; i++) {
670 if (ccs_file_matches_to_pattern2(filename + i,
671 filename_end,
672 pattern + 1,
673 pattern_end))
674 return true;
675 }
676 return false; /* Not matched or bad pattern. */
677 }
678 filename++;
679 pattern++;
680 }
681 while (*pattern == '\\' &&
682 (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
683 pattern += 2;
684 return filename == filename_end && pattern == pattern_end;
685 }
686
687 /**
688 * ccs_file_matches_to_pattern - Pattern matching without without '/' character.
689 *
690 * @filename: The start of string to check.
691 * @filename_end: The end of string to check.
692 * @pattern: The start of pattern to compare.
693 * @pattern_end: The end of pattern to compare.
694 *
695 * Returns true if @filename matches @pattern, false otherwise.
696 */
697 static bool ccs_file_matches_to_pattern(const char *filename,
698 const char *filename_end,
699 const char *pattern,
700 const char *pattern_end)
701 {
702 const char *pattern_start = pattern;
703 bool first = true;
704 bool result;
705 while (pattern < pattern_end - 1) {
706 /* Split at "\-" pattern. */
707 if (*pattern++ != '\\' || *pattern++ != '-')
708 continue;
709 result = ccs_file_matches_to_pattern2(filename, filename_end,
710 pattern_start,
711 pattern - 2);
712 if (first)
713 result = !result;
714 if (result)
715 return false;
716 first = false;
717 pattern_start = pattern;
718 }
719 result = ccs_file_matches_to_pattern2(filename, filename_end,
720 pattern_start, pattern_end);
721 return first ? result : !result;
722 }
723
724 /**
725 * ccs_path_matches_pattern - Check whether the given filename matches the given pattern.
726 * @filename: The filename to check.
727 * @pattern: The pattern to compare.
728 *
729 * Returns true if matches, false otherwise.
730 *
731 * The following patterns are available.
732 * \\ \ itself.
733 * \ooo Octal representation of a byte.
734 * \* More than or equals to 0 character other than '/'.
735 * \@ More than or equals to 0 character other than '/' or '.'.
736 * \? 1 byte character other than '/'.
737 * \$ More than or equals to 1 decimal digit.
738 * \+ 1 decimal digit.
739 * \X More than or equals to 1 hexadecimal digit.
740 * \x 1 hexadecimal digit.
741 * \A More than or equals to 1 alphabet character.
742 * \a 1 alphabet character.
743 * \- Subtraction operator.
744 */
745 bool ccs_path_matches_pattern(const struct ccs_path_info *filename,
746 const struct ccs_path_info *pattern)
747 {
748 /*
749 if (!filename || !pattern)
750 return false;
751 */
752 const char *f = filename->name;
753 const char *p = pattern->name;
754 const int len = pattern->const_len;
755 /* If @pattern doesn't contain pattern, I can use strcmp(). */
756 if (!pattern->is_patterned)
757 return !ccs_pathcmp(filename, pattern);
758 /* Dont compare if the number of '/' differs. */
759 if (filename->depth != pattern->depth)
760 return false;
761 /* Compare the initial length without patterns. */
762 if (strncmp(f, p, len))
763 return false;
764 f += len;
765 p += len;
766 /* Main loop. Compare each directory component. */
767 while (*f && *p) {
768 const char *f_delimiter = strchr(f, '/');
769 const char *p_delimiter = strchr(p, '/');
770 if (!f_delimiter)
771 f_delimiter = f + strlen(f);
772 if (!p_delimiter)
773 p_delimiter = p + strlen(p);
774 if (!ccs_file_matches_to_pattern(f, f_delimiter,
775 p, p_delimiter))
776 return false;
777 f = f_delimiter;
778 if (*f)
779 f++;
780 p = p_delimiter;
781 if (*p)
782 p++;
783 }
784 /* Ignore trailing "\*" and "\@" in @pattern. */
785 while (*p == '\\' &&
786 (*(p + 1) == '*' || *(p + 1) == '@'))
787 p += 2;
788 return !*f && !*p;
789 }
790
791 /**
792 * ccs_io_printf - Transactional printf() to "struct ccs_io_buffer" structure.
793 *
794 * @head: Pointer to "struct ccs_io_buffer".
795 * @fmt: The printf()'s format string, followed by parameters.
796 *
797 * Returns true on success, false otherwise.
798 *
799 * The snprintf() will truncate, but ccs_io_printf() won't.
800 */
801 bool ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
802 {
803 va_list args;
804 int len;
805 int pos = head->read_avail;
806 int size = head->readbuf_size - pos;
807 if (size <= 0)
808 return false;
809 va_start(args, fmt);
810 len = vsnprintf(head->read_buf + pos, size, fmt, args);
811 va_end(args);
812 if (pos + len >= head->readbuf_size)
813 return false;
814 head->read_avail += len;
815 return true;
816 }
817
818 /**
819 * ccs_get_exe - Get ccs_realpath() of current process.
820 *
821 * Returns the ccs_realpath() of current process on success, NULL otherwise.
822 *
823 * This function uses ccs_alloc(), so the caller must ccs_free()
824 * if this function didn't return NULL.
825 */
826 const char *ccs_get_exe(void)
827 {
828 struct mm_struct *mm = current->mm;
829 struct vm_area_struct *vma;
830 const char *cp = NULL;
831 if (!mm)
832 return NULL;
833 down_read(&mm->mmap_sem);
834 for (vma = mm->mmap; vma; vma = vma->vm_next) {
835 if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
836 cp = ccs_realpath_from_dentry(vma->vm_file->f_dentry,
837 vma->vm_file->f_vfsmnt);
838 break;
839 }
840 }
841 up_read(&mm->mmap_sem);
842 return cp;
843 }
844
845 /**
846 * ccs_get_msg - Get warning message.
847 *
848 * @is_enforce: Is it enforcing mode?
849 *
850 * Returns "ERROR" or "WARNING".
851 */
852 const char *ccs_get_msg(const bool is_enforce)
853 {
854 if (is_enforce)
855 return "ERROR";
856 else
857 return "WARNING";
858 }
859
860 /**
861 * ccs_can_sleep - Check whether it is permitted to do operations that may sleep.
862 *
863 * Returns true if it is permitted to do operations that may sleep,
864 * false otherwise.
865 *
866 * TOMOYO Linux supports interactive enforcement that lets processes
867 * wait for the administrator's decision.
868 * All hooks but the one for ccs_may_autobind() are inserted where
869 * it is permitted to do operations that may sleep.
870 * Thus, this warning should not happen.
871 */
872 bool ccs_can_sleep(void)
873 {
874 static u8 count = 20;
875 if (likely(!in_interrupt()))
876 return true;
877 if (count) {
878 count--;
879 printk(KERN_ERR "BUG: sleeping function called "
880 "from invalid context.\n");
881 dump_stack();
882 }
883 return false;
884 }
885
886 /**
887 * ccs_check_flags - Check mode for specified functionality.
888 *
889 * @domain: Pointer to "struct domain_info". NULL for current->domain_info.
890 * @index: The functionality to check mode.
891 *
892 * Returns the mode of specified functionality.
893 */
894 unsigned int ccs_check_flags(const struct domain_info *domain, const u8 index)
895 {
896 u8 profile;
897 if (!domain)
898 domain = current->domain_info;
899 profile = domain->profile;
900 return ccs_sbin_init_started && index < CCS_MAX_CONTROL_INDEX
901 #if MAX_PROFILES != 256
902 && profile < MAX_PROFILES
903 #endif
904 && ccs_profile_ptr[profile] ?
905 ccs_profile_ptr[profile]->value[index] : 0;
906 }
907
908 #ifdef CONFIG_TOMOYO
909 /**
910 * ccs_check_capability_flags - Check mode for specified capability.
911 *
912 * @domain: Pointer to "struct domain_info". NULL for current->domain_info.
913 * @index: The capability to check mode.
914 *
915 * Returns the mode of specified capability.
916 */
917 static u8 ccs_check_capability_flags(const struct domain_info *domain,
918 const u8 index)
919 {
920 const u8 profile = domain ? domain->profile :
921 current->domain_info->profile;
922 return ccs_sbin_init_started && index < TOMOYO_MAX_CAPABILITY_INDEX
923 #if MAX_PROFILES != 256
924 && profile < MAX_PROFILES
925 #endif
926 && ccs_profile_ptr[profile] ?
927 ccs_profile_ptr[profile]->capability_value[index] : 0;
928 }
929
930 /**
931 * ccs_cap2keyword - Convert capability operation to capability name.
932 *
933 * @operation: The capability index.
934 *
935 * Returns the name of the specified capability's name.
936 */
937 const char *ccs_cap2keyword(const u8 operation)
938 {
939 return operation < TOMOYO_MAX_CAPABILITY_INDEX
940 ? ccs_capability_control_keyword[operation] : NULL;
941 }
942
943 #endif
944
945 /**
946 * ccs_init_request_info - Initialize "struct ccs_request_info" members.
947 *
948 * @r: Pointer to "struct ccs_request_info" to initialize.
949 * @domain: Pointer to "struct domain_info". NULL for current->domain_info.
950 * @index: Index number of functionality.
951 */
952 void ccs_init_request_info(struct ccs_request_info *r,
953 struct domain_info *domain, const u8 index)
954 {
955 memset(r, 0, sizeof(*r));
956 if (!domain)
957 domain = current->domain_info;
958 r->domain = domain;
959 r->profile = domain->profile;
960 if (index < CCS_MAX_CONTROL_INDEX)
961 r->mode = ccs_check_flags(domain, index);
962 #ifdef CONFIG_TOMOYO
963 else
964 r->mode = ccs_check_capability_flags(domain, index
965 - CCS_MAX_CONTROL_INDEX);
966 #endif
967 }
968
969 /**
970 * ccs_verbose_mode - Check whether TOMOYO is verbose mode.
971 *
972 * @domain: Pointer to "struct domain_info". NULL for current->domain_info.
973 *
974 * Returns true if domain policy violation warning should be printed to
975 * console.
976 */
977 bool ccs_verbose_mode(const struct domain_info *domain)
978 {
979 return ccs_check_flags(domain, CCS_TOMOYO_VERBOSE) != 0;
980 }
981
982 /**
983 * ccs_check_domain_quota - Check for domain's quota.
984 *
985 * @domain: Pointer to "struct domain_info".
986 *
987 * Returns true if the domain is not exceeded quota, false otherwise.
988 */
989 bool ccs_check_domain_quota(struct domain_info * const domain)
990 {
991 unsigned int count = 0;
992 struct ccs_acl_info *ptr;
993 if (!domain)
994 return true;
995 list1_for_each_entry(ptr, &domain->acl_info_list, list) {
996 if (ptr->type & ACL_DELETED)
997 continue;
998 switch (ccs_acl_type2(ptr)) {
999 struct ccs_single_path_acl_record *acl1;
1000 struct ccs_double_path_acl_record *acl2;
1001 u16 perm;
1002 case TYPE_SINGLE_PATH_ACL:
1003 acl1 = container_of(ptr,
1004 struct ccs_single_path_acl_record,
1005 head);
1006 perm = acl1->perm;
1007 if (perm & (1 << TYPE_EXECUTE_ACL))
1008 count++;
1009 if (perm &
1010 ((1 << TYPE_READ_ACL) | (1 << TYPE_WRITE_ACL)))
1011 count++;
1012 if (perm & (1 << TYPE_CREATE_ACL))
1013 count++;
1014 if (perm & (1 << TYPE_UNLINK_ACL))
1015 count++;
1016 if (perm & (1 << TYPE_MKDIR_ACL))
1017 count++;
1018 if (perm & (1 << TYPE_RMDIR_ACL))
1019 count++;
1020 if (perm & (1 << TYPE_MKFIFO_ACL))
1021 count++;
1022 if (perm & (1 << TYPE_MKSOCK_ACL))
1023 count++;
1024 if (perm & (1 << TYPE_MKBLOCK_ACL))
1025 count++;
1026 if (perm & (1 << TYPE_MKCHAR_ACL))
1027 count++;
1028 if (perm & (1 << TYPE_TRUNCATE_ACL))
1029 count++;
1030 if (perm & (1 << TYPE_SYMLINK_ACL))
1031 count++;
1032 if (perm & (1 << TYPE_REWRITE_ACL))
1033 count++;
1034 break;
1035 case TYPE_DOUBLE_PATH_ACL:
1036 acl2 = container_of(ptr,
1037 struct ccs_double_path_acl_record,
1038 head);
1039 perm = acl2->perm;
1040 if (perm & (1 << TYPE_LINK_ACL))
1041 count++;
1042 if (perm & (1 << TYPE_RENAME_ACL))
1043 count++;
1044 break;
1045 case TYPE_EXECUTE_HANDLER:
1046 case TYPE_DENIED_EXECUTE_HANDLER:
1047 break;
1048 default:
1049 count++;
1050 }
1051 }
1052 if (count < ccs_check_flags(domain, CCS_TOMOYO_MAX_ACCEPT_ENTRY))
1053 return true;
1054 if (!domain->quota_warned) {
1055 domain->quota_warned = true;
1056 printk(KERN_WARNING "TOMOYO-WARNING: "
1057 "Domain '%s' has so many ACLs to hold. "
1058 "Stopped learning mode.\n", domain->domainname->name);
1059 }
1060 return false;
1061 }
1062
1063 /**
1064 * ccs_find_or_assign_new_profile - Create a new profile.
1065 *
1066 * @profile: Profile number to create.
1067 *
1068 * Returns pointer to "struct ccs_profile" on success, NULL otherwise.
1069 */
1070 static struct ccs_profile *ccs_find_or_assign_new_profile(const unsigned int
1071 profile)
1072 {
1073 static DEFINE_MUTEX(lock);
1074 struct ccs_profile *ptr = NULL;
1075 mutex_lock(&lock);
1076 if (profile < MAX_PROFILES) {
1077 ptr = ccs_profile_ptr[profile];
1078 if (ptr)
1079 goto ok;
1080 ptr = ccs_alloc_element(sizeof(*ptr));
1081 if (ptr) {
1082 int i;
1083 for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++)
1084 ptr->value[i]
1085 = ccs_control_array[i].current_value;
1086 /*
1087 * Needn't to initialize "ptr->capability_value"
1088 * because they are always 0.
1089 */
1090 mb(); /* Avoid out-of-order execution. */
1091 ccs_profile_ptr[profile] = ptr;
1092 }
1093 }
1094 ok:
1095 mutex_unlock(&lock);
1096 return ptr;
1097 }
1098
1099 /**
1100 * ccs_write_profile - Write profile table.
1101 *
1102 * @head: Pointer to "struct ccs_io_buffer".
1103 *
1104 * Returns 0 on success, negative value otherwise.
1105 */
1106 static int ccs_write_profile(struct ccs_io_buffer *head)
1107 {
1108 char *data = head->write_buf;
1109 unsigned int i;
1110 unsigned int value;
1111 char *cp;
1112 struct ccs_profile *ccs_profile;
1113 i = simple_strtoul(data, &cp, 10);
1114 if (data != cp) {
1115 if (*cp != '-')
1116 return -EINVAL;
1117 data = cp + 1;
1118 }
1119 ccs_profile = ccs_find_or_assign_new_profile(i);
1120 if (!ccs_profile)
1121 return -EINVAL;
1122 cp = strchr(data, '=');
1123 if (!cp)
1124 return -EINVAL;
1125 *cp = '\0';
1126 ccs_update_counter(CCS_UPDATES_COUNTER_PROFILE);
1127 if (!strcmp(data, "COMMENT")) {
1128 ccs_profile->comment = ccs_save_name(cp + 1);
1129 return 0;
1130 }
1131 #ifdef CONFIG_TOMOYO
1132 if (ccs_str_starts(&data, KEYWORD_MAC_FOR_CAPABILITY)) {
1133 if (sscanf(cp + 1, "%u", &value) != 1) {
1134 for (i = 0; i < 4; i++) {
1135 if (strcmp(cp + 1, ccs_mode_4[i]))
1136 continue;
1137 value = i;
1138 break;
1139 }
1140 if (i == 4)
1141 return -EINVAL;
1142 }
1143 if (value > 3)
1144 value = 3;
1145 for (i = 0; i < TOMOYO_MAX_CAPABILITY_INDEX; i++) {
1146 if (strcmp(data, ccs_capability_control_keyword[i]))
1147 continue;
1148 ccs_profile->capability_value[i] = value;
1149 return 0;
1150 }
1151 return -EINVAL;
1152 }
1153 #endif
1154 for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) {
1155 if (strcmp(data, ccs_control_array[i].keyword))
1156 continue;
1157 if (sscanf(cp + 1, "%u", &value) != 1) {
1158 int j;
1159 const char **modes;
1160 switch (i) {
1161 case CCS_SAKURA_RESTRICT_AUTOBIND:
1162 case CCS_TOMOYO_VERBOSE:
1163 modes = ccs_mode_2;
1164 break;
1165 default:
1166 modes = ccs_mode_4;
1167 break;
1168 }
1169 for (j = 0; j < 4; j++) {
1170 if (strcmp(cp + 1, modes[j]))
1171 continue;
1172 value = j;
1173 break;
1174 }
1175 if (j == 4)
1176 return -EINVAL;
1177 } else if (value > ccs_control_array[i].max_value) {
1178 value = ccs_control_array[i].max_value;
1179 }
1180 switch (i) {
1181 case CCS_SAKURA_DENY_CONCEAL_MOUNT:
1182 case CCS_SAKURA_RESTRICT_UNMOUNT:
1183 if (value == 1)
1184 value = 2; /* learning mode is not supported. */
1185 }
1186 ccs_profile->value[i] = value;
1187 return 0;
1188 }
1189 return -EINVAL;
1190 }
1191
1192 /**
1193 * ccs_read_profile - Read profile table.
1194 *
1195 * @head: Pointer to "struct ccs_io_buffer".
1196 *
1197 * Returns 0.
1198 */
1199 static int ccs_read_profile(struct ccs_io_buffer *head)
1200 {
1201 static const int ccs_total
1202 = CCS_MAX_CONTROL_INDEX + TOMOYO_MAX_CAPABILITY_INDEX + 1;
1203 int step;
1204 if (head->read_eof)
1205 return 0;
1206 for (step = head->read_step; step < MAX_PROFILES * ccs_total; step++) {
1207 const u8 index = step / ccs_total;
1208 u8 type = step % ccs_total;
1209 const struct ccs_profile *ccs_profile = ccs_profile_ptr[index];
1210 head->read_step = step;
1211 if (!ccs_profile)
1212 continue;
1213 #if !defined(CONFIG_SAKURA) || !defined(CONFIG_TOMOYO)
1214 switch (type) {
1215 #ifndef CONFIG_SAKURA
1216 case CCS_SAKURA_DENY_CONCEAL_MOUNT:
1217 case CCS_SAKURA_RESTRICT_CHROOT:
1218 case CCS_SAKURA_RESTRICT_MOUNT:
1219 case CCS_SAKURA_RESTRICT_UNMOUNT:
1220 case CCS_SAKURA_RESTRICT_PIVOT_ROOT:
1221 case CCS_SAKURA_RESTRICT_AUTOBIND:
1222 #endif
1223 #ifndef CONFIG_TOMOYO
1224 case CCS_TOMOYO_MAC_FOR_FILE:
1225 case CCS_TOMOYO_MAC_FOR_ARGV0:
1226 case CCS_TOMOYO_MAC_FOR_ENV:
1227 case CCS_TOMOYO_MAC_FOR_NETWORK:
1228 case CCS_TOMOYO_MAC_FOR_SIGNAL:
1229 case CCS_TOMOYO_MAX_ACCEPT_ENTRY:
1230 case CCS_TOMOYO_MAX_GRANT_LOG:
1231 case CCS_TOMOYO_MAX_REJECT_LOG:
1232 case CCS_TOMOYO_VERBOSE:
1233 #endif
1234 continue;
1235 }
1236 #endif
1237 if (!type) { /* Print profile' comment tag. */
1238 if (!ccs_io_printf(head, "%u-COMMENT=%s\n",
1239 index, ccs_profile->comment ?
1240 ccs_profile->comment->name : ""))
1241 break;
1242 continue;
1243 }
1244 type--;
1245 if (type >= CCS_MAX_CONTROL_INDEX) {
1246 #ifdef CONFIG_TOMOYO
1247 const int i = type - CCS_MAX_CONTROL_INDEX;
1248 const u8 value = ccs_profile->capability_value[i];
1249 if (!ccs_io_printf(head,
1250 "%u-" KEYWORD_MAC_FOR_CAPABILITY
1251 "%s=%s\n", index,
1252 ccs_capability_control_keyword[i],
1253 ccs_mode_4[value]))
1254 break;
1255 #endif
1256 } else {
1257 const unsigned int value = ccs_profile->value[type];
1258 const char **modes = NULL;
1259 const char *keyword = ccs_control_array[type].keyword;
1260 switch (ccs_control_array[type].max_value) {
1261 case 3:
1262 modes = ccs_mode_4;
1263 break;
1264 case 1:
1265 modes = ccs_mode_2;
1266 break;
1267 }
1268 if (modes) {
1269 if (!ccs_io_printf(head, "%u-%s=%s\n", index,
1270 keyword, modes[value]))
1271 break;
1272 } else {
1273 if (!ccs_io_printf(head, "%u-%s=%u\n", index,
1274 keyword, value))
1275 break;
1276 }
1277 }
1278 }
1279 if (step == MAX_PROFILES * ccs_total)
1280 head->read_eof = true;
1281 return 0;
1282 }
1283
1284 /* Structure for policy manager. */
1285 struct ccs_policy_manager_entry {
1286 struct list1_head list;
1287 /* A path to program or a domainname. */
1288 const struct ccs_path_info *manager;
1289 bool is_domain; /* True if manager is a domainname. */
1290 bool is_deleted; /* True if this entry is deleted. */
1291 };
1292
1293 /* The list for "struct ccs_policy_manager_entry". */
1294 static LIST1_HEAD(ccs_policy_manager_list);
1295
1296 /**
1297 * ccs_update_manager_entry - Add a manager entry.
1298 *
1299 * @manager: The path to manager or the domainnamme.
1300 * @is_delete: True if it is a delete request.
1301 *
1302 * Returns 0 on success, negative value otherwise.
1303 */
1304 static int ccs_update_manager_entry(const char *manager, const bool is_delete)
1305 {
1306 struct ccs_policy_manager_entry *new_entry;
1307 struct ccs_policy_manager_entry *ptr;
1308 static DEFINE_MUTEX(lock);
1309 const struct ccs_path_info *saved_manager;
1310 int error = -ENOMEM;
1311 bool is_domain = false;
1312 if (ccs_is_domain_def(manager)) {
1313 if (!ccs_is_correct_domain(manager, __func__))
1314 return -EINVAL;
1315 is_domain = true;
1316 } else {
1317 if (!ccs_is_correct_path(manager, 1, -1, -1, __func__))
1318 return -EINVAL;
1319 }
1320 saved_manager = ccs_save_name(manager);
1321 if (!saved_manager)
1322 return -ENOMEM;
1323 mutex_lock(&lock);
1324 list1_for_each_entry(ptr, &ccs_policy_manager_list, list) {
1325 if (ptr->manager != saved_manager)
1326 continue;
1327 ptr->is_deleted = is_delete;
1328 error = 0;
1329 goto out;
1330 }
1331 if (is_delete) {
1332 error = -ENOENT;
1333 goto out;
1334 }
1335 new_entry = ccs_alloc_element(sizeof(*new_entry));
1336 if (!new_entry)
1337 goto out;
1338 new_entry->manager = saved_manager;
1339 new_entry->is_domain = is_domain;
1340 list1_add_tail_mb(&new_entry->list, &ccs_policy_manager_list);
1341 error = 0;
1342 out:
1343 mutex_unlock(&lock);
1344 if (!error)
1345 ccs_update_counter(CCS_UPDATES_COUNTER_MANAGER);
1346 return error;
1347 }
1348
1349 /**
1350 * ccs_write_manager_policy - Write manager policy.
1351 *
1352 * @head: Pointer to "struct ccs_io_buffer".
1353 *
1354 * Returns 0 on success, negative value otherwise.
1355 */
1356 static int ccs_write_manager_policy(struct ccs_io_buffer *head)
1357 {
1358 char *data = head->write_buf;
1359 bool is_delete = ccs_str_starts(&data, KEYWORD_DELETE);
1360 if (!strcmp(data, "manage_by_non_root")) {
1361 ccs_manage_by_non_root = !is_delete;
1362 return 0;
1363 }
1364 return ccs_update_manager_entry(data, is_delete);
1365 }
1366
1367 /**
1368 * ccs_read_manager_policy - Read manager policy.
1369 *
1370 * @head: Pointer to "struct ccs_io_buffer".
1371 *
1372 * Returns 0.
1373 */
1374 static int ccs_read_manager_policy(struct ccs_io_buffer *head)
1375 {
1376 struct list1_head *pos;
1377 if (head->read_eof)
1378 return 0;
1379 list1_for_each_cookie(pos, head->read_var2, &ccs_policy_manager_list) {
1380 struct ccs_policy_manager_entry *ptr;
1381 ptr = list1_entry(pos, struct ccs_policy_manager_entry, list);
1382 if (ptr->is_deleted)
1383 continue;
1384 if (!ccs_io_printf(head, "%s\n", ptr->manager->name))
1385 return 0;
1386 }
1387 head->read_eof = true;
1388 return 0;
1389 }
1390
1391 /**
1392 * ccs_is_policy_manager - Check whether the current process is a policy manager.
1393 *
1394 * Returns true if the current process is permitted to modify policy
1395 * via /proc/ccs/ interface.
1396 */
1397 static bool ccs_is_policy_manager(void)
1398 {
1399 struct ccs_policy_manager_entry *ptr;
1400 const char *exe;
1401 struct task_struct *task = current;
1402 const struct ccs_path_info *domainname = task->domain_info->domainname;
1403 bool found = false;
1404 if (!ccs_sbin_init_started)
1405 return true;
1406 if (task->tomoyo_flags & CCS_TASK_IS_POLICY_MANAGER)
1407 return true;
1408 if (!ccs_manage_by_non_root && (current_uid() || current_euid()))
1409 return false;
1410 list1_for_each_entry(ptr, &ccs_policy_manager_list, list) {
1411 if (!ptr->is_deleted && ptr->is_domain
1412 && !ccs_pathcmp(domainname, ptr->manager)) {
1413 /* Set manager flag. */
1414 task->tomoyo_flags |= CCS_TASK_IS_POLICY_MANAGER;
1415 return true;
1416 }
1417 }
1418 exe = ccs_get_exe();
1419 if (!exe)
1420 return false;
1421 list1_for_each_entry(ptr, &ccs_policy_manager_list, list) {
1422 if (!ptr->is_deleted && !ptr->is_domain
1423 && !strcmp(exe, ptr->manager->name)) {
1424 found = true;
1425 /* Set manager flag. */
1426 task->tomoyo_flags |= CCS_TASK_IS_POLICY_MANAGER;
1427 break;
1428 }
1429 }
1430 if (!found) { /* Reduce error messages. */
1431 static pid_t ccs_last_pid;
1432 const pid_t pid = current->pid;
1433 if (ccs_last_pid != pid) {
1434 printk(KERN_WARNING "%s ( %s ) is not permitted to "
1435 "update policies.\n", domainname->name, exe);
1436 ccs_last_pid = pid;
1437 }
1438 }
1439 ccs_free(exe);
1440 return found;
1441 }
1442
1443 #ifdef CONFIG_TOMOYO
1444
1445 /**
1446 * ccs_find_condition_part - Find condition part from the statement.
1447 *
1448 * @data: String to parse.
1449 *
1450 * Returns pointer to the condition part if it was found in the statement,
1451 * NULL otherwise.
1452 */
1453 static char *ccs_find_condition_part(char *data)
1454 {
1455 char *cp = strstr(data, " if ");
1456 if (cp) {
1457 while (1) {
1458 char *cp2 = strstr(cp + 3, " if ");
1459 if (!cp2)
1460 break;
1461 cp = cp2;
1462 }
1463 *cp++ = '\0';
1464 } else {
1465 cp = strstr(data, " ; set ");
1466 if (cp)
1467 *cp++ = '\0';
1468 }
1469 return cp;
1470 }
1471
1472 /**
1473 * ccs_is_select_one - Parse select command.
1474 *
1475 * @head: Pointer to "struct ccs_io_buffer".
1476 * @data: String to parse.
1477 *
1478 * Returns true on success, false otherwise.
1479 */
1480 static bool ccs_is_select_one(struct ccs_io_buffer *head, const char *data)
1481 {
1482 unsigned int pid;
1483 struct domain_info *domain = NULL;
1484 if (!strcmp(data, "allow_execute")) {
1485 head->read_execute_only = true;
1486 return true;
1487 }
1488 if (sscanf(data, "pid=%u", &pid) == 1) {
1489 struct task_struct *p;
1490 /***** CRITICAL SECTION START *****/
1491 read_lock(&tasklist_lock);
1492 p = find_task_by_pid(pid);
1493 if (p)
1494 domain = p->domain_info;
1495 read_unlock(&tasklist_lock);
1496 /***** CRITICAL SECTION END *****/
1497 } else if (!strncmp(data, "domain=", 7)) {
1498 if (ccs_is_domain_def(data + 7))
1499 domain = ccs_find_domain(data + 7);
1500 } else
1501 return false;
1502 head->write_var1 = domain;
1503 /* Accessing read_buf is safe because head->io_sem is held. */
1504 if (!head->read_buf)
1505 return true; /* Do nothing if open(O_WRONLY). */
1506 head->read_avail = 0;
1507 ccs_io_printf(head, "# select %s\n", data);
1508 head->read_single_domain = true;
1509 head->read_eof = !domain;
1510 if (domain) {
1511 struct domain_info *d;
1512 head->read_var1 = NULL;
1513 list1_for_each_entry(d, &ccs_domain_list, list) {
1514 if (d == domain)
1515 break;
1516 head->read_var1 = &d->list;
1517 }
1518 head->read_var2 = NULL;
1519 head->read_bit = 0;
1520 head->read_step = 0;
1521 if (domain->is_deleted)
1522 ccs_io_printf(head, "# This is a deleted domain.\n");
1523 }
1524 return true;
1525 }
1526
1527 /**
1528 * ccs_write_domain_policy - Write domain policy.
1529 *
1530 * @head: Pointer to "struct ccs_io_buffer".
1531 *
1532 * Returns 0 on success, negative value otherwise.
1533 */
1534 static int ccs_write_domain_policy(struct ccs_io_buffer *head)
1535 {
1536 char *data = head->write_buf;
1537 struct domain_info *domain = head->write_var1;
1538 bool is_delete = false;
1539 bool is_select = false;
1540 bool is_undelete = false;
1541 unsigned int profile;
1542 const struct ccs_condition_list *cond = NULL;
1543 char *cp;
1544 if (ccs_str_starts(&data, KEYWORD_DELETE))
1545 is_delete = true;
1546 else if (ccs_str_starts(&data, KEYWORD_SELECT))
1547 is_select = true;
1548 else if (ccs_str_starts(&data, KEYWORD_UNDELETE))
1549 is_undelete = true;
1550 if (is_select && ccs_is_select_one(head, data))
1551 return 0;
1552 /* Don't allow updating policies by non manager programs. */
1553 if (!ccs_is_policy_manager())
1554 return -EPERM;
1555 if (ccs_is_domain_def(data)) {
1556 domain = NULL;
1557 if (is_delete)
1558 ccs_delete_domain(data);
1559 else if (is_select)
1560 domain = ccs_find_domain(data);
1561 else if (is_undelete)
1562 domain = ccs_undelete_domain(data);
1563 else
1564 domain = ccs_find_or_assign_new_domain(data, 0);
1565 head->write_var1 = domain;
1566 ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
1567 return 0;
1568 }
1569 if (!domain)
1570 return -EINVAL;
1571
1572 if (sscanf(data, KEYWORD_USE_PROFILE "%u", &profile) == 1
1573 && profile < MAX_PROFILES) {
1574 if (ccs_profile_ptr[profile] || !ccs_sbin_init_started)
1575 domain->profile = (u8) profile;
1576 return 0;
1577 }
1578 if (!strcmp(data, KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) {
1579 ccs_set_domain_flag(domain, is_delete,
1580 DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ);
1581 return 0;
1582 }
1583 if (!strcmp(data, KEYWORD_IGNORE_GLOBAL_ALLOW_ENV)) {
1584 ccs_set_domain_flag(domain, is_delete,
1585 DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_ENV);
1586 return 0;
1587 }
1588 cp = ccs_find_condition_part(data);
1589 if (cp) {
1590 cond = ccs_find_or_assign_new_condition(cp);
1591 if (!cond)
1592 return -EINVAL;
1593 }
1594 if (ccs_str_starts(&data, KEYWORD_ALLOW_CAPABILITY))
1595 return ccs_write_capability_policy(data, domain, cond,
1596 is_delete);
1597 else if (ccs_str_starts(&data, KEYWORD_ALLOW_NETWORK))
1598 return ccs_write_network_policy(data, domain, cond, is_delete);
1599 else if (ccs_str_starts(&data, KEYWORD_ALLOW_SIGNAL))
1600 return ccs_write_signal_policy(data, domain, cond, is_delete);
1601 else if (ccs_str_starts(&data, KEYWORD_ALLOW_ARGV0))
1602 return ccs_write_argv0_policy(data, domain, cond, is_delete);
1603 else if (ccs_str_starts(&data, KEYWORD_ALLOW_ENV))
1604 return ccs_write_env_policy(data, domain, cond, is_delete);
1605 else
1606 return ccs_write_file_policy(data, domain, cond, is_delete);
1607 }
1608
1609 /**
1610 * ccs_print_single_path_acl - Print a single path ACL entry.
1611 *
1612 * @head: Pointer to "struct ccs_io_buffer".
1613 * @ptr: Pointer to "struct ccs_single_path_acl_record".
1614 * @cond: Pointer to "struct ccs_condition_list". May be NULL.
1615 *
1616 * Returns true on success, false otherwise.
1617 */
1618 static bool ccs_print_single_path_acl(struct ccs_io_buffer *head,
1619 struct ccs_single_path_acl_record *ptr,
1620 const struct ccs_condition_list *cond)
1621 {
1622 int pos;
1623 u8 bit;
1624 const char *atmark = "";
1625 const char *filename;
1626 const u16 perm = ptr->perm;
1627 if (ptr->u_is_group) {
1628 atmark = "@";
1629 filename = ptr->u.group->group_name->name;
1630 } else {
1631 filename = ptr->u.filename->name;
1632 }
1633 for (bit = head->read_bit; bit < MAX_SINGLE_PATH_OPERATION; bit++) {
1634 const char *msg;
1635 if (!(perm & (1 << bit)))
1636 continue;
1637 if (head->read_execute_only && bit != TYPE_EXECUTE_ACL)
1638 continue;
1639 /* Print "read/write" instead of "read" and "write". */
1640 if ((bit == TYPE_READ_ACL || bit == TYPE_WRITE_ACL)
1641 && (perm & (1 << TYPE_READ_WRITE_ACL)))
1642 continue;
1643 msg = ccs_sp2keyword(bit);
1644 pos = head->read_avail;
1645 if (!ccs_io_printf(head, "allow_%s %s%s", msg,
1646 atmark, filename) ||
1647 !ccs_print_condition(head, cond))
1648 goto out;
1649 }
1650 head->read_bit = 0;
1651 return true;
1652 out:
1653 head->read_bit = bit;
1654 head->read_avail = pos;
1655 return false;
1656 }
1657
1658 /**
1659 * ccs_print_double_path_acl - Print a double path ACL entry.
1660 *
1661 * @head: Pointer to "struct ccs_io_buffer".
1662 * @ptr: Pointer to "struct ccs_double_path_acl_record".
1663 * @cond: Pointer to "struct ccs_condition_list". May be NULL.
1664 *
1665 * Returns true on success, false otherwise.
1666 */
1667 static bool ccs_print_double_path_acl(struct ccs_io_buffer *head,
1668 struct ccs_double_path_acl_record *ptr,
1669 const struct ccs_condition_list *cond)
1670 {
1671 int pos;
1672 const char *atmark1 = "";
1673 const char *atmark2 = "";
1674 const char *filename1;
1675 const char *filename2;
1676 const u8 perm = ptr->perm;
1677 u8 bit;
1678 if (ptr->u1_is_group) {
1679 atmark1 = "@";
1680 filename1 = ptr->u1.group1->group_name->name;
1681 } else {
1682 filename1 = ptr->u1.filename1->name;
1683 }
1684 if (ptr->u2_is_group) {
1685 atmark2 = "@";
1686 filename2 = ptr->u2.group2->group_name->name;
1687 } else {
1688 filename2 = ptr->u2.filename2->name;
1689 }
1690 for (bit = head->read_bit; bit < MAX_DOUBLE_PATH_OPERATION; bit++) {
1691 const char *msg;
1692 if (!(perm & (1 << bit)))
1693 continue;
1694 msg = ccs_dp2keyword(bit);
1695 pos = head->read_avail;
1696 if (!ccs_io_printf(head, "allow_%s %s%s %s%s", msg,
1697 atmark1, filename1, atmark2, filename2) ||
1698 !ccs_print_condition(head, cond))
1699 goto out;
1700 }
1701 head->read_bit = 0;
1702 return true;
1703 out:
1704 head->read_bit = bit;
1705 head->read_avail = pos;
1706 return false;
1707 }
1708
1709 /**
1710 * ccs_print_argv0_acl - Print an argv[0] ACL entry.
1711 *
1712 * @head: Pointer to "struct ccs_io_buffer".
1713 * @ptr: Pointer to "struct ccs_argv0_acl_record".
1714 * @cond: Pointer to "struct ccs_condition_list". May be NULL.
1715 *
1716 * Returns true on success, false otherwise.
1717 */
1718 static bool ccs_print_argv0_acl(struct ccs_io_buffer *head,
1719 struct ccs_argv0_acl_record *ptr,
1720 const struct ccs_condition_list *cond)
1721 {
1722 int pos = head->read_avail;
1723 if (!ccs_io_printf(head, KEYWORD_ALLOW_ARGV0 "%s %s",
1724 ptr->filename->name, ptr->argv0->name))
1725 goto out;
1726 if (!ccs_print_condition(head, cond))
1727 goto out;
1728 return true;
1729 out:
1730 head->read_avail = pos;
1731 return false;
1732 }
1733
1734 /**
1735 * ccs_print_env_acl - Print an evironment variable name's ACL entry.
1736 *
1737 * @head: Pointer to "struct ccs_io_buffer".
1738 * @ptr: Pointer to "struct ccs_env_acl_record".
1739 * @cond: Pointer to "struct ccs_condition_list". May be NULL.
1740 *
1741 * Returns true on success, false otherwise.
1742 */
1743 static bool ccs_print_env_acl(struct ccs_io_buffer *head,
1744 struct ccs_env_acl_record *ptr,
1745 const struct ccs_condition_list *cond)
1746 {
1747 int pos = head->read_avail;
1748 if (!ccs_io_printf(head, KEYWORD_ALLOW_ENV "%s", ptr->env->name))
1749 goto out;
1750 if (!ccs_print_condition(head, cond))
1751 goto out;
1752 return true;
1753 out:
1754 head->read_avail = pos;
1755 return false;
1756 }
1757
1758 /**
1759 * ccs_print_capability_acl - Print a capability ACL entry.
1760 *
1761 * @head: Pointer to "struct ccs_io_buffer".
1762 * @ptr: Pointer to "struct ccs_capability_acl_record".
1763 * @cond: Pointer to "struct ccs_condition_list". May be NULL.
1764 *
1765 * Returns true on success, false otherwise.
1766 */
1767 static bool ccs_print_capability_acl(struct ccs_io_buffer *head,
1768 struct ccs_capability_acl_record *ptr,
1769 const struct ccs_condition_list *cond)
1770 {
1771 int pos = head->read_avail;
1772 if (!ccs_io_printf(head, KEYWORD_ALLOW_CAPABILITY "%s",
1773 ccs_cap2keyword(ptr->operation)))
1774 goto out;
1775 if (!ccs_print_condition(head, cond))
1776 goto out;
1777 return true;
1778 out:
1779 head->read_avail = pos;
1780 return false;
1781 }
1782
1783 /**
1784 * ccs_print_ipv4_entry - Print IPv4 address of a network ACL entry.
1785 *
1786 * @head: Pointer to "struct ccs_io_buffer".
1787 * @ptr: Pointer to "struct ccs_ip_network_acl_record".
1788 *
1789 * Returns true on success, false otherwise.
1790 */
1791 static bool ccs_print_ipv4_entry(struct ccs_io_buffer *head,
1792 struct ccs_ip_network_acl_record *ptr)
1793 {
1794 const u32 min_address = ptr->u.ipv4.min;
1795 const u32 max_address = ptr->u.ipv4.max;
1796 if (!ccs_io_printf(head, "%u.%u.%u.%u", HIPQUAD(min_address)))
1797 return false;
1798 if (min_address != max_address
1799 && !ccs_io_printf(head, "-%u.%u.%u.%u", HIPQUAD(max_address)))
1800 return false;
1801 return true;
1802 }
1803
1804 /**
1805 * ccs_print_ipv6_entry - Print IPv6 address of a network ACL entry.
1806 *
1807 * @head: Pointer to "struct ccs_io_buffer".
1808 * @ptr: Pointer to "struct ccs_ip_network_acl_record".
1809 *
1810 * Returns true on success, false otherwise.
1811 */
1812 static bool ccs_print_ipv6_entry(struct ccs_io_buffer *head,
1813 struct ccs_ip_network_acl_record *ptr)
1814 {
1815 char buf[64];
1816 const struct in6_addr *min_address = ptr->u.ipv6.min;
1817 const struct in6_addr *max_address = ptr->u.ipv6.max;
1818 ccs_print_ipv6(buf, sizeof(buf), min_address);
1819 if (!ccs_io_printf(head, "%s", buf))
1820 return false;
1821 if (min_address != max_address) {
1822 ccs_print_ipv6(buf, sizeof(buf), max_address);
1823 if (!ccs_io_printf(head, "-%s", buf))
1824 return false;
1825 }
1826 return true;
1827 }
1828
1829 /**
1830 * ccs_print_port_entry - Print port number of a network ACL entry.
1831 *
1832 * @head: Pointer to "struct ccs_io_buffer".
1833 * @ptr: Pointer to "struct ccs_ip_network_acl_record".
1834 *
1835 * Returns true on success, false otherwise.
1836 */
1837 static bool ccs_print_port_entry(struct ccs_io_buffer *head,
1838 struct ccs_ip_network_acl_record *ptr)
1839 {
1840 const u16 min_port = ptr->min_port, max_port = ptr->max_port;
1841 if (!ccs_io_printf(head, " %u", min_port))
1842 return false;
1843 if (min_port != max_port && !ccs_io_printf(head, "-%u", max_port))
1844 return false;
1845 return true;
1846 }
1847
1848 /**
1849 * ccs_print_network_acl - Print a network ACL entry.
1850 *
1851 * @head: Pointer to "struct ccs_io_buffer".
1852 * @ptr: Pointer to "struct ccs_ip_network_acl_record".
1853 * @cond: Pointer to "struct ccs_condition_list". May be NULL.
1854 *
1855 * Returns true on success, false otherwise.
1856 */
1857 static bool ccs_print_network_acl(struct ccs_io_buffer *head,
1858 struct ccs_ip_network_acl_record *ptr,
1859 const struct ccs_condition_list *cond)
1860 {
1861 int pos = head->read_avail;
1862 if (!ccs_io_printf(head, KEYWORD_ALLOW_NETWORK "%s ",
1863 ccs_net2keyword(ptr->operation_type)))
1864 goto out;
1865 switch (ptr->record_type) {
1866 case IP_RECORD_TYPE_ADDRESS_GROUP:
1867 if (!ccs_io_printf(head, "@%s", ptr->u.group->group_name->name))
1868 goto out;
1869 break;
1870 case IP_RECORD_TYPE_IPv4:
1871 if (!ccs_print_ipv4_entry(head, ptr))
1872 goto out;
1873 break;
1874 case IP_RECORD_TYPE_IPv6:
1875 if (!ccs_print_ipv6_entry(head, ptr))
1876 goto out;
1877 break;
1878 }
1879 if (!ccs_print_port_entry(head, ptr))
1880 goto out;
1881 if (!ccs_print_condition(head, cond))
1882 goto out;
1883 return true;
1884 out:
1885 head->read_avail = pos;
1886 return false;
1887 }
1888
1889 /**
1890 * ccs_print_signal_acl - Print a signal ACL entry.
1891 *
1892 * @head: Pointer to "struct ccs_io_buffer".
1893 * @ptr: Pointer to "struct signale_acl_record".
1894 * @cond: Pointer to "struct ccs_condition_list". May be NULL.
1895 *
1896 * Returns true on success, false otherwise.
1897 */
1898 static bool ccs_print_signal_acl(struct ccs_io_buffer *head,
1899 struct ccs_signal_acl_record *ptr,
1900 const struct ccs_condition_list *cond)
1901 {
1902 int pos = head->read_avail;
1903 if (!ccs_io_printf(head, KEYWORD_ALLOW_SIGNAL "%u %s",
1904 ptr->sig, ptr->domainname->name))
1905 goto out;
1906 if (!ccs_print_condition(head, cond))
1907 goto out;
1908 return true;
1909 out:
1910 head->read_avail = pos;
1911 return false;
1912 }
1913
1914 /**
1915 * ccs_print_execute_handler_record - Print an execute handler ACL entry.
1916 *
1917 * @head: Pointer to "struct ccs_io_buffer".
1918 * @keyword: Name of the keyword.
1919 * @ptr: Pointer to "struct ccs_execute_handler_record".
1920 *
1921 * Returns true on success, false otherwise.
1922 */
1923 static bool ccs_print_execute_handler_record(struct ccs_io_buffer *head,
1924 const char *keyword,
1925 struct ccs_execute_handler_record *
1926 ptr)
1927 {
1928 return ccs_io_printf(head, "%s %s\n", keyword, ptr->handler->name);
1929 }
1930
1931 /**
1932 * ccs_print_entry - Print an ACL entry.
1933 *
1934 * @head: Pointer to "struct ccs_io_buffer".
1935 * @ptr: Pointer to an ACL entry.
1936 *
1937 * Returns true on success, false otherwise.
1938 */
1939 static bool ccs_print_entry(struct ccs_io_buffer *head,
1940 struct ccs_acl_info *ptr)
1941 {
1942 const struct ccs_condition_list *cond = ccs_get_condition_part(ptr);
1943 const u8 acl_type = ccs_acl_type2(ptr);
1944 if (acl_type & ACL_DELETED)
1945 return true;
1946 if (acl_type == TYPE_SINGLE_PATH_ACL) {
1947 struct ccs_single_path_acl_record *acl
1948 = container_of(ptr, struct ccs_single_path_acl_record,
1949 head);
1950 return ccs_print_single_path_acl(head, acl, cond);
1951 }
1952 if (acl_type == TYPE_EXECUTE_HANDLER) {
1953 struct ccs_execute_handler_record *acl
1954 = container_of(ptr, struct ccs_execute_handler_record,
1955 head);
1956 const char *keyword = KEYWORD_EXECUTE_HANDLER;
1957 return ccs_print_execute_handler_record(head, keyword, acl);
1958 }
1959 if (acl_type == TYPE_DENIED_EXECUTE_HANDLER) {
1960 struct ccs_execute_handler_record *acl
1961 = container_of(ptr, struct ccs_execute_handler_record,
1962 head);
1963 const char *keyword = KEYWORD_DENIED_EXECUTE_HANDLER;
1964 return ccs_print_execute_handler_record(head, keyword, acl);
1965 }
1966 if (head->read_execute_only)
1967 return true;
1968 if (acl_type == TYPE_DOUBLE_PATH_ACL) {
1969 struct ccs_double_path_acl_record *acl
1970 = container_of(ptr, struct ccs_double_path_acl_record,
1971 head);
1972 return ccs_print_double_path_acl(head, acl, cond);
1973 }
1974 if (acl_type == TYPE_ARGV0_ACL) {
1975 struct ccs_argv0_acl_record *acl
1976 = container_of(ptr, struct ccs_argv0_acl_record, head);
1977 return ccs_print_argv0_acl(head, acl, cond);
1978 }
1979 if (acl_type == TYPE_ENV_ACL) {
1980 struct ccs_env_acl_record *acl
1981 = container_of(ptr, struct ccs_env_acl_record, head);
1982 return ccs_print_env_acl(head, acl, cond);
1983 }
1984 if (acl_type == TYPE_CAPABILITY_ACL) {
1985 struct ccs_capability_acl_record *acl
1986 = container_of(ptr, struct ccs_capability_acl_record,
1987 head);
1988 return ccs_print_capability_acl(head, acl, cond);
1989 }
1990 if (acl_type == TYPE_IP_NETWORK_ACL) {
1991 struct ccs_ip_network_acl_record *acl
1992 = container_of(ptr, struct ccs_ip_network_acl_record,
1993 head);
1994 return ccs_print_network_acl(head, acl, cond);
1995 }
1996 if (acl_type == TYPE_SIGNAL_ACL) {
1997 struct ccs_signal_acl_record *acl
1998 = container_of(ptr, struct ccs_signal_acl_record, head);
1999 return ccs_print_signal_acl(head, acl, cond);
2000 }
2001 /* Workaround for gcc 3.2.2's inline bug. */
2002 if (acl_type & ACL_DELETED)
2003 return true;
2004 BUG(); /* This must not happen. */
2005 return false;
2006 }
2007
2008 /**
2009 * ccs_read_domain_policy - Read domain policy.
2010 *
2011 * @head: Pointer to "struct ccs_io_buffer".
2012 *
2013 * Returns 0.
2014 */
2015 static int ccs_read_domain_policy(struct ccs_io_buffer *head)
2016 {
2017 struct list1_head *dpos;
2018 struct list1_head *apos;
2019 if (head->read_eof)
2020 return 0;
2021 if (head->read_step == 0)
2022 head->read_step = 1;
2023 list1_for_each_cookie(dpos, head->read_var1, &ccs_domain_list) {
2024 struct domain_info *domain;
2025 const char *quota_exceeded = "";
2026 const char *transition_failed = "";
2027 const char *ignore_global_allow_read = "";
2028 const char *ignore_global_allow_env = "";
2029 domain = list1_entry(dpos, struct domain_info, list);
2030 if (head->read_step != 1)
2031 goto acl_loop;
2032 if (domain->is_deleted && !head->read_single_domain)
2033 continue;
2034 /* Print domainname and flags. */
2035 if (domain->quota_warned)
2036 quota_exceeded = "quota_exceeded\n";
2037 if (domain->flags & DOMAIN_FLAGS_TRANSITION_FAILED)
2038 transition_failed = "transition_failed\n";
2039 if (domain->flags & DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ)
2040 ignore_global_allow_read
2041 = KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n";
2042 if (domain->flags & DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_ENV)
2043 ignore_global_allow_env
2044 = KEYWORD_IGNORE_GLOBAL_ALLOW_ENV "\n";
2045 if (!ccs_io_printf(head, "%s\n" KEYWORD_USE_PROFILE "%u\n"
2046 "%s%s%s%s\n", domain->domainname->name,
2047 domain->profile, quota_exceeded,
2048 transition_failed,
2049 ignore_global_allow_read,
2050 ignore_global_allow_env))
2051 return 0;
2052 head->read_step = 2;
2053 acl_loop:
2054 if (head->read_step == 3)
2055 goto tail_mark;
2056 /* Print ACL entries in the domain. */
2057 list1_for_each_cookie(apos, head->read_var2,
2058 &domain->acl_info_list) {
2059 struct ccs_acl_info *ptr
2060 = list1_entry(apos, struct ccs_acl_info, list);
2061 if (!ccs_print_entry(head, ptr))
2062 return 0;
2063 }
2064 head->read_step = 3;
2065 tail_mark:
2066 if (!ccs_io_printf(head, "\n"))
2067 return 0;
2068 head->read_step = 1;
2069 if (head->read_single_domain)
2070 break;
2071 }
2072 head->read_eof = true;
2073 return 0;
2074 }
2075
2076 #endif
2077
2078 /**
2079 * ccs_write_domain_profile - Assign profile for specified domain.
2080 *
2081 * @head: Pointer to "struct ccs_io_buffer".
2082 *
2083 * Returns 0 on success, -EINVAL otherwise.
2084 *
2085 * This is equivalent to doing
2086 *
2087 * ( echo "select " $domainname; echo "use_profile " $profile ) |
2088 * /usr/lib/ccs/loadpolicy -d
2089 */
2090 static int ccs_write_domain_profile(struct ccs_io_buffer *head)
2091 {
2092 char *data = head->write_buf;
2093 char *cp = strchr(data, ' ');
2094 struct domain_info *domain;
2095 unsigned int profile;
2096 if (!cp)
2097 return -EINVAL;
2098 *cp = '\0';
2099 domain = ccs_find_domain(cp + 1);
2100 profile = simple_strtoul(data, NULL, 10);
2101 if (domain && profile < MAX_PROFILES
2102 && (ccs_profile_ptr[profile] || !ccs_sbin_init_started))
2103 domain->profile = (u8) profile;
2104 ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
2105 return 0;
2106 }
2107
2108 /**
2109 * ccs_read_domain_profile - Read only domainname and profile.
2110 *
2111 * @head: Pointer to "struct ccs_io_buffer".
2112 *
2113 * Returns list of profile number and domainname pairs.
2114 *
2115 * This is equivalent to doing
2116 *
2117 * grep -A 1 '^<kernel>' /proc/ccs/domain_policy |
2118 * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
2119 * domainname = $0; } else if ( $1 == "use_profile" ) {
2120 * print $2 " " domainname; domainname = ""; } } ; '
2121 */
2122 static int ccs_read_domain_profile(struct ccs_io_buffer *head)
2123 {
2124 struct list1_head *pos;
2125 if (head->read_eof)
2126 return 0;
2127 list1_for_each_cookie(pos, head->read_var1, &ccs_domain_list) {
2128 struct domain_info *domain;
2129 domain = list1_entry(pos, struct domain_info, list);
2130 if (domain->is_deleted)
2131 continue;
2132 if (!ccs_io_printf(head, "%u %s\n", domain->profile,
2133 domain->domainname->name))
2134 return 0;
2135 }
2136 head->read_eof = true;
2137 return 0;
2138 }
2139
2140 /**
2141 * ccs_write_pid: Specify PID to obtain domainname.
2142 *
2143 * @head: Pointer to "struct ccs_io_buffer".
2144 *
2145 * Returns 0.
2146 */
2147 static int ccs_write_pid(struct ccs_io_buffer *head)
2148 {
2149 head->read_eof = false;
2150 return 0;
2151 }
2152
2153 /**
2154 * ccs_read_pid - Read information of a process.
2155 *
2156 * @head: Pointer to "struct ccs_io_buffer".
2157 *
2158 * Returns the domainname which the specified PID is in or
2159 * process information of the specified PID on success,
2160 * empty string otherwise.
2161 */
2162 static int ccs_read_pid(struct ccs_io_buffer *head)
2163 {
2164 char *buf = head->write_buf;
2165 bool task_info = false;
2166 unsigned int pid;
2167 struct task_struct *p;
2168 struct domain_info *domain = NULL;
2169 u32 tomoyo_flags = 0;
2170 /* Accessing write_buf is safe because head->io_sem is held. */
2171 if (!buf)
2172 goto done; /* Do nothing if open(O_RDONLY). */
2173 if (head->read_avail || head->read_eof)
2174 goto done;
2175 head->read_eof = true;
2176 if (ccs_str_starts(&buf, "info "))
2177 task_info = true;
2178 pid = (unsigned int) simple_strtoul(buf, NULL, 10);
2179 /***** CRITICAL SECTION START *****/
2180 read_lock(&tasklist_lock);
2181 p = find_task_by_pid(pid);
2182 if (p) {
2183 domain = p->domain_info;
2184 tomoyo_flags = p->tomoyo_flags;
2185 }
2186 read_unlock(&tasklist_lock);
2187 /***** CRITICAL SECTION END *****/
2188 if (!domain)
2189 goto done;
2190 if (!task_info)
2191 ccs_io_printf(head, "%u %u %s", pid, domain->profile,
2192 domain->domainname->name);
2193 else
2194 ccs_io_printf(head, "%u manager=%s execute_handler=%s "
2195 "state[0]=%u state[1]=%u state[2]=%u", pid,
2196 tomoyo_flags & CCS_TASK_IS_POLICY_MANAGER ?
2197 "yes" : "no",
2198 tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER ?
2199 "yes" : "no",
2200 (u8) (tomoyo_flags >> 24),
2201 (u8) (tomoyo_flags >> 16),
2202 (u8) (tomoyo_flags >> 8));
2203 done:
2204 return 0;
2205 }
2206
2207 #ifdef CONFIG_TOMOYO
2208
2209 /**
2210 * ccs_write_exception_policy - Write exception policy.
2211 *
2212 * @head: Pointer to "struct ccs_io_buffer".
2213 *
2214 * Returns 0 on success, negative value otherwise.
2215 */
2216 static int ccs_write_exception_policy(struct ccs_io_buffer *head)
2217 {
2218 char *data = head->write_buf;
2219 bool is_delete = ccs_str_starts(&data, KEYWORD_DELETE);
2220 if (ccs_str_starts(&data, KEYWORD_KEEP_DOMAIN))
2221 return ccs_write_domain_keeper_policy(data, false, is_delete);
2222 if (ccs_str_starts(&data, KEYWORD_NO_KEEP_DOMAIN))
2223 return ccs_write_domain_keeper_policy(data, true, is_delete);
2224 if (ccs_str_starts(&data, KEYWORD_INITIALIZE_DOMAIN))
2225 return ccs_write_domain_initializer_policy(data, false,
2226 is_delete);
2227 if (ccs_str_starts(&data, KEYWORD_NO_INITIALIZE_DOMAIN))
2228 return ccs_write_domain_initializer_policy(data, true,
2229 is_delete);
2230 if (ccs_str_starts(&data, KEYWORD_ALIAS))
2231 return ccs_write_alias_policy(data, is_delete);
2232 if (ccs_str_starts(&data, KEYWORD_AGGREGATOR))
2233 return ccs_write_aggregator_policy(data, is_delete);
2234 if (ccs_str_starts(&data, KEYWORD_ALLOW_READ))
2235 return ccs_write_globally_readable_policy(data, is_delete);
2236 if (ccs_str_starts(&data, KEYWORD_ALLOW_ENV))
2237 return ccs_write_globally_usable_env_policy(data, is_delete);
2238 if (ccs_str_starts(&data, KEYWORD_FILE_PATTERN))
2239 return ccs_write_pattern_policy(data, is_delete);
2240 if (ccs_str_starts(&data, KEYWORD_PATH_GROUP))
2241 return ccs_write_path_group_policy(data, is_delete);
2242 if (ccs_str_starts(&data, KEYWORD_DENY_REWRITE))
2243 return ccs_write_no_rewrite_policy(data, is_delete);
2244 if (ccs_str_starts(&data, KEYWORD_ADDRESS_GROUP))
2245 return ccs_write_address_group_policy(data, is_delete);
2246 return -EINVAL;
2247 }
2248
2249 /**
2250 * ccs_read_exception_policy - Read exception policy.
2251 *
2252 * @head: Pointer to "struct ccs_io_buffer".
2253 *
2254 * Returns 0 on success, -EINVAL otherwise.
2255 */
2256 static int ccs_read_exception_policy(struct ccs_io_buffer *head)
2257 {
2258 if (!head->read_eof) {
2259 switch (head->read_step) {
2260 case 0:
2261 head->read_var2 = NULL;
2262 head->read_step = 1;
2263 case 1:
2264 if (!ccs_read_domain_keeper_policy(head))
2265 break;
2266 head->read_var2 = NULL;
2267 head->read_step = 2;
2268 case 2:
2269 if (!ccs_read_globally_readable_policy(head))
2270 break;
2271 head->read_var2 = NULL;
2272 head->read_step = 3;
2273 case 3:
2274 if (!ccs_read_globally_usable_env_policy(head))
2275 break;
2276 head->read_var2 = NULL;
2277 head->read_step = 4;
2278 case 4:
2279 if (!ccs_read_domain_initializer_policy(head))
2280 break;
2281 head->read_var2 = NULL;
2282 head->read_step = 5;
2283 case 5:
2284 if (!ccs_read_alias_policy(head))
2285 break;
2286 head->read_var2 = NULL;
2287 head->read_step = 6;
2288 case 6:
2289 if (!ccs_read_aggregator_policy(head))
2290 break;
2291 head->read_var2 = NULL;
2292 head->read_step = 7;
2293 case 7:
2294 if (!ccs_read_file_pattern(head))
2295 break;
2296 head->read_var2 = NULL;
2297 head->read_step = 8;
2298 case 8:
2299 if (!ccs_read_no_rewrite_policy(head))
2300 break;
2301 head->read_var2 = NULL;
2302 head->read_step = 9;
2303 case 9:
2304 if (!ccs_read_path_group_policy(head))
2305 break;
2306 head->read_var1 = NULL;
2307 head->read_var2 = NULL;
2308 head->read_step = 10;
2309 case 10:
2310 if (!ccs_read_address_group_policy(head))
2311 break;
2312 head->read_eof = true;
2313 break;
2314 default:
2315 return -EINVAL;
2316 }
2317 }
2318 return 0;
2319 }
2320
2321 #endif
2322
2323 #ifdef CONFIG_SAKURA
2324
2325 /**
2326 * ccs_write_system_policy - Write system policy.
2327 *
2328 * @head: Pointer to "struct ccs_io_buffer".
2329 *
2330 * Returns 0 on success, negative value otherwise.
2331 */
2332 static int ccs_write_system_policy(struct ccs_io_buffer *head)
2333 {
2334 char *data = head->write_buf;
2335 bool is_delete = false;
2336 if (ccs_str_starts(&data, KEYWORD_DELETE))
2337 is_delete = true;
2338 if (ccs_str_starts(&data, KEYWORD_ALLOW_MOUNT))
2339 return ccs_write_mount_policy(data, is_delete);
2340 if (ccs_str_starts(&data, KEYWORD_DENY_UNMOUNT))
2341 return ccs_write_no_umount_policy(data, is_delete);
2342 if (ccs_str_starts(&data, KEYWORD_ALLOW_CHROOT))
2343 return ccs_write_chroot_policy(data, is_delete);
2344 if (ccs_str_starts(&data, KEYWORD_ALLOW_PIVOT_ROOT))
2345 return ccs_write_pivot_root_policy(data, is_delete);
2346 if (ccs_str_starts(&data, KEYWORD_DENY_AUTOBIND))
2347 return ccs_write_reserved_port_policy(data, is_delete);
2348 return -EINVAL;
2349 }
2350
2351 /**
2352 * ccs_read_system_policy - Read system policy.
2353 *
2354 * @head: Pointer to "struct ccs_io_buffer".
2355 *
2356 * Returns 0 on success, -EINVAL otherwise.
2357 */
2358 static int ccs_read_system_policy(struct ccs_io_buffer *head)
2359 {
2360 if (!head->read_eof) {
2361 switch (head->read_step) {
2362 case 0:
2363 head->read_var2 = NULL;
2364 head->read_step = 1;
2365 case 1:
2366 if (!ccs_read_mount_policy(head))
2367 break;
2368 head->read_var2 = NULL;
2369 head->read_step = 2;
2370 case 2:
2371 if (!ccs_read_no_umount_policy(head))
2372 break;
2373 head->read_var2 = NULL;
2374 head->read_step = 3;
2375 case 3:
2376 if (!ccs_read_chroot_policy(head))
2377 break;
2378 head->read_var2 = NULL;
2379 head->read_step = 4;
2380 case 4:
2381 if (!ccs_read_pivot_root_policy(head))
2382 break;
2383 head->read_var2 = NULL;
2384 head->read_step = 5;
2385 case 5:
2386 if (!ccs_read_reserved_port_policy(head))
2387 break;
2388 head->read_eof = true;
2389 break;
2390 default:
2391 return -EINVAL;
2392 }
2393 }
2394 return 0;
2395 }
2396
2397 #endif
2398
2399 /* Path to the policy loader. The default is /sbin/ccs-init. */
2400 static const char *ccs_loader;
2401
2402 /**
2403 * ccs_loader_setup - Specify the policy loader to use.
2404 *
2405 * @str: Path to the policy loader.
2406 *
2407 * Returns 0.
2408 */
2409 static int __init ccs_loader_setup(char *str)
2410 {
2411 ccs_loader = str;
2412 return 0;
2413 }
2414
2415 __setup("CCS_loader=", ccs_loader_setup);
2416
2417 /**
2418 * ccs_policy_loader_exists - Check whether /sbin/ccs-init exists.
2419 *
2420 * Returns true if /sbin/ccs-init exists, false otherwise.
2421 */
2422 static bool ccs_policy_loader_exists(void)
2423 {
2424 /*
2425 * Don't activate MAC if the path given by 'CCS_loader=' option doesn't
2426 * exist. If the initrd includes /sbin/init but real-root-dev has not
2427 * mounted on / yet, activating MAC will block the system since
2428 * policies are not loaded yet.
2429 * Thus, let do_execve() call this function everytime.
2430 */
2431 struct nameidata nd;
2432 if (!ccs_loader)
2433 ccs_loader = "/sbin/ccs-init";
2434 if (path_lookup(ccs_loader, ccs_lookup_flags, &nd)) {
2435 printk(KERN_INFO "Not activating Mandatory Access Control now "
2436 "since %s doesn't exist.\n", ccs_loader);
2437 return false;
2438 }
2439 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
2440 path_put(&nd.path);
2441 #else
2442 path_release(&nd);
2443 #endif
2444 return true;
2445 }
2446
2447 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
2448 /**
2449 * ccs_run_loader - Start /sbin/ccs-init .
2450 *
2451 * @unused: Not used.
2452 *
2453 * Returns PID of /sbin/ccs-init on success, negative value otherwise.
2454 */
2455 static int ccs_run_loader(void *unused)
2456 {
2457 char *argv[2];
2458 char *envp[3];
2459 printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
2460 ccs_loader);
2461 argv[0] = (char *) ccs_loader;
2462 argv[1] = NULL;
2463 envp[0] = "HOME=/";
2464 envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
2465 envp[2] = NULL;
2466 return exec_usermodehelper(argv[0], argv, envp);
2467 }
2468 #endif
2469
2470 /**
2471 * ccs_load_policy - Run external policy loader to load policy.
2472 *
2473 * @filename: The program about to start.
2474 *
2475 * This function checks whether @filename is /sbin/init , and if so
2476 * invoke /sbin/ccs-init and wait for the termination of /sbin/ccs-init
2477 * and then continues invocation of /sbin/init.
2478 * /sbin/ccs-init reads policy files in /etc/ccs/ directory and
2479 * writes to /proc/ccs/ interfaces.
2480 *
2481 * Returns nothing.
2482 */
2483 void ccs_load_policy(const char *filename)
2484 {
2485 if (ccs_sbin_init_started)
2486 return;
2487 /*
2488 * Check filename is /sbin/init or /sbin/ccs-start.
2489 * /sbin/ccs-start is a dummy filename in case where /sbin/init can't
2490 * be passed.
2491 * You can create /sbin/ccs-start by "ln -s /bin/true /sbin/ccs-start".
2492 */
2493 if (strcmp(filename, "/sbin/init") &&
2494 strcmp(filename, "/sbin/ccs-start"))
2495 return;
2496 if (!ccs_policy_loader_exists())
2497 return;
2498 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
2499 {
2500 char *argv[2];
2501 char *envp[3];
2502 printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
2503 ccs_loader);
2504 argv[0] = (char *) ccs_loader;
2505 argv[1] = NULL;
2506 envp[0] = "HOME=/";
2507 envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
2508 envp[2] = NULL;
2509 call_usermodehelper(argv[0], argv, envp, 1);
2510 }
2511 #elif defined(TASK_DEAD)
2512 {
2513 /* Copied from kernel/kmod.c */
2514 struct task_struct *task = current;
2515 pid_t pid = kernel_thread(ccs_run_loader, NULL, 0);
2516 sigset_t tmpsig;
2517 spin_lock_irq(&task->sighand->siglock);
2518 tmpsig = task->blocked;
2519 siginitsetinv(&task->blocked,
2520 sigmask(SIGKILL) | sigmask(SIGSTOP));
2521 recalc_sigpending();
2522 spin_unlock_irq(&current->sighand->siglock);
2523 if (pid >= 0)
2524 waitpid(pid, NULL, __WCLONE);
2525 spin_lock_irq(&task->sighand->siglock);
2526 task->blocked = tmpsig;
2527 recalc_sigpending();
2528 spin_unlock_irq(&task->sighand->siglock);
2529 }
2530 #else
2531 {
2532 /* Copied from kernel/kmod.c */
2533 struct task_struct *task = current;
2534 pid_t pid = kernel_thread(ccs_run_loader, NULL, 0);
2535 sigset_t tmpsig;
2536 spin_lock_irq(&task->sigmask_lock);
2537 tmpsig = task->blocked;
2538 siginitsetinv(&task->blocked,
2539 sigmask(SIGKILL) | sigmask(SIGSTOP));
2540 recalc_sigpending(task);
2541 spin_unlock_irq(&task->sigmask_lock);
2542 if (pid >= 0)
2543 waitpid(pid, NULL, __WCLONE);
2544 spin_lock_irq(&task->sigmask_lock);
2545 task->blocked = tmpsig;
2546 recalc_sigpending(task);
2547 spin_unlock_irq(&task->sigmask_lock);
2548 }
2549 #endif
2550 #ifdef CONFIG_SAKURA
2551 printk(KERN_INFO "SAKURA: 1.6.6-pre 2009/01/05\n");
2552 #endif
2553 #ifdef CONFIG_TOMOYO
2554 printk(KERN_INFO "TOMOYO: 1.6.6-pre 2009/01/05\n");
2555 #endif
2556 printk(KERN_INFO "Mandatory Access Control activated.\n");
2557 ccs_sbin_init_started = true;
2558 ccs_log_level = KERN_WARNING;
2559 { /* Check all profiles currently assigned to domains are defined. */
2560 struct domain_info *domain;
2561 list1_for_each_entry(domain, &ccs_domain_list, list) {
2562 const u8 profile = domain->profile;
2563 if (ccs_profile_ptr[profile])
2564 continue;
2565 panic("Profile %u (used by '%s') not defined.\n",
2566 profile, domain->domainname->name);
2567 }
2568 }
2569 }
2570
2571 /* Wait queue for ccs_query_list. */
2572 static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait);
2573
2574 /* Lock for manipulating ccs_query_list. */
2575 static DEFINE_SPINLOCK(ccs_query_list_lock);
2576
2577 /* Structure for query. */
2578 struct ccs_query_entry {
2579 struct list_head list;
2580 char *query;
2581 int query_len;
2582 unsigned int serial;
2583 int timer;
2584 int answer;
2585 };
2586
2587 /* The list for "struct ccs_query_entry". */
2588 static LIST_HEAD(ccs_query_list);
2589
2590 /* Number of "struct file" referring /proc/ccs/query interface. */
2591 static atomic_t ccs_queryd_watcher = ATOMIC_INIT(0);
2592
2593 /**
2594 * ccs_check_supervisor - Ask for the supervisor's decision.
2595 *
2596 * @r: Pointer to "struct ccs_request_info".
2597 * @fmt: The printf()'s format string, followed by parameters.
2598 *
2599 * Returns 0 if the supervisor decided to permit the access request which
2600 * violated the policy in enforcing mode, 1 if the supervisor decided to
2601 * retry the access request which violated the policy in enforcing mode,
2602 * -EPERM otherwise.
2603 */
2604 int ccs_check_supervisor(struct ccs_request_info *r, const char *fmt, ...)
2605 {
2606 va_list args;
2607 int error = -EPERM;
2608 int pos;
2609 int len;
2610 static unsigned int ccs_serial;
2611 struct ccs_query_entry *ccs_query_entry = NULL;
2612 char *header;
2613 if (!r->domain)
2614 r->domain = current->domain_info;
2615 if (!atomic_read(&ccs_queryd_watcher)) {
2616 int i;
2617 if (current->tomoyo_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR)
2618 return -EPERM;
2619 for (i = 0; i < ccs_check_flags(r->domain, CCS_SLEEP_PERIOD);
2620 i++) {
2621 set_current_state(TASK_INTERRUPTIBLE);
2622 schedule_timeout(HZ / 10);
2623 }
2624 return -EPERM;
2625 }
2626 va_start(args, fmt);
2627 len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;
2628 va_end(args);
2629 #ifdef CONFIG_TOMOYO
2630 header = ccs_init_audit_log(&len, r);
2631 #else
2632 header = ccs_alloc(1, true);
2633 #endif
2634 if (!header)
2635 goto out;
2636 ccs_query_entry = ccs_alloc(sizeof(*ccs_query_entry), true);
2637 if (!ccs_query_entry)
2638 goto out;
2639 ccs_query_entry->query = ccs_alloc(len, true);
2640 if (!ccs_query_entry->query)
2641 goto out;
2642 INIT_LIST_HEAD(&ccs_query_entry->list);
2643 /***** CRITICAL SECTION START *****/
2644 spin_lock(&ccs_query_list_lock);
2645 ccs_query_entry->serial = ccs_serial++;
2646 spin_unlock(&ccs_query_list_lock);
2647 /***** CRITICAL SECTION END *****/
2648 pos = snprintf(ccs_query_entry->query, len - 1, "Q%u-%hu\n%s",
2649 ccs_query_entry->serial, r->retry, header);
2650 ccs_free(header);
2651 header = NULL;
2652 va_start(args, fmt);
2653 vsnprintf(ccs_query_entry->query + pos, len - 1 - pos, fmt, args);
2654 ccs_query_entry->query_len = strlen(ccs_query_entry->query) + 1;
2655 va_end(args);
2656 /***** CRITICAL SECTION START *****/
2657 spin_lock(&ccs_query_list_lock);
2658 list_add_tail(&ccs_query_entry->list, &ccs_query_list);
2659 spin_unlock(&ccs_query_list_lock);
2660 /***** CRITICAL SECTION END *****/
2661 ccs_update_counter(CCS_UPDATES_COUNTER_QUERY);
2662 /* Give 10 seconds for supervisor's opinion. */
2663 for (ccs_query_entry->timer = 0;
2664 atomic_read(&ccs_queryd_watcher) && ccs_query_entry->timer < 100;
2665 ccs_query_entry->timer++) {
2666 wake_up(&ccs_query_wait);
2667 set_current_state(TASK_INTERRUPTIBLE);
2668 schedule_timeout(HZ / 10);
2669 if (ccs_query_entry->answer)
2670 break;
2671 }
2672 ccs_update_counter(CCS_UPDATES_COUNTER_QUERY);
2673 /***** CRITICAL SECTION START *****/
2674 spin_lock(&ccs_query_list_lock);
2675 list_del(&ccs_query_entry->list);
2676 spin_unlock(&ccs_query_list_lock);
2677 /***** CRITICAL SECTION END *****/
2678 switch (ccs_query_entry->answer) {
2679 case 3: /* Asked to retry by administrator. */
2680 error = 1;
2681 r->retry++;
2682 break;
2683 case 1:
2684 /* Granted by administrator. */
2685 error = 0;
2686 break;
2687 case 0:
2688 /* Timed out. */
2689 break;
2690 default:
2691 /* Rejected by administrator. */
2692 break;
2693 }
2694 out:
2695 if (ccs_query_entry)
2696 ccs_free(ccs_query_entry->query);
2697 ccs_free(ccs_query_entry);
2698 ccs_free(header);
2699 return error;
2700 }
2701
2702 /**
2703 * ccs_poll_query - poll() for /proc/ccs/query.
2704 *
2705 * @file: Pointer to "struct file".
2706 * @wait: Pointer to "poll_table".
2707 *
2708 * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise.
2709 *
2710 * Waits for access requests which violated policy in enforcing mode.
2711 */
2712 static int ccs_poll_query(struct file *file, poll_table *wait)
2713 {
2714 struct list_head *tmp;
2715 bool found = false;
2716 u8 i;
2717 for (i = 0; i < 2; i++) {
2718 /***** CRITICAL SECTION START *****/
2719 spin_lock(&ccs_query_list_lock);
2720 list_for_each(tmp, &ccs_query_list) {
2721 struct ccs_query_entry *ptr
2722 = list_entry(tmp, struct ccs_query_entry, list);
2723 if (ptr->answer)
2724 continue;
2725 found = true;
2726 break;
2727 }
2728 spin_unlock(&ccs_query_list_lock);
2729 /***** CRITICAL SECTION END *****/
2730 if (found)
2731 return POLLIN | POLLRDNORM;
2732 if (i)
2733 break;
2734 poll_wait(file, &ccs_query_wait, wait);
2735 }
2736 return 0;
2737 }
2738
2739 /**
2740 * ccs_read_query - Read access requests which violated policy in enforcing mode.
2741 *
2742 * @head: Pointer to "struct ccs_io_buffer".
2743 *
2744 * Returns 0.
2745 */
2746 static int ccs_read_query(struct ccs_io_buffer *head)
2747 {
2748 struct list_head *tmp;
2749 int pos = 0;
2750 int len = 0;
2751 char *buf;
2752 if (head->read_avail)
2753 return 0;
2754 if (head->read_buf) {
2755 ccs_free(head->read_buf);
2756 head->read_buf = NULL;
2757 head->readbuf_size = 0;
2758 }
2759 /***** CRITICAL SECTION START *****/
2760 spin_lock(&ccs_query_list_lock);
2761 list_for_each(tmp, &ccs_query_list) {
2762 struct ccs_query_entry *ptr
2763 = list_entry(tmp, struct ccs_query_entry, list);
2764 if (ptr->answer)
2765 continue;
2766 if (pos++ != head->read_step)
2767 continue;
2768 len = ptr->query_len;
2769 break;
2770 }
2771 spin_unlock(&ccs_query_list_lock);
2772 /***** CRITICAL SECTION END *****/
2773 if (!len) {
2774 head->read_step = 0;
2775 return 0;
2776 }
2777 buf = ccs_alloc(len, false);
2778 if (!buf)
2779 return 0;
2780 pos = 0;
2781 /***** CRITICAL SECTION START *****/
2782 spin_lock(&ccs_query_list_lock);
2783 list_for_each(tmp, &ccs_query_list) {
2784 struct ccs_query_entry *ptr
2785 = list_entry(tmp, struct ccs_query_entry, list);
2786 if (ptr->answer)
2787 continue;
2788 if (pos++ != head->read_step)
2789 continue;
2790 /*
2791 * Some query can be skipped because ccs_query_list
2792 * can change, but I don't care.
2793 */
2794 if (len == ptr->query_len)
2795 memmove(buf, ptr->query, len);
2796 break;
2797 }
2798 spin_unlock(&ccs_query_list_lock);
2799 /***** CRITICAL SECTION END *****/
2800 if (buf[0]) {
2801 head->read_avail = len;
2802 head->readbuf_size = head->read_avail;
2803 head->read_buf = buf;
2804 head->read_step++;
2805 } else {
2806 ccs_free(buf);
2807 }
2808 return 0;
2809 }
2810
2811 /**
2812 * ccs_write_answer - Write the supervisor's decision.
2813 *
2814 * @head: Pointer to "struct ccs_io_buffer".
2815 *
2816 * Returns 0 on success, -EINVAL otherwise.
2817 */
2818 static int ccs_write_answer(struct ccs_io_buffer *head)
2819 {
2820 char *data = head->write_buf;
2821 struct list_head *tmp;
2822 unsigned int serial;
2823 unsigned int answer;
2824 /***** CRITICAL SECTION START *****/
2825 spin_lock(&ccs_query_list_lock);
2826 list_for_each(tmp, &ccs_query_list) {
2827 struct ccs_query_entry *ptr
2828 = list_entry(tmp, struct ccs_query_entry, list);
2829 ptr->timer = 0;
2830 }
2831 spin_unlock(&ccs_query_list_lock);
2832 /***** CRITICAL SECTION END *****/
2833 if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
2834 return -EINVAL;
2835 /***** CRITICAL SECTION START *****/
2836 spin_lock(&ccs_query_list_lock);
2837 list_for_each(tmp, &ccs_query_list) {
2838 struct ccs_query_entry *ptr
2839 = list_entry(tmp, struct ccs_query_entry, list);
2840 if (ptr->serial != serial)
2841 continue;
2842 if (!ptr->answer)
2843 ptr->answer = answer;
2844 break;
2845 }
2846 spin_unlock(&ccs_query_list_lock);
2847 /***** CRITICAL SECTION END *****/
2848 return 0;
2849 }
2850
2851 /* Policy updates counter. */
2852 static unsigned int ccs_updates_counter[MAX_CCS_UPDATES_COUNTER];
2853
2854 /* Policy updates counter lock. */
2855 static DEFINE_SPINLOCK(ccs_updates_counter_lock);
2856
2857 /**
2858 * ccs_update_counter - Increment policy change counter.
2859 *
2860 * @index: Type of policy.
2861 *
2862 * Returns nothing.
2863 */
2864 void ccs_update_counter(const unsigned char index)
2865 {
2866 /***** CRITICAL SECTION START *****/
2867 spin_lock(&ccs_updates_counter_lock);
2868 if (index < MAX_CCS_UPDATES_COUNTER)
2869 ccs_updates_counter[index]++;
2870 spin_unlock(&ccs_updates_counter_lock);
2871 /***** CRITICAL SECTION END *****/
2872 }
2873
2874 /**
2875 * ccs_read_updates_counter - Check for policy change counter.
2876 *
2877 * @head: Pointer to "struct ccs_io_buffer".
2878 *
2879 * Returns how many times policy has changed since the previous check.
2880 */
2881 static int ccs_read_updates_counter(struct ccs_io_buffer *head)
2882 {
2883 if (!head->read_eof) {
2884 unsigned int counter[MAX_CCS_UPDATES_COUNTER];
2885 /***** CRITICAL SECTION START *****/
2886 spin_lock(&ccs_updates_counter_lock);
2887 memmove(counter, ccs_updates_counter,
2888 sizeof(ccs_updates_counter));
2889 memset(ccs_updates_counter, 0, sizeof(ccs_updates_counter));
2890 spin_unlock(&ccs_updates_counter_lock);
2891 /***** CRITICAL SECTION END *****/
2892 ccs_io_printf(head,
2893 "/proc/ccs/system_policy: %10u\n"
2894 "/proc/ccs/domain_policy: %10u\n"
2895 "/proc/ccs/exception_policy: %10u\n"
2896 "/proc/ccs/profile: %10u\n"
2897 "/proc/ccs/query: %10u\n"
2898 "/proc/ccs/manager: %10u\n"
2899 "/proc/ccs/grant_log: %10u\n"
2900 "/proc/ccs/reject_log: %10u\n",
2901 counter[CCS_UPDATES_COUNTER_SYSTEM_POLICY],
2902 counter[CCS_UPDATES_COUNTER_DOMAIN_POLICY],
2903 counter[CCS_UPDATES_COUNTER_EXCEPTION_POLICY],
2904 counter[CCS_UPDATES_COUNTER_PROFILE],
2905 counter[CCS_UPDATES_COUNTER_QUERY],
2906 counter[CCS_UPDATES_COUNTER_MANAGER],
2907 counter[CCS_UPDATES_COUNTER_GRANT_LOG],
2908 counter[CCS_UPDATES_COUNTER_REJECT_LOG]);
2909 head->read_eof = true;
2910 }
2911 return 0;
2912 }
2913
2914 /**
2915 * ccs_read_version: Get version.
2916 *
2917 * @head: Pointer to "struct ccs_io_buffer".
2918 *
2919 * Returns version information.
2920 */
2921 static int ccs_read_version(struct ccs_io_buffer *head)
2922 {
2923 if (!head->read_eof) {
2924 ccs_io_printf(head, "1.6.6-pre");
2925 head->read_eof = true;
2926 }
2927 return 0;
2928 }
2929
2930 /**
2931 * ccs_read_self_domain - Get the current process's domainname.
2932 *
2933 * @head: Pointer to "struct ccs_io_buffer".
2934 *
2935 * Returns the current process's domainname.
2936 */
2937 static int ccs_read_self_domain(struct ccs_io_buffer *head)
2938 {
2939 if (!head->read_eof) {
2940 /*
2941 * current->domain_info->domainname != NULL
2942 * because every process belongs to a domain and
2943 * the domain's name cannot be NULL.
2944 */
2945 ccs_io_printf(head, "%s",
2946 current->domain_info->domainname->name);
2947 head->read_eof = true;
2948 }
2949 return 0;
2950 }
2951
2952 /**
2953 * ccs_open_control - open() for /proc/ccs/ interface.
2954 *
2955 * @type: Type of interface.
2956 * @file: Pointer to "struct file".
2957 *
2958 * Associates policy handler and returns 0 on success, -ENOMEM otherwise.
2959 */
2960 int ccs_open_control(const u8 type, struct file *file)
2961 {
2962 struct ccs_io_buffer *head = ccs_alloc(sizeof(*head), false);
2963 if (!head)
2964 return -ENOMEM;
2965 mutex_init(&head->io_sem);
2966 switch (type) {
2967 #ifdef CONFIG_SAKURA
2968 case CCS_SYSTEMPOLICY: /* /proc/ccs/system_policy */
2969 head->write = ccs_write_system_policy;
2970 head->read = ccs_read_system_policy;
2971 break;
2972 #endif
2973 #ifdef CONFIG_TOMOYO
2974 case CCS_DOMAINPOLICY: /* /proc/ccs/domain_policy */
2975 head->write = ccs_write_domain_policy;
2976 head->read = ccs_read_domain_policy;
2977 break;
2978 case CCS_EXCEPTIONPOLICY: /* /proc/ccs/exception_policy */
2979 head->write = ccs_write_exception_policy;
2980 head->read = ccs_read_exception_policy;
2981 break;
2982 case CCS_GRANTLOG: /* /proc/ccs/grant_log */
2983 head->poll = ccs_poll_grant_log;
2984 head->read = ccs_read_grant_log;
2985 break;
2986 case CCS_REJECTLOG: /* /proc/ccs/reject_log */
2987 head->poll = ccs_poll_reject_log;
2988 head->read = ccs_read_reject_log;
2989 break;
2990 #endif
2991 case CCS_SELFDOMAIN: /* /proc/ccs/self_domain */
2992 head->read = ccs_read_self_domain;
2993 break;
2994 case CCS_DOMAIN_STATUS: /* /proc/ccs/.domain_status */
2995 head->write = ccs_write_domain_profile;
2996 head->read = ccs_read_domain_profile;
2997 break;
2998 case CCS_EXECUTE_HANDLER: /* /proc/ccs/.execute_handler */
2999 /* Allow execute_handler to read process's status. */
3000 if (!(current->tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER)) {
3001 ccs_free(head);
3002 return -EPERM;
3003 }
3004 /* fall through */
3005 case CCS_PROCESS_STATUS: /* /proc/ccs/.process_status */
3006 head->write = ccs_write_pid;
3007 head->read = ccs_read_pid;
3008 break;
3009 case CCS_VERSION: /* /proc/ccs/version */
3010 head->read = ccs_read_version;
3011 head->readbuf_size = 128;
3012 break;
3013 case CCS_MEMINFO: /* /proc/ccs/meminfo */
3014 head->write = ccs_write_memory_quota;
3015 head->read = ccs_read_memory_counter;
3016 head->readbuf_size = 512;
3017 break;
3018 case CCS_PROFILE: /* /proc/ccs/profile */
3019 head->write = ccs_write_profile;
3020 head->read = ccs_read_profile;
3021 break;
3022 case CCS_QUERY: /* /proc/ccs/query */
3023 head->poll = ccs_poll_query;
3024 head->write = ccs_write_answer;
3025 head->read = ccs_read_query;
3026 break;
3027 case CCS_MANAGER: /* /proc/ccs/manager */
3028 head->write = ccs_write_manager_policy;
3029 head->read = ccs_read_manager_policy;
3030 break;
3031 case CCS_UPDATESCOUNTER: /* /proc/ccs/.ccs_updates_counter */
3032 head->read = ccs_read_updates_counter;
3033 break;
3034 }
3035 if (!(file->f_mode & FMODE_READ)) {
3036 /*
3037 * No need to allocate read_buf since it is not opened
3038 * for reading.
3039 */
3040 head->read = NULL;
3041 head->poll = NULL;
3042 } else if (type != CCS_GRANTLOG && type != CCS_REJECTLOG
3043 && type != CCS_QUERY) {
3044 /*
3045 * Don't allocate buffer for reading if the file is one of
3046 * /proc/ccs/grant_log , /proc/ccs/reject_log , /proc/ccs/query.
3047 */
3048 if (!head->readbuf_size)
3049 head->readbuf_size = 4096 * 2;
3050 head->read_buf = ccs_alloc(head->readbuf_size, false);
3051 if (!head->read_buf) {
3052 ccs_free(head);
3053 return -ENOMEM;
3054 }
3055 }
3056 if (!(file->f_mode & FMODE_WRITE)) {
3057 /*
3058 * No need to allocate write_buf since it is not opened
3059 * for writing.
3060 */
3061 head->write = NULL;
3062 } else if (head->write) {
3063 head->writebuf_size = 4096 * 2;
3064 head->write_buf = ccs_alloc(head->writebuf_size, false);
3065 if (!head->write_buf) {
3066 ccs_free(head->read_buf);
3067 ccs_free(head);
3068 return -ENOMEM;
3069 }
3070 }
3071 file->private_data = head;
3072 /*
3073 * Call the handler now if the file is /proc/ccs/self_domain
3074 * so that the user can use "cat < /proc/ccs/self_domain" to
3075 * know the current process's domainname.
3076 */
3077 if (type == CCS_SELFDOMAIN)
3078 ccs_read_control(file, NULL, 0);
3079 /*
3080 * If the file is /proc/ccs/query , increment the monitor count.
3081 * The monitor count is used by ccs_check_supervisor() to see if
3082 * there is some process monitoring /proc/ccs/query.
3083 */
3084 else if (head->write == ccs_write_answer ||
3085 head->read == ccs_read_query)
3086 atomic_inc(&ccs_queryd_watcher);
3087 return 0;
3088 }
3089
3090 /**
3091 * ccs_poll_control - poll() for /proc/ccs/ interface.
3092 *
3093 * @file: Pointer to "struct file".
3094 * @wait: Pointer to "poll_table".
3095 *
3096 * Waits for read readiness.
3097 * /proc/ccs/query is handled by /usr/lib/ccs/ccs-queryd and
3098 * /proc/ccs/grant_log and /proc/ccs/reject_log are handled by
3099 * /usr/lib/ccs/ccs-auditd.
3100 */
3101 int ccs_poll_control(struct file *file, poll_table *wait)
3102 {
3103 struct ccs_io_buffer *head = file->private_data;
3104 if (!head->poll)
3105 return -ENOSYS;
3106 return head->poll(file, wait);
3107 }
3108
3109 /**
3110 * ccs_read_control - read() for /proc/ccs/ interface.
3111 *
3112 * @file: Pointer to "struct file".
3113 * @buffer: Poiner to buffer to write to.
3114 * @buffer_len: Size of @buffer.
3115 *
3116 * Returns bytes read on success, negative value otherwise.
3117 */
3118 int ccs_read_control(struct file *file, char __user *buffer,
3119 const int buffer_len)
3120 {
3121 int len = 0;
3122 struct ccs_io_buffer *head = file->private_data;
3123 char *cp;
3124 if (!head->read)
3125 return -ENOSYS;
3126 if (!access_ok(VERIFY_WRITE, buffer, buffer_len))
3127 return -EFAULT;
3128 if (mutex_lock_interruptible(&head->io_sem))
3129 return -EINTR;
3130 /* Call the policy handler. */
3131 len = head->read(head);
3132 if (len < 0)
3133 goto out;
3134 /* Write to buffer. */
3135 len = head->read_avail;
3136 if (len > buffer_len)
3137 len = buffer_len;
3138 if (!len)
3139 goto out;
3140 /* head->read_buf changes by some functions. */
3141 cp = head->read_buf;
3142 if (copy_to_user(buffer, cp, len)) {
3143 len = -EFAULT;
3144 goto out;
3145 }
3146 head->read_avail -= len;
3147 memmove(cp, cp + len, head->read_avail);
3148 out:
3149 mutex_unlock(&head->io_sem);
3150 return len;
3151 }
3152
3153 /**
3154 * ccs_write_control - write() for /proc/ccs/ interface.
3155 *
3156 * @file: Pointer to "struct file".
3157 * @buffer: Pointer to buffer to read from.
3158 * @buffer_len: Size of @buffer.
3159 *
3160 * Returns @buffer_len on success, negative value otherwise.
3161 */
3162 int ccs_write_control(struct file *file, const char __user *buffer,
3163 const int buffer_len)
3164 {
3165 struct ccs_io_buffer *head = file->private_data;
3166 int error = buffer_len;
3167 int avail_len = buffer_len;
3168 char *cp0 = head->write_buf;
3169 if (!head->write)
3170 return -ENOSYS;
3171 if (!access_ok(VERIFY_READ, buffer, buffer_len))
3172 return -EFAULT;
3173 /* Don't allow updating policies by non manager programs. */
3174 if (head->write != ccs_write_pid &&
3175 #ifdef CONFIG_TOMOYO
3176 head->write != ccs_write_domain_policy &&
3177 #endif
3178 !ccs_is_policy_manager())
3179 return -EPERM;
3180 if (mutex_lock_interruptible(&head->io_sem))
3181 return -EINTR;
3182 /* Read a line and dispatch it to the policy handler. */
3183 while (avail_len > 0) {
3184 char c;
3185 if (head->write_avail >= head->writebuf_size - 1) {
3186 error = -ENOMEM;
3187 break;
3188 } else if (get_user(c, buffer)) {
3189 error = -EFAULT;
3190 break;
3191 }
3192 buffer++;
3193 avail_len--;
3194 cp0[head->write_avail++] = c;
3195 if (c != '\n')
3196 continue;
3197 cp0[head->write_avail - 1] = '\0';
3198 head->write_avail = 0;
3199 ccs_normalize_line(cp0);
3200 head->write(head);
3201 }
3202 mutex_unlock(&head->io_sem);
3203 return error;
3204 }
3205
3206 /**
3207 * ccs_close_control - close() for /proc/ccs/ interface.
3208 *
3209 * @file: Pointer to "struct file".
3210 *
3211 * Releases memory and returns 0.
3212 */
3213 int ccs_close_control(struct file *file)
3214 {
3215 struct ccs_io_buffer *head = file->private_data;
3216 /*
3217 * If the file is /proc/ccs/query , decrement the monitor count.
3218 */
3219 if (head->write == ccs_write_answer || head->read == ccs_read_query)
3220 atomic_dec(&ccs_queryd_watcher);
3221 /* Release memory used for policy I/O. */
3222 ccs_free(head->read_buf);
3223 head->read_buf = NULL;
3224 ccs_free(head->write_buf);
3225 head->write_buf = NULL;
3226 ccs_free(head);
3227 head = NULL;
3228 file->private_data = NULL;
3229 return 0;
3230 }
3231
3232 /**
3233 * ccs_alloc_acl_element - Allocate permanent memory for ACL entry.
3234 *
3235 * @acl_type: Type of ACL entry.
3236 * @condition: Pointer to condition part of the ACL entry. May be NULL.
3237 *
3238 * Returns pointer to the ACL entry on success, NULL otherwise.
3239 */
3240 void *ccs_alloc_acl_element(const u8 acl_type,
3241 const struct ccs_condition_list *condition)
3242 {
3243 int len;
3244 struct ccs_acl_info *ptr;
3245 switch (acl_type) {
3246 case TYPE_SINGLE_PATH_ACL:
3247 len = sizeof(struct ccs_single_path_acl_record);
3248 break;
3249 case TYPE_DOUBLE_PATH_ACL:
3250 len = sizeof(struct ccs_double_path_acl_record);
3251 break;
3252 case TYPE_ARGV0_ACL:
3253 len = sizeof(struct ccs_argv0_acl_record);
3254 break;
3255 case TYPE_ENV_ACL:
3256 len = sizeof(struct ccs_env_acl_record);
3257 break;
3258 case TYPE_CAPABILITY_ACL:
3259 len = sizeof(struct ccs_capability_acl_record);
3260 break;
3261 case TYPE_IP_NETWORK_ACL:
3262 len = sizeof(struct ccs_ip_network_acl_record);
3263 break;
3264 case TYPE_SIGNAL_ACL:
3265 len = sizeof(struct ccs_signal_acl_record);
3266 break;
3267 case TYPE_EXECUTE_HANDLER:
3268 case TYPE_DENIED_EXECUTE_HANDLER:
3269 len = sizeof(struct ccs_execute_handler_record);
3270 break;
3271 default:
3272 return NULL;
3273 }
3274 /*
3275 * If the ACL doesn't have condition part, reduce memory usage
3276 * by eliminating sizeof(struct ccs_condition_list *).
3277 */
3278 if (!condition)
3279 len -= sizeof(ptr->access_me_via_ccs_get_condition_part);
3280 ptr = ccs_alloc_element(len);
3281 if (!ptr)
3282 return NULL;
3283 if (condition) {
3284 ptr->access_me_via_ccs_get_condition_part = condition;
3285 ptr->type = acl_type | ACL_WITH_CONDITION;
3286 return ptr;
3287 }
3288 /*
3289 * Substract sizeof(struct ccs_condition_list *) because I eliminated
3290 * sizeof(struct ccs_condition_list *) from "struct ccs_acl_info"
3291 * but I must return the start address of "struct ccs_acl_info".
3292 */
3293 ptr = (void *) (((u8 *) ptr)
3294 - sizeof(ptr->access_me_via_ccs_get_condition_part));
3295 ptr->type = acl_type;
3296 return ptr;
3297 }

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