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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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