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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 776 - (hide annotations) (download) (as text)
Wed Dec 5 05:29:11 2007 UTC (16 years, 5 months ago) by kumaneko
Original Path: trunk/1.5.x/ccs-patch/fs/ccs_common.c
File MIME type: text/x-csrc
File size: 52943 byte(s)


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

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