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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 214 - (show annotations) (download) (as text)
Wed May 16 10:04:31 2007 UTC (17 years ago) by kumaneko
Original Path: trunk/ccs-patch/fs/ccs_common.c
File MIME type: text/x-csrc
File size: 51101 byte(s)
typedef removal
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 2007/04/01
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
485 unsigned int TomoyoVerboseMode(void)
486 {
487 return CheckCCSFlags(CCS_TOMOYO_VERBOSE);
488 }
489
490 /* Check whether the given access control is enforce mode. */
491 unsigned int CheckCCSEnforce(const unsigned int index)
492 {
493 return CheckCCSFlags(index) == 3;
494 }
495
496 /* Check whether the given access control is accept mode. */
497 unsigned int CheckCCSAccept(const unsigned int index)
498 {
499 return CheckCCSFlags(index) == 1;
500 }
501
502 static struct profile *FindOrAssignNewProfile(const unsigned int profile)
503 {
504 static DECLARE_MUTEX(profile_lock);
505 struct profile *ptr = NULL;
506 down(&profile_lock);
507 if (profile < MAX_PROFILES && (ptr = profile_ptr[profile]) == NULL) {
508 if ((ptr = alloc_element(sizeof(*ptr))) != NULL) {
509 int i;
510 for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) ptr->value[i] = ccs_control_array[i].current_value;
511 mb(); /* Instead of using spinlock. */
512 profile_ptr[profile] = ptr;
513 }
514 }
515 up(&profile_lock);
516 return ptr;
517 }
518
519 static int profile_loaded = 0;
520
521 static int SetStatus(struct io_buffer *head)
522 {
523 char *data = head->write_buf;
524 unsigned int i, value;
525 char *cp;
526 struct profile *profile;
527 if (!isRoot()) return -EPERM;
528 i = simple_strtoul(data, &cp, 10);
529 if (data != cp) {
530 if (*cp != '-') return -EINVAL;
531 data= cp + 1;
532 }
533 profile = FindOrAssignNewProfile(i);
534 if (!profile) return -EINVAL;
535 cp = strchr(data, '=');
536 if (!cp) return -EINVAL;
537 *cp = '\0';
538 profile_loaded = 1;
539 UpdateCounter(CCS_UPDATES_COUNTER_STATUS);
540 if (strcmp(data, ccs_control_array[CCS_PROFILE_COMMENT].keyword) == 0) {
541 profile->comment = SaveName(cp + 1);
542 return 0;
543 }
544 if (sscanf(cp + 1, "%u", &value) != 1) return -EINVAL;
545 #ifdef CONFIG_TOMOYO_MAC_FOR_CAPABILITY
546 if (strncmp(data, KEYWORD_MAC_FOR_CAPABILITY, KEYWORD_MAC_FOR_CAPABILITY_LEN) == 0) {
547 return SetCapabilityStatus(data + KEYWORD_MAC_FOR_CAPABILITY_LEN, value, i);
548 }
549 #endif
550 for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) {
551 if (strcmp(data, ccs_control_array[i].keyword)) continue;
552 if (value > ccs_control_array[i].max_value) value = ccs_control_array[i].max_value;
553 profile->value[i] = value;
554 return 0;
555 }
556 return -EINVAL;
557 }
558
559 static int ReadStatus(struct io_buffer *head)
560 {
561 if (!head->read_eof) {
562 if (!isRoot()) return -EPERM;
563 if (!head->read_var2) {
564 int step;
565 for (step = head->read_step; step < MAX_PROFILES * CCS_MAX_CONTROL_INDEX; step++) {
566 const int i = step / CCS_MAX_CONTROL_INDEX, j = step % CCS_MAX_CONTROL_INDEX;
567 const struct profile *profile = profile_ptr[i];
568 head->read_step = step;
569 if (!profile) continue;
570 switch (j) {
571 case -1: // Dummy
572 #ifndef CONFIG_TOMOYO_MAC_FOR_FILE
573 case CCS_TOMOYO_MAC_FOR_FILE:
574 #endif
575 #ifndef CONFIG_TOMOYO_MAC_FOR_ARGV0
576 case CCS_TOMOYO_MAC_FOR_ARGV0:
577 #endif
578 #ifndef CONFIG_TOMOYO_MAC_FOR_NETWORK
579 case CCS_TOMOYO_MAC_FOR_NETWORK:
580 #endif
581 #ifndef CONFIG_TOMOYO_MAC_FOR_SIGNAL
582 case CCS_TOMOYO_MAC_FOR_SIGNAL:
583 #endif
584 #ifndef CONFIG_SAKURA_DENY_CONCEAL_MOUNT
585 case CCS_SAKURA_DENY_CONCEAL_MOUNT:
586 #endif
587 #ifndef CONFIG_SAKURA_RESTRICT_CHROOT
588 case CCS_SAKURA_RESTRICT_CHROOT:
589 #endif
590 #ifndef CONFIG_SAKURA_RESTRICT_MOUNT
591 case CCS_SAKURA_RESTRICT_MOUNT:
592 #endif
593 #ifndef CONFIG_SAKURA_RESTRICT_UNMOUNT
594 case CCS_SAKURA_RESTRICT_UNMOUNT:
595 #endif
596 #ifndef CONFIG_SAKURA_RESTRICT_PIVOT_ROOT
597 case CCS_SAKURA_RESTRICT_PIVOT_ROOT:
598 #endif
599 #ifndef CONFIG_SAKURA_RESTRICT_AUTOBIND
600 case CCS_SAKURA_RESTRICT_AUTOBIND:
601 #endif
602 #ifndef CONFIG_TOMOYO
603 case CCS_TOMOYO_MAX_ACCEPT_ENTRY:
604 case CCS_TOMOYO_MAX_GRANT_LOG:
605 case CCS_TOMOYO_MAX_REJECT_LOG:
606 case CCS_TOMOYO_VERBOSE:
607 #endif
608 continue;
609 }
610 if (j == CCS_PROFILE_COMMENT) {
611 if (io_printf(head, "%u-%s=%s\n", i, ccs_control_array[CCS_PROFILE_COMMENT].keyword, profile->comment ? profile->comment->name : "")) break;
612 } else {
613 if (io_printf(head, "%u-%s=%u\n", i, ccs_control_array[j].keyword, profile->value[j])) break;
614 }
615 }
616 if (step == MAX_PROFILES * CCS_MAX_CONTROL_INDEX) {
617 head->read_var2 = "";
618 head->read_step = 0;
619 }
620 }
621 if (head->read_var2) {
622 #ifdef CONFIG_TOMOYO_MAC_FOR_CAPABILITY
623 if (ReadCapabilityStatus(head) == 0) head->read_eof = 1;
624 #else
625 head->read_eof = 1;
626 #endif
627 }
628 }
629 return 0;
630 }
631
632 /************************* POLICY MANAGER HANDLER *************************/
633
634 struct policy_manager_entry {
635 struct policy_manager_entry *next;
636 const struct path_info *manager;
637 u8 is_domain;
638 u8 is_deleted;
639 };
640
641 static struct policy_manager_entry *policy_manager_list = NULL;
642
643 static int AddManagerEntry(const char *manager, u8 is_delete)
644 {
645 struct policy_manager_entry *new_entry, *ptr;
646 static DECLARE_MUTEX(lock);
647 const struct path_info *saved_manager;
648 int error = -ENOMEM;
649 u8 is_domain = 0;
650 if (!isRoot()) return -EPERM;
651 if (IsDomainDef(manager)) {
652 if (!IsCorrectDomain(manager, __FUNCTION__)) return -EINVAL;
653 is_domain = 1;
654 } else {
655 if (!IsCorrectPath(manager, 1, -1, -1, __FUNCTION__)) return -EINVAL;
656 }
657 if ((saved_manager = SaveName(manager)) == NULL) return -ENOMEM;
658 down(&lock);
659 for (ptr = policy_manager_list; ptr; ptr = ptr->next) {
660 if (ptr->manager == saved_manager) {
661 ptr->is_deleted = is_delete;
662 error = 0;
663 goto out;
664 }
665 }
666 if (is_delete) {
667 error = -ENOENT;
668 goto out;
669 }
670 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
671 new_entry->manager = saved_manager;
672 new_entry->is_domain = is_domain;
673 mb(); /* Instead of using spinlock. */
674 if ((ptr = policy_manager_list) != NULL) {
675 while (ptr->next) ptr = ptr->next; ptr->next = new_entry;
676 } else {
677 policy_manager_list = new_entry;
678 }
679 error = 0;
680 out:
681 up(&lock);
682 if (!error) UpdateCounter(CCS_UPDATES_COUNTER_MANAGER);
683 return error;
684 }
685
686 static int AddManagerPolicy(struct io_buffer *head)
687 {
688 const char *data = head->write_buf;
689 int is_delete = 0;
690 if (!isRoot()) return -EPERM;
691 if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {
692 data += KEYWORD_DELETE_LEN;
693 is_delete = 1;
694 }
695 return AddManagerEntry(data, is_delete);
696 }
697
698 static int ReadManagerPolicy(struct io_buffer *head)
699 {
700 if (!head->read_eof) {
701 struct policy_manager_entry *ptr = head->read_var2;
702 if (!isRoot()) return -EPERM;
703 if (!ptr) ptr = policy_manager_list;
704 while (ptr) {
705 head->read_var2 = ptr;
706 if (!ptr->is_deleted && io_printf(head, "%s\n", ptr->manager->name)) break;
707 ptr = ptr->next;
708 }
709 if (!ptr) head->read_eof = 1;
710 }
711 return 0;
712 }
713
714 /* Check whether the current process is a policy manager. */
715 static int IsPolicyManager(void)
716 {
717 struct policy_manager_entry *ptr;
718 const char *exe;
719 const struct path_info *domainname = current->domain_info->domainname;
720 if (!sbin_init_started) return 1;
721 for (ptr = policy_manager_list; ptr; ptr = ptr->next) {
722 if (!ptr->is_deleted && ptr->is_domain && !pathcmp(domainname, ptr->manager)) return 1;
723 }
724 if ((exe = GetEXE()) == NULL) return 0;
725 for (ptr = policy_manager_list; ptr; ptr = ptr->next) {
726 if (!ptr->is_deleted && !ptr->is_domain && !strcmp(exe, ptr->manager->name)) break;
727 }
728 if (!ptr) { /* Reduce error messages. */
729 static pid_t last_pid = 0;
730 const pid_t pid = current->pid;
731 if (last_pid != pid) {
732 printk("%s is not permitted to update policies.\n", exe);
733 last_pid = pid;
734 }
735 }
736 ccs_free(exe);
737 return ptr ? 1 : 0;
738 }
739
740 #ifdef CONFIG_TOMOYO
741
742 /************************* DOMAIN POLICY HANDLER *************************/
743
744 static int AddDomainPolicy(struct io_buffer *head)
745 {
746 char *data = head->write_buf;
747 struct domain_info *domain = head->write_var1;
748 int is_delete = 0, is_select = 0, is_undelete = 0;
749 unsigned int profile;
750 if (!isRoot()) return -EPERM;
751 if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {
752 data += KEYWORD_DELETE_LEN;
753 is_delete = 1;
754 } else if (strncmp(data, KEYWORD_SELECT, KEYWORD_SELECT_LEN) == 0) {
755 data += KEYWORD_SELECT_LEN;
756 is_select = 1;
757 } else if (strncmp(data, KEYWORD_UNDELETE, KEYWORD_UNDELETE_LEN) == 0) {
758 data += KEYWORD_UNDELETE_LEN;
759 is_undelete = 1;
760 }
761 UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
762 if (IsDomainDef(data)) {
763 if (is_delete) {
764 DeleteDomain(data);
765 domain = NULL;
766 } else if (is_select) {
767 domain = FindDomain(data);
768 } else if (is_undelete) {
769 domain = UndeleteDomain(data);
770 } else {
771 domain = FindOrAssignNewDomain(data, 0);
772 }
773 head->write_var1 = domain;
774 return 0;
775 }
776 if (!domain) return -EINVAL;
777 if (sscanf(data, KEYWORD_USE_PROFILE "%u", &profile) == 1 && profile < MAX_PROFILES) {
778 if (profile_ptr[profile] || !sbin_init_started) domain->profile = (u8) profile;
779 #ifdef CONFIG_TOMOYO_MAC_FOR_CAPABILITY
780 } else if (strncmp(data, KEYWORD_ALLOW_CAPABILITY, KEYWORD_ALLOW_CAPABILITY_LEN) == 0) {
781 return AddCapabilityPolicy(data + KEYWORD_ALLOW_CAPABILITY_LEN, domain, is_delete);
782 #endif
783 #ifdef CONFIG_TOMOYO_MAC_FOR_NETWORK
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 #endif
787 #ifdef CONFIG_TOMOYO_MAC_FOR_SIGNAL
788 } else if (strncmp(data, KEYWORD_ALLOW_SIGNAL, KEYWORD_ALLOW_SIGNAL_LEN) == 0) {
789 return AddSignalPolicy(data + KEYWORD_ALLOW_SIGNAL_LEN, domain, is_delete);
790 #endif
791 #ifdef CONFIG_TOMOYO_MAC_FOR_ARGV0
792 } else if (strncmp(data, KEYWORD_ALLOW_ARGV0, KEYWORD_ALLOW_ARGV0_LEN) == 0) {
793 return AddArgv0Policy(data + KEYWORD_ALLOW_ARGV0_LEN, domain, is_delete);
794 #endif
795 } else {
796 #ifdef CONFIG_TOMOYO_MAC_FOR_FILE
797 return AddFilePolicy(data, domain, is_delete);
798 #endif
799 }
800 return -EINVAL;
801 }
802
803 static int ReadDomainPolicy(struct io_buffer *head)
804 {
805 if (!head->read_eof) {
806 struct domain_info *domain = head->read_var1;
807 switch (head->read_step) {
808 case 0: break;
809 case 1: goto step1;
810 case 2: goto step2;
811 case 3: goto step3;
812 default: return -EINVAL;
813 }
814 if (!isRoot()) return -EPERM;
815 for (domain = &KERNEL_DOMAIN; domain; domain = domain->next) {
816 struct acl_info *ptr;
817 if (domain->is_deleted) continue;
818 head->read_var1 = domain;
819 head->read_var2 = NULL; head->read_step = 1;
820 step1:
821 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;
822 head->read_var2 = domain->first_acl_ptr; head->read_step = 2;
823 step2:
824 for (ptr = head->read_var2; ptr; ptr = ptr->next) {
825 const u8 acl_type = ptr->type;
826 const int pos = head->read_avail;
827 head->read_var2 = ptr;
828 if (ptr->is_deleted) continue;
829 if (0) {
830 #ifdef CONFIG_TOMOYO_MAC_FOR_FILE
831 } else if (acl_type == TYPE_FILE_ACL) {
832 const unsigned char b = ptr->u.b[1];
833 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)
834 || DumpCondition(head, ptr->cond)) {
835 head->read_avail = pos; break;
836 }
837 #endif
838 #ifdef CONFIG_TOMOYO_MAC_FOR_ARGV0
839 } else if (acl_type == TYPE_ARGV0_ACL) {
840 if (io_printf(head, KEYWORD_ALLOW_ARGV0 "%s %s", ((struct argv0_acl_record *) ptr)->filename->name, ((struct argv0_acl_record *) ptr)->argv0->name) ||
841 DumpCondition(head, ptr->cond)) {
842 head->read_avail = pos; break;
843 }
844 #endif
845 #ifdef CONFIG_TOMOYO_MAC_FOR_CAPABILITY
846 } else if (acl_type == TYPE_CAPABILITY_ACL) {
847 if (io_printf(head, KEYWORD_ALLOW_CAPABILITY "%s", capability2keyword(ptr->u.w)) ||
848 DumpCondition(head, ptr->cond)) {
849 head->read_avail = pos; break;
850 }
851 #endif
852 #ifdef CONFIG_TOMOYO_MAC_FOR_NETWORK
853 } else if (acl_type == TYPE_IP_NETWORK_ACL) {
854 if (io_printf(head, KEYWORD_ALLOW_NETWORK "%s ", network2keyword(ptr->u.b[0]))) break;
855 switch (ptr->u.b[1]) {
856 case IP_RECORD_TYPE_ADDRESS_GROUP:
857 if (io_printf(head, "@%s", ((struct ip_network_acl_record *) ptr)->u.group->group_name->name)) goto print_ip_record_out;
858 break;
859 case IP_RECORD_TYPE_IPv4:
860 {
861 const u32 min_address = ((struct ip_network_acl_record *) ptr)->u.ipv4.min, max_address = ((struct ip_network_acl_record *) ptr)->u.ipv4.max;
862 if (io_printf(head, "%u.%u.%u.%u", HIPQUAD(min_address))) goto print_ip_record_out;
863 if (min_address != max_address && io_printf(head, "-%u.%u.%u.%u", HIPQUAD(max_address))) goto print_ip_record_out;
864 }
865 break;
866 case IP_RECORD_TYPE_IPv6:
867 {
868 char buf[64];
869 const u16 *min_address = ((struct ip_network_acl_record *) ptr)->u.ipv6.min, *max_address = ((struct ip_network_acl_record *) ptr)->u.ipv6.max;
870 print_ipv6(buf, sizeof(buf), min_address);
871 if (io_printf(head, "%s", buf)) goto print_ip_record_out;
872 if (memcmp(min_address, max_address, 16)) {
873 print_ipv6(buf, sizeof(buf), max_address);
874 if (io_printf(head, "-%s", buf)) goto print_ip_record_out;
875 }
876 }
877 break;
878 }
879 {
880 const u16 min_port = ((struct ip_network_acl_record *) ptr)->min_port, max_port = ((struct ip_network_acl_record *) ptr)->max_port;
881 if (io_printf(head, " %u", min_port)) goto print_ip_record_out;
882 if (min_port != max_port && io_printf(head, "-%u", max_port)) goto print_ip_record_out;
883 }
884 if (DumpCondition(head, ptr->cond)) {
885 print_ip_record_out: ;
886 head->read_avail = pos; break;
887 }
888 #endif
889 #ifdef CONFIG_TOMOYO_MAC_FOR_SIGNAL
890 } else if (acl_type == TYPE_SIGNAL_ACL) {
891 if (io_printf(head, KEYWORD_ALLOW_SIGNAL "%u %s", ptr->u.w, ((struct signal_acl_record *) ptr)->domainname->name) ||
892 DumpCondition(head, ptr->cond)) {
893 head->read_avail = pos; break;
894 }
895 #endif
896 #ifdef CONFIG_TOMOYO_MAC_FOR_FILE
897 } else {
898 const char *keyword = acltype2keyword(acl_type);
899 if (keyword) {
900 if (acltype2paths(acl_type) == 2) {
901 const u8 b0 = ptr->u.b[0], b1 = ptr->u.b[1];
902 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)
903 || DumpCondition(head, ptr->cond)) {
904 head->read_avail = pos; break;
905 }
906 } else {
907 const u8 b = ptr->u.b[0];
908 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)
909 || DumpCondition(head, ptr->cond)) {
910 head->read_avail = pos; break;
911 }
912 }
913 }
914 #endif
915 }
916 }
917 if (ptr) break;
918 head->read_var2 = NULL; head->read_step = 3;
919 step3:
920 if (io_printf(head, "\n")) break;
921 }
922 if (!domain) head->read_eof = 1;
923 }
924 return 0;
925 }
926
927 static int ReadDomainProfile(struct io_buffer *head)
928 {
929 if (!head->read_eof) {
930 struct domain_info *domain;
931 if (head->read_step == 0) {
932 head->read_var1 = &KERNEL_DOMAIN;
933 head->read_step = 1;
934 }
935 if (!isRoot()) return -EPERM;
936 for (domain = head->read_var1; domain; domain = domain->next) {
937 if (domain->is_deleted) continue;
938 head->read_var1 = domain;
939 if (io_printf(head, "%u %s\n", domain->profile, domain->domainname->name)) break;
940 }
941 if (!domain) head->read_eof = 1;
942 }
943 return 0;
944 }
945
946 static int WritePID(struct io_buffer *head)
947 {
948 head->read_step = (int) simple_strtoul(head->write_buf, NULL, 10);
949 head->read_eof = 0;
950 return 0;
951 }
952
953 static int ReadPID(struct io_buffer *head)
954 {
955 if (head->read_avail == 0 && !head->read_eof) {
956 const int pid = head->read_step;
957 struct task_struct *p;
958 struct domain_info *domain = NULL;
959 /***** CRITICAL SECTION START *****/
960 read_lock(&tasklist_lock);
961 p = find_task_by_pid(pid);
962 if (p) domain = p->domain_info;
963 read_unlock(&tasklist_lock);
964 /***** CRITICAL SECTION END *****/
965 if (domain) io_printf(head, "%d %u %s", pid, domain->profile, domain->domainname->name);
966 head->read_eof = 1;
967 }
968 return 0;
969 }
970
971 static int UpdateDomainProfile(struct io_buffer *head)
972 {
973 char *data = head->write_buf;
974 char *cp = strchr(data, ' ');
975 struct domain_info *domain;
976 unsigned int profile;
977 if (!isRoot()) return -EPERM;
978 if (!cp) return -EINVAL;
979 *cp = '\0';
980 domain = FindDomain(cp + 1);
981 profile = simple_strtoul(data, NULL, 10);
982 if (domain && profile < MAX_PROFILES && (profile_ptr[profile] || !sbin_init_started)) domain->profile = (u8) profile;
983 UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
984 return 0;
985 }
986
987 #endif
988
989 /************************* EXCEPTION POLICY HANDLER *************************/
990
991 #ifdef CONFIG_TOMOYO
992
993 static int AddExceptionPolicy(struct io_buffer *head)
994 {
995 char *data = head->write_buf;
996 int is_delete = 0;
997 if (!isRoot()) return -EPERM;
998 UpdateCounter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
999 if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {
1000 data += KEYWORD_DELETE_LEN;
1001 is_delete = 1;
1002 }
1003 if (strncmp(data, KEYWORD_KEEP_DOMAIN, KEYWORD_KEEP_DOMAIN_LEN) == 0) {
1004 return AddDomainKeeperPolicy(data + KEYWORD_KEEP_DOMAIN_LEN, 0, is_delete);
1005 } else if (strncmp(data, KEYWORD_NO_KEEP_DOMAIN, KEYWORD_NO_KEEP_DOMAIN_LEN) == 0) {
1006 return AddDomainKeeperPolicy(data + KEYWORD_NO_KEEP_DOMAIN_LEN, 1, is_delete);
1007 } else if (strncmp(data, KEYWORD_INITIALIZE_DOMAIN, KEYWORD_INITIALIZE_DOMAIN_LEN) == 0) {
1008 return AddDomainInitializerPolicy(data + KEYWORD_INITIALIZE_DOMAIN_LEN, 0, is_delete, 0);
1009 } else if (strncmp(data, KEYWORD_NO_INITIALIZE_DOMAIN, KEYWORD_NO_INITIALIZE_DOMAIN_LEN) == 0) {
1010 return AddDomainInitializerPolicy(data + KEYWORD_NO_INITIALIZE_DOMAIN_LEN, 1, is_delete, 0);
1011 } else if (strncmp(data, KEYWORD_INITIALIZER, KEYWORD_INITIALIZER_LEN) == 0) {
1012 return AddDomainInitializerPolicy(data + KEYWORD_INITIALIZER_LEN, 0, is_delete, 1);
1013 } else if (strncmp(data, KEYWORD_NO_INITIALIZER, KEYWORD_NO_INITIALIZER_LEN) == 0) {
1014 return AddDomainInitializerPolicy(data + KEYWORD_NO_INITIALIZER_LEN, 1, is_delete, 1);
1015 } else if (strncmp(data, KEYWORD_ALIAS, KEYWORD_ALIAS_LEN) == 0) {
1016 return AddAliasPolicy(data + KEYWORD_ALIAS_LEN, is_delete);
1017 } else if (strncmp(data, KEYWORD_AGGREGATOR, KEYWORD_AGGREGATOR_LEN) == 0) {
1018 return AddAggregatorPolicy(data + KEYWORD_AGGREGATOR_LEN, is_delete);
1019 #ifdef CONFIG_TOMOYO_MAC_FOR_FILE
1020 } else if (strncmp(data, KEYWORD_ALLOW_READ, KEYWORD_ALLOW_READ_LEN) == 0) {
1021 return AddGloballyReadablePolicy(data + KEYWORD_ALLOW_READ_LEN, is_delete);
1022 } else if (strncmp(data, KEYWORD_FILE_PATTERN, KEYWORD_FILE_PATTERN_LEN) == 0) {
1023 return AddPatternPolicy(data + KEYWORD_FILE_PATTERN_LEN, is_delete);
1024 } else if (strncmp(data, KEYWORD_PATH_GROUP, KEYWORD_PATH_GROUP_LEN) == 0) {
1025 return AddGroupPolicy(data + KEYWORD_PATH_GROUP_LEN, is_delete);
1026 } else if (strncmp(data, KEYWORD_DENY_REWRITE, KEYWORD_DENY_REWRITE_LEN) == 0) {
1027 return AddNoRewritePolicy(data + KEYWORD_DENY_REWRITE_LEN, is_delete);
1028 #endif
1029 #ifdef CONFIG_TOMOYO_MAC_FOR_NETWORK
1030 } else if (strncmp(data, KEYWORD_ADDRESS_GROUP, KEYWORD_ADDRESS_GROUP_LEN) == 0) {
1031 return AddAddressGroupPolicy(data + KEYWORD_ADDRESS_GROUP_LEN, is_delete);
1032 #endif
1033 }
1034 return -EINVAL;
1035 }
1036
1037 static int ReadExceptionPolicy(struct io_buffer *head)
1038 {
1039 if (!head->read_eof) {
1040 switch (head->read_step) {
1041 case 0:
1042 if (!isRoot()) return -EPERM;
1043 head->read_var2 = NULL; head->read_step = 1;
1044 case 1:
1045 if (ReadDomainKeeperPolicy(head)) break;
1046 head->read_var2 = NULL; head->read_step = 2;
1047 case 2:
1048 #ifdef CONFIG_TOMOYO_MAC_FOR_FILE
1049 if (ReadGloballyReadablePolicy(head)) break;
1050 #endif
1051 head->read_var2 = NULL; head->read_step = 3;
1052 case 3:
1053 if (ReadDomainInitializerPolicy(head)) break;
1054 head->read_var2 = NULL; head->read_step = 4;
1055 case 4:
1056 if (ReadAliasPolicy(head)) break;
1057 head->read_var2 = NULL; head->read_step = 5;
1058 case 5:
1059 if (ReadAggregatorPolicy(head)) break;
1060 head->read_var2 = NULL; head->read_step = 6;
1061 case 6:
1062 #ifdef CONFIG_TOMOYO_MAC_FOR_FILE
1063 if (ReadPatternPolicy(head)) break;
1064 #endif
1065 head->read_var2 = NULL; head->read_step = 7;
1066 case 7:
1067 #ifdef CONFIG_TOMOYO_MAC_FOR_FILE
1068 if (ReadNoRewritePolicy(head)) break;
1069 #endif
1070 head->read_var2 = NULL; head->read_step = 8;
1071 case 8:
1072 #ifdef CONFIG_TOMOYO_MAC_FOR_FILE
1073 if (ReadGroupPolicy(head)) break;
1074 #endif
1075 head->read_var2 = NULL; head->read_step = 9;
1076 case 9:
1077 #ifdef CONFIG_TOMOYO_MAC_FOR_NETWORK
1078 if (ReadAddressGroupPolicy(head)) break;
1079 #endif
1080 head->read_eof = 1;
1081 break;
1082 default:
1083 return -EINVAL;
1084 }
1085 }
1086 return 0;
1087 }
1088
1089 #endif
1090
1091 /************************* SYSTEM POLICY HANDLER *************************/
1092
1093 #ifdef CONFIG_SAKURA
1094
1095 static int AddSystemPolicy(struct io_buffer *head)
1096 {
1097 char *data = head->write_buf;
1098 int is_delete = 0;
1099 if (!isRoot()) return -EPERM;
1100 UpdateCounter(CCS_UPDATES_COUNTER_SYSTEM_POLICY);
1101 if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {
1102 data += KEYWORD_DELETE_LEN;
1103 is_delete = 1;
1104 }
1105 #ifdef CONFIG_SAKURA_RESTRICT_MOUNT
1106 if (strncmp(data, KEYWORD_ALLOW_MOUNT, KEYWORD_ALLOW_MOUNT_LEN) == 0)
1107 return AddMountPolicy(data + KEYWORD_ALLOW_MOUNT_LEN, is_delete);
1108 #endif
1109 #ifdef CONFIG_SAKURA_RESTRICT_UNMOUNT
1110 if (strncmp(data, KEYWORD_DENY_UNMOUNT, KEYWORD_DENY_UNMOUNT_LEN) == 0)
1111 return AddNoUmountPolicy(data + KEYWORD_DENY_UNMOUNT_LEN, is_delete);
1112 #endif
1113 #ifdef CONFIG_SAKURA_RESTRICT_CHROOT
1114 if (strncmp(data, KEYWORD_ALLOW_CHROOT, KEYWORD_ALLOW_CHROOT_LEN) == 0)
1115 return AddChrootPolicy(data + KEYWORD_ALLOW_CHROOT_LEN, is_delete);
1116 #endif
1117 #ifdef CONFIG_SAKURA_RESTRICT_PIVOT_ROOT
1118 if (strncmp(data, KEYWORD_ALLOW_PIVOT_ROOT, KEYWORD_ALLOW_PIVOT_ROOT_LEN) == 0)
1119 return AddPivotRootPolicy(data + KEYWORD_ALLOW_PIVOT_ROOT_LEN, is_delete);
1120 #endif
1121 #ifdef CONFIG_SAKURA_RESTRICT_AUTOBIND
1122 if (strncmp(data, KEYWORD_DENY_AUTOBIND, KEYWORD_DENY_AUTOBIND_LEN) == 0)
1123 return AddReservedPortPolicy(data + KEYWORD_DENY_AUTOBIND_LEN, is_delete);
1124 #endif
1125 return -EINVAL;
1126 }
1127
1128 static int ReadSystemPolicy(struct io_buffer *head)
1129 {
1130 if (!head->read_eof) {
1131 switch (head->read_step) {
1132 case 0:
1133 if (!isRoot()) return -EPERM;
1134 head->read_var2 = NULL; head->read_step = 1;
1135 case 1:
1136 #ifdef CONFIG_SAKURA_RESTRICT_MOUNT
1137 if (ReadMountPolicy(head)) break;
1138 #endif
1139 head->read_var2 = NULL; head->read_step = 2;
1140 case 2:
1141 #ifdef CONFIG_SAKURA_RESTRICT_UNMOUNT
1142 if (ReadNoUmountPolicy(head)) break;
1143 #endif
1144 head->read_var2 = NULL; head->read_step = 3;
1145 case 3:
1146 #ifdef CONFIG_SAKURA_RESTRICT_CHROOT
1147 if (ReadChrootPolicy(head)) break;
1148 #endif
1149 head->read_var2 = NULL; head->read_step = 4;
1150 case 4:
1151 #ifdef CONFIG_SAKURA_RESTRICT_PIVOT_ROOT
1152 if (ReadPivotRootPolicy(head)) break;
1153 #endif
1154 head->read_var2 = NULL; head->read_step = 5;
1155 case 5:
1156 #ifdef CONFIG_SAKURA_RESTRICT_AUTOBIND
1157 if (ReadReservedPortPolicy(head)) break;
1158 #endif
1159 head->read_eof = 1;
1160 break;
1161 default:
1162 return -EINVAL;
1163 }
1164 }
1165 return 0;
1166 }
1167
1168 #endif
1169
1170 /************************* POLICY LOADER *************************/
1171
1172 static const char *ccs_loader = NULL;
1173
1174 static int __init CCS_loader_Setup(char *str)
1175 {
1176 ccs_loader = str;
1177 return 0;
1178 }
1179
1180 __setup("CCS_loader=", CCS_loader_Setup);
1181
1182 void CCS_LoadPolicy(const char *filename)
1183 {
1184 if (sbin_init_started) return;
1185 /*
1186 * Check filename is /sbin/init or /sbin/ccs-start .
1187 * /sbin/ccs-start is a dummy filename in case where /sbin/init can't be passed.
1188 * You can create /sbin/ccs-start by "ln -s /bin/true /sbin/ccs-start", for
1189 * only the pathname is needed to activate Mandatory Access Control.
1190 */
1191 if (strcmp(filename, "/sbin/init") != 0 && strcmp(filename, "/sbin/ccs-start") != 0) return;
1192 /*
1193 * Don't activate MAC if the path given by 'CCS_loader=' option doesn't exist.
1194 * If initrd.img includes /sbin/init but real-root-dev has not mounted on / yet,
1195 * activating MAC will block the system since policies are not loaded yet.
1196 * So let do_execve() call this function everytime.
1197 */
1198 {
1199 struct nameidata nd;
1200 if (!ccs_loader) ccs_loader = "/.init";
1201 if (path_lookup(ccs_loader, lookup_flags, &nd)) {
1202 printk("Not activating Mandatory Access Control now since %s doesn't exist.\n", ccs_loader);
1203 return;
1204 }
1205 path_release(&nd);
1206 }
1207
1208 #ifdef CONFIG_SAKURA
1209 printk("SAKURA: 1.4+ 2007/05/16\n");
1210 #endif
1211 #ifdef CONFIG_TOMOYO
1212 printk("TOMOYO: 1.4+ 2007/05/16\n");
1213 #endif
1214 if (!profile_loaded) panic("No profiles loaded. Run policy loader using 'init=' option.\n");
1215 printk("Mandatory Access Control activated.\n");
1216 sbin_init_started = 1;
1217 ccs_log_level = KERN_WARNING;
1218 { /* Check all profiles currently assigned to domains are defined. */
1219 struct domain_info *domain;
1220 for (domain = &KERNEL_DOMAIN; domain; domain = domain->next) {
1221 const u8 profile = domain->profile;
1222 if (!profile_ptr[profile]) panic("Profile %u (used by '%s') not defined.\n", profile, domain->domainname->name);
1223 }
1224 }
1225 }
1226
1227
1228 /************************* MAC Decision Delayer *************************/
1229
1230 static DECLARE_WAIT_QUEUE_HEAD(query_wait);
1231
1232 static spinlock_t query_lock = SPIN_LOCK_UNLOCKED;
1233
1234 struct query_entry {
1235 struct list_head list;
1236 char *query;
1237 int query_len;
1238 unsigned int serial;
1239 int timer;
1240 int answer;
1241 };
1242
1243 static LIST_HEAD(query_list);
1244 static atomic_t queryd_watcher = ATOMIC_INIT(0);
1245
1246 int CheckSupervisor(const char *fmt, ...)
1247 {
1248 va_list args;
1249 int error = -EPERM;
1250 int pos, len;
1251 static unsigned int serial = 0;
1252 struct query_entry *query_entry;
1253 if (!CheckCCSFlags(CCS_ALLOW_ENFORCE_GRACE)) return -EPERM;
1254 if (!atomic_read(&queryd_watcher)) return -EPERM;
1255 va_start(args, fmt);
1256 len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;
1257 va_end(args);
1258 if ((query_entry = ccs_alloc(sizeof(*query_entry))) == NULL ||
1259 (query_entry->query = ccs_alloc(len)) == NULL) goto out;
1260 INIT_LIST_HEAD(&query_entry->list);
1261 /***** CRITICAL SECTION START *****/
1262 spin_lock(&query_lock);
1263 query_entry->serial = serial++;
1264 spin_unlock(&query_lock);
1265 /***** CRITICAL SECTION END *****/
1266 pos = snprintf(query_entry->query, len - 1, "Q%u\n", query_entry->serial);
1267 va_start(args, fmt);
1268 vsnprintf(query_entry->query + pos, len - 1 - pos, fmt, args);
1269 query_entry->query_len = strlen(query_entry->query) + 1;
1270 va_end(args);
1271 /***** CRITICAL SECTION START *****/
1272 spin_lock(&query_lock);
1273 list_add_tail(&query_entry->list, &query_list);
1274 spin_unlock(&query_lock);
1275 /***** CRITICAL SECTION END *****/
1276 UpdateCounter(CCS_UPDATES_COUNTER_QUERY);
1277 /* Give 10 seconds for supervisor's opinion. */
1278 for (query_entry->timer = 0; atomic_read(&queryd_watcher) && CheckCCSFlags(CCS_ALLOW_ENFORCE_GRACE) && query_entry->timer < 100; query_entry->timer++) {
1279 wake_up(&query_wait);
1280 set_current_state(TASK_INTERRUPTIBLE);
1281 schedule_timeout(HZ / 10);
1282 if (query_entry->answer) break;
1283 }
1284 UpdateCounter(CCS_UPDATES_COUNTER_QUERY);
1285 /***** CRITICAL SECTION START *****/
1286 spin_lock(&query_lock);
1287 list_del(&query_entry->list);
1288 spin_unlock(&query_lock);
1289 /***** CRITICAL SECTION END *****/
1290 switch (query_entry->answer) {
1291 case 1:
1292 /* Granted by administrator. */
1293 error = 0;
1294 break;
1295 case 0:
1296 /* Timed out. */
1297 break;
1298 default:
1299 /* Rejected by administrator. */
1300 break;
1301 }
1302 out: ;
1303 if (query_entry) ccs_free(query_entry->query);
1304 ccs_free(query_entry);
1305 return error;
1306 }
1307
1308 static int PollQuery(struct file *file, poll_table *wait)
1309 {
1310 int found;
1311 /***** CRITICAL SECTION START *****/
1312 spin_lock(&query_lock);
1313 found = !list_empty(&query_list);
1314 spin_unlock(&query_lock);
1315 /***** CRITICAL SECTION END *****/
1316 if (found) return POLLIN | POLLRDNORM;
1317 poll_wait(file, &query_wait, wait);
1318 /***** CRITICAL SECTION START *****/
1319 spin_lock(&query_lock);
1320 found = !list_empty(&query_list);
1321 spin_unlock(&query_lock);
1322 /***** CRITICAL SECTION END *****/
1323 if (found) return POLLIN | POLLRDNORM;
1324 return 0;
1325 }
1326
1327 static int ReadQuery(struct io_buffer *head)
1328 {
1329 struct list_head *tmp;
1330 int pos = 0, len = 0;
1331 char *buf;
1332 if (head->read_avail) return 0;
1333 if (head->read_buf) {
1334 ccs_free(head->read_buf); head->read_buf = NULL;
1335 head->readbuf_size = 0;
1336 }
1337 /***** CRITICAL SECTION START *****/
1338 spin_lock(&query_lock);
1339 list_for_each(tmp, &query_list) {
1340 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);
1341 if (pos++ == head->read_step) {
1342 len = ptr->query_len;
1343 break;
1344 }
1345 }
1346 spin_unlock(&query_lock);
1347 /***** CRITICAL SECTION END *****/
1348 if (!len) {
1349 head->read_step = 0;
1350 return 0;
1351 }
1352 if ((buf = ccs_alloc(len)) != NULL) {
1353 pos = 0;
1354 /***** CRITICAL SECTION START *****/
1355 spin_lock(&query_lock);
1356 list_for_each(tmp, &query_list) {
1357 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);
1358 if (pos++ == head->read_step) {
1359 /* Some query can be skiipped since query_list can change, but I don't care. */
1360 if (len == ptr->query_len) memmove(buf, ptr->query, len);
1361 break;
1362 }
1363 }
1364 spin_unlock(&query_lock);
1365 /***** CRITICAL SECTION END *****/
1366 if (buf[0]) {
1367 head->readbuf_size = head->read_avail = len;
1368 head->read_buf = buf;
1369 head->read_step++;
1370 } else {
1371 ccs_free(buf);
1372 }
1373 }
1374 return 0;
1375 }
1376
1377 static int WriteAnswer(struct io_buffer *head)
1378 {
1379 char *data = head->write_buf;
1380 struct list_head *tmp;
1381 unsigned int serial, answer;
1382 /***** CRITICAL SECTION START *****/
1383 spin_lock(&query_lock);
1384 list_for_each(tmp, &query_list) {
1385 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);
1386 ptr->timer = 0;
1387 }
1388 spin_unlock(&query_lock);
1389 /***** CRITICAL SECTION END *****/
1390 if (sscanf(data, "A%u=%u", &serial, &answer) != 2) return -EINVAL;
1391 /***** CRITICAL SECTION START *****/
1392 spin_lock(&query_lock);
1393 list_for_each(tmp, &query_list) {
1394 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);
1395 if (ptr->serial != serial) continue;
1396 if (!ptr->answer) ptr->answer = answer;
1397 break;
1398 }
1399 spin_unlock(&query_lock);
1400 /***** CRITICAL SECTION END *****/
1401 return 0;
1402 }
1403
1404 /************************* /proc INTERFACE HANDLER *************************/
1405
1406 /* Policy updates counter. */
1407 static unsigned int updates_counter[MAX_CCS_UPDATES_COUNTER];
1408 static spinlock_t updates_counter_lock = SPIN_LOCK_UNLOCKED;
1409
1410 void UpdateCounter(const unsigned char index)
1411 {
1412 /***** CRITICAL SECTION START *****/
1413 spin_lock(&updates_counter_lock);
1414 if (index < MAX_CCS_UPDATES_COUNTER) updates_counter[index]++;
1415 spin_unlock(&updates_counter_lock);
1416 /***** CRITICAL SECTION END *****/
1417 }
1418
1419 static int ReadUpdatesCounter(struct io_buffer *head)
1420 {
1421 if (!head->read_eof) {
1422 unsigned int counter[MAX_CCS_UPDATES_COUNTER];
1423 /***** CRITICAL SECTION START *****/
1424 spin_lock(&updates_counter_lock);
1425 memmove(counter, updates_counter, sizeof(updates_counter));
1426 memset(updates_counter, 0, sizeof(updates_counter));
1427 spin_unlock(&updates_counter_lock);
1428 /***** CRITICAL SECTION END *****/
1429 io_printf(head,
1430 "/proc/ccs/policy/system_policy: %10u\n"
1431 "/proc/ccs/policy/domain_policy: %10u\n"
1432 "/proc/ccs/policy/exception_policy: %10u\n"
1433 "/proc/ccs/status: %10u\n"
1434 "/proc/ccs/policy/query: %10u\n"
1435 "/proc/ccs/policy/manager: %10u\n"
1436 "/proc/ccs/info/grant_log: %10u\n"
1437 "/proc/ccs/info/reject_log: %10u\n",
1438 counter[CCS_UPDATES_COUNTER_SYSTEM_POLICY],
1439 counter[CCS_UPDATES_COUNTER_DOMAIN_POLICY],
1440 counter[CCS_UPDATES_COUNTER_EXCEPTION_POLICY],
1441 counter[CCS_UPDATES_COUNTER_STATUS],
1442 counter[CCS_UPDATES_COUNTER_QUERY],
1443 counter[CCS_UPDATES_COUNTER_MANAGER],
1444 counter[CCS_UPDATES_COUNTER_GRANT_LOG],
1445 counter[CCS_UPDATES_COUNTER_REJECT_LOG]);
1446 head->read_eof = 1;
1447 }
1448 return 0;
1449 }
1450
1451 static int ReadMemoryCounter(struct io_buffer *head)
1452 {
1453 if (!head->read_eof) {
1454 const int shared = GetMemoryUsedForSaveName(), private = GetMemoryUsedForElements(), dynamic = GetMemoryUsedForDynamic();
1455 if (io_printf(head, "Shared: %10u\nPrivate: %10u\nDynamic: %10u\nTotal: %10u\n", shared, private, dynamic, shared + private + dynamic) == 0) head->read_eof = 1;
1456 }
1457 return 0;
1458 }
1459
1460 int CCS_OpenControl(const int type, struct file *file)
1461 {
1462 struct io_buffer *head = ccs_alloc(sizeof(*head));
1463 if (!head) return -ENOMEM;
1464 init_MUTEX(&head->read_sem);
1465 init_MUTEX(&head->write_sem);
1466 switch (type) {
1467 #ifdef CONFIG_TOMOYO
1468 case CCS_POLICY_DOMAINPOLICY:
1469 head->write = AddDomainPolicy;
1470 head->read = ReadDomainPolicy;
1471 break;
1472 case CCS_POLICY_EXCEPTIONPOLICY:
1473 head->write = AddExceptionPolicy;
1474 head->read = ReadExceptionPolicy;
1475 break;
1476 case CCS_POLICY_DOMAIN_STATUS:
1477 head->write = UpdateDomainProfile;
1478 head->read = ReadDomainProfile;
1479 break;
1480 case CCS_INFO_PROCESS_STATUS:
1481 head->write = WritePID;
1482 head->read = ReadPID;
1483 break;
1484 #ifdef CONFIG_TOMOYO_AUDIT
1485 case CCS_INFO_GRANTLOG:
1486 head->poll = PollGrantLog;
1487 head->read = ReadGrantLog;
1488 break;
1489 case CCS_INFO_REJECTLOG:
1490 head->poll = PollRejectLog;
1491 head->read = ReadRejectLog;
1492 break;
1493 #endif
1494 case CCS_INFO_SELFDOMAIN:
1495 head->read = ReadSelfDomain;
1496 break;
1497 #ifdef CONFIG_TOMOYO_MAC_FOR_FILE
1498 case CCS_INFO_MAPPING:
1499 if (!sbin_init_started) head->write = SetPermissionMapping;
1500 head->read = ReadPermissionMapping;
1501 break;
1502 #endif
1503 #endif
1504 #ifdef CONFIG_SAKURA
1505 case CCS_POLICY_SYSTEMPOLICY:
1506 head->write = AddSystemPolicy;
1507 head->read = ReadSystemPolicy;
1508 break;
1509 #endif
1510 case CCS_INFO_MEMINFO:
1511 head->read = ReadMemoryCounter;
1512 head->readbuf_size = 128;
1513 break;
1514 case CCS_STATUS:
1515 head->write = SetStatus;
1516 head->read = ReadStatus;
1517 break;
1518 case CCS_POLICY_QUERY:
1519 head->poll = PollQuery;
1520 head->write = WriteAnswer;
1521 head->read = ReadQuery;
1522 break;
1523 case CCS_POLICY_MANAGER:
1524 head->write = AddManagerPolicy;
1525 head->read = ReadManagerPolicy;
1526 break;
1527 case CCS_INFO_UPDATESCOUNTER:
1528 head->read = ReadUpdatesCounter;
1529 break;
1530 }
1531 if (type != CCS_INFO_GRANTLOG && type != CCS_INFO_REJECTLOG && type != CCS_POLICY_QUERY) {
1532 if (!head->readbuf_size) head->readbuf_size = PAGE_SIZE * 2;
1533 if ((head->read_buf = ccs_alloc(head->readbuf_size)) == NULL) {
1534 ccs_free(head);
1535 return -ENOMEM;
1536 }
1537 }
1538 if (head->write) {
1539 head->writebuf_size = PAGE_SIZE * 2;
1540 if ((head->write_buf = ccs_alloc(head->writebuf_size)) == NULL) {
1541 ccs_free(head->read_buf);
1542 ccs_free(head);
1543 return -ENOMEM;
1544 }
1545 }
1546 file->private_data = head;
1547 if (type == CCS_INFO_SELFDOMAIN) CCS_ReadControl(file, NULL, 0);
1548 else if (head->write == WriteAnswer) atomic_inc(&queryd_watcher);
1549 return 0;
1550 }
1551
1552 static int CopyToUser(struct io_buffer *head, char __user * buffer, int buffer_len)
1553 {
1554 int len = head->read_avail;
1555 char *cp = head->read_buf;
1556 if (len > buffer_len) len = buffer_len;
1557 if (len) {
1558 if (copy_to_user(buffer, cp, len)) return -EFAULT;
1559 head->read_avail -= len;
1560 memmove(cp, cp + len, head->read_avail);
1561 }
1562 return len;
1563 }
1564
1565 int CCS_PollControl(struct file *file, poll_table *wait)
1566 {
1567 struct io_buffer *head = file->private_data;
1568 if (!head->poll) return -ENOSYS;
1569 return head->poll(file, wait);
1570 }
1571
1572 int CCS_ReadControl(struct file *file, char __user *buffer, const int buffer_len)
1573 {
1574 int len = 0;
1575 struct io_buffer *head = file->private_data;
1576 if (!head->read) return -ENOSYS;
1577 if (!access_ok(VERIFY_WRITE, buffer, buffer_len)) return -EFAULT;
1578 if (down_interruptible(&head->read_sem)) return -EINTR;
1579 len = head->read(head);
1580 if (len >= 0) len = CopyToUser(head, buffer, buffer_len);
1581 up(&head->read_sem);
1582 return len;
1583 }
1584
1585 int CCS_WriteControl(struct file *file, const char __user *buffer, const int buffer_len)
1586 {
1587 struct io_buffer *head = file->private_data;
1588 int error = buffer_len;
1589 int avail_len = buffer_len;
1590 char *cp0 = head->write_buf;
1591 if (!head->write) return -ENOSYS;
1592 if (!access_ok(VERIFY_READ, buffer, buffer_len)) return -EFAULT;
1593 if (!isRoot()) return -EPERM;
1594 if (head->write != WritePID && !IsPolicyManager()) {
1595 return -EPERM; /* Forbid updating policies for non manager programs. */
1596 }
1597 if (down_interruptible(&head->write_sem)) return -EINTR;
1598 while (avail_len > 0) {
1599 char c;
1600 if (head->write_avail >= head->writebuf_size - 1) {
1601 error = -ENOMEM;
1602 break;
1603 } else if (get_user(c, buffer)) {
1604 error = -EFAULT;
1605 break;
1606 }
1607 buffer++; avail_len--;
1608 cp0[head->write_avail++] = c;
1609 if (c != '\n') continue;
1610 cp0[head->write_avail - 1] = '\0';
1611 head->write_avail = 0;
1612 NormalizeLine(cp0);
1613 head->write(head);
1614 }
1615 up(&head->write_sem);
1616 return error;
1617 }
1618
1619
1620 int CCS_CloseControl(struct file *file)
1621 {
1622 struct io_buffer *head = file->private_data;
1623 if (head->write == WriteAnswer) atomic_dec(&queryd_watcher);
1624 ccs_free(head->read_buf); head->read_buf = NULL;
1625 ccs_free(head->write_buf); head->write_buf = NULL;
1626 ccs_free(head); head = NULL;
1627 file->private_data = NULL;
1628 return 0;
1629 }
1630
1631 EXPORT_SYMBOL(CheckCCSFlags);
1632 EXPORT_SYMBOL(CheckCCSEnforce);
1633 EXPORT_SYMBOL(CheckCCSAccept);

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