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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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