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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1012 - (show annotations) (download) (as text)
Mon Mar 3 05:07:11 2008 UTC (16 years, 2 months ago) by kumaneko
Original Path: trunk/1.6.x/ccs-patch/fs/ccs_common.c
File MIME type: text/x-csrc
File size: 57079 byte(s)


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

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