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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 512 - (show annotations) (download) (as text)
Thu Sep 27 08:52:16 2007 UTC (16 years, 8 months ago) by kumaneko
Original Path: trunk/1.5.x/ccs-patch/fs/ccs_common.c
File MIME type: text/x-csrc
File size: 50971 byte(s)


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

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