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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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