開發和下載開源軟體

Browse Subversion Repository

Contents of /trunk/1.5.x/ccs-patch/fs/ccs_common.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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