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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 851 - (hide annotations) (download) (as text)
Wed Jan 2 06:29:56 2008 UTC (16 years, 4 months ago) by kumaneko
Original Path: trunk/1.5.x/ccs-patch/fs/ccs_common.c
File MIME type: text/x-csrc
File size: 53233 byte(s)


1 kumaneko 111 /*
2     * fs/ccs_common.c
3     *
4     * Common functions for SAKURA and TOMOYO.
5     *
6 kumaneko 849 * Copyright (C) 2005-2008 NTT DATA CORPORATION
7 kumaneko 111 *
8 kumaneko 849 * Version: 1.5.3-pre 2008/01/02
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 kumaneko 851 unsigned int CheckCCSFlags(const u8 index)
507 kumaneko 111 {
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    
516 kumaneko 621 bool TomoyoVerboseMode(void)
517 kumaneko 111 {
518 kumaneko 621 return CheckCCSFlags(CCS_TOMOYO_VERBOSE) != 0;
519 kumaneko 111 }
520    
521 kumaneko 621 bool CheckDomainQuota(struct domain_info * const domain)
522 kumaneko 512 {
523     unsigned int count = 0;
524     struct acl_info *ptr;
525     if (!domain) return 1;
526 kumaneko 722 list1_for_each_entry(ptr, &domain->acl_info_list, list) {
527 kumaneko 512 if (!ptr->is_deleted) count++;
528     }
529     if (count < CheckCCSFlags(CCS_TOMOYO_MAX_ACCEPT_ENTRY)) return 1;
530     if (!domain->quota_warned) {
531     domain->quota_warned = 1;
532     printk("TOMOYO-WARNING: Domain '%s' has so many ACLs to hold. Stopped learning mode.\n", domain->domainname->name);
533     }
534     return 0;
535     }
536    
537 kumaneko 214 static struct profile *FindOrAssignNewProfile(const unsigned int profile)
538 kumaneko 111 {
539 kumaneko 652 static DEFINE_MUTEX(profile_lock);
540 kumaneko 214 struct profile *ptr = NULL;
541 kumaneko 652 mutex_lock(&profile_lock);
542 kumaneko 111 if (profile < MAX_PROFILES && (ptr = profile_ptr[profile]) == NULL) {
543 kumaneko 214 if ((ptr = alloc_element(sizeof(*ptr))) != NULL) {
544 kumaneko 111 int i;
545     for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) ptr->value[i] = ccs_control_array[i].current_value;
546 kumaneko 708 mb(); /* Avoid out-of-order execution. */
547 kumaneko 111 profile_ptr[profile] = ptr;
548     }
549     }
550 kumaneko 652 mutex_unlock(&profile_lock);
551 kumaneko 111 return ptr;
552     }
553    
554 kumaneko 740 /* #define ALT_EXEC */
555    
556 kumaneko 418 static int SetProfile(struct io_buffer *head)
557 kumaneko 111 {
558     char *data = head->write_buf;
559     unsigned int i, value;
560     char *cp;
561 kumaneko 214 struct profile *profile;
562 kumaneko 111 if (!isRoot()) return -EPERM;
563     i = simple_strtoul(data, &cp, 10);
564     if (data != cp) {
565     if (*cp != '-') return -EINVAL;
566     data= cp + 1;
567     }
568     profile = FindOrAssignNewProfile(i);
569     if (!profile) return -EINVAL;
570     cp = strchr(data, '=');
571     if (!cp) return -EINVAL;
572     *cp = '\0';
573 kumaneko 418 UpdateCounter(CCS_UPDATES_COUNTER_PROFILE);
574 kumaneko 111 if (strcmp(data, ccs_control_array[CCS_PROFILE_COMMENT].keyword) == 0) {
575     profile->comment = SaveName(cp + 1);
576     return 0;
577     }
578 kumaneko 740 #ifdef ALT_EXEC
579 kumaneko 708 #ifdef CONFIG_TOMOYO
580     if (strcmp(data, ccs_control_array[CCS_TOMOYO_ALT_EXEC].keyword) == 0) {
581     cp++;
582     if (*cp && !IsCorrectPath(cp, 1, -1, -1, __FUNCTION__)) cp = "";
583     profile->alt_exec = SaveName(cp);
584     return 0;
585     }
586     #endif
587     #endif
588 kumaneko 111 if (sscanf(cp + 1, "%u", &value) != 1) return -EINVAL;
589 kumaneko 461 #ifdef CONFIG_TOMOYO
590 kumaneko 111 if (strncmp(data, KEYWORD_MAC_FOR_CAPABILITY, KEYWORD_MAC_FOR_CAPABILITY_LEN) == 0) {
591     return SetCapabilityStatus(data + KEYWORD_MAC_FOR_CAPABILITY_LEN, value, i);
592     }
593 kumaneko 461 #endif
594 kumaneko 111 for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) {
595     if (strcmp(data, ccs_control_array[i].keyword)) continue;
596     if (value > ccs_control_array[i].max_value) value = ccs_control_array[i].max_value;
597     profile->value[i] = value;
598     return 0;
599     }
600     return -EINVAL;
601     }
602    
603 kumaneko 418 static int ReadProfile(struct io_buffer *head)
604 kumaneko 111 {
605     if (!head->read_eof) {
606     if (!isRoot()) return -EPERM;
607     if (!head->read_var2) {
608     int step;
609     for (step = head->read_step; step < MAX_PROFILES * CCS_MAX_CONTROL_INDEX; step++) {
610     const int i = step / CCS_MAX_CONTROL_INDEX, j = step % CCS_MAX_CONTROL_INDEX;
611 kumaneko 214 const struct profile *profile = profile_ptr[i];
612 kumaneko 111 head->read_step = step;
613     if (!profile) continue;
614     switch (j) {
615 kumaneko 240 case -1: /* Dummy */
616 kumaneko 461 #ifndef CONFIG_SAKURA
617     case CCS_SAKURA_DENY_CONCEAL_MOUNT:
618     case CCS_SAKURA_RESTRICT_CHROOT:
619     case CCS_SAKURA_RESTRICT_MOUNT:
620     case CCS_SAKURA_RESTRICT_UNMOUNT:
621     case CCS_SAKURA_RESTRICT_PIVOT_ROOT:
622     case CCS_SAKURA_RESTRICT_AUTOBIND:
623     #endif
624 kumaneko 111 #ifndef CONFIG_TOMOYO
625 kumaneko 461 case CCS_TOMOYO_MAC_FOR_FILE:
626     case CCS_TOMOYO_MAC_FOR_ARGV0:
627 kumaneko 581 case CCS_TOMOYO_MAC_FOR_ENV:
628 kumaneko 461 case CCS_TOMOYO_MAC_FOR_NETWORK:
629     case CCS_TOMOYO_MAC_FOR_SIGNAL:
630 kumaneko 120 case CCS_TOMOYO_MAX_ACCEPT_ENTRY:
631 kumaneko 111 case CCS_TOMOYO_MAX_GRANT_LOG:
632     case CCS_TOMOYO_MAX_REJECT_LOG:
633     case CCS_TOMOYO_VERBOSE:
634     #endif
635 kumaneko 740 #ifndef ALT_EXEC
636 kumaneko 708 case CCS_TOMOYO_ALT_EXEC:
637     case CCS_SLEEP_PERIOD:
638 kumaneko 740 #endif
639 kumaneko 111 continue;
640     }
641     if (j == CCS_PROFILE_COMMENT) {
642     if (io_printf(head, "%u-%s=%s\n", i, ccs_control_array[CCS_PROFILE_COMMENT].keyword, profile->comment ? profile->comment->name : "")) break;
643 kumaneko 708 } else if (j == CCS_TOMOYO_ALT_EXEC) {
644     const struct path_info *alt_exec = profile->alt_exec;
645     if (io_printf(head, "%u-%s=%s\n", i, ccs_control_array[CCS_TOMOYO_ALT_EXEC].keyword, alt_exec ? alt_exec->name : "")) break;
646 kumaneko 111 } else {
647     if (io_printf(head, "%u-%s=%u\n", i, ccs_control_array[j].keyword, profile->value[j])) break;
648     }
649     }
650     if (step == MAX_PROFILES * CCS_MAX_CONTROL_INDEX) {
651 kumaneko 708 head->read_var2 = (void *) "";
652 kumaneko 111 head->read_step = 0;
653     }
654     }
655     if (head->read_var2) {
656 kumaneko 461 #ifdef CONFIG_TOMOYO
657     if (ReadCapabilityStatus(head) == 0)
658     #endif
659     head->read_eof = 1;
660 kumaneko 111 }
661     }
662     return 0;
663     }
664    
665     /************************* POLICY MANAGER HANDLER *************************/
666    
667 kumaneko 214 struct policy_manager_entry {
668 kumaneko 722 struct list1_head list;
669 kumaneko 111 const struct path_info *manager;
670 kumaneko 621 bool is_domain;
671     bool is_deleted;
672 kumaneko 214 };
673 kumaneko 111
674 kumaneko 722 static LIST1_HEAD(policy_manager_list);
675 kumaneko 111
676 kumaneko 621 static int AddManagerEntry(const char *manager, const bool is_delete)
677 kumaneko 111 {
678 kumaneko 214 struct policy_manager_entry *new_entry, *ptr;
679 kumaneko 652 static DEFINE_MUTEX(lock);
680 kumaneko 111 const struct path_info *saved_manager;
681     int error = -ENOMEM;
682 kumaneko 621 bool is_domain = 0;
683 kumaneko 111 if (!isRoot()) return -EPERM;
684     if (IsDomainDef(manager)) {
685     if (!IsCorrectDomain(manager, __FUNCTION__)) return -EINVAL;
686     is_domain = 1;
687     } else {
688     if (!IsCorrectPath(manager, 1, -1, -1, __FUNCTION__)) return -EINVAL;
689     }
690     if ((saved_manager = SaveName(manager)) == NULL) return -ENOMEM;
691 kumaneko 652 mutex_lock(&lock);
692 kumaneko 722 list1_for_each_entry(ptr, &policy_manager_list, list) {
693 kumaneko 111 if (ptr->manager == saved_manager) {
694     ptr->is_deleted = is_delete;
695     error = 0;
696     goto out;
697     }
698     }
699     if (is_delete) {
700     error = -ENOENT;
701     goto out;
702     }
703 kumaneko 214 if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;
704 kumaneko 111 new_entry->manager = saved_manager;
705     new_entry->is_domain = is_domain;
706 kumaneko 722 list1_add_tail_mb(&new_entry->list, &policy_manager_list);
707 kumaneko 111 error = 0;
708     out:
709 kumaneko 652 mutex_unlock(&lock);
710 kumaneko 111 if (!error) UpdateCounter(CCS_UPDATES_COUNTER_MANAGER);
711     return error;
712     }
713    
714 kumaneko 214 static int AddManagerPolicy(struct io_buffer *head)
715 kumaneko 111 {
716     const char *data = head->write_buf;
717 kumaneko 621 bool is_delete = 0;
718 kumaneko 111 if (!isRoot()) return -EPERM;
719     if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {
720     data += KEYWORD_DELETE_LEN;
721     is_delete = 1;
722     }
723     return AddManagerEntry(data, is_delete);
724     }
725    
726 kumaneko 214 static int ReadManagerPolicy(struct io_buffer *head)
727 kumaneko 111 {
728 kumaneko 722 struct list1_head *pos;
729 kumaneko 708 if (head->read_eof) return 0;
730     if (!isRoot()) return -EPERM;
731 kumaneko 722 list1_for_each_cookie(pos, head->read_var2, &policy_manager_list) {
732 kumaneko 708 struct policy_manager_entry *ptr;
733 kumaneko 722 ptr = list1_entry(pos, struct policy_manager_entry, list);
734 kumaneko 708 if (ptr->is_deleted) continue;
735     if (io_printf(head, "%s\n", ptr->manager->name)) return 0;
736 kumaneko 111 }
737 kumaneko 708 head->read_eof = 1;
738 kumaneko 111 return 0;
739     }
740    
741     /* Check whether the current process is a policy manager. */
742     static int IsPolicyManager(void)
743     {
744 kumaneko 214 struct policy_manager_entry *ptr;
745 kumaneko 111 const char *exe;
746     const struct path_info *domainname = current->domain_info->domainname;
747 kumaneko 708 bool found = 0;
748 kumaneko 111 if (!sbin_init_started) return 1;
749 kumaneko 722 list1_for_each_entry(ptr, &policy_manager_list, list) {
750 kumaneko 111 if (!ptr->is_deleted && ptr->is_domain && !pathcmp(domainname, ptr->manager)) return 1;
751     }
752     if ((exe = GetEXE()) == NULL) return 0;
753 kumaneko 722 list1_for_each_entry(ptr, &policy_manager_list, list) {
754 kumaneko 708 if (!ptr->is_deleted && !ptr->is_domain && !strcmp(exe, ptr->manager->name)) {
755     found = 1;
756     break;
757     }
758 kumaneko 111 }
759 kumaneko 708 if (!found) { /* Reduce error messages. */
760 kumaneko 111 static pid_t last_pid = 0;
761     const pid_t pid = current->pid;
762     if (last_pid != pid) {
763 kumaneko 248 printk("%s ( %s ) is not permitted to update policies.\n", domainname->name, exe);
764 kumaneko 111 last_pid = pid;
765     }
766     }
767     ccs_free(exe);
768 kumaneko 708 return found;
769 kumaneko 111 }
770    
771     #ifdef CONFIG_TOMOYO
772    
773     /************************* DOMAIN POLICY HANDLER *************************/
774    
775 kumaneko 581 static char *FindConditionPart(char *data)
776     {
777     char *cp = strstr(data, " if "), *cp2;
778     if (cp) {
779     while ((cp2 = strstr(cp + 3, " if ")) != NULL) cp = cp2;
780     *cp++ = '\0';
781     }
782     return cp;
783     }
784    
785 kumaneko 214 static int AddDomainPolicy(struct io_buffer *head)
786 kumaneko 111 {
787     char *data = head->write_buf;
788     struct domain_info *domain = head->write_var1;
789 kumaneko 621 bool is_delete = 0, is_select = 0, is_undelete = 0;
790 kumaneko 111 unsigned int profile;
791 kumaneko 581 const struct condition_list *cond = NULL;
792     char *cp;
793 kumaneko 111 if (!isRoot()) return -EPERM;
794     if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {
795     data += KEYWORD_DELETE_LEN;
796     is_delete = 1;
797     } else if (strncmp(data, KEYWORD_SELECT, KEYWORD_SELECT_LEN) == 0) {
798     data += KEYWORD_SELECT_LEN;
799     is_select = 1;
800     } else if (strncmp(data, KEYWORD_UNDELETE, KEYWORD_UNDELETE_LEN) == 0) {
801     data += KEYWORD_UNDELETE_LEN;
802     is_undelete = 1;
803     }
804     UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
805     if (IsDomainDef(data)) {
806     if (is_delete) {
807     DeleteDomain(data);
808     domain = NULL;
809     } else if (is_select) {
810     domain = FindDomain(data);
811     } else if (is_undelete) {
812     domain = UndeleteDomain(data);
813     } else {
814     domain = FindOrAssignNewDomain(data, 0);
815     }
816     head->write_var1 = domain;
817     return 0;
818     }
819     if (!domain) return -EINVAL;
820 kumaneko 581
821 kumaneko 111 if (sscanf(data, KEYWORD_USE_PROFILE "%u", &profile) == 1 && profile < MAX_PROFILES) {
822     if (profile_ptr[profile] || !sbin_init_started) domain->profile = (u8) profile;
823 kumaneko 581 return 0;
824     }
825     cp = FindConditionPart(data);
826     if (cp && (cond = FindOrAssignNewCondition(cp)) == NULL) return -EINVAL;
827     if (strncmp(data, KEYWORD_ALLOW_CAPABILITY, KEYWORD_ALLOW_CAPABILITY_LEN) == 0) {
828     return AddCapabilityPolicy(data + KEYWORD_ALLOW_CAPABILITY_LEN, domain, cond, is_delete);
829 kumaneko 111 } else if (strncmp(data, KEYWORD_ALLOW_NETWORK, KEYWORD_ALLOW_NETWORK_LEN) == 0) {
830 kumaneko 581 return AddNetworkPolicy(data + KEYWORD_ALLOW_NETWORK_LEN, domain, cond, is_delete);
831 kumaneko 111 } else if (strncmp(data, KEYWORD_ALLOW_SIGNAL, KEYWORD_ALLOW_SIGNAL_LEN) == 0) {
832 kumaneko 581 return AddSignalPolicy(data + KEYWORD_ALLOW_SIGNAL_LEN, domain, cond, is_delete);
833 kumaneko 111 } else if (strncmp(data, KEYWORD_ALLOW_ARGV0, KEYWORD_ALLOW_ARGV0_LEN) == 0) {
834 kumaneko 581 return AddArgv0Policy(data + KEYWORD_ALLOW_ARGV0_LEN, domain, cond, is_delete);
835     } else if (strncmp(data, KEYWORD_ALLOW_ENV, KEYWORD_ALLOW_ENV_LEN) == 0) {
836     return AddEnvPolicy(data + KEYWORD_ALLOW_ENV_LEN, domain, cond, is_delete);
837 kumaneko 111 } else {
838 kumaneko 581 return AddFilePolicy(data, domain, cond, is_delete);
839 kumaneko 111 }
840     return -EINVAL;
841     }
842    
843 kumaneko 214 static int ReadDomainPolicy(struct io_buffer *head)
844 kumaneko 111 {
845 kumaneko 722 struct list1_head *dpos;
846     struct list1_head *apos;
847 kumaneko 708 if (head->read_eof) return 0;
848     if (head->read_step == 0) {
849 kumaneko 111 if (!isRoot()) return -EPERM;
850 kumaneko 708 head->read_step = 1;
851     }
852 kumaneko 722 list1_for_each_cookie(dpos, head->read_var1, &domain_list) {
853 kumaneko 708 struct domain_info *domain;
854 kumaneko 722 domain = list1_entry(dpos, struct domain_info, list);
855 kumaneko 708 if (head->read_step != 1) goto acl_loop;
856     if (domain->is_deleted) continue;
857     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;
858     head->read_step = 2;
859     acl_loop: ;
860     if (head->read_step == 3) goto tail_mark;
861 kumaneko 722 list1_for_each_cookie(apos, head->read_var2, &domain->acl_info_list) {
862 kumaneko 111 struct acl_info *ptr;
863 kumaneko 708 int pos;
864     u8 acl_type;
865 kumaneko 722 ptr = list1_entry(apos, struct acl_info, list);
866 kumaneko 708 if (ptr->is_deleted) continue;
867     pos = head->read_avail;
868     acl_type = ptr->type;
869 kumaneko 850 if (acl_type == TYPE_SINGLE_PATH_ACL) {
870 kumaneko 849 struct single_acl_record *ptr2 = container_of(ptr, struct single_acl_record, head);
871     const bool b = ptr2->u_is_group;
872     const u16 perm = ptr2->perm;
873     u8 bit = head->read_bit;
874     while (bit < MAX_SINGLE_PATH_OPERATION) {
875     if (perm & (1 << bit)) {
876     pos = head->read_avail;
877     if (io_printf(head, "allow_%s %s%s ", sp_operation2keyword(bit),
878     b ? "@" : "", b ? ptr2->u.group->group_name->name : ptr2->u.filename->name)
879     || DumpCondition(head, ptr->cond)) {
880     head->read_bit = bit;
881     head->read_avail = pos;
882     return 0;
883     }
884     }
885     bit++;
886     }
887     head->read_bit = 0;
888     } else if (acl_type == TYPE_DOUBLE_PATH_ACL) {
889     struct double_acl_record *ptr2 = container_of(ptr, struct double_acl_record, head);
890     const bool b0 = ptr2->u1_is_group, b1 = ptr2->u2_is_group;
891     const u8 perm = ptr2->perm;
892     u8 bit = head->read_bit;
893     while (bit < MAX_DOUBLE_PATH_OPERATION) {
894     if (perm & (1 << bit)) {
895     pos = head->read_avail;
896     if (io_printf(head, "allow_%s %s%s %s%s", dp_operation2keyword(bit),
897     b0 ? "@" : "", b0 ? ptr2->u1.group1->group_name->name : ptr2->u1.filename1->name,
898     b1 ? "@" : "", b1 ? ptr2->u2.group2->group_name->name : ptr2->u2.filename2->name)
899     || DumpCondition(head, ptr->cond)) {
900     head->read_bit = bit;
901     head->read_avail = pos;
902     return 0;
903     }
904     }
905     bit++;
906     }
907     head->read_bit = 0;
908 kumaneko 708 } else if (acl_type == TYPE_ARGV0_ACL) {
909 kumaneko 712 struct argv0_acl_record *ptr2 = container_of(ptr, struct argv0_acl_record, head);
910 kumaneko 708 if (io_printf(head, KEYWORD_ALLOW_ARGV0 "%s %s",
911     ptr2->filename->name, ptr2->argv0->name)) goto print_acl_rollback;
912     } else if (acl_type == TYPE_ENV_ACL) {
913 kumaneko 712 struct env_acl_record *ptr2 = container_of(ptr, struct env_acl_record, head);
914 kumaneko 708 if (io_printf(head, KEYWORD_ALLOW_ENV "%s", ptr2->env->name)) goto print_acl_rollback;
915     } else if (acl_type == TYPE_CAPABILITY_ACL) {
916 kumaneko 712 struct capability_acl_record *ptr2 = container_of(ptr, struct capability_acl_record, head);
917 kumaneko 849 const u32 capability = ptr2->capability;
918     u8 bit = head->read_bit;
919     while (bit < TOMOYO_MAX_CAPABILITY_INDEX) {
920     if (capability & (1 << bit)) {
921     pos = head->read_avail;
922 kumaneko 851 if (io_printf(head, KEYWORD_ALLOW_CAPABILITY "%s", cap_operation2keyword(bit)) ||
923 kumaneko 849 DumpCondition(head, ptr->cond)) {
924     head->read_bit = bit;
925     head->read_avail = pos;
926     return 0;
927     }
928     }
929     bit++;
930     }
931     head->read_bit = 0;
932 kumaneko 708 } else if (acl_type == TYPE_IP_NETWORK_ACL) {
933 kumaneko 712 struct ip_network_acl_record *ptr2 = container_of(ptr, struct ip_network_acl_record, head);
934 kumaneko 851 if (io_printf(head, KEYWORD_ALLOW_NETWORK "%s ", net_operation2keyword(ptr2->operation_type))) goto print_acl_rollback;
935 kumaneko 708 switch (ptr2->record_type) {
936     case IP_RECORD_TYPE_ADDRESS_GROUP:
937     if (io_printf(head, "@%s", ptr2->u.group->group_name->name)) goto print_acl_rollback;
938     break;
939     case IP_RECORD_TYPE_IPv4:
940     {
941     const u32 min_address = ptr2->u.ipv4.min, max_address = ptr2->u.ipv4.max;
942     if (io_printf(head, "%u.%u.%u.%u", HIPQUAD(min_address))) goto print_acl_rollback;
943     if (min_address != max_address && io_printf(head, "-%u.%u.%u.%u", HIPQUAD(max_address))) goto print_acl_rollback;
944 kumaneko 111 }
945 kumaneko 708 break;
946     case IP_RECORD_TYPE_IPv6:
947 kumaneko 111 {
948 kumaneko 708 char buf[64];
949 kumaneko 719 const struct in6_addr *min_address = ptr2->u.ipv6.min, *max_address = ptr2->u.ipv6.max;
950 kumaneko 708 print_ipv6(buf, sizeof(buf), min_address);
951     if (io_printf(head, "%s", buf)) goto print_acl_rollback;
952 kumaneko 719 if (min_address != max_address) {
953 kumaneko 708 print_ipv6(buf, sizeof(buf), max_address);
954     if (io_printf(head, "-%s", buf)) goto print_acl_rollback;
955 kumaneko 111 }
956     }
957 kumaneko 708 break;
958 kumaneko 111 }
959 kumaneko 708 {
960     const u16 min_port = ptr2->min_port, max_port = ptr2->max_port;
961     if (io_printf(head, " %u", min_port)) goto print_acl_rollback;
962     if (min_port != max_port && io_printf(head, "-%u", max_port)) goto print_acl_rollback;
963     }
964     } else if (acl_type == TYPE_SIGNAL_ACL) {
965 kumaneko 712 struct signal_acl_record *ptr2 = container_of(ptr, struct signal_acl_record, head);
966 kumaneko 708 if (io_printf(head, KEYWORD_ALLOW_SIGNAL "%u %s", ptr2->sig, ptr2->domainname->name)) goto print_acl_rollback;
967     } else {
968 kumaneko 849 BUG();
969 kumaneko 111 }
970 kumaneko 849 if (acl_type != TYPE_SINGLE_PATH_ACL && acl_type != TYPE_DOUBLE_PATH_ACL && acl_type != TYPE_CAPABILITY_ACL && DumpCondition(head, ptr->cond)) {
971 kumaneko 708 print_acl_rollback: ;
972     head->read_avail = pos;
973     return 0;
974     }
975 kumaneko 111 }
976 kumaneko 708 head->read_step = 3;
977     tail_mark: ;
978     if (io_printf(head, "\n")) return 0;
979     head->read_step = 1;
980 kumaneko 111 }
981 kumaneko 708 head->read_eof = 1;
982 kumaneko 111 return 0;
983     }
984    
985 kumaneko 461 #endif
986    
987     static int UpdateDomainProfile(struct io_buffer *head)
988     {
989     char *data = head->write_buf;
990     char *cp = strchr(data, ' ');
991     struct domain_info *domain;
992     unsigned int profile;
993     if (!isRoot()) return -EPERM;
994     if (!cp) return -EINVAL;
995     *cp = '\0';
996     domain = FindDomain(cp + 1);
997     profile = simple_strtoul(data, NULL, 10);
998     if (domain && profile < MAX_PROFILES && (profile_ptr[profile] || !sbin_init_started)) domain->profile = (u8) profile;
999     UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
1000     return 0;
1001     }
1002    
1003 kumaneko 214 static int ReadDomainProfile(struct io_buffer *head)
1004 kumaneko 111 {
1005 kumaneko 722 struct list1_head *pos;
1006 kumaneko 708 if (head->read_eof) return 0;
1007     if (!isRoot()) return -EPERM;
1008 kumaneko 722 list1_for_each_cookie(pos, head->read_var1, &domain_list) {
1009 kumaneko 111 struct domain_info *domain;
1010 kumaneko 722 domain = list1_entry(pos, struct domain_info, list);
1011 kumaneko 708 if (domain->is_deleted) continue;
1012     if (io_printf(head, "%u %s\n", domain->profile, domain->domainname->name)) return 0;
1013 kumaneko 111 }
1014 kumaneko 708 head->read_eof = 1;
1015 kumaneko 111 return 0;
1016     }
1017    
1018 kumaneko 214 static int WritePID(struct io_buffer *head)
1019 kumaneko 111 {
1020     head->read_step = (int) simple_strtoul(head->write_buf, NULL, 10);
1021     head->read_eof = 0;
1022     return 0;
1023     }
1024    
1025 kumaneko 214 static int ReadPID(struct io_buffer *head)
1026 kumaneko 111 {
1027     if (head->read_avail == 0 && !head->read_eof) {
1028     const int pid = head->read_step;
1029     struct task_struct *p;
1030     struct domain_info *domain = NULL;
1031     /***** CRITICAL SECTION START *****/
1032     read_lock(&tasklist_lock);
1033     p = find_task_by_pid(pid);
1034     if (p) domain = p->domain_info;
1035     read_unlock(&tasklist_lock);
1036     /***** CRITICAL SECTION END *****/
1037     if (domain) io_printf(head, "%d %u %s", pid, domain->profile, domain->domainname->name);
1038     head->read_eof = 1;
1039     }
1040     return 0;
1041     }
1042    
1043     /************************* EXCEPTION POLICY HANDLER *************************/
1044    
1045     #ifdef CONFIG_TOMOYO
1046    
1047 kumaneko 214 static int AddExceptionPolicy(struct io_buffer *head)
1048 kumaneko 111 {
1049     char *data = head->write_buf;
1050 kumaneko 621 bool is_delete = 0;
1051 kumaneko 111 if (!isRoot()) return -EPERM;
1052     UpdateCounter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);
1053     if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {
1054     data += KEYWORD_DELETE_LEN;
1055     is_delete = 1;
1056     }
1057     if (strncmp(data, KEYWORD_KEEP_DOMAIN, KEYWORD_KEEP_DOMAIN_LEN) == 0) {
1058     return AddDomainKeeperPolicy(data + KEYWORD_KEEP_DOMAIN_LEN, 0, is_delete);
1059     } else if (strncmp(data, KEYWORD_NO_KEEP_DOMAIN, KEYWORD_NO_KEEP_DOMAIN_LEN) == 0) {
1060     return AddDomainKeeperPolicy(data + KEYWORD_NO_KEEP_DOMAIN_LEN, 1, is_delete);
1061     } else if (strncmp(data, KEYWORD_INITIALIZE_DOMAIN, KEYWORD_INITIALIZE_DOMAIN_LEN) == 0) {
1062 kumaneko 366 return AddDomainInitializerPolicy(data + KEYWORD_INITIALIZE_DOMAIN_LEN, 0, is_delete);
1063 kumaneko 111 } else if (strncmp(data, KEYWORD_NO_INITIALIZE_DOMAIN, KEYWORD_NO_INITIALIZE_DOMAIN_LEN) == 0) {
1064 kumaneko 366 return AddDomainInitializerPolicy(data + KEYWORD_NO_INITIALIZE_DOMAIN_LEN, 1, is_delete);
1065 kumaneko 111 } else if (strncmp(data, KEYWORD_ALIAS, KEYWORD_ALIAS_LEN) == 0) {
1066     return AddAliasPolicy(data + KEYWORD_ALIAS_LEN, is_delete);
1067     } else if (strncmp(data, KEYWORD_AGGREGATOR, KEYWORD_AGGREGATOR_LEN) == 0) {
1068     return AddAggregatorPolicy(data + KEYWORD_AGGREGATOR_LEN, is_delete);
1069     } else if (strncmp(data, KEYWORD_ALLOW_READ, KEYWORD_ALLOW_READ_LEN) == 0) {
1070     return AddGloballyReadablePolicy(data + KEYWORD_ALLOW_READ_LEN, is_delete);
1071 kumaneko 581 } else if (strncmp(data, KEYWORD_ALLOW_ENV, KEYWORD_ALLOW_ENV_LEN) == 0) {
1072     return AddGloballyUsableEnvPolicy(data + KEYWORD_ALLOW_ENV_LEN, is_delete);
1073 kumaneko 111 } else if (strncmp(data, KEYWORD_FILE_PATTERN, KEYWORD_FILE_PATTERN_LEN) == 0) {
1074 kumaneko 851 return AddFilePatternPolicy(data + KEYWORD_FILE_PATTERN_LEN, is_delete);
1075 kumaneko 111 } else if (strncmp(data, KEYWORD_PATH_GROUP, KEYWORD_PATH_GROUP_LEN) == 0) {
1076 kumaneko 708 return AddPathGroupPolicy(data + KEYWORD_PATH_GROUP_LEN, is_delete);
1077 kumaneko 111 } else if (strncmp(data, KEYWORD_DENY_REWRITE, KEYWORD_DENY_REWRITE_LEN) == 0) {
1078     return AddNoRewritePolicy(data + KEYWORD_DENY_REWRITE_LEN, is_delete);
1079     } else if (strncmp(data, KEYWORD_ADDRESS_GROUP, KEYWORD_ADDRESS_GROUP_LEN) == 0) {
1080     return AddAddressGroupPolicy(data + KEYWORD_ADDRESS_GROUP_LEN, is_delete);
1081     }
1082     return -EINVAL;
1083     }
1084    
1085 kumaneko 214 static int ReadExceptionPolicy(struct io_buffer *head)
1086 kumaneko 111 {
1087     if (!head->read_eof) {
1088     switch (head->read_step) {
1089     case 0:
1090     if (!isRoot()) return -EPERM;
1091     head->read_var2 = NULL; head->read_step = 1;
1092     case 1:
1093     if (ReadDomainKeeperPolicy(head)) break;
1094     head->read_var2 = NULL; head->read_step = 2;
1095     case 2:
1096     if (ReadGloballyReadablePolicy(head)) break;
1097     head->read_var2 = NULL; head->read_step = 3;
1098     case 3:
1099 kumaneko 581 if (ReadGloballyUsableEnvPolicy(head)) break;
1100 kumaneko 111 head->read_var2 = NULL; head->read_step = 4;
1101     case 4:
1102 kumaneko 581 if (ReadDomainInitializerPolicy(head)) break;
1103 kumaneko 111 head->read_var2 = NULL; head->read_step = 5;
1104     case 5:
1105 kumaneko 581 if (ReadAliasPolicy(head)) break;
1106 kumaneko 111 head->read_var2 = NULL; head->read_step = 6;
1107     case 6:
1108 kumaneko 581 if (ReadAggregatorPolicy(head)) break;
1109 kumaneko 111 head->read_var2 = NULL; head->read_step = 7;
1110     case 7:
1111 kumaneko 851 if (ReadFilePatternPolicy(head)) break;
1112 kumaneko 111 head->read_var2 = NULL; head->read_step = 8;
1113     case 8:
1114 kumaneko 581 if (ReadNoRewritePolicy(head)) break;
1115     head->read_var2 = NULL; head->read_step = 9;
1116     case 9:
1117 kumaneko 708 if (ReadPathGroupPolicy(head)) break;
1118 kumaneko 581 head->read_var1 = head->read_var2 = NULL; head->read_step = 10;
1119     case 10:
1120 kumaneko 111 if (ReadAddressGroupPolicy(head)) break;
1121     head->read_eof = 1;
1122     break;
1123     default:
1124     return -EINVAL;
1125     }
1126     }
1127     return 0;
1128     }
1129    
1130     #endif
1131    
1132     /************************* SYSTEM POLICY HANDLER *************************/
1133    
1134     #ifdef CONFIG_SAKURA
1135    
1136 kumaneko 214 static int AddSystemPolicy(struct io_buffer *head)
1137 kumaneko 111 {
1138     char *data = head->write_buf;
1139 kumaneko 621 bool is_delete = 0;
1140 kumaneko 111 if (!isRoot()) return -EPERM;
1141     UpdateCounter(CCS_UPDATES_COUNTER_SYSTEM_POLICY);
1142     if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {
1143     data += KEYWORD_DELETE_LEN;
1144     is_delete = 1;
1145     }
1146     if (strncmp(data, KEYWORD_ALLOW_MOUNT, KEYWORD_ALLOW_MOUNT_LEN) == 0)
1147     return AddMountPolicy(data + KEYWORD_ALLOW_MOUNT_LEN, is_delete);
1148     if (strncmp(data, KEYWORD_DENY_UNMOUNT, KEYWORD_DENY_UNMOUNT_LEN) == 0)
1149     return AddNoUmountPolicy(data + KEYWORD_DENY_UNMOUNT_LEN, is_delete);
1150     if (strncmp(data, KEYWORD_ALLOW_CHROOT, KEYWORD_ALLOW_CHROOT_LEN) == 0)
1151     return AddChrootPolicy(data + KEYWORD_ALLOW_CHROOT_LEN, is_delete);
1152 kumaneko 141 if (strncmp(data, KEYWORD_ALLOW_PIVOT_ROOT, KEYWORD_ALLOW_PIVOT_ROOT_LEN) == 0)
1153     return AddPivotRootPolicy(data + KEYWORD_ALLOW_PIVOT_ROOT_LEN, is_delete);
1154 kumaneko 111 if (strncmp(data, KEYWORD_DENY_AUTOBIND, KEYWORD_DENY_AUTOBIND_LEN) == 0)
1155     return AddReservedPortPolicy(data + KEYWORD_DENY_AUTOBIND_LEN, is_delete);
1156     return -EINVAL;
1157     }
1158    
1159 kumaneko 214 static int ReadSystemPolicy(struct io_buffer *head)
1160 kumaneko 111 {
1161     if (!head->read_eof) {
1162     switch (head->read_step) {
1163     case 0:
1164     if (!isRoot()) return -EPERM;
1165     head->read_var2 = NULL; head->read_step = 1;
1166     case 1:
1167     if (ReadMountPolicy(head)) break;
1168     head->read_var2 = NULL; head->read_step = 2;
1169     case 2:
1170     if (ReadNoUmountPolicy(head)) break;
1171     head->read_var2 = NULL; head->read_step = 3;
1172     case 3:
1173     if (ReadChrootPolicy(head)) break;
1174     head->read_var2 = NULL; head->read_step = 4;
1175     case 4:
1176 kumaneko 141 if (ReadPivotRootPolicy(head)) break;
1177     head->read_var2 = NULL; head->read_step = 5;
1178     case 5:
1179 kumaneko 111 if (ReadReservedPortPolicy(head)) break;
1180     head->read_eof = 1;
1181     break;
1182     default:
1183     return -EINVAL;
1184     }
1185     }
1186     return 0;
1187     }
1188    
1189     #endif
1190    
1191     /************************* POLICY LOADER *************************/
1192    
1193 kumaneko 325 static int profile_loaded = 0;
1194    
1195 kumaneko 111 static const char *ccs_loader = NULL;
1196    
1197     static int __init CCS_loader_Setup(char *str)
1198     {
1199     ccs_loader = str;
1200     return 0;
1201     }
1202    
1203     __setup("CCS_loader=", CCS_loader_Setup);
1204    
1205     void CCS_LoadPolicy(const char *filename)
1206     {
1207     if (sbin_init_started) return;
1208     /*
1209     * Check filename is /sbin/init or /sbin/ccs-start .
1210     * /sbin/ccs-start is a dummy filename in case where /sbin/init can't be passed.
1211     * You can create /sbin/ccs-start by "ln -s /bin/true /sbin/ccs-start", for
1212     * only the pathname is needed to activate Mandatory Access Control.
1213     */
1214     if (strcmp(filename, "/sbin/init") != 0 && strcmp(filename, "/sbin/ccs-start") != 0) return;
1215     /*
1216     * Don't activate MAC if the path given by 'CCS_loader=' option doesn't exist.
1217     * If initrd.img includes /sbin/init but real-root-dev has not mounted on / yet,
1218     * activating MAC will block the system since policies are not loaded yet.
1219     * So let do_execve() call this function everytime.
1220     */
1221     {
1222     struct nameidata nd;
1223 kumaneko 325 if (!ccs_loader) ccs_loader = "/sbin/ccs-init";
1224 kumaneko 111 if (path_lookup(ccs_loader, lookup_flags, &nd)) {
1225     printk("Not activating Mandatory Access Control now since %s doesn't exist.\n", ccs_loader);
1226     return;
1227     }
1228     path_release(&nd);
1229     }
1230 kumaneko 325 if (!profile_loaded) {
1231     char *argv[2], *envp[3];
1232     printk("Calling %s to load policy. Please wait.\n", ccs_loader);
1233     argv[0] = (char *) ccs_loader;
1234     argv[1] = NULL;
1235     envp[0] = "HOME=/";
1236     envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
1237     envp[2] = NULL;
1238     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
1239     call_usermodehelper(argv[0], argv, envp, 1);
1240     #else
1241     call_usermodehelper(argv[0], argv, envp);
1242     #endif
1243     while (!profile_loaded) {
1244     set_current_state(TASK_INTERRUPTIBLE);
1245     schedule_timeout(HZ / 10);
1246     }
1247     }
1248 kumaneko 473 #ifdef CONFIG_SAKURA
1249 kumaneko 813 printk("SAKURA: 1.5.3-pre 2007/12/18\n");
1250 kumaneko 473 #endif
1251     #ifdef CONFIG_TOMOYO
1252 kumaneko 849 printk("TOMOYO: 1.5.3-pre 2008/01/02\n");
1253 kumaneko 473 #endif
1254 kumaneko 325 //if (!profile_loaded) panic("No profiles loaded. Run policy loader using 'init=' option.\n");
1255 kumaneko 111 printk("Mandatory Access Control activated.\n");
1256     sbin_init_started = 1;
1257     ccs_log_level = KERN_WARNING;
1258     { /* Check all profiles currently assigned to domains are defined. */
1259     struct domain_info *domain;
1260 kumaneko 722 list1_for_each_entry(domain, &domain_list, list) {
1261 kumaneko 111 const u8 profile = domain->profile;
1262 kumaneko 708 if (!profile_ptr[profile]) panic("Profile %u (used by '%s') not defined.\n", profile, domain->domainname->name);
1263 kumaneko 111 }
1264     }
1265     }
1266    
1267    
1268     /************************* MAC Decision Delayer *************************/
1269    
1270     static DECLARE_WAIT_QUEUE_HEAD(query_wait);
1271    
1272     static spinlock_t query_lock = SPIN_LOCK_UNLOCKED;
1273    
1274 kumaneko 214 struct query_entry {
1275 kumaneko 111 struct list_head list;
1276     char *query;
1277     int query_len;
1278     unsigned int serial;
1279     int timer;
1280     int answer;
1281 kumaneko 214 };
1282 kumaneko 111
1283     static LIST_HEAD(query_list);
1284     static atomic_t queryd_watcher = ATOMIC_INIT(0);
1285    
1286     int CheckSupervisor(const char *fmt, ...)
1287     {
1288     va_list args;
1289     int error = -EPERM;
1290     int pos, len;
1291     static unsigned int serial = 0;
1292 kumaneko 214 struct query_entry *query_entry;
1293 kumaneko 708 if (!CheckCCSFlags(CCS_ALLOW_ENFORCE_GRACE) || !atomic_read(&queryd_watcher)) {
1294 kumaneko 742 #ifdef ALT_EXEC
1295 kumaneko 708 if ((current->tomoyo_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR) == 0) {
1296     int i;
1297     for (i = 0; i < CheckCCSFlags(CCS_SLEEP_PERIOD); i++) {
1298     set_current_state(TASK_INTERRUPTIBLE);
1299     schedule_timeout(HZ / 10);
1300     }
1301     }
1302     #endif
1303     return -EPERM;
1304     }
1305 kumaneko 111 va_start(args, fmt);
1306     len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;
1307     va_end(args);
1308 kumaneko 214 if ((query_entry = ccs_alloc(sizeof(*query_entry))) == NULL ||
1309 kumaneko 111 (query_entry->query = ccs_alloc(len)) == NULL) goto out;
1310     INIT_LIST_HEAD(&query_entry->list);
1311     /***** CRITICAL SECTION START *****/
1312     spin_lock(&query_lock);
1313     query_entry->serial = serial++;
1314     spin_unlock(&query_lock);
1315     /***** CRITICAL SECTION END *****/
1316     pos = snprintf(query_entry->query, len - 1, "Q%u\n", query_entry->serial);
1317     va_start(args, fmt);
1318     vsnprintf(query_entry->query + pos, len - 1 - pos, fmt, args);
1319     query_entry->query_len = strlen(query_entry->query) + 1;
1320     va_end(args);
1321     /***** CRITICAL SECTION START *****/
1322     spin_lock(&query_lock);
1323     list_add_tail(&query_entry->list, &query_list);
1324     spin_unlock(&query_lock);
1325     /***** CRITICAL SECTION END *****/
1326     UpdateCounter(CCS_UPDATES_COUNTER_QUERY);
1327     /* Give 10 seconds for supervisor's opinion. */
1328     for (query_entry->timer = 0; atomic_read(&queryd_watcher) && CheckCCSFlags(CCS_ALLOW_ENFORCE_GRACE) && query_entry->timer < 100; query_entry->timer++) {
1329     wake_up(&query_wait);
1330     set_current_state(TASK_INTERRUPTIBLE);
1331     schedule_timeout(HZ / 10);
1332     if (query_entry->answer) break;
1333     }
1334     UpdateCounter(CCS_UPDATES_COUNTER_QUERY);
1335     /***** CRITICAL SECTION START *****/
1336     spin_lock(&query_lock);
1337     list_del(&query_entry->list);
1338     spin_unlock(&query_lock);
1339     /***** CRITICAL SECTION END *****/
1340     switch (query_entry->answer) {
1341     case 1:
1342     /* Granted by administrator. */
1343     error = 0;
1344     break;
1345     case 0:
1346     /* Timed out. */
1347     break;
1348     default:
1349     /* Rejected by administrator. */
1350     break;
1351     }
1352     out: ;
1353     if (query_entry) ccs_free(query_entry->query);
1354     ccs_free(query_entry);
1355     return error;
1356     }
1357    
1358     static int PollQuery(struct file *file, poll_table *wait)
1359     {
1360     int found;
1361     /***** CRITICAL SECTION START *****/
1362     spin_lock(&query_lock);
1363     found = !list_empty(&query_list);
1364     spin_unlock(&query_lock);
1365     /***** CRITICAL SECTION END *****/
1366     if (found) return POLLIN | POLLRDNORM;
1367     poll_wait(file, &query_wait, wait);
1368     /***** CRITICAL SECTION START *****/
1369     spin_lock(&query_lock);
1370     found = !list_empty(&query_list);
1371     spin_unlock(&query_lock);
1372     /***** CRITICAL SECTION END *****/
1373     if (found) return POLLIN | POLLRDNORM;
1374     return 0;
1375     }
1376    
1377 kumaneko 214 static int ReadQuery(struct io_buffer *head)
1378 kumaneko 111 {
1379     struct list_head *tmp;
1380     int pos = 0, len = 0;
1381     char *buf;
1382     if (head->read_avail) return 0;
1383     if (head->read_buf) {
1384     ccs_free(head->read_buf); head->read_buf = NULL;
1385     head->readbuf_size = 0;
1386     }
1387     /***** CRITICAL SECTION START *****/
1388     spin_lock(&query_lock);
1389     list_for_each(tmp, &query_list) {
1390 kumaneko 214 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);
1391 kumaneko 111 if (pos++ == head->read_step) {
1392     len = ptr->query_len;
1393     break;
1394     }
1395     }
1396     spin_unlock(&query_lock);
1397     /***** CRITICAL SECTION END *****/
1398     if (!len) {
1399     head->read_step = 0;
1400     return 0;
1401     }
1402 kumaneko 214 if ((buf = ccs_alloc(len)) != NULL) {
1403 kumaneko 111 pos = 0;
1404     /***** CRITICAL SECTION START *****/
1405     spin_lock(&query_lock);
1406     list_for_each(tmp, &query_list) {
1407 kumaneko 214 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);
1408 kumaneko 111 if (pos++ == head->read_step) {
1409     /* Some query can be skiipped since query_list can change, but I don't care. */
1410     if (len == ptr->query_len) memmove(buf, ptr->query, len);
1411     break;
1412     }
1413     }
1414     spin_unlock(&query_lock);
1415     /***** CRITICAL SECTION END *****/
1416     if (buf[0]) {
1417     head->readbuf_size = head->read_avail = len;
1418     head->read_buf = buf;
1419     head->read_step++;
1420     } else {
1421     ccs_free(buf);
1422     }
1423     }
1424     return 0;
1425     }
1426    
1427 kumaneko 214 static int WriteAnswer(struct io_buffer *head)
1428 kumaneko 111 {
1429     char *data = head->write_buf;
1430     struct list_head *tmp;
1431     unsigned int serial, answer;
1432     /***** CRITICAL SECTION START *****/
1433     spin_lock(&query_lock);
1434     list_for_each(tmp, &query_list) {
1435 kumaneko 214 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);
1436 kumaneko 111 ptr->timer = 0;
1437     }
1438     spin_unlock(&query_lock);
1439     /***** CRITICAL SECTION END *****/
1440     if (sscanf(data, "A%u=%u", &serial, &answer) != 2) return -EINVAL;
1441     /***** CRITICAL SECTION START *****/
1442     spin_lock(&query_lock);
1443     list_for_each(tmp, &query_list) {
1444 kumaneko 214 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);
1445 kumaneko 111 if (ptr->serial != serial) continue;
1446     if (!ptr->answer) ptr->answer = answer;
1447     break;
1448     }
1449     spin_unlock(&query_lock);
1450     /***** CRITICAL SECTION END *****/
1451     return 0;
1452     }
1453    
1454     /************************* /proc INTERFACE HANDLER *************************/
1455    
1456     /* Policy updates counter. */
1457     static unsigned int updates_counter[MAX_CCS_UPDATES_COUNTER];
1458     static spinlock_t updates_counter_lock = SPIN_LOCK_UNLOCKED;
1459    
1460     void UpdateCounter(const unsigned char index)
1461     {
1462     /***** CRITICAL SECTION START *****/
1463     spin_lock(&updates_counter_lock);
1464     if (index < MAX_CCS_UPDATES_COUNTER) updates_counter[index]++;
1465     spin_unlock(&updates_counter_lock);
1466     /***** CRITICAL SECTION END *****/
1467     }
1468    
1469 kumaneko 214 static int ReadUpdatesCounter(struct io_buffer *head)
1470 kumaneko 111 {
1471     if (!head->read_eof) {
1472     unsigned int counter[MAX_CCS_UPDATES_COUNTER];
1473     /***** CRITICAL SECTION START *****/
1474     spin_lock(&updates_counter_lock);
1475     memmove(counter, updates_counter, sizeof(updates_counter));
1476     memset(updates_counter, 0, sizeof(updates_counter));
1477     spin_unlock(&updates_counter_lock);
1478     /***** CRITICAL SECTION END *****/
1479     io_printf(head,
1480 kumaneko 346 "/proc/ccs/system_policy: %10u\n"
1481     "/proc/ccs/domain_policy: %10u\n"
1482     "/proc/ccs/exception_policy: %10u\n"
1483 kumaneko 418 "/proc/ccs/profile: %10u\n"
1484 kumaneko 346 "/proc/ccs/query: %10u\n"
1485     "/proc/ccs/manager: %10u\n"
1486     "/proc/ccs/grant_log: %10u\n"
1487     "/proc/ccs/reject_log: %10u\n",
1488 kumaneko 111 counter[CCS_UPDATES_COUNTER_SYSTEM_POLICY],
1489     counter[CCS_UPDATES_COUNTER_DOMAIN_POLICY],
1490     counter[CCS_UPDATES_COUNTER_EXCEPTION_POLICY],
1491 kumaneko 418 counter[CCS_UPDATES_COUNTER_PROFILE],
1492 kumaneko 111 counter[CCS_UPDATES_COUNTER_QUERY],
1493     counter[CCS_UPDATES_COUNTER_MANAGER],
1494     counter[CCS_UPDATES_COUNTER_GRANT_LOG],
1495     counter[CCS_UPDATES_COUNTER_REJECT_LOG]);
1496     head->read_eof = 1;
1497     }
1498     return 0;
1499     }
1500    
1501 kumaneko 332 static int ReadVersion(struct io_buffer *head)
1502     {
1503     if (!head->read_eof) {
1504 kumaneko 746 if (io_printf(head, "1.5.3-pre") == 0) head->read_eof = 1;
1505 kumaneko 332 }
1506     return 0;
1507     }
1508    
1509 kumaneko 214 static int ReadMemoryCounter(struct io_buffer *head)
1510 kumaneko 111 {
1511     if (!head->read_eof) {
1512     const int shared = GetMemoryUsedForSaveName(), private = GetMemoryUsedForElements(), dynamic = GetMemoryUsedForDynamic();
1513     if (io_printf(head, "Shared: %10u\nPrivate: %10u\nDynamic: %10u\nTotal: %10u\n", shared, private, dynamic, shared + private + dynamic) == 0) head->read_eof = 1;
1514     }
1515     return 0;
1516     }
1517    
1518 kumaneko 461 static int ReadSelfDomain(struct io_buffer *head)
1519     {
1520     if (!head->read_eof) {
1521     io_printf(head, "%s", current->domain_info->domainname->name);
1522     head->read_eof = 1;
1523     }
1524     return 0;
1525     }
1526    
1527 kumaneko 111 int CCS_OpenControl(const int type, struct file *file)
1528     {
1529 kumaneko 214 struct io_buffer *head = ccs_alloc(sizeof(*head));
1530 kumaneko 111 if (!head) return -ENOMEM;
1531 kumaneko 652 mutex_init(&head->read_sem);
1532     mutex_init(&head->write_sem);
1533 kumaneko 111 switch (type) {
1534 kumaneko 461 #ifdef CONFIG_SAKURA
1535     case CCS_SYSTEMPOLICY:
1536     head->write = AddSystemPolicy;
1537     head->read = ReadSystemPolicy;
1538     break;
1539     #endif
1540 kumaneko 111 #ifdef CONFIG_TOMOYO
1541 kumaneko 418 case CCS_DOMAINPOLICY:
1542 kumaneko 111 head->write = AddDomainPolicy;
1543     head->read = ReadDomainPolicy;
1544     break;
1545 kumaneko 418 case CCS_EXCEPTIONPOLICY:
1546 kumaneko 111 head->write = AddExceptionPolicy;
1547     head->read = ReadExceptionPolicy;
1548     break;
1549 kumaneko 418 case CCS_GRANTLOG:
1550 kumaneko 111 head->poll = PollGrantLog;
1551     head->read = ReadGrantLog;
1552     break;
1553 kumaneko 418 case CCS_REJECTLOG:
1554 kumaneko 111 head->poll = PollRejectLog;
1555     head->read = ReadRejectLog;
1556     break;
1557 kumaneko 461 #endif
1558 kumaneko 418 case CCS_SELFDOMAIN:
1559 kumaneko 111 head->read = ReadSelfDomain;
1560     break;
1561 kumaneko 461 case CCS_DOMAIN_STATUS:
1562     head->write = UpdateDomainProfile;
1563     head->read = ReadDomainProfile;
1564 kumaneko 111 break;
1565 kumaneko 461 case CCS_PROCESS_STATUS:
1566     head->write = WritePID;
1567     head->read = ReadPID;
1568     break;
1569 kumaneko 332 case CCS_VERSION:
1570     head->read = ReadVersion;
1571     head->readbuf_size = 128;
1572     break;
1573 kumaneko 418 case CCS_MEMINFO:
1574 kumaneko 111 head->read = ReadMemoryCounter;
1575     head->readbuf_size = 128;
1576     break;
1577 kumaneko 418 case CCS_PROFILE:
1578     head->write = SetProfile;
1579     head->read = ReadProfile;
1580 kumaneko 111 break;
1581 kumaneko 418 case CCS_QUERY:
1582 kumaneko 111 head->poll = PollQuery;
1583     head->write = WriteAnswer;
1584     head->read = ReadQuery;
1585     break;
1586 kumaneko 418 case CCS_MANAGER:
1587 kumaneko 111 head->write = AddManagerPolicy;
1588     head->read = ReadManagerPolicy;
1589     break;
1590 kumaneko 418 case CCS_UPDATESCOUNTER:
1591 kumaneko 111 head->read = ReadUpdatesCounter;
1592     break;
1593     }
1594 kumaneko 418 if (type != CCS_GRANTLOG && type != CCS_REJECTLOG && type != CCS_QUERY) {
1595 kumaneko 111 if (!head->readbuf_size) head->readbuf_size = PAGE_SIZE * 2;
1596     if ((head->read_buf = ccs_alloc(head->readbuf_size)) == NULL) {
1597     ccs_free(head);
1598     return -ENOMEM;
1599     }
1600     }
1601     if (head->write) {
1602     head->writebuf_size = PAGE_SIZE * 2;
1603     if ((head->write_buf = ccs_alloc(head->writebuf_size)) == NULL) {
1604     ccs_free(head->read_buf);
1605     ccs_free(head);
1606     return -ENOMEM;
1607     }
1608     }
1609     file->private_data = head;
1610 kumaneko 418 if (type == CCS_SELFDOMAIN) CCS_ReadControl(file, NULL, 0);
1611 kumaneko 111 else if (head->write == WriteAnswer) atomic_inc(&queryd_watcher);
1612     return 0;
1613     }
1614    
1615 kumaneko 214 static int CopyToUser(struct io_buffer *head, char __user * buffer, int buffer_len)
1616 kumaneko 111 {
1617     int len = head->read_avail;
1618     char *cp = head->read_buf;
1619     if (len > buffer_len) len = buffer_len;
1620     if (len) {
1621     if (copy_to_user(buffer, cp, len)) return -EFAULT;
1622     head->read_avail -= len;
1623     memmove(cp, cp + len, head->read_avail);
1624     }
1625     return len;
1626     }
1627    
1628     int CCS_PollControl(struct file *file, poll_table *wait)
1629     {
1630 kumaneko 214 struct io_buffer *head = file->private_data;
1631 kumaneko 111 if (!head->poll) return -ENOSYS;
1632     return head->poll(file, wait);
1633     }
1634    
1635     int CCS_ReadControl(struct file *file, char __user *buffer, const int buffer_len)
1636     {
1637     int len = 0;
1638 kumaneko 214 struct io_buffer *head = file->private_data;
1639 kumaneko 111 if (!head->read) return -ENOSYS;
1640     if (!access_ok(VERIFY_WRITE, buffer, buffer_len)) return -EFAULT;
1641 kumaneko 652 if (mutex_lock_interruptible(&head->read_sem)) return -EINTR;
1642 kumaneko 111 len = head->read(head);
1643     if (len >= 0) len = CopyToUser(head, buffer, buffer_len);
1644 kumaneko 652 mutex_unlock(&head->read_sem);
1645 kumaneko 111 return len;
1646     }
1647    
1648     int CCS_WriteControl(struct file *file, const char __user *buffer, const int buffer_len)
1649     {
1650 kumaneko 214 struct io_buffer *head = file->private_data;
1651 kumaneko 111 int error = buffer_len;
1652     int avail_len = buffer_len;
1653     char *cp0 = head->write_buf;
1654     if (!head->write) return -ENOSYS;
1655     if (!access_ok(VERIFY_READ, buffer, buffer_len)) return -EFAULT;
1656     if (!isRoot()) return -EPERM;
1657     if (head->write != WritePID && !IsPolicyManager()) {
1658     return -EPERM; /* Forbid updating policies for non manager programs. */
1659     }
1660 kumaneko 652 if (mutex_lock_interruptible(&head->write_sem)) return -EINTR;
1661 kumaneko 111 while (avail_len > 0) {
1662     char c;
1663     if (head->write_avail >= head->writebuf_size - 1) {
1664     error = -ENOMEM;
1665     break;
1666     } else if (get_user(c, buffer)) {
1667     error = -EFAULT;
1668     break;
1669     }
1670     buffer++; avail_len--;
1671     cp0[head->write_avail++] = c;
1672     if (c != '\n') continue;
1673     cp0[head->write_avail - 1] = '\0';
1674     head->write_avail = 0;
1675     NormalizeLine(cp0);
1676     head->write(head);
1677     }
1678 kumaneko 652 mutex_unlock(&head->write_sem);
1679 kumaneko 111 return error;
1680     }
1681    
1682    
1683     int CCS_CloseControl(struct file *file)
1684     {
1685 kumaneko 214 struct io_buffer *head = file->private_data;
1686 kumaneko 111 if (head->write == WriteAnswer) atomic_dec(&queryd_watcher);
1687 kumaneko 325 else if (head->read == ReadMemoryCounter) profile_loaded = 1;
1688 kumaneko 111 ccs_free(head->read_buf); head->read_buf = NULL;
1689     ccs_free(head->write_buf); head->write_buf = NULL;
1690     ccs_free(head); head = NULL;
1691     file->private_data = NULL;
1692     return 0;
1693     }

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