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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1029 - (show annotations) (download) (as text)
Mon Mar 10 08:00:50 2008 UTC (16 years, 2 months ago) by kumaneko
Original Path: trunk/1.6.x/ccs-patch/fs/ccs_common.c
File MIME type: text/x-csrc
File size: 60489 byte(s)


1 /*
2 * fs/ccs_common.c
3 *
4 * Common functions for SAKURA and TOMOYO.
5 *
6 * Copyright (C) 2005-2008 NTT DATA CORPORATION
7 *
8 * Version: 1.6.0-pre 2008/03/10
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/string.h>
16 #include <linux/mm.h>
17 #include <linux/utime.h>
18 #include <linux/file.h>
19 #include <linux/module.h>
20 #include <linux/slab.h>
21 #include <asm/uaccess.h>
22 #include <stdarg.h>
23 #include <linux/version.h>
24 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
25 #include <linux/namei.h>
26 #include <linux/mount.h>
27 static const int lookup_flags = LOOKUP_FOLLOW;
28 #else
29 static const int lookup_flags = LOOKUP_FOLLOW | LOOKUP_POSITIVE;
30 #endif
31 #include <linux/realpath.h>
32 #include <linux/ccs_common.h>
33 #include <linux/ccs_proc.h>
34 #include <linux/tomoyo.h>
35 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
36 #define find_task_by_pid find_task_by_vpid
37 #endif
38
39 #ifdef CONFIG_TOMOYO_MAX_ACCEPT_ENTRY
40 #define MAX_ACCEPT_ENTRY (CONFIG_TOMOYO_MAX_ACCEPT_ENTRY)
41 #else
42 #define MAX_ACCEPT_ENTRY 2048
43 #endif
44 #ifdef CONFIG_TOMOYO_MAX_GRANT_LOG
45 #define MAX_GRANT_LOG (CONFIG_TOMOYO_MAX_GRANT_LOG)
46 #else
47 #define MAX_GRANT_LOG 1024
48 #endif
49 #ifdef CONFIG_TOMOYO_MAX_REJECT_LOG
50 #define MAX_REJECT_LOG (CONFIG_TOMOYO_MAX_REJECT_LOG)
51 #else
52 #define MAX_REJECT_LOG 1024
53 #endif
54
55 /************************* VARIABLES *************************/
56
57 /* /sbin/init started? */
58 bool sbin_init_started = false;
59
60 const char *ccs_log_level = KERN_DEBUG;
61
62 static const char *mode_4[4] = { "disabled", "learning", "permissive", "enforcing" };
63 static const char *mode_2[4] = { "disabled", "enabled", "enabled", "enabled" };
64
65 static struct {
66 const char *keyword;
67 unsigned int current_value;
68 const unsigned int max_value;
69 } ccs_control_array[CCS_MAX_CONTROL_INDEX] = {
70 [CCS_PROFILE_COMMENT] = { "COMMENT", 0, 0 }, /* Reserved for string. */
71 [CCS_TOMOYO_MAC_FOR_FILE] = { "MAC_FOR_FILE", 0, 3 },
72 [CCS_TOMOYO_MAC_FOR_ARGV0] = { "MAC_FOR_ARGV0", 0, 3 },
73 [CCS_TOMOYO_MAC_FOR_ENV] = { "MAC_FOR_ENV", 0, 3 },
74 [CCS_TOMOYO_MAC_FOR_NETWORK] = { "MAC_FOR_NETWORK", 0, 3 },
75 [CCS_TOMOYO_MAC_FOR_SIGNAL] = { "MAC_FOR_SIGNAL", 0, 3 },
76 [CCS_SAKURA_DENY_CONCEAL_MOUNT] = { "DENY_CONCEAL_MOUNT", 0, 3 },
77 [CCS_SAKURA_RESTRICT_CHROOT] = { "RESTRICT_CHROOT", 0, 3 },
78 [CCS_SAKURA_RESTRICT_MOUNT] = { "RESTRICT_MOUNT", 0, 3 },
79 [CCS_SAKURA_RESTRICT_UNMOUNT] = { "RESTRICT_UNMOUNT", 0, 3 },
80 [CCS_SAKURA_RESTRICT_PIVOT_ROOT] = { "RESTRICT_PIVOT_ROOT", 0, 3 },
81 [CCS_SAKURA_RESTRICT_AUTOBIND] = { "RESTRICT_AUTOBIND", 0, 1 },
82 [CCS_TOMOYO_MAX_ACCEPT_ENTRY] = { "MAX_ACCEPT_ENTRY", MAX_ACCEPT_ENTRY, INT_MAX },
83 [CCS_TOMOYO_MAX_GRANT_LOG] = { "MAX_GRANT_LOG", MAX_GRANT_LOG, INT_MAX },
84 [CCS_TOMOYO_MAX_REJECT_LOG] = { "MAX_REJECT_LOG", MAX_REJECT_LOG, INT_MAX },
85 [CCS_TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 },
86 [CCS_ALLOW_ENFORCE_GRACE] = { "ALLOW_ENFORCE_GRACE", 0, 1 },
87 [CCS_SLEEP_PERIOD] = { "SLEEP_PERIOD", 0, 3000 }, /* in 0.1 second */
88 };
89
90 #ifdef CONFIG_TOMOYO
91 const char *capability_control_keyword[TOMOYO_MAX_CAPABILITY_INDEX] = {
92 [TOMOYO_INET_STREAM_SOCKET_CREATE] = "inet_tcp_create",
93 [TOMOYO_INET_STREAM_SOCKET_LISTEN] = "inet_tcp_listen",
94 [TOMOYO_INET_STREAM_SOCKET_CONNECT] = "inet_tcp_connect",
95 [TOMOYO_USE_INET_DGRAM_SOCKET] = "use_inet_udp",
96 [TOMOYO_USE_INET_RAW_SOCKET] = "use_inet_ip",
97 [TOMOYO_USE_ROUTE_SOCKET] = "use_route",
98 [TOMOYO_USE_PACKET_SOCKET] = "use_packet",
99 [TOMOYO_SYS_MOUNT] = "SYS_MOUNT",
100 [TOMOYO_SYS_UMOUNT] = "SYS_UMOUNT",
101 [TOMOYO_SYS_REBOOT] = "SYS_REBOOT",
102 [TOMOYO_SYS_CHROOT] = "SYS_CHROOT",
103 [TOMOYO_SYS_KILL] = "SYS_KILL",
104 [TOMOYO_SYS_VHANGUP] = "SYS_VHANGUP",
105 [TOMOYO_SYS_SETTIME] = "SYS_TIME",
106 [TOMOYO_SYS_NICE] = "SYS_NICE",
107 [TOMOYO_SYS_SETHOSTNAME] = "SYS_SETHOSTNAME",
108 [TOMOYO_USE_KERNEL_MODULE] = "use_kernel_module",
109 [TOMOYO_CREATE_FIFO] = "create_fifo",
110 [TOMOYO_CREATE_BLOCK_DEV] = "create_block_dev",
111 [TOMOYO_CREATE_CHAR_DEV] = "create_char_dev",
112 [TOMOYO_CREATE_UNIX_SOCKET] = "create_unix_socket",
113 [TOMOYO_SYS_LINK] = "SYS_LINK",
114 [TOMOYO_SYS_SYMLINK] = "SYS_SYMLINK",
115 [TOMOYO_SYS_RENAME] = "SYS_RENAME",
116 [TOMOYO_SYS_UNLINK] = "SYS_UNLINK",
117 [TOMOYO_SYS_CHMOD] = "SYS_CHMOD",
118 [TOMOYO_SYS_CHOWN] = "SYS_CHOWN",
119 [TOMOYO_SYS_IOCTL] = "SYS_IOCTL",
120 [TOMOYO_SYS_KEXEC_LOAD] = "SYS_KEXEC_LOAD",
121 [TOMOYO_SYS_PIVOT_ROOT] = "SYS_PIVOT_ROOT",
122 [TOMOYO_SYS_PTRACE] = "SYS_PTRACE",
123 };
124 #endif
125
126 struct profile {
127 unsigned int value[CCS_MAX_CONTROL_INDEX];
128 const struct path_info *comment;
129 #ifdef CONFIG_TOMOYO
130 unsigned char capability_value[TOMOYO_MAX_CAPABILITY_INDEX];
131 #endif
132 };
133
134 static struct profile *profile_ptr[MAX_PROFILES];
135 static bool manage_by_non_root = false;
136
137 /************************* UTILITY FUNCTIONS *************************/
138
139 #ifdef CONFIG_TOMOYO
140 static int __init TOMOYO_Quiet_Setup(char *str)
141 {
142 ccs_control_array[CCS_TOMOYO_VERBOSE].current_value = 0;
143 return 0;
144 }
145
146 __setup("TOMOYO_QUIET", TOMOYO_Quiet_Setup);
147 #endif
148
149 /*
150 * Format string.
151 * Leading and trailing whitespaces are removed.
152 * Multiple whitespaces are packed into single space.
153 */
154 static void NormalizeLine(unsigned char *buffer)
155 {
156 unsigned char *sp = buffer, *dp = buffer;
157 bool first = true;
158 while (*sp && (*sp <= ' ' || *sp >= 127)) sp++;
159 while (*sp) {
160 if (!first) *dp++ = ' ';
161 first = false;
162 while (*sp > ' ' && *sp < 127) *dp++ = *sp++;
163 while (*sp && (*sp <= ' ' || *sp >= 127)) sp++;
164 }
165 *dp = '\0';
166 }
167
168 /*
169 * Check whether the given filename follows the naming rules.
170 * Returns true if follows, false otherwise.
171 */
172 bool IsCorrectPath(const char *filename, const s8 start_type, const s8 pattern_type, const s8 end_type, const char *function)
173 {
174 bool contains_pattern = false;
175 char c, d, e;
176 const char *original_filename = filename;
177 if (!filename) goto out;
178 c = *filename;
179 if (start_type == 1) { /* Must start with '/' */
180 if (c != '/') goto out;
181 } else if (start_type == -1) { /* Must not start with '/' */
182 if (c == '/') goto out;
183 }
184 if (c) c = * (strchr(filename, '\0') - 1);
185 if (end_type == 1) { /* Must end with '/' */
186 if (c != '/') goto out;
187 } else if (end_type == -1) { /* Must not end with '/' */
188 if (c == '/') goto out;
189 }
190 while ((c = *filename++) != '\0') {
191 if (c == '\\') {
192 switch ((c = *filename++)) {
193 case '\\': /* "\\" */
194 continue;
195 case '$': /* "\$" */
196 case '+': /* "\+" */
197 case '?': /* "\?" */
198 case '*': /* "\*" */
199 case '@': /* "\@" */
200 case 'x': /* "\x" */
201 case 'X': /* "\X" */
202 case 'a': /* "\a" */
203 case 'A': /* "\A" */
204 case '-': /* "\-" */
205 if (pattern_type == -1) break; /* Must not contain pattern */
206 contains_pattern = true;
207 continue;
208 case '0': /* "\ooo" */
209 case '1':
210 case '2':
211 case '3':
212 if ((d = *filename++) >= '0' && d <= '7' && (e = *filename++) >= '0' && e <= '7') {
213 const unsigned char f =
214 (((unsigned char) (c - '0')) << 6) +
215 (((unsigned char) (d - '0')) << 3) +
216 (((unsigned char) (e - '0')));
217 if (f && (f <= ' ' || f >= 127)) continue; /* pattern is not \000 */
218 }
219 }
220 goto out;
221 } else if (c <= ' ' || c >= 127) {
222 goto out;
223 }
224 }
225 if (pattern_type == 1) { /* Must contain pattern */
226 if (!contains_pattern) goto out;
227 }
228 return true;
229 out:
230 printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function, original_filename);
231 return false;
232 }
233
234 /*
235 * Check whether the given domainname follows the naming rules.
236 * Returns true if follows, false otherwise.
237 */
238 bool IsCorrectDomain(const unsigned char *domainname, const char *function)
239 {
240 unsigned char c, d, e;
241 const char *org_domainname = domainname;
242 if (!domainname || strncmp(domainname, ROOT_NAME, ROOT_NAME_LEN)) goto out;
243 domainname += ROOT_NAME_LEN;
244 if (!*domainname) return true;
245 do {
246 if (*domainname++ != ' ') goto out;
247 if (*domainname++ != '/') goto out;
248 while ((c = *domainname) != '\0' && c != ' ') {
249 domainname++;
250 if (c == '\\') {
251 switch ((c = *domainname++)) {
252 case '\\': /* "\\" */
253 continue;
254 case '0': /* "\ooo" */
255 case '1':
256 case '2':
257 case '3':
258 if ((d = *domainname++) >= '0' && d <= '7' && (e = *domainname++) >= '0' && e <= '7') {
259 const unsigned char f =
260 (((unsigned char) (c - '0')) << 6) +
261 (((unsigned char) (d - '0')) << 3) +
262 (((unsigned char) (e - '0')));
263 if (f && (f <= ' ' || f >= 127)) continue; /* pattern is not \000 */
264 }
265 }
266 goto out;
267 } else if (c < ' ' || c >= 127) {
268 goto out;
269 }
270 }
271 } while (*domainname);
272 return true;
273 out:
274 printk(KERN_DEBUG "%s: Invalid domainname '%s'\n", function, org_domainname);
275 return false;
276 }
277
278 bool IsDomainDef(const unsigned char *buffer)
279 {
280 /* while (*buffer && (*buffer <= ' ' || *buffer >= 127)) buffer++; */
281 return strncmp(buffer, ROOT_NAME, ROOT_NAME_LEN) == 0;
282 }
283
284 struct domain_info *FindDomain(const char *domainname0)
285 {
286 struct domain_info *domain;
287 struct path_info domainname;
288 domainname.name = domainname0;
289 fill_path_info(&domainname);
290 list1_for_each_entry(domain, &domain_list, list) {
291 if (!domain->is_deleted && !pathcmp(&domainname, domain->domainname)) return domain;
292 }
293 return NULL;
294 }
295
296 static int PathDepth(const char *pathname)
297 {
298 int i = 0;
299 if (pathname) {
300 char *ep = strchr(pathname, '\0');
301 if (pathname < ep--) {
302 if (*ep != '/') i++;
303 while (pathname <= ep) if (*ep-- == '/') i += 2;
304 }
305 }
306 return i;
307 }
308
309 static int const_part_length(const char *filename)
310 {
311 int len = 0;
312 if (filename) {
313 char c;
314 while ((c = *filename++) != '\0') {
315 if (c != '\\') { len++; continue; }
316 switch (c = *filename++) {
317 case '\\': /* "\\" */
318 len += 2; continue;
319 case '0': /* "\ooo" */
320 case '1':
321 case '2':
322 case '3':
323 if ((c = *filename++) >= '0' && c <= '7' && (c = *filename++) >= '0' && c <= '7') { len += 4; continue; }
324 }
325 break;
326 }
327 }
328 return len;
329 }
330
331 void fill_path_info(struct path_info *ptr)
332 {
333 const char *name = ptr->name;
334 const int len = strlen(name);
335 ptr->total_len = len;
336 ptr->const_len = const_part_length(name);
337 ptr->is_dir = len && (name[len - 1] == '/');
338 ptr->is_patterned = (ptr->const_len < len);
339 ptr->hash = full_name_hash(name, len);
340 ptr->depth = PathDepth(name);
341 }
342
343 static bool FileMatchesToPattern2(const char *filename, const char *filename_end, const char *pattern, const char *pattern_end)
344 {
345 while (filename < filename_end && pattern < pattern_end) {
346 if (*pattern != '\\') {
347 if (*filename++ != *pattern++) return false;
348 } else {
349 char c = *filename;
350 pattern++;
351 switch (*pattern) {
352 case '?':
353 if (c == '/') {
354 return false;
355 } else if (c == '\\') {
356 if ((c = filename[1]) == '\\') {
357 filename++; /* safe because filename is \\ */
358 } else if (c >= '0' && c <= '3' && (c = filename[2]) >= '0' && c <= '7' && (c = filename[3]) >= '0' && c <= '7') {
359 filename += 3; /* safe because filename is \ooo */
360 } else {
361 return false;
362 }
363 }
364 break;
365 case '\\':
366 if (c != '\\') return false;
367 if (*++filename != '\\') return false; /* safe because *filename != '\0' */
368 break;
369 case '+':
370 if (c < '0' || c > '9') return false;
371 break;
372 case 'x':
373 if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) return false;
374 break;
375 case 'a':
376 if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))) return false;
377 break;
378 case '0':
379 case '1':
380 case '2':
381 case '3':
382 if (c == '\\' && (c = filename[1]) >= '0' && c <= '3' && c == *pattern
383 && (c = filename[2]) >= '0' && c <= '7' && c == pattern[1]
384 && (c = filename[3]) >= '0' && c <= '7' && c == pattern[2]) {
385 filename += 3; /* safe because filename is \ooo */
386 pattern += 2; /* safe because pattern is \ooo */
387 break;
388 }
389 return false; /* Not matched. */
390 case '*':
391 case '@':
392 {
393 int i;
394 for (i = 0; i <= filename_end - filename; i++) {
395 if (FileMatchesToPattern2(filename + i, filename_end, pattern + 1, pattern_end)) return true;
396 if ((c = filename[i]) == '.' && *pattern == '@') break;
397 if (c == '\\') {
398 if ((c = filename[i + 1]) == '\\') {
399 i++; /* safe because filename is \\ */
400 } else if (c >= '0' && c <= '3' && (c = filename[i + 2]) >= '0' && c <= '7' && (c = filename[i + 3]) >= '0' && c <= '7') {
401 i += 3; /* safe because filename is \ooo */
402 } else {
403 break; /* Bad pattern. */
404 }
405 }
406 }
407 return false; /* Not matched. */
408 }
409 default:
410 {
411 int i, j = 0;
412 if ((c = *pattern) == '$') {
413 while ((c = filename[j]) >= '0' && c <= '9') j++;
414 } else if (c == 'X') {
415 while (((c = filename[j]) >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) j++;
416 } else if (c == 'A') {
417 while (((c = filename[j]) >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) j++;
418 }
419 for (i = 1; i <= j; i++) {
420 if (FileMatchesToPattern2(filename + i, filename_end, pattern + 1, pattern_end)) return true;
421 }
422 }
423 return false; /* Not matched or bad pattern. */
424 }
425 filename++; /* safe because *filename != '\0' */
426 pattern++; /* safe because *pattern != '\0' */
427 }
428 }
429 while (*pattern == '\\' && (*(pattern + 1) == '*' || *(pattern + 1) == '@')) pattern += 2;
430 return (filename == filename_end && pattern == pattern_end);
431 }
432
433 static bool FileMatchesToPattern(const char *filename, const char *filename_end, const char *pattern, const char *pattern_end)
434 {
435 const char *pattern_start = pattern;
436 bool first = true;
437 bool result;
438 while (pattern < pattern_end - 1) {
439 if (*pattern++ != '\\' || *pattern++ != '-') continue;
440 result = FileMatchesToPattern2(filename, filename_end, pattern_start, pattern - 2);
441 if (first) result = !result;
442 if (result) return false;
443 first = false;
444 pattern_start = pattern;
445 }
446 result = FileMatchesToPattern2(filename, filename_end, pattern_start, pattern_end);
447 return first ? result : !result;
448 }
449
450 /*
451 * Check whether the given pathname matches to the given pattern.
452 * Returns true if matches, false otherwise.
453 *
454 * The following patterns are available.
455 * \\ \ itself.
456 * \ooo Octal representation of a byte.
457 * \* More than or equals to 0 character other than '/'.
458 * \@ More than or equals to 0 character other than '/' or '.'.
459 * \? 1 byte character other than '/'.
460 * \$ More than or equals to 1 decimal digit.
461 * \+ 1 decimal digit.
462 * \X More than or equals to 1 hexadecimal digit.
463 * \x 1 hexadecimal digit.
464 * \A More than or equals to 1 alphabet character.
465 * \a 1 alphabet character.
466 * \- Subtraction operator.
467 */
468
469 bool PathMatchesToPattern(const struct path_info *pathname0, const struct path_info *pattern0)
470 {
471 /* if (!pathname || !pattern) return false; */
472 const char *pathname = pathname0->name, *pattern = pattern0->name;
473 const int len = pattern0->const_len;
474 if (!pattern0->is_patterned) return !pathcmp(pathname0, pattern0);
475 if (pathname0->depth != pattern0->depth) return false;
476 if (strncmp(pathname, pattern, len)) return false;
477 pathname += len; pattern += len;
478 while (*pathname && *pattern) {
479 const char *pathname_delimiter = strchr(pathname, '/'), *pattern_delimiter = strchr(pattern, '/');
480 if (!pathname_delimiter) pathname_delimiter = strchr(pathname, '\0');
481 if (!pattern_delimiter) pattern_delimiter = strchr(pattern, '\0');
482 if (!FileMatchesToPattern(pathname, pathname_delimiter, pattern, pattern_delimiter)) return false;
483 pathname = *pathname_delimiter ? pathname_delimiter + 1 : pathname_delimiter;
484 pattern = *pattern_delimiter ? pattern_delimiter + 1 : pattern_delimiter;
485 }
486 while (*pattern == '\\' && (*(pattern + 1) == '*' || *(pattern + 1) == '@')) pattern += 2;
487 return (!*pathname && !*pattern);
488 }
489
490 /*
491 * Transactional printf() to struct io_buffer structure.
492 * snprintf() will truncate, but io_printf() won't.
493 * Returns zero on success, nonzero otherwise.
494 */
495 int io_printf(struct io_buffer *head, const char *fmt, ...)
496 {
497 va_list args;
498 int len, pos = head->read_avail, size = head->readbuf_size - pos;
499 if (size <= 0) return -ENOMEM;
500 va_start(args, fmt);
501 len = vsnprintf(head->read_buf + pos, size, fmt, args);
502 va_end(args);
503 if (pos + len >= head->readbuf_size) return -ENOMEM;
504 head->read_avail += len;
505 return 0;
506 }
507
508 /*
509 * Get realpath() of current process.
510 * This function uses ccs_alloc(), so caller must ccs_free() if this function didn't return NULL.
511 */
512 const char *GetEXE(void)
513 {
514 struct mm_struct *mm = current->mm;
515 struct vm_area_struct *vma;
516 const char *cp = NULL;
517 if (!mm) return NULL;
518 down_read(&mm->mmap_sem);
519 for (vma = mm->mmap; vma; vma = vma->vm_next) {
520 if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
521 cp = realpath_from_dentry(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt);
522 break;
523 }
524 }
525 up_read(&mm->mmap_sem);
526 return cp;
527 }
528
529 const char *GetMSG(const bool is_enforce)
530 {
531 if (is_enforce) return "ERROR"; else return "WARNING";
532 }
533
534 /************************* DOMAIN POLICY HANDLER *************************/
535
536 /* Check whether the given access control is enabled. */
537 unsigned int CheckCCSFlags_NoSleepCheck(const u8 index)
538 {
539 const u8 profile = current->domain_info->profile;
540 return sbin_init_started && index < CCS_MAX_CONTROL_INDEX
541 #if MAX_PROFILES != 256
542 && profile < MAX_PROFILES
543 #endif
544 && profile_ptr[profile] ? profile_ptr[profile]->value[index] : 0;
545 }
546
547 static bool sleep_check(void)
548 {
549 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
550 if (unlikely(in_interrupt()))
551 #else
552 if (unlikely(in_atomic()))
553 #endif
554 {
555 static u8 count = 20;
556 if (count) {
557 count--;
558 printk(KERN_ERR "BUG: sleeping function called from invalid context.\n");
559 dump_stack();
560 }
561 return false;
562 }
563 return true;
564 }
565
566 unsigned int CheckCCSFlags(const u8 index)
567 {
568 return sleep_check() ? CheckCCSFlags_NoSleepCheck(index) : 0;
569 }
570
571 #ifdef CONFIG_TOMOYO
572 /* Check whether the given capability control is enabled. */
573 u8 CheckCapabilityFlags(const u8 index)
574 {
575 const u8 profile = current->domain_info->profile;
576 return sbin_init_started && index < TOMOYO_MAX_CAPABILITY_INDEX
577 #if MAX_PROFILES != 256
578 && profile < MAX_PROFILES
579 #endif
580 && sleep_check()
581 && profile_ptr[profile] ? profile_ptr[profile]->capability_value[index] : 0;
582 }
583
584 const char *cap_operation2keyword(const u8 operation)
585 {
586 return operation < TOMOYO_MAX_CAPABILITY_INDEX ? capability_control_keyword[operation] : NULL;
587 }
588
589 #endif
590
591 bool TomoyoVerboseMode(void)
592 {
593 return CheckCCSFlags(CCS_TOMOYO_VERBOSE) != 0;
594 }
595
596 bool CheckDomainQuota(struct domain_info * const domain)
597 {
598 unsigned int count = 0;
599 struct acl_info *ptr;
600 if (!domain) return true;
601 list1_for_each_entry(ptr, &domain->acl_info_list, list) {
602 if (!(ptr->type & ACL_DELETED)) count++;
603 }
604 if (count < CheckCCSFlags(CCS_TOMOYO_MAX_ACCEPT_ENTRY)) return true;
605 if (!domain->quota_warned) {
606 domain->quota_warned = true;
607 printk("TOMOYO-WARNING: Domain '%s' has so many ACLs to hold. Stopped learning mode.\n", domain->domainname->name);
608 }
609 return false;
610 }
611
612 static struct profile *FindOrAssignNewProfile(const unsigned int profile)
613 {
614 static DEFINE_MUTEX(profile_lock);
615 struct profile *ptr = NULL;
616 mutex_lock(&profile_lock);
617 if (profile < MAX_PROFILES && (ptr = profile_ptr[profile]) == NULL) {
618 if ((ptr = alloc_element(sizeof(*ptr))) != NULL) {
619 int i;
620 for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) ptr->value[i] = ccs_control_array[i].current_value;
621 /* Needn't to initialize "ptr->capability_value" because they are always 0. */
622 mb(); /* Avoid out-of-order execution. */
623 profile_ptr[profile] = ptr;
624 }
625 }
626 mutex_unlock(&profile_lock);
627 return ptr;
628 }
629
630 static int SetProfile(struct io_buffer *head)
631 {
632 char *data = head->write_buf;
633 unsigned int i, value;
634 char *cp;
635 struct profile *profile;
636 i = simple_strtoul(data, &cp, 10);
637 if (data != cp) {
638 if (*cp != '-') return -EINVAL;
639 data= cp + 1;
640 }
641 profile = FindOrAssignNewProfile(i);
642 if (!profile) return -EINVAL;
643 cp = strchr(data, '=');
644 if (!cp) return -EINVAL;
645 *cp = '\0';
646 UpdateCounter(CCS_UPDATES_COUNTER_PROFILE);
647 if (strcmp(data, ccs_control_array[CCS_PROFILE_COMMENT].keyword) == 0) {
648 profile->comment = SaveName(cp + 1);
649 return 0;
650 }
651 #ifdef CONFIG_TOMOYO
652 if (strncmp(data, KEYWORD_MAC_FOR_CAPABILITY, KEYWORD_MAC_FOR_CAPABILITY_LEN) == 0) {
653 if (sscanf(cp + 1, "%u", &value) != 1) {
654 for (i = 0; i < 4; i++) {
655 if (strcmp(cp + 1, mode_4[i])) continue;
656 value = i;
657 break;
658 }
659 if (i == 4) return -EINVAL;
660 }
661 if (value > 3) value = 3;
662 data += KEYWORD_MAC_FOR_CAPABILITY_LEN;
663 for (i = 0; i < TOMOYO_MAX_CAPABILITY_INDEX; i++) {
664 if (strcmp(data, capability_control_keyword[i])) continue;
665 profile->capability_value[i] = value;
666 return 0;
667 }
668 return -EINVAL;
669 }
670 #endif
671 for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) {
672 if (strcmp(data, ccs_control_array[i].keyword)) continue;
673 if (sscanf(cp + 1, "%u", &value) != 1) {
674 int j;
675 const char **modes;
676 switch (i) {
677 case CCS_SAKURA_RESTRICT_AUTOBIND:
678 case CCS_TOMOYO_VERBOSE:
679 case CCS_ALLOW_ENFORCE_GRACE:
680 modes = mode_2;
681 break;
682 default:
683 modes = mode_4;
684 break;
685 }
686 for (j = 0; j < 4; j++) {
687 if (strcmp(cp + 1, modes[j])) continue;
688 value = j;
689 break;
690 }
691 if (j == 4) return -EINVAL;
692 } else if (value > ccs_control_array[i].max_value) {
693 value = ccs_control_array[i].max_value;
694 }
695 switch (i) {
696 case CCS_SAKURA_DENY_CONCEAL_MOUNT:
697 case CCS_SAKURA_RESTRICT_UNMOUNT:
698 if (value == 1) value = 2; /* learning mode is not supported. */
699 }
700 profile->value[i] = value;
701 return 0;
702 }
703 return -EINVAL;
704 }
705
706 static int ReadProfile(struct io_buffer *head)
707 {
708 int step;
709 if (head->read_eof) return 0;
710 for (step = head->read_step; step < MAX_PROFILES * (CCS_MAX_CONTROL_INDEX + TOMOYO_MAX_CAPABILITY_INDEX); step++) {
711 const int i = step / (CCS_MAX_CONTROL_INDEX + TOMOYO_MAX_CAPABILITY_INDEX), j = step % (CCS_MAX_CONTROL_INDEX + TOMOYO_MAX_CAPABILITY_INDEX);
712 const struct profile *profile = profile_ptr[i];
713 head->read_step = step;
714 if (!profile) continue;
715 switch (j) {
716 case -1: /* Dummy */
717 #ifndef CONFIG_SAKURA
718 case CCS_SAKURA_DENY_CONCEAL_MOUNT:
719 case CCS_SAKURA_RESTRICT_CHROOT:
720 case CCS_SAKURA_RESTRICT_MOUNT:
721 case CCS_SAKURA_RESTRICT_UNMOUNT:
722 case CCS_SAKURA_RESTRICT_PIVOT_ROOT:
723 case CCS_SAKURA_RESTRICT_AUTOBIND:
724 #endif
725 #ifndef CONFIG_TOMOYO
726 case CCS_TOMOYO_MAC_FOR_FILE:
727 case CCS_TOMOYO_MAC_FOR_ARGV0:
728 case CCS_TOMOYO_MAC_FOR_ENV:
729 case CCS_TOMOYO_MAC_FOR_NETWORK:
730 case CCS_TOMOYO_MAC_FOR_SIGNAL:
731 case CCS_TOMOYO_MAX_ACCEPT_ENTRY:
732 case CCS_TOMOYO_MAX_GRANT_LOG:
733 case CCS_TOMOYO_MAX_REJECT_LOG:
734 case CCS_TOMOYO_VERBOSE:
735 #endif
736 continue;
737 }
738 if (j == CCS_PROFILE_COMMENT) {
739 if (io_printf(head, "%u-%s=%s\n", i, ccs_control_array[CCS_PROFILE_COMMENT].keyword, profile->comment ? profile->comment->name : "")) break;
740 } else if (j >= CCS_MAX_CONTROL_INDEX) {
741 #ifdef CONFIG_TOMOYO
742 const int k = j - CCS_MAX_CONTROL_INDEX;
743 if (io_printf(head, "%u-" KEYWORD_MAC_FOR_CAPABILITY "%s=%s\n", i, capability_control_keyword[k], mode_4[profile->capability_value[k]])) break;
744 #endif
745 } else {
746 const unsigned int value = profile->value[j];
747 const char **modes = NULL;
748 switch (ccs_control_array[j].max_value) {
749 case 3:
750 modes = mode_4;
751 break;
752 case 1:
753 modes = mode_2;
754 break;
755 }
756 if (modes) {
757 if (io_printf(head, "%u-%s=%s\n", i, ccs_control_array[j].keyword, modes[value])) break;
758 } else {
759 if (io_printf(head, "%u-%s=%u\n", i, ccs_control_array[j].keyword, value)) break;
760 }
761 }
762 }
763 if (step == MAX_PROFILES * (CCS_MAX_CONTROL_INDEX + TOMOYO_MAX_CAPABILITY_INDEX)) head->read_eof = true;
764 return 0;
765 }
766
767 /************************* POLICY MANAGER HANDLER *************************/
768
769 struct policy_manager_entry {
770 struct list1_head list;
771 const struct path_info *manager;
772 bool is_domain;
773 bool is_deleted;
774 };
775
776 static LIST1_HEAD(policy_manager_list);
777
778 static int AddManagerEntry(const char *manager, const bool is_delete)
779 {
780 struct policy_manager_entry *new_entry, *ptr;
781 static DEFINE_MUTEX(lock);
782 const struct path_info *saved_manager;
783 int error = -ENOMEM;
784 bool is_domain = false;
785 if (IsDomainDef(manager)) {
786 if (!IsCorrectDomain(manager, __FUNCTION__)) return -EINVAL;
787 is_domain = true;
788 } else {
789 if (!IsCorrectPath(manager, 1, -1, -1, __FUNCTION__)) return -EINVAL;
790 }
791 if ((saved_manager = SaveName(manager)) == NULL) return -ENOMEM;
792 mutex_lock(&lock);
793 list1_for_each_entry(ptr, &policy_manager_list, list) {
794 if (ptr->manager == saved_manager) {
795 ptr->is_deleted = is_delete;
796 error = 0;
797 goto out;
798 }
799 }
800 if (is_delete) {
801 error = -ENOENT;
802 goto out;
803 }
804 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
805 new_entry->manager = saved_manager;
806 new_entry->is_domain = is_domain;
807 list1_add_tail_mb(&new_entry->list, &policy_manager_list);
808 error = 0;
809 out:
810 mutex_unlock(&lock);
811 if (!error) UpdateCounter(CCS_UPDATES_COUNTER_MANAGER);
812 return error;
813 }
814
815 static int AddManagerPolicy(struct io_buffer *head)
816 {
817 const char *data = head->write_buf;
818 bool is_delete = false;
819 if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {
820 data += KEYWORD_DELETE_LEN;
821 is_delete = true;
822 }
823 if (strcmp(data, "manage_by_non_root") == 0) {
824 manage_by_non_root = !is_delete;
825 return 0;
826 }
827 return AddManagerEntry(data, is_delete);
828 }
829
830 static int ReadManagerPolicy(struct io_buffer *head)
831 {
832 struct list1_head *pos;
833 if (head->read_eof) return 0;
834 list1_for_each_cookie(pos, head->read_var2, &policy_manager_list) {
835 struct policy_manager_entry *ptr;
836 ptr = list1_entry(pos, struct policy_manager_entry, list);
837 if (ptr->is_deleted) continue;
838 if (io_printf(head, "%s\n", ptr->manager->name)) return 0;
839 }
840 head->read_eof = true;
841 return 0;
842 }
843
844 /* Check whether the current process is a policy manager. */
845 static bool IsPolicyManager(void)
846 {
847 struct policy_manager_entry *ptr;
848 const char *exe;
849 const struct task_struct *task = current;
850 const struct path_info *domainname = task->domain_info->domainname;
851 bool found = false;
852 if (!sbin_init_started) return true;
853 if (!manage_by_non_root && (task->uid || task->euid)) return false;
854 list1_for_each_entry(ptr, &policy_manager_list, list) {
855 if (!ptr->is_deleted && ptr->is_domain && !pathcmp(domainname, ptr->manager)) return true;
856 }
857 if ((exe = GetEXE()) == NULL) return false;
858 list1_for_each_entry(ptr, &policy_manager_list, list) {
859 if (!ptr->is_deleted && !ptr->is_domain && !strcmp(exe, ptr->manager->name)) {
860 found = true;
861 break;
862 }
863 }
864 if (!found) { /* Reduce error messages. */
865 static pid_t last_pid = 0;
866 const pid_t pid = current->pid;
867 if (last_pid != pid) {
868 printk("%s ( %s ) is not permitted to update policies.\n", domainname->name, exe);
869 last_pid = pid;
870 }
871 }
872 ccs_free(exe);
873 return found;
874 }
875
876 #ifdef CONFIG_TOMOYO
877
878 /************************* DOMAIN POLICY HANDLER *************************/
879
880 static char *FindConditionPart(char *data)
881 {
882 char *cp = strstr(data, " if "), *cp2;
883 if (cp) {
884 while ((cp2 = strstr(cp + 3, " if ")) != NULL) cp = cp2;
885 *cp++ = '\0';
886 } else if ((cp = strstr(data, " ; set ")) != NULL) {
887 *cp++ = '\0';
888 }
889 return cp;
890 }
891
892 static int AddDomainPolicy(struct io_buffer *head)
893 {
894 char *data = head->write_buf;
895 struct domain_info *domain = head->write_var1;
896 bool is_delete = false, is_select = false, is_undelete = false;
897 unsigned int profile;
898 const struct condition_list *cond = NULL;
899 char *cp;
900 if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {
901 data += KEYWORD_DELETE_LEN;
902 is_delete = true;
903 } else if (strncmp(data, KEYWORD_SELECT, KEYWORD_SELECT_LEN) == 0) {
904 data += KEYWORD_SELECT_LEN;
905 is_select = true;
906 } else if (strncmp(data, KEYWORD_UNDELETE, KEYWORD_UNDELETE_LEN) == 0) {
907 data += KEYWORD_UNDELETE_LEN;
908 is_undelete = true;
909 }
910 if (IsDomainDef(data)) {
911 if (is_delete) {
912 DeleteDomain(data);
913 domain = NULL;
914 } else if (is_select) {
915 domain = FindDomain(data);
916 } else if (is_undelete) {
917 domain = UndeleteDomain(data);
918 } else {
919 domain = FindOrAssignNewDomain(data, 0);
920 }
921 head->write_var1 = domain;
922 UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
923 return 0;
924 }
925 if (!domain) return -EINVAL;
926
927 if (sscanf(data, KEYWORD_USE_PROFILE "%u", &profile) == 1 && profile < MAX_PROFILES) {
928 if (profile_ptr[profile] || !sbin_init_started) domain->profile = (u8) profile;
929 return 0;
930 }
931 if (strcmp(data, KEYWORD_IGNORE_GLOBAL_ALLOW_READ) == 0) {
932 SetDomainFlag(domain, is_delete, DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ);
933 return 0;
934 }
935 if (strcmp(data, KEYWORD_IGNORE_GLOBAL_ALLOW_ENV) == 0) {
936 SetDomainFlag(domain, is_delete, DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_ENV);
937 return 0;
938 }
939 cp = FindConditionPart(data);
940 if (cp && (cond = FindOrAssignNewCondition(cp)) == NULL) return -EINVAL;
941 if (strncmp(data, KEYWORD_ALLOW_CAPABILITY, KEYWORD_ALLOW_CAPABILITY_LEN) == 0) {
942 return AddCapabilityPolicy(data + KEYWORD_ALLOW_CAPABILITY_LEN, domain, cond, is_delete);
943 } else if (strncmp(data, KEYWORD_ALLOW_NETWORK, KEYWORD_ALLOW_NETWORK_LEN) == 0) {
944 return AddNetworkPolicy(data + KEYWORD_ALLOW_NETWORK_LEN, domain, cond, is_delete);
945 } else if (strncmp(data, KEYWORD_ALLOW_SIGNAL, KEYWORD_ALLOW_SIGNAL_LEN) == 0) {
946 return AddSignalPolicy(data + KEYWORD_ALLOW_SIGNAL_LEN, domain, cond, is_delete);
947 } else if (strncmp(data, KEYWORD_ALLOW_ARGV0, KEYWORD_ALLOW_ARGV0_LEN) == 0) {
948 return AddArgv0Policy(data + KEYWORD_ALLOW_ARGV0_LEN, domain, cond, is_delete);
949 } else if (strncmp(data, KEYWORD_ALLOW_ENV, KEYWORD_ALLOW_ENV_LEN) == 0) {
950 return AddEnvPolicy(data + KEYWORD_ALLOW_ENV_LEN, domain, cond, is_delete);
951 } else {
952 return AddFilePolicy(data, domain, cond, is_delete);
953 }
954 return -EINVAL;
955 }
956
957 static bool print_single_path_acl(struct io_buffer *head, struct single_path_acl_record *ptr, const struct condition_list *cond)
958 {
959 int pos;
960 u8 bit;
961 const bool b = ptr->u_is_group;
962 const u16 perm = ptr->perm;
963 for (bit = head->read_bit; bit < MAX_SINGLE_PATH_OPERATION; bit++) {
964 const char *msg;
965 if (!(perm & (1 << bit))) continue;
966 /* Print "read/write" instead of "read" and "write". */
967 if ((bit == TYPE_READ_ACL || bit == TYPE_WRITE_ACL) && (perm & (1 << TYPE_READ_WRITE_ACL))) continue;
968 msg = sp_operation2keyword(bit);
969 pos = head->read_avail;
970 if (b && io_printf(head, "allow_%s @%s ", msg, ptr->u.group->group_name->name)) goto out;
971 if (!b && io_printf(head, "allow_%s %s ", msg, ptr->u.filename->name)) goto out;
972 if (DumpCondition(head, cond)) goto out;
973 }
974 head->read_bit = 0;
975 return true;
976 out:
977 head->read_bit = bit;
978 head->read_avail = pos;
979 return false;
980 }
981
982 static bool print_double_path_acl(struct io_buffer *head, struct double_path_acl_record *ptr, const struct condition_list *cond)
983 {
984 int pos;
985 const bool b0 = ptr->u1_is_group, b1 = ptr->u2_is_group;
986 const u8 perm = ptr->perm;
987 u8 bit;
988 for (bit = head->read_bit; bit < MAX_DOUBLE_PATH_OPERATION; bit++) {
989 const char *msg;
990 if (!(perm & (1 << bit))) continue;
991 msg = dp_operation2keyword(bit);
992 pos = head->read_avail;
993 if (io_printf(head, "allow_%s ", msg)) goto out;
994 if (b0 && io_printf(head, "@%s ", ptr->u1.group1->group_name->name)) goto out;
995 if (!b0 && io_printf(head, "%s ", ptr->u1.filename1->name)) goto out;
996 if (b1 && io_printf(head, "@%s", ptr->u2.group2->group_name->name)) goto out;
997 if (!b1 && io_printf(head, "%s", ptr->u2.filename2->name)) goto out;
998 if (DumpCondition(head, cond)) goto out;
999 }
1000 head->read_bit = 0;
1001 return true;
1002 out:
1003 head->read_bit = bit;
1004 head->read_avail = pos;
1005 return false;
1006 }
1007
1008 static bool print_argv0_acl(struct io_buffer *head, struct argv0_acl_record *ptr, const struct condition_list *cond)
1009 {
1010 int pos = head->read_avail;
1011 if (io_printf(head, KEYWORD_ALLOW_ARGV0 "%s %s",
1012 ptr->filename->name, ptr->argv0->name)) goto out;
1013 if (DumpCondition(head, cond)) goto out;
1014 return true;
1015 out:
1016 head->read_avail = pos;
1017 return false;
1018 }
1019
1020 static bool print_env_acl(struct io_buffer *head, struct env_acl_record *ptr, const struct condition_list *cond)
1021 {
1022 int pos = head->read_avail;
1023 if (io_printf(head, KEYWORD_ALLOW_ENV "%s", ptr->env->name)) goto out;
1024 if (DumpCondition(head, cond)) goto out;
1025 return true;
1026 out:
1027 head->read_avail = pos;
1028 return false;
1029 }
1030
1031 static bool print_capability_acl(struct io_buffer *head, struct capability_acl_record *ptr, const struct condition_list *cond)
1032 {
1033 int pos = head->read_avail;
1034 if (io_printf(head, KEYWORD_ALLOW_CAPABILITY "%s", cap_operation2keyword(ptr->operation))) goto out;
1035 if (DumpCondition(head, cond)) goto out;
1036 return true;
1037 out:
1038 head->read_avail = pos;
1039 return false;
1040 }
1041
1042 static bool print_network_acl(struct io_buffer *head, struct ip_network_acl_record *ptr, const struct condition_list *cond)
1043 {
1044 int pos = head->read_avail;
1045 if (io_printf(head, KEYWORD_ALLOW_NETWORK "%s ", net_operation2keyword(ptr->operation_type))) goto out;
1046 switch (ptr->record_type) {
1047 case IP_RECORD_TYPE_ADDRESS_GROUP:
1048 if (io_printf(head, "@%s", ptr->u.group->group_name->name)) goto out;
1049 break;
1050 case IP_RECORD_TYPE_IPv4:
1051 {
1052 const u32 min_address = ptr->u.ipv4.min, max_address = ptr->u.ipv4.max;
1053 if (io_printf(head, "%u.%u.%u.%u", HIPQUAD(min_address))) goto out;
1054 if (min_address != max_address && io_printf(head, "-%u.%u.%u.%u", HIPQUAD(max_address))) goto out;
1055 }
1056 break;
1057 case IP_RECORD_TYPE_IPv6:
1058 {
1059 char buf[64];
1060 const struct in6_addr *min_address = ptr->u.ipv6.min, *max_address = ptr->u.ipv6.max;
1061 print_ipv6(buf, sizeof(buf), min_address);
1062 if (io_printf(head, "%s", buf)) goto out;
1063 if (min_address != max_address) {
1064 print_ipv6(buf, sizeof(buf), max_address);
1065 if (io_printf(head, "-%s", buf)) goto out;
1066 }
1067 }
1068 break;
1069 }
1070 {
1071 const u16 min_port = ptr->min_port, max_port = ptr->max_port;
1072 if (io_printf(head, " %u", min_port)) goto out;
1073 if (min_port != max_port && io_printf(head, "-%u", max_port)) goto out;
1074 }
1075 if (DumpCondition(head, cond)) goto out;
1076 return true;
1077 out:
1078 head->read_avail = pos;
1079 return false;
1080 }
1081
1082 static bool print_signal_acl(struct io_buffer *head, struct signal_acl_record *ptr, const struct condition_list *cond)
1083 {
1084 int pos = head->read_avail;
1085 if (io_printf(head, KEYWORD_ALLOW_SIGNAL "%u %s", ptr->sig, ptr->domainname->name)) goto out;
1086 if (DumpCondition(head, cond)) goto out;
1087 return true;
1088 out:
1089 head->read_avail = pos;
1090 return false;
1091 }
1092
1093 static bool print_execute_handler_record(struct io_buffer *head, const char *keyword, struct execute_handler_record *ptr)
1094 {
1095 return io_printf(head, "%s %s\n", keyword, ptr->handler->name) == 0;
1096 }
1097
1098 static int ReadDomainPolicy(struct io_buffer *head)
1099 {
1100 struct list1_head *dpos;
1101 struct list1_head *apos;
1102 if (head->read_eof) return 0;
1103 if (head->read_step == 0) head->read_step = 1;
1104 list1_for_each_cookie(dpos, head->read_var1, &domain_list) {
1105 struct domain_info *domain;
1106 domain = list1_entry(dpos, struct domain_info, list);
1107 if (head->read_step != 1) goto acl_loop;
1108 if (domain->is_deleted) continue;
1109 if (io_printf(head, "%s\n" KEYWORD_USE_PROFILE "%u\n%s\n%s%s", domain->domainname->name, domain->profile, domain->quota_warned ? "quota_exceeded\n" : "", domain->flags & DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ ? KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n" : "", domain->flags & DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_ENV ? KEYWORD_IGNORE_GLOBAL_ALLOW_ENV "\n" : "")) return 0;
1110 head->read_step = 2;
1111 acl_loop: ;
1112 if (head->read_step == 3) goto tail_mark;
1113 list1_for_each_cookie(apos, head->read_var2, &domain->acl_info_list) {
1114 struct acl_info *ptr;
1115 u8 acl_type;
1116 const struct condition_list *cond;
1117 ptr = list1_entry(apos, struct acl_info, list);
1118 cond = GetConditionPart(ptr);
1119 acl_type = ptr->type & ~ACL_WITH_CONDITION;
1120 if (acl_type & ACL_DELETED) {
1121 /* Deleted entry. */
1122 } else if (acl_type == TYPE_SINGLE_PATH_ACL) {
1123 if (!print_single_path_acl(head, container_of(ptr, struct single_path_acl_record, head), cond)) return 0;
1124 } else if (acl_type == TYPE_DOUBLE_PATH_ACL) {
1125 if (!print_double_path_acl(head, container_of(ptr, struct double_path_acl_record, head), cond)) return 0;
1126 } else if (acl_type == TYPE_ARGV0_ACL) {
1127 if (!print_argv0_acl(head, container_of(ptr, struct argv0_acl_record, head), cond)) return 0;
1128 } else if (acl_type == TYPE_ENV_ACL) {
1129 if (!print_env_acl(head, container_of(ptr, struct env_acl_record, head), cond)) return 0;
1130 } else if (acl_type == TYPE_CAPABILITY_ACL) {
1131 if (!print_capability_acl(head, container_of(ptr, struct capability_acl_record, head), cond)) return 0;
1132 } else if (acl_type == TYPE_IP_NETWORK_ACL) {
1133 if (!print_network_acl(head, container_of(ptr, struct ip_network_acl_record, head), cond)) return 0;
1134 } else if (acl_type == TYPE_SIGNAL_ACL) {
1135 if (!print_signal_acl(head, container_of(ptr, struct signal_acl_record, head), cond)) return 0;
1136 } else if (acl_type == TYPE_PREFERRED_EXECUTE_HANDLER) {
1137 if (!print_execute_handler_record(head, KEYWORD_PREFERRED_EXECUTE_HANDLER, container_of(ptr, struct execute_handler_record, head))) return 0;
1138 } else if (acl_type == TYPE_DEFAULT_EXECUTE_HANDLER) {
1139 if (!print_execute_handler_record(head, KEYWORD_DEFAULT_EXECUTE_HANDLER, container_of(ptr, struct execute_handler_record, head))) return 0;
1140 } else {
1141 BUG();
1142 }
1143 }
1144 head->read_step = 3;
1145 tail_mark: ;
1146 if (io_printf(head, "\n")) return 0;
1147 head->read_step = 1;
1148 }
1149 head->read_eof = true;
1150 return 0;
1151 }
1152
1153 #endif
1154
1155 static int UpdateDomainProfile(struct io_buffer *head)
1156 {
1157 char *data = head->write_buf;
1158 char *cp = strchr(data, ' ');
1159 struct domain_info *domain;
1160 unsigned int profile;
1161 if (!cp) return -EINVAL;
1162 *cp = '\0';
1163 domain = FindDomain(cp + 1);
1164 profile = simple_strtoul(data, NULL, 10);
1165 if (domain && profile < MAX_PROFILES && (profile_ptr[profile] || !sbin_init_started)) domain->profile = (u8) profile;
1166 UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
1167 return 0;
1168 }
1169
1170 static int ReadDomainProfile(struct io_buffer *head)
1171 {
1172 struct list1_head *pos;
1173 if (head->read_eof) return 0;
1174 list1_for_each_cookie(pos, head->read_var1, &domain_list) {
1175 struct domain_info *domain;
1176 domain = list1_entry(pos, struct domain_info, list);
1177 if (domain->is_deleted) continue;
1178 if (io_printf(head, "%u %s\n", domain->profile, domain->domainname->name)) return 0;
1179 }
1180 head->read_eof = true;
1181 return 0;
1182 }
1183
1184 static int WritePID(struct io_buffer *head)
1185 {
1186 head->read_step = (int) simple_strtoul(head->write_buf, NULL, 10);
1187 head->read_eof = false;
1188 return 0;
1189 }
1190
1191 static int ReadPID(struct io_buffer *head)
1192 {
1193 if (head->read_avail == 0 && !head->read_eof) {
1194 const int pid = head->read_step;
1195 struct task_struct *p;
1196 struct domain_info *domain = NULL;
1197 /***** CRITICAL SECTION START *****/
1198 read_lock(&tasklist_lock);
1199 p = find_task_by_pid(pid);
1200 if (p) domain = p->domain_info;
1201 read_unlock(&tasklist_lock);
1202 /***** CRITICAL SECTION END *****/
1203 if (domain) io_printf(head, "%d %u %s", pid, domain->profile, domain->domainname->name);
1204 head->read_eof = true;
1205 }
1206 return 0;
1207 }
1208
1209 /************************* EXCEPTION POLICY HANDLER *************************/
1210
1211 #ifdef CONFIG_TOMOYO
1212
1213 static int AddExceptionPolicy(struct io_buffer *head)
1214 {
1215 char *data = head->write_buf;
1216 bool is_delete = false;
1217 UpdateCounter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
1218 if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {
1219 data += KEYWORD_DELETE_LEN;
1220 is_delete = true;
1221 }
1222 if (strncmp(data, KEYWORD_KEEP_DOMAIN, KEYWORD_KEEP_DOMAIN_LEN) == 0) {
1223 return AddDomainKeeperPolicy(data + KEYWORD_KEEP_DOMAIN_LEN, 0, is_delete);
1224 } else if (strncmp(data, KEYWORD_NO_KEEP_DOMAIN, KEYWORD_NO_KEEP_DOMAIN_LEN) == 0) {
1225 return AddDomainKeeperPolicy(data + KEYWORD_NO_KEEP_DOMAIN_LEN, 1, is_delete);
1226 } else if (strncmp(data, KEYWORD_INITIALIZE_DOMAIN, KEYWORD_INITIALIZE_DOMAIN_LEN) == 0) {
1227 return AddDomainInitializerPolicy(data + KEYWORD_INITIALIZE_DOMAIN_LEN, 0, is_delete);
1228 } else if (strncmp(data, KEYWORD_NO_INITIALIZE_DOMAIN, KEYWORD_NO_INITIALIZE_DOMAIN_LEN) == 0) {
1229 return AddDomainInitializerPolicy(data + KEYWORD_NO_INITIALIZE_DOMAIN_LEN, 1, is_delete);
1230 } else if (strncmp(data, KEYWORD_ALIAS, KEYWORD_ALIAS_LEN) == 0) {
1231 return AddAliasPolicy(data + KEYWORD_ALIAS_LEN, is_delete);
1232 } else if (strncmp(data, KEYWORD_AGGREGATOR, KEYWORD_AGGREGATOR_LEN) == 0) {
1233 return AddAggregatorPolicy(data + KEYWORD_AGGREGATOR_LEN, is_delete);
1234 } else if (strncmp(data, KEYWORD_ALLOW_READ, KEYWORD_ALLOW_READ_LEN) == 0) {
1235 return AddGloballyReadablePolicy(data + KEYWORD_ALLOW_READ_LEN, is_delete);
1236 } else if (strncmp(data, KEYWORD_ALLOW_ENV, KEYWORD_ALLOW_ENV_LEN) == 0) {
1237 return AddGloballyUsableEnvPolicy(data + KEYWORD_ALLOW_ENV_LEN, is_delete);
1238 } else if (strncmp(data, KEYWORD_FILE_PATTERN, KEYWORD_FILE_PATTERN_LEN) == 0) {
1239 return AddFilePatternPolicy(data + KEYWORD_FILE_PATTERN_LEN, is_delete);
1240 } else if (strncmp(data, KEYWORD_PATH_GROUP, KEYWORD_PATH_GROUP_LEN) == 0) {
1241 return AddPathGroupPolicy(data + KEYWORD_PATH_GROUP_LEN, is_delete);
1242 } else if (strncmp(data, KEYWORD_DENY_REWRITE, KEYWORD_DENY_REWRITE_LEN) == 0) {
1243 return AddNoRewritePolicy(data + KEYWORD_DENY_REWRITE_LEN, is_delete);
1244 } else if (strncmp(data, KEYWORD_ADDRESS_GROUP, KEYWORD_ADDRESS_GROUP_LEN) == 0) {
1245 return AddAddressGroupPolicy(data + KEYWORD_ADDRESS_GROUP_LEN, is_delete);
1246 }
1247 return -EINVAL;
1248 }
1249
1250 static int ReadExceptionPolicy(struct io_buffer *head)
1251 {
1252 if (!head->read_eof) {
1253 switch (head->read_step) {
1254 case 0:
1255 head->read_var2 = NULL; head->read_step = 1;
1256 case 1:
1257 if (ReadDomainKeeperPolicy(head)) break;
1258 head->read_var2 = NULL; head->read_step = 2;
1259 case 2:
1260 if (ReadGloballyReadablePolicy(head)) break;
1261 head->read_var2 = NULL; head->read_step = 3;
1262 case 3:
1263 if (ReadGloballyUsableEnvPolicy(head)) break;
1264 head->read_var2 = NULL; head->read_step = 4;
1265 case 4:
1266 if (ReadDomainInitializerPolicy(head)) break;
1267 head->read_var2 = NULL; head->read_step = 5;
1268 case 5:
1269 if (ReadAliasPolicy(head)) break;
1270 head->read_var2 = NULL; head->read_step = 6;
1271 case 6:
1272 if (ReadAggregatorPolicy(head)) break;
1273 head->read_var2 = NULL; head->read_step = 7;
1274 case 7:
1275 if (ReadFilePatternPolicy(head)) break;
1276 head->read_var2 = NULL; head->read_step = 8;
1277 case 8:
1278 if (ReadNoRewritePolicy(head)) break;
1279 head->read_var2 = NULL; head->read_step = 9;
1280 case 9:
1281 if (ReadPathGroupPolicy(head)) break;
1282 head->read_var1 = head->read_var2 = NULL; head->read_step = 10;
1283 case 10:
1284 if (ReadAddressGroupPolicy(head)) break;
1285 head->read_eof = true;
1286 break;
1287 default:
1288 return -EINVAL;
1289 }
1290 }
1291 return 0;
1292 }
1293
1294 #endif
1295
1296 /************************* SYSTEM POLICY HANDLER *************************/
1297
1298 #ifdef CONFIG_SAKURA
1299
1300 static int AddSystemPolicy(struct io_buffer *head)
1301 {
1302 char *data = head->write_buf;
1303 bool is_delete = false;
1304 UpdateCounter(CCS_UPDATES_COUNTER_SYSTEM_POLICY);
1305 if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {
1306 data += KEYWORD_DELETE_LEN;
1307 is_delete = true;
1308 }
1309 if (strncmp(data, KEYWORD_ALLOW_MOUNT, KEYWORD_ALLOW_MOUNT_LEN) == 0)
1310 return AddMountPolicy(data + KEYWORD_ALLOW_MOUNT_LEN, is_delete);
1311 if (strncmp(data, KEYWORD_DENY_UNMOUNT, KEYWORD_DENY_UNMOUNT_LEN) == 0)
1312 return AddNoUmountPolicy(data + KEYWORD_DENY_UNMOUNT_LEN, is_delete);
1313 if (strncmp(data, KEYWORD_ALLOW_CHROOT, KEYWORD_ALLOW_CHROOT_LEN) == 0)
1314 return AddChrootPolicy(data + KEYWORD_ALLOW_CHROOT_LEN, is_delete);
1315 if (strncmp(data, KEYWORD_ALLOW_PIVOT_ROOT, KEYWORD_ALLOW_PIVOT_ROOT_LEN) == 0)
1316 return AddPivotRootPolicy(data + KEYWORD_ALLOW_PIVOT_ROOT_LEN, is_delete);
1317 if (strncmp(data, KEYWORD_DENY_AUTOBIND, KEYWORD_DENY_AUTOBIND_LEN) == 0)
1318 return AddReservedPortPolicy(data + KEYWORD_DENY_AUTOBIND_LEN, is_delete);
1319 return -EINVAL;
1320 }
1321
1322 static int ReadSystemPolicy(struct io_buffer *head)
1323 {
1324 if (!head->read_eof) {
1325 switch (head->read_step) {
1326 case 0:
1327 head->read_var2 = NULL; head->read_step = 1;
1328 case 1:
1329 if (ReadMountPolicy(head)) break;
1330 head->read_var2 = NULL; head->read_step = 2;
1331 case 2:
1332 if (ReadNoUmountPolicy(head)) break;
1333 head->read_var2 = NULL; head->read_step = 3;
1334 case 3:
1335 if (ReadChrootPolicy(head)) break;
1336 head->read_var2 = NULL; head->read_step = 4;
1337 case 4:
1338 if (ReadPivotRootPolicy(head)) break;
1339 head->read_var2 = NULL; head->read_step = 5;
1340 case 5:
1341 if (ReadReservedPortPolicy(head)) break;
1342 head->read_eof = true;
1343 break;
1344 default:
1345 return -EINVAL;
1346 }
1347 }
1348 return 0;
1349 }
1350
1351 #endif
1352
1353 /************************* POLICY LOADER *************************/
1354
1355 static bool profile_loaded = false;
1356
1357 static const char *ccs_loader = NULL;
1358
1359 static int __init CCS_loader_Setup(char *str)
1360 {
1361 ccs_loader = str;
1362 return 0;
1363 }
1364
1365 __setup("CCS_loader=", CCS_loader_Setup);
1366
1367 void CCS_LoadPolicy(const char *filename)
1368 {
1369 if (sbin_init_started) return;
1370 /*
1371 * Check filename is /sbin/init or /sbin/ccs-start .
1372 * /sbin/ccs-start is a dummy filename in case where /sbin/init can't be passed.
1373 * You can create /sbin/ccs-start by "ln -s /bin/true /sbin/ccs-start", for
1374 * only the pathname is needed to activate Mandatory Access Control.
1375 */
1376 if (strcmp(filename, "/sbin/init") != 0 && strcmp(filename, "/sbin/ccs-start") != 0) return;
1377 /*
1378 * Don't activate MAC if the path given by 'CCS_loader=' option doesn't exist.
1379 * If initrd.img includes /sbin/init but real-root-dev has not mounted on / yet,
1380 * activating MAC will block the system since policies are not loaded yet.
1381 * So let do_execve() call this function everytime.
1382 */
1383 {
1384 struct nameidata nd;
1385 if (!ccs_loader) ccs_loader = "/sbin/ccs-init";
1386 if (path_lookup(ccs_loader, lookup_flags, &nd)) {
1387 printk("Not activating Mandatory Access Control now since %s doesn't exist.\n", ccs_loader);
1388 return;
1389 }
1390 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
1391 path_put(&nd.path);
1392 #else
1393 path_release(&nd);
1394 #endif
1395 }
1396 if (!profile_loaded) {
1397 char *argv[2], *envp[3];
1398 printk("Calling %s to load policy. Please wait.\n", ccs_loader);
1399 argv[0] = (char *) ccs_loader;
1400 argv[1] = NULL;
1401 envp[0] = "HOME=/";
1402 envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
1403 envp[2] = NULL;
1404 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1405 call_usermodehelper(argv[0], argv, envp, 1);
1406 #else
1407 call_usermodehelper(argv[0], argv, envp);
1408 #endif
1409 while (!profile_loaded) {
1410 set_current_state(TASK_INTERRUPTIBLE);
1411 schedule_timeout(HZ / 10);
1412 }
1413 }
1414 #ifdef CONFIG_SAKURA
1415 printk("SAKURA: 1.6.0-pre 2008/03/10\n");
1416 #endif
1417 #ifdef CONFIG_TOMOYO
1418 printk("TOMOYO: 1.6.0-pre 2008/03/10\n");
1419 #endif
1420 printk("Mandatory Access Control activated.\n");
1421 sbin_init_started = true;
1422 ccs_log_level = KERN_WARNING;
1423 { /* Check all profiles currently assigned to domains are defined. */
1424 struct domain_info *domain;
1425 list1_for_each_entry(domain, &domain_list, list) {
1426 const u8 profile = domain->profile;
1427 if (!profile_ptr[profile]) panic("Profile %u (used by '%s') not defined.\n", profile, domain->domainname->name);
1428 }
1429 }
1430 }
1431
1432 /************************* MAC Decision Delayer *************************/
1433
1434 static DECLARE_WAIT_QUEUE_HEAD(query_wait);
1435
1436 static spinlock_t query_lock = SPIN_LOCK_UNLOCKED;
1437
1438 struct query_entry {
1439 struct list_head list;
1440 char *query;
1441 int query_len;
1442 unsigned int serial;
1443 int timer;
1444 int answer;
1445 };
1446
1447 static LIST_HEAD(query_list);
1448 static atomic_t queryd_watcher = ATOMIC_INIT(0);
1449
1450 int CheckSupervisor(const char *fmt, ...)
1451 {
1452 va_list args;
1453 int error = -EPERM;
1454 int pos, len;
1455 static unsigned int serial = 0;
1456 struct query_entry *query_entry;
1457 if (!CheckCCSFlags(CCS_ALLOW_ENFORCE_GRACE) || !atomic_read(&queryd_watcher)) {
1458 if ((current->tomoyo_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR) == 0) {
1459 int i;
1460 for (i = 0; i < CheckCCSFlags(CCS_SLEEP_PERIOD); i++) {
1461 set_current_state(TASK_INTERRUPTIBLE);
1462 schedule_timeout(HZ / 10);
1463 }
1464 }
1465 return -EPERM;
1466 }
1467 va_start(args, fmt);
1468 len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;
1469 va_end(args);
1470 if ((query_entry = ccs_alloc(sizeof(*query_entry))) == NULL ||
1471 (query_entry->query = ccs_alloc(len)) == NULL) goto out;
1472 INIT_LIST_HEAD(&query_entry->list);
1473 /***** CRITICAL SECTION START *****/
1474 spin_lock(&query_lock);
1475 query_entry->serial = serial++;
1476 spin_unlock(&query_lock);
1477 /***** CRITICAL SECTION END *****/
1478 pos = snprintf(query_entry->query, len - 1, "Q%u\n", query_entry->serial);
1479 va_start(args, fmt);
1480 vsnprintf(query_entry->query + pos, len - 1 - pos, fmt, args);
1481 query_entry->query_len = strlen(query_entry->query) + 1;
1482 va_end(args);
1483 /***** CRITICAL SECTION START *****/
1484 spin_lock(&query_lock);
1485 list_add_tail(&query_entry->list, &query_list);
1486 spin_unlock(&query_lock);
1487 /***** CRITICAL SECTION END *****/
1488 UpdateCounter(CCS_UPDATES_COUNTER_QUERY);
1489 /* Give 10 seconds for supervisor's opinion. */
1490 for (query_entry->timer = 0; atomic_read(&queryd_watcher) && CheckCCSFlags(CCS_ALLOW_ENFORCE_GRACE) && query_entry->timer < 100; query_entry->timer++) {
1491 wake_up(&query_wait);
1492 set_current_state(TASK_INTERRUPTIBLE);
1493 schedule_timeout(HZ / 10);
1494 if (query_entry->answer) break;
1495 }
1496 UpdateCounter(CCS_UPDATES_COUNTER_QUERY);
1497 /***** CRITICAL SECTION START *****/
1498 spin_lock(&query_lock);
1499 list_del(&query_entry->list);
1500 spin_unlock(&query_lock);
1501 /***** CRITICAL SECTION END *****/
1502 switch (query_entry->answer) {
1503 case 1:
1504 /* Granted by administrator. */
1505 error = 0;
1506 break;
1507 case 0:
1508 /* Timed out. */
1509 break;
1510 default:
1511 /* Rejected by administrator. */
1512 break;
1513 }
1514 out: ;
1515 if (query_entry) ccs_free(query_entry->query);
1516 ccs_free(query_entry);
1517 return error;
1518 }
1519
1520 static int PollQuery(struct file *file, poll_table *wait)
1521 {
1522 bool found;
1523 /***** CRITICAL SECTION START *****/
1524 spin_lock(&query_lock);
1525 found = !list_empty(&query_list);
1526 spin_unlock(&query_lock);
1527 /***** CRITICAL SECTION END *****/
1528 if (found) return POLLIN | POLLRDNORM;
1529 poll_wait(file, &query_wait, wait);
1530 /***** CRITICAL SECTION START *****/
1531 spin_lock(&query_lock);
1532 found = !list_empty(&query_list);
1533 spin_unlock(&query_lock);
1534 /***** CRITICAL SECTION END *****/
1535 if (found) return POLLIN | POLLRDNORM;
1536 return 0;
1537 }
1538
1539 static int ReadQuery(struct io_buffer *head)
1540 {
1541 struct list_head *tmp;
1542 int pos = 0, len = 0;
1543 char *buf;
1544 if (head->read_avail) return 0;
1545 if (head->read_buf) {
1546 ccs_free(head->read_buf); head->read_buf = NULL;
1547 head->readbuf_size = 0;
1548 }
1549 /***** CRITICAL SECTION START *****/
1550 spin_lock(&query_lock);
1551 list_for_each(tmp, &query_list) {
1552 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);
1553 if (pos++ == head->read_step) {
1554 len = ptr->query_len;
1555 break;
1556 }
1557 }
1558 spin_unlock(&query_lock);
1559 /***** CRITICAL SECTION END *****/
1560 if (!len) {
1561 head->read_step = 0;
1562 return 0;
1563 }
1564 if ((buf = ccs_alloc(len)) != NULL) {
1565 pos = 0;
1566 /***** CRITICAL SECTION START *****/
1567 spin_lock(&query_lock);
1568 list_for_each(tmp, &query_list) {
1569 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);
1570 if (pos++ == head->read_step) {
1571 /* Some query can be skiipped since query_list can change, but I don't care. */
1572 if (len == ptr->query_len) memmove(buf, ptr->query, len);
1573 break;
1574 }
1575 }
1576 spin_unlock(&query_lock);
1577 /***** CRITICAL SECTION END *****/
1578 if (buf[0]) {
1579 head->readbuf_size = head->read_avail = len;
1580 head->read_buf = buf;
1581 head->read_step++;
1582 } else {
1583 ccs_free(buf);
1584 }
1585 }
1586 return 0;
1587 }
1588
1589 static int WriteAnswer(struct io_buffer *head)
1590 {
1591 char *data = head->write_buf;
1592 struct list_head *tmp;
1593 unsigned int serial, answer;
1594 /***** CRITICAL SECTION START *****/
1595 spin_lock(&query_lock);
1596 list_for_each(tmp, &query_list) {
1597 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);
1598 ptr->timer = 0;
1599 }
1600 spin_unlock(&query_lock);
1601 /***** CRITICAL SECTION END *****/
1602 if (sscanf(data, "A%u=%u", &serial, &answer) != 2) return -EINVAL;
1603 /***** CRITICAL SECTION START *****/
1604 spin_lock(&query_lock);
1605 list_for_each(tmp, &query_list) {
1606 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);
1607 if (ptr->serial != serial) continue;
1608 if (!ptr->answer) ptr->answer = answer;
1609 break;
1610 }
1611 spin_unlock(&query_lock);
1612 /***** CRITICAL SECTION END *****/
1613 return 0;
1614 }
1615
1616 /************************* /proc INTERFACE HANDLER *************************/
1617
1618 /* Policy updates counter. */
1619 static unsigned int updates_counter[MAX_CCS_UPDATES_COUNTER];
1620 static spinlock_t updates_counter_lock = SPIN_LOCK_UNLOCKED;
1621
1622 void UpdateCounter(const unsigned char index)
1623 {
1624 /***** CRITICAL SECTION START *****/
1625 spin_lock(&updates_counter_lock);
1626 if (index < MAX_CCS_UPDATES_COUNTER) updates_counter[index]++;
1627 spin_unlock(&updates_counter_lock);
1628 /***** CRITICAL SECTION END *****/
1629 }
1630
1631 static int ReadUpdatesCounter(struct io_buffer *head)
1632 {
1633 if (!head->read_eof) {
1634 unsigned int counter[MAX_CCS_UPDATES_COUNTER];
1635 /***** CRITICAL SECTION START *****/
1636 spin_lock(&updates_counter_lock);
1637 memmove(counter, updates_counter, sizeof(updates_counter));
1638 memset(updates_counter, 0, sizeof(updates_counter));
1639 spin_unlock(&updates_counter_lock);
1640 /***** CRITICAL SECTION END *****/
1641 io_printf(head,
1642 "/proc/ccs/system_policy: %10u\n"
1643 "/proc/ccs/domain_policy: %10u\n"
1644 "/proc/ccs/exception_policy: %10u\n"
1645 "/proc/ccs/profile: %10u\n"
1646 "/proc/ccs/query: %10u\n"
1647 "/proc/ccs/manager: %10u\n"
1648 "/proc/ccs/grant_log: %10u\n"
1649 "/proc/ccs/reject_log: %10u\n",
1650 counter[CCS_UPDATES_COUNTER_SYSTEM_POLICY],
1651 counter[CCS_UPDATES_COUNTER_DOMAIN_POLICY],
1652 counter[CCS_UPDATES_COUNTER_EXCEPTION_POLICY],
1653 counter[CCS_UPDATES_COUNTER_PROFILE],
1654 counter[CCS_UPDATES_COUNTER_QUERY],
1655 counter[CCS_UPDATES_COUNTER_MANAGER],
1656 counter[CCS_UPDATES_COUNTER_GRANT_LOG],
1657 counter[CCS_UPDATES_COUNTER_REJECT_LOG]);
1658 head->read_eof = true;
1659 }
1660 return 0;
1661 }
1662
1663 static int ReadVersion(struct io_buffer *head)
1664 {
1665 if (!head->read_eof) {
1666 if (io_printf(head, "1.6.0-pre") == 0) head->read_eof = true;
1667 }
1668 return 0;
1669 }
1670
1671 static int ReadMemoryCounter(struct io_buffer *head)
1672 {
1673 if (!head->read_eof) {
1674 const int shared = GetMemoryUsedForSaveName(), private = GetMemoryUsedForElements(), dynamic = GetMemoryUsedForDynamic();
1675 if (io_printf(head, "Shared: %10u\nPrivate: %10u\nDynamic: %10u\nTotal: %10u\n", shared, private, dynamic, shared + private + dynamic) == 0) head->read_eof = true;
1676 }
1677 return 0;
1678 }
1679
1680 static int ReadSelfDomain(struct io_buffer *head)
1681 {
1682 if (!head->read_eof) {
1683 io_printf(head, "%s", current->domain_info->domainname->name);
1684 head->read_eof = true;
1685 }
1686 return 0;
1687 }
1688
1689 int CCS_OpenControl(const u8 type, struct file *file)
1690 {
1691 struct io_buffer *head = ccs_alloc(sizeof(*head));
1692 if (!head) return -ENOMEM;
1693 mutex_init(&head->read_sem);
1694 mutex_init(&head->write_sem);
1695 switch (type) {
1696 #ifdef CONFIG_SAKURA
1697 case CCS_SYSTEMPOLICY:
1698 head->write = AddSystemPolicy;
1699 head->read = ReadSystemPolicy;
1700 break;
1701 #endif
1702 #ifdef CONFIG_TOMOYO
1703 case CCS_DOMAINPOLICY:
1704 head->write = AddDomainPolicy;
1705 head->read = ReadDomainPolicy;
1706 break;
1707 case CCS_EXCEPTIONPOLICY:
1708 head->write = AddExceptionPolicy;
1709 head->read = ReadExceptionPolicy;
1710 break;
1711 case CCS_GRANTLOG:
1712 head->poll = PollGrantLog;
1713 head->read = ReadGrantLog;
1714 break;
1715 case CCS_REJECTLOG:
1716 head->poll = PollRejectLog;
1717 head->read = ReadRejectLog;
1718 break;
1719 #endif
1720 case CCS_SELFDOMAIN:
1721 head->read = ReadSelfDomain;
1722 break;
1723 case CCS_DOMAIN_STATUS:
1724 head->write = UpdateDomainProfile;
1725 head->read = ReadDomainProfile;
1726 break;
1727 case CCS_PROCESS_STATUS:
1728 head->write = WritePID;
1729 head->read = ReadPID;
1730 break;
1731 case CCS_VERSION:
1732 head->read = ReadVersion;
1733 head->readbuf_size = 128;
1734 break;
1735 case CCS_MEMINFO:
1736 head->read = ReadMemoryCounter;
1737 head->readbuf_size = 128;
1738 break;
1739 case CCS_PROFILE:
1740 head->write = SetProfile;
1741 head->read = ReadProfile;
1742 break;
1743 case CCS_QUERY:
1744 head->poll = PollQuery;
1745 head->write = WriteAnswer;
1746 head->read = ReadQuery;
1747 break;
1748 case CCS_MANAGER:
1749 head->write = AddManagerPolicy;
1750 head->read = ReadManagerPolicy;
1751 break;
1752 case CCS_UPDATESCOUNTER:
1753 head->read = ReadUpdatesCounter;
1754 break;
1755 }
1756 if (type != CCS_GRANTLOG && type != CCS_REJECTLOG && type != CCS_QUERY) {
1757 if (!head->readbuf_size) head->readbuf_size = PAGE_SIZE * 2;
1758 if ((head->read_buf = ccs_alloc(head->readbuf_size)) == NULL) {
1759 ccs_free(head);
1760 return -ENOMEM;
1761 }
1762 }
1763 if (head->write) {
1764 head->writebuf_size = PAGE_SIZE * 2;
1765 if ((head->write_buf = ccs_alloc(head->writebuf_size)) == NULL) {
1766 ccs_free(head->read_buf);
1767 ccs_free(head);
1768 return -ENOMEM;
1769 }
1770 }
1771 file->private_data = head;
1772 if (type == CCS_SELFDOMAIN) CCS_ReadControl(file, NULL, 0);
1773 else if (head->write == WriteAnswer) atomic_inc(&queryd_watcher);
1774 return 0;
1775 }
1776
1777 static int CopyToUser(struct io_buffer *head, char __user * buffer, int buffer_len)
1778 {
1779 int len = head->read_avail;
1780 char *cp = head->read_buf;
1781 if (len > buffer_len) len = buffer_len;
1782 if (len) {
1783 if (copy_to_user(buffer, cp, len)) return -EFAULT;
1784 head->read_avail -= len;
1785 memmove(cp, cp + len, head->read_avail);
1786 }
1787 return len;
1788 }
1789
1790 int CCS_PollControl(struct file *file, poll_table *wait)
1791 {
1792 struct io_buffer *head = file->private_data;
1793 if (!head->poll) return -ENOSYS;
1794 return head->poll(file, wait);
1795 }
1796
1797 int CCS_ReadControl(struct file *file, char __user *buffer, const int buffer_len)
1798 {
1799 int len = 0;
1800 struct io_buffer *head = file->private_data;
1801 if (!head->read) return -ENOSYS;
1802 if (!access_ok(VERIFY_WRITE, buffer, buffer_len)) return -EFAULT;
1803 if (mutex_lock_interruptible(&head->read_sem)) return -EINTR;
1804 len = head->read(head);
1805 if (len >= 0) len = CopyToUser(head, buffer, buffer_len);
1806 mutex_unlock(&head->read_sem);
1807 return len;
1808 }
1809
1810 int CCS_WriteControl(struct file *file, const char __user *buffer, const int buffer_len)
1811 {
1812 struct io_buffer *head = file->private_data;
1813 int error = buffer_len;
1814 int avail_len = buffer_len;
1815 char *cp0 = head->write_buf;
1816 if (!head->write) return -ENOSYS;
1817 if (!access_ok(VERIFY_READ, buffer, buffer_len)) return -EFAULT;
1818 if (head->write != WritePID && !IsPolicyManager()) {
1819 return -EPERM; /* Forbid updating policies for non manager programs. */
1820 }
1821 if (mutex_lock_interruptible(&head->write_sem)) return -EINTR;
1822 while (avail_len > 0) {
1823 char c;
1824 if (head->write_avail >= head->writebuf_size - 1) {
1825 error = -ENOMEM;
1826 break;
1827 } else if (get_user(c, buffer)) {
1828 error = -EFAULT;
1829 break;
1830 }
1831 buffer++; avail_len--;
1832 cp0[head->write_avail++] = c;
1833 if (c != '\n') continue;
1834 cp0[head->write_avail - 1] = '\0';
1835 head->write_avail = 0;
1836 NormalizeLine(cp0);
1837 head->write(head);
1838 }
1839 mutex_unlock(&head->write_sem);
1840 return error;
1841 }
1842
1843
1844 int CCS_CloseControl(struct file *file)
1845 {
1846 struct io_buffer *head = file->private_data;
1847 if (head->write == WriteAnswer) atomic_dec(&queryd_watcher);
1848 else if (head->read == ReadMemoryCounter) profile_loaded = true;
1849 ccs_free(head->read_buf); head->read_buf = NULL;
1850 ccs_free(head->write_buf); head->write_buf = NULL;
1851 ccs_free(head); head = NULL;
1852 file->private_data = NULL;
1853 return 0;
1854 }
1855
1856 void *alloc_acl_element(const u8 acl_type, const struct condition_list *condition)
1857 {
1858 int len;
1859 struct acl_info *ptr;
1860 switch (acl_type) {
1861 case TYPE_SINGLE_PATH_ACL:
1862 len = sizeof(struct single_path_acl_record);
1863 break;
1864 case TYPE_DOUBLE_PATH_ACL:
1865 len = sizeof(struct double_path_acl_record);
1866 break;
1867 case TYPE_ARGV0_ACL:
1868 len = sizeof(struct argv0_acl_record);
1869 break;
1870 case TYPE_ENV_ACL:
1871 len = sizeof(struct env_acl_record);
1872 break;
1873 case TYPE_CAPABILITY_ACL:
1874 len = sizeof(struct capability_acl_record);
1875 break;
1876 case TYPE_IP_NETWORK_ACL:
1877 len = sizeof(struct ip_network_acl_record);
1878 break;
1879 case TYPE_SIGNAL_ACL:
1880 len = sizeof(struct signal_acl_record);
1881 break;
1882 case TYPE_PREFERRED_EXECUTE_HANDLER:
1883 case TYPE_DEFAULT_EXECUTE_HANDLER:
1884 len = sizeof(struct execute_handler_record);
1885 break;
1886 default:
1887 return NULL;
1888 }
1889 if (!condition) len -= sizeof(ptr->cond);
1890 ptr = alloc_element(len);
1891 if (!ptr) return NULL;
1892 if (condition) {
1893 ptr->cond = condition;
1894 ptr->type = acl_type | ACL_WITH_CONDITION;
1895 return ptr;
1896 }
1897 ptr = (void *) (((u8 *) ptr) - sizeof(ptr->cond));
1898 ptr->type = acl_type;
1899 return ptr;
1900 }
1901
1902 const struct condition_list *GetConditionPart(const struct acl_info *acl)
1903 {
1904 return (acl->type & ACL_WITH_CONDITION) ? acl->cond : NULL;
1905 }

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