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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 502 - (show annotations) (download) (as text)
Tue Sep 25 13:33:45 2007 UTC (16 years, 8 months ago) by kumaneko
Original Path: trunk/1.5.x/ccs-patch/fs/ccs_common.c
File MIME type: text/x-csrc
File size: 50412 byte(s)


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

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