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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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