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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/1.5.x/ccs-patch/fs/ccs_common.c revision 853 by kumaneko, Wed Jan 2 07:32:11 2008 UTC trunk/1.7.x/ccs-patch/security/ccsecurity/util.c revision 3014 by kumaneko, Fri Sep 11 01:01:43 2009 UTC
# Line 1  Line 1 
1  /*  /*
2   * fs/ccs_common.c   * security/ccsecurity/util.c
3   *   *
4   * Common functions for SAKURA and TOMOYO.   * Copyright (C) 2005-2009  NTT DATA CORPORATION
5   *   *
6   * Copyright (C) 2005-2008  NTT DATA CORPORATION   * Version: 1.7.0   2009/09/11
  *  
  * Version: 1.5.3-pre   2008/01/02  
7   *   *
8   * This file is applicable to both 2.4.30 and 2.6.11 and later.   * This file is applicable to both 2.4.30 and 2.6.11 and later.
9   * See README.ccs for ChangeLog.   * See README.ccs for ChangeLog.
10   *   *
11   */   */
12    
13  #include <linux/string.h>  #include "internal.h"
 #include <linux/mm.h>  
 #include <linux/utime.h>  
 #include <linux/file.h>  
 #include <linux/module.h>  
 #include <linux/slab.h>  
 #include <asm/uaccess.h>  
 #include <stdarg.h>  
 #include <linux/version.h>  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)  
 #include <linux/namei.h>  
 #include <linux/mount.h>  
 static const int lookup_flags = LOOKUP_FOLLOW;  
 #else  
 static const int lookup_flags = LOOKUP_FOLLOW | LOOKUP_POSITIVE;  
 #endif  
 #include <linux/realpath.h>  
 #include <linux/ccs_common.h>  
 #include <linux/ccs_proc.h>  
 #include <linux/tomoyo.h>  
14    
15  #ifdef CONFIG_TOMOYO_MAX_ACCEPT_ENTRY  /* Lock for protecting policy. */
16  #define MAX_ACCEPT_ENTRY (CONFIG_TOMOYO_MAX_ACCEPT_ENTRY)  DEFINE_MUTEX(ccs_policy_lock);
 #else  
 #define MAX_ACCEPT_ENTRY 2048  
 #endif  
 #ifdef CONFIG_TOMOYO_MAX_GRANT_LOG  
 #define MAX_GRANT_LOG (CONFIG_TOMOYO_MAX_GRANT_LOG)  
 #else  
 #define MAX_GRANT_LOG 1024  
 #endif  
 #ifdef CONFIG_TOMOYO_MAX_REJECT_LOG  
 #define MAX_REJECT_LOG (CONFIG_TOMOYO_MAX_REJECT_LOG)  
 #else  
 #define MAX_REJECT_LOG 1024  
 #endif  
17    
18  /*************************  VARIABLES  *************************/  /* Has /sbin/init started? */
19    bool ccs_policy_loaded;
20    
21  /* /sbin/init started? */  /* Index table for searching parent category. */
22  bool sbin_init_started = 0;  static const u8 ccs_index2category[CCS_MAX_MAC_INDEX +
23                                       CCS_MAX_CAPABILITY_INDEX] = {
24            [CCS_MAC_FILE_EXECUTE]    = CCS_MAC_CATEGORY_FILE,
25            [CCS_MAC_FILE_OPEN]       = CCS_MAC_CATEGORY_FILE,
26            [CCS_MAC_FILE_CREATE]     = CCS_MAC_CATEGORY_FILE,
27            [CCS_MAC_FILE_UNLINK]     = CCS_MAC_CATEGORY_FILE,
28            [CCS_MAC_FILE_MKDIR]      = CCS_MAC_CATEGORY_FILE,
29            [CCS_MAC_FILE_RMDIR]      = CCS_MAC_CATEGORY_FILE,
30            [CCS_MAC_FILE_MKFIFO]     = CCS_MAC_CATEGORY_FILE,
31            [CCS_MAC_FILE_MKSOCK]     = CCS_MAC_CATEGORY_FILE,
32            [CCS_MAC_FILE_TRUNCATE]   = CCS_MAC_CATEGORY_FILE,
33            [CCS_MAC_FILE_SYMLINK]    = CCS_MAC_CATEGORY_FILE,
34            [CCS_MAC_FILE_REWRITE]    = CCS_MAC_CATEGORY_FILE,
35            [CCS_MAC_FILE_MKBLOCK]    = CCS_MAC_CATEGORY_FILE,
36            [CCS_MAC_FILE_MKCHAR]     = CCS_MAC_CATEGORY_FILE,
37            [CCS_MAC_FILE_LINK]       = CCS_MAC_CATEGORY_FILE,
38            [CCS_MAC_FILE_RENAME]     = CCS_MAC_CATEGORY_FILE,
39            [CCS_MAC_FILE_CHMOD]      = CCS_MAC_CATEGORY_FILE,
40            [CCS_MAC_FILE_CHOWN]      = CCS_MAC_CATEGORY_FILE,
41            [CCS_MAC_FILE_CHGRP]      = CCS_MAC_CATEGORY_FILE,
42            [CCS_MAC_FILE_IOCTL]      = CCS_MAC_CATEGORY_FILE,
43            [CCS_MAC_FILE_CHROOT]     = CCS_MAC_CATEGORY_FILE,
44            [CCS_MAC_FILE_MOUNT]      = CCS_MAC_CATEGORY_FILE,
45            [CCS_MAC_FILE_UMOUNT]     = CCS_MAC_CATEGORY_FILE,
46            [CCS_MAC_FILE_PIVOT_ROOT] = CCS_MAC_CATEGORY_FILE,
47            [CCS_MAC_ENVIRON]         = CCS_MAC_CATEGORY_MISC,
48            [CCS_MAC_NETWORK_UDP_BIND]    = CCS_MAC_CATEGORY_NETWORK,
49            [CCS_MAC_NETWORK_UDP_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
50            [CCS_MAC_NETWORK_TCP_BIND]    = CCS_MAC_CATEGORY_NETWORK,
51            [CCS_MAC_NETWORK_TCP_LISTEN]  = CCS_MAC_CATEGORY_NETWORK,
52            [CCS_MAC_NETWORK_TCP_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
53            [CCS_MAC_NETWORK_TCP_ACCEPT]  = CCS_MAC_CATEGORY_NETWORK,
54            [CCS_MAC_NETWORK_RAW_BIND]    = CCS_MAC_CATEGORY_NETWORK,
55            [CCS_MAC_NETWORK_RAW_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
56            [CCS_MAC_SIGNAL]          = CCS_MAC_CATEGORY_IPC,
57            [CCS_MAX_MAC_INDEX + CCS_INET_STREAM_SOCKET_CREATE]
58            = CCS_MAC_CATEGORY_CAPABILITY,
59            [CCS_MAX_MAC_INDEX + CCS_INET_STREAM_SOCKET_LISTEN]
60            = CCS_MAC_CATEGORY_CAPABILITY,
61            [CCS_MAX_MAC_INDEX + CCS_INET_STREAM_SOCKET_CONNECT]
62            = CCS_MAC_CATEGORY_CAPABILITY,
63            [CCS_MAX_MAC_INDEX + CCS_USE_INET_DGRAM_SOCKET]
64            = CCS_MAC_CATEGORY_CAPABILITY,
65            [CCS_MAX_MAC_INDEX + CCS_USE_INET_RAW_SOCKET]
66            = CCS_MAC_CATEGORY_CAPABILITY,
67            [CCS_MAX_MAC_INDEX + CCS_USE_ROUTE_SOCKET]
68            = CCS_MAC_CATEGORY_CAPABILITY,
69            [CCS_MAX_MAC_INDEX + CCS_USE_PACKET_SOCKET]
70            = CCS_MAC_CATEGORY_CAPABILITY,
71            [CCS_MAX_MAC_INDEX + CCS_SYS_MOUNT]
72            = CCS_MAC_CATEGORY_CAPABILITY,
73            [CCS_MAX_MAC_INDEX + CCS_SYS_UMOUNT]
74            = CCS_MAC_CATEGORY_CAPABILITY,
75            [CCS_MAX_MAC_INDEX + CCS_SYS_REBOOT]
76            = CCS_MAC_CATEGORY_CAPABILITY,
77            [CCS_MAX_MAC_INDEX + CCS_SYS_CHROOT]
78            = CCS_MAC_CATEGORY_CAPABILITY,
79            [CCS_MAX_MAC_INDEX + CCS_SYS_KILL]
80            = CCS_MAC_CATEGORY_CAPABILITY,
81            [CCS_MAX_MAC_INDEX + CCS_SYS_VHANGUP]
82            = CCS_MAC_CATEGORY_CAPABILITY,
83            [CCS_MAX_MAC_INDEX + CCS_SYS_SETTIME]
84            = CCS_MAC_CATEGORY_CAPABILITY,
85            [CCS_MAX_MAC_INDEX + CCS_SYS_NICE]
86            = CCS_MAC_CATEGORY_CAPABILITY,
87            [CCS_MAX_MAC_INDEX + CCS_SYS_SETHOSTNAME]
88            = CCS_MAC_CATEGORY_CAPABILITY,
89            [CCS_MAX_MAC_INDEX + CCS_USE_KERNEL_MODULE]
90            = CCS_MAC_CATEGORY_CAPABILITY,
91            [CCS_MAX_MAC_INDEX + CCS_CREATE_FIFO]
92            = CCS_MAC_CATEGORY_CAPABILITY,
93            [CCS_MAX_MAC_INDEX + CCS_CREATE_BLOCK_DEV]
94            = CCS_MAC_CATEGORY_CAPABILITY,
95            [CCS_MAX_MAC_INDEX + CCS_CREATE_CHAR_DEV]
96            = CCS_MAC_CATEGORY_CAPABILITY,
97            [CCS_MAX_MAC_INDEX + CCS_CREATE_UNIX_SOCKET]
98            = CCS_MAC_CATEGORY_CAPABILITY,
99            [CCS_MAX_MAC_INDEX + CCS_SYS_LINK]
100            = CCS_MAC_CATEGORY_CAPABILITY,
101            [CCS_MAX_MAC_INDEX + CCS_SYS_SYMLINK]
102            = CCS_MAC_CATEGORY_CAPABILITY,
103            [CCS_MAX_MAC_INDEX + CCS_SYS_RENAME]
104            = CCS_MAC_CATEGORY_CAPABILITY,
105            [CCS_MAX_MAC_INDEX + CCS_SYS_UNLINK]
106            = CCS_MAC_CATEGORY_CAPABILITY,
107            [CCS_MAX_MAC_INDEX + CCS_SYS_CHMOD]
108            = CCS_MAC_CATEGORY_CAPABILITY,
109            [CCS_MAX_MAC_INDEX + CCS_SYS_CHOWN]
110            = CCS_MAC_CATEGORY_CAPABILITY,
111            [CCS_MAX_MAC_INDEX + CCS_SYS_IOCTL]
112            = CCS_MAC_CATEGORY_CAPABILITY,
113            [CCS_MAX_MAC_INDEX + CCS_SYS_KEXEC_LOAD]
114            = CCS_MAC_CATEGORY_CAPABILITY,
115            [CCS_MAX_MAC_INDEX + CCS_SYS_PIVOT_ROOT]
116            = CCS_MAC_CATEGORY_CAPABILITY,
117            [CCS_MAX_MAC_INDEX + CCS_SYS_PTRACE]
118            = CCS_MAC_CATEGORY_CAPABILITY,
119            [CCS_MAX_MAC_INDEX + CCS_CONCEAL_MOUNT]
120            = CCS_MAC_CATEGORY_CAPABILITY,
121    };
122    
123  const char *ccs_log_level = KERN_DEBUG;  /* Utility functions. */
124    
125  static struct {  /**
126          const char *keyword;   * ccs_parse_ulong - Parse an "unsigned long" value.
127          unsigned int current_value;   *
128          const unsigned int max_value;   * @result: Pointer to "unsigned long".
129  } ccs_control_array[CCS_MAX_CONTROL_INDEX] = {   * @str:    Pointer to string to parse.
130          [CCS_PROFILE_COMMENT]            = { "COMMENT",             0, 0 }, /* Reserved for string. */   *
131          [CCS_TOMOYO_MAC_FOR_FILE]        = { "MAC_FOR_FILE",        0, 3 },   * Returns value type on success, 0 otherwise.
132          [CCS_TOMOYO_MAC_FOR_ARGV0]       = { "MAC_FOR_ARGV0",       0, 3 },   *
133          [CCS_TOMOYO_MAC_FOR_ENV]         = { "MAC_FOR_ENV",         0, 3 },   * The @src is updated to point the first character after the value
134          [CCS_TOMOYO_MAC_FOR_NETWORK]     = { "MAC_FOR_NETWORK",     0, 3 },   * on success.
135          [CCS_TOMOYO_MAC_FOR_SIGNAL]      = { "MAC_FOR_SIGNAL",      0, 3 },   */
136          [CCS_SAKURA_DENY_CONCEAL_MOUNT]  = { "DENY_CONCEAL_MOUNT",  0, 3 },  u8 ccs_parse_ulong(unsigned long *result, char **str)
137          [CCS_SAKURA_RESTRICT_CHROOT]     = { "RESTRICT_CHROOT",     0, 3 },  {
138          [CCS_SAKURA_RESTRICT_MOUNT]      = { "RESTRICT_MOUNT",      0, 3 },          const char *cp = *str;
139          [CCS_SAKURA_RESTRICT_UNMOUNT]    = { "RESTRICT_UNMOUNT",    0, 3 },          char *ep;
140          [CCS_SAKURA_RESTRICT_PIVOT_ROOT] = { "RESTRICT_PIVOT_ROOT", 0, 3 },          int base = 10;
141          [CCS_SAKURA_RESTRICT_AUTOBIND]   = { "RESTRICT_AUTOBIND",   0, 1 },          if (*cp == '0') {
142          [CCS_TOMOYO_MAX_ACCEPT_ENTRY]    = { "MAX_ACCEPT_ENTRY",    MAX_ACCEPT_ENTRY, INT_MAX },                  char c = *(cp + 1);
143          [CCS_TOMOYO_MAX_GRANT_LOG]       = { "MAX_GRANT_LOG",       MAX_GRANT_LOG, INT_MAX },                  if (c == 'x' || c == 'X') {
144          [CCS_TOMOYO_MAX_REJECT_LOG]      = { "MAX_REJECT_LOG",      MAX_REJECT_LOG, INT_MAX },                          base = 16;
145          [CCS_TOMOYO_VERBOSE]             = { "TOMOYO_VERBOSE",      1, 1 },                          cp += 2;
146          [CCS_ALLOW_ENFORCE_GRACE]        = { "ALLOW_ENFORCE_GRACE", 0, 1 },                  } else if (c >= '0' && c <= '7') {
147          [CCS_SLEEP_PERIOD]               = { "SLEEP_PERIOD",        0, 3000 }, /* in 0.1 second */                          base = 8;
148          [CCS_TOMOYO_ALT_EXEC]            = { "ALT_EXEC",            0, 0 }, /* Reserved for string. */                          cp++;
149  };                  }
150            }
151            *result = simple_strtoul(cp, &ep, base);
152            if (cp == ep)
153                    return 0;
154            *str = ep;
155            switch (base) {
156            case 16:
157                    return CCS_VALUE_TYPE_HEXADECIMAL;
158            case 8:
159                    return CCS_VALUE_TYPE_OCTAL;
160            default:
161                    return CCS_VALUE_TYPE_DECIMAL;
162            }
163    }
164    
165  struct profile {  /**
166          unsigned int value[CCS_MAX_CONTROL_INDEX];   * ccs_print_ulong - Print an "unsigned long" value.
167          const struct path_info *comment;   *
168          const struct path_info *alt_exec;   * @buffer:     Pointer to buffer.
169  };   * @buffer_len: Size of @buffer.
170     * @value:      An "unsigned long" value.
171     * @type:       Type of @value.
172     *
173     * Returns nothing.
174     */
175    void ccs_print_ulong(char *buffer, const int buffer_len,
176                         const unsigned long value, const u8 type)
177    {
178            if (type == CCS_VALUE_TYPE_DECIMAL)
179                    snprintf(buffer, buffer_len, "%lu", value);
180            else if (type == CCS_VALUE_TYPE_OCTAL)
181                    snprintf(buffer, buffer_len, "0%lo", value);
182            else if (type == CCS_VALUE_TYPE_HEXADECIMAL)
183                    snprintf(buffer, buffer_len, "0x%lX", value);
184            else
185                    snprintf(buffer, buffer_len, "type(%u)", type);
186    }
187    
188  static struct profile *profile_ptr[MAX_PROFILES];  /**
189     * ccs_parse_name_union - Parse a ccs_name_union.
190     *
191     * @filename: Name or name group.
192     * @ptr:      Pointer to "struct ccs_name_union".
193     *
194     * Returns true on success, false otherwise.
195     */
196    bool ccs_parse_name_union(const char *filename, struct ccs_name_union *ptr)
197    {
198            if (!ccs_is_correct_path(filename, 0, 0, 0))
199                    return false;
200            if (filename[0] == '@') {
201                    ptr->group = ccs_get_path_group(filename + 1);
202                    ptr->is_group = true;
203                    return ptr->group != NULL;
204            }
205            ptr->filename = ccs_get_name(filename);
206            ptr->is_group = false;
207            return ptr->filename != NULL;
208    }
209    
210  /*************************  UTILITY FUNCTIONS  *************************/  /**
211     * ccs_parse_number_union - Parse a ccs_number_union.
212     *
213     * @data: Number or number range or number group.
214     * @ptr:  Pointer to "struct ccs_number_union".
215     *
216     * Returns true on success, false otherwise.
217     */
218    bool ccs_parse_number_union(char *data, struct ccs_number_union *num)
219    {
220            u8 type;
221            unsigned long v;
222            memset(num, 0, sizeof(*num));
223            if (data[0] == '@') {
224                    if (!ccs_is_correct_path(data, 0, 0, 0))
225                            return false;
226                    num->group = ccs_get_number_group(data + 1);
227                    num->is_group = true;
228                    return num->group != NULL;
229            }
230            type = ccs_parse_ulong(&v, &data);
231            if (!type)
232                    return false;
233            num->values[0] = v;
234            num->min_type = type;
235            if (!*data) {
236                    num->values[1] = v;
237                    num->max_type = type;
238                    return true;
239            }
240            if (*data++ != '-')
241                    return false;
242            type = ccs_parse_ulong(&v, &data);
243            if (!type || *data)
244                    return false;
245            num->values[1] = v;
246            num->max_type = type;
247            return true;
248    }
249    
250  #ifdef CONFIG_TOMOYO  /**
251  static int __init TOMOYO_Quiet_Setup(char *str)   * ccs_is_byte_range - Check whether the string isa \ooo style octal value.
252     *
253     * @str: Pointer to the string.
254     *
255     * Returns true if @str is a \ooo style octal value, false otherwise.
256     */
257    static inline bool ccs_is_byte_range(const char *str)
258  {  {
259          ccs_control_array[CCS_TOMOYO_VERBOSE].current_value = 0;          return *str >= '0' && *str++ <= '3' &&
260          return 0;                  *str >= '0' && *str++ <= '7' &&
261                    *str >= '0' && *str <= '7';
262  }  }
263    
264  __setup("TOMOYO_QUIET", TOMOYO_Quiet_Setup);  /**
265  #endif   * ccs_is_decimal - Check whether the character is a decimal character.
266     *
267     * @c: The character to check.
268     *
269     * Returns true if @c is a decimal character, false otherwise.
270     */
271    static inline bool ccs_is_decimal(const char c)
272    {
273            return c >= '0' && c <= '9';
274    }
275    
276    /**
277     * ccs_is_hexadecimal - Check whether the character is a hexadecimal character.
278     *
279     * @c: The character to check.
280     *
281     * Returns true if @c is a hexadecimal character, false otherwise.
282     */
283    static inline bool ccs_is_hexadecimal(const char c)
284    {
285            return (c >= '0' && c <= '9') ||
286                    (c >= 'A' && c <= 'F') ||
287                    (c >= 'a' && c <= 'f');
288    }
289    
290  /* Am I root? */  /**
291  static int isRoot(void)   * ccs_is_alphabet_char - Check whether the character is an alphabet.
292     *
293     * @c: The character to check.
294     *
295     * Returns true if @c is an alphabet character, false otherwise.
296     */
297    static inline bool ccs_is_alphabet_char(const char c)
298  {  {
299          return !current->uid && !current->euid;          return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
300  }  }
301    
302  /*  /**
303   * Format string.   * ccs_make_byte - Make byte value from three octal characters.
304     *
305     * @c1: The first character.
306     * @c2: The second character.
307     * @c3: The third character.
308     *
309     * Returns byte value.
310     */
311    static inline u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3)
312    {
313            return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
314    }
315    
316    /**
317     * ccs_str_starts - Check whether the given string starts with the given keyword.
318     *
319     * @src:  Pointer to pointer to the string.
320     * @find: Pointer to the keyword.
321     *
322     * Returns true if @src starts with @find, false otherwise.
323     *
324     * The @src is updated to point the first character after the @find
325     * if @src starts with @find.
326     */
327    bool ccs_str_starts(char **src, const char *find)
328    {
329            const int len = strlen(find);
330            char *tmp = *src;
331            if (strncmp(tmp, find, len))
332                    return false;
333            tmp += len;
334            *src = tmp;
335            return true;
336    }
337    
338    /**
339     * ccs_normalize_line - Format string.
340     *
341     * @buffer: The line to normalize.
342     *
343   * Leading and trailing whitespaces are removed.   * Leading and trailing whitespaces are removed.
344   * Multiple whitespaces are packed into single space.   * Multiple whitespaces are packed into single space.
345     *
346     * Returns nothing.
347   */   */
348  static void NormalizeLine(unsigned char *buffer)  void ccs_normalize_line(unsigned char *buffer)
349  {  {
350          unsigned char *sp = buffer, *dp = buffer;          unsigned char *sp = buffer;
351          int first = 1;          unsigned char *dp = buffer;
352          while (*sp && (*sp <= ' ' || *sp >= 127)) sp++;          bool first = true;
353            while (*sp && (*sp <= ' ' || *sp >= 127))
354                    sp++;
355          while (*sp) {          while (*sp) {
356                  if (!first) *dp++ = ' ';                  if (!first)
357                  first = 0;                          *dp++ = ' ';
358                  while (*sp > ' ' && *sp < 127) *dp++ = *sp++;                  first = false;
359                  while (*sp && (*sp <= ' ' || *sp >= 127)) sp++;                  while (*sp > ' ' && *sp < 127)
360                            *dp++ = *sp++;
361                    while (*sp && (*sp <= ' ' || *sp >= 127))
362                            sp++;
363          }          }
364          *dp = '\0';          *dp = '\0';
365  }  }
366    
367  /*  /**
368   *  Check whether the given filename follows the naming rules.   * ccs_tokenize - Tokenize string.
369   *  Returns nonzero if follows, zero otherwise.   *
370     * @buffer: The line to tokenize.
371     * @w:      Pointer to "char *".
372     * @size:   Sizeof @w .
373     *
374     * Returns true on success, false otherwise.
375     */
376    bool ccs_tokenize(char *buffer, char *w[], size_t size)
377    {
378            int count = size / sizeof(char *);
379            int i;
380            for (i = 0; i < count; i++)
381                    w[i] = "";
382            for (i = 0; i < count; i++) {
383                    char *cp = strchr(buffer, ' ');
384                    if (cp)
385                            *cp = '\0';
386                    w[i] = buffer;
387                    if (!cp)
388                            break;
389                    buffer = cp + 1;
390            }
391            return i < count || !*buffer;
392    }
393    
394    /**
395     * ccs_is_correct_path - Validate a pathname.
396     * @filename:     The pathname to check.
397     * @start_type:   Should the pathname start with '/'?
398     *                1 = must / -1 = must not / 0 = don't care
399     * @pattern_type: Can the pathname contain a wildcard?
400     *                1 = must / -1 = must not / 0 = don't care
401     * @end_type:     Should the pathname end with '/'?
402     *                1 = must / -1 = must not / 0 = don't care
403     *
404     * Check whether the given filename follows the naming rules.
405     * Returns true if @filename follows the naming rules, false otherwise.
406   */   */
407  bool IsCorrectPath(const char *filename, const s8 start_type, const s8 pattern_type, const s8 end_type, const char *function)  bool ccs_is_correct_path(const char *filename, const s8 start_type,
408                             const s8 pattern_type, const s8 end_type)
409  {  {
410          int contains_pattern = 0;          const char *const start = filename;
411          char c, d, e;          bool in_repetition = false;
412          const char *original_filename = filename;          bool contains_pattern = false;
413          if (!filename) goto out;          unsigned char c;
414            unsigned char d;
415            unsigned char e;
416            if (!filename)
417                    goto out;
418          c = *filename;          c = *filename;
419          if (start_type == 1) { /* Must start with '/' */          if (start_type == 1) { /* Must start with '/' */
420                  if (c != '/') goto out;                  if (c != '/')
421                            goto out;
422          } else if (start_type == -1) { /* Must not start with '/' */          } else if (start_type == -1) { /* Must not start with '/' */
423                  if (c == '/') goto out;                  if (c == '/')
424                            goto out;
425          }          }
426          if (c) c = * (strchr(filename, '\0') - 1);          if (c)
427                    c = *(filename + strlen(filename) - 1);
428          if (end_type == 1) { /* Must end with '/' */          if (end_type == 1) { /* Must end with '/' */
429                  if (c != '/') goto out;                  if (c != '/')
430                            goto out;
431          } else if (end_type == -1) { /* Must not end with '/' */          } else if (end_type == -1) { /* Must not end with '/' */
432                  if (c == '/') goto out;                  if (c == '/')
433                            goto out;
434          }          }
435          while ((c = *filename++) != '\0') {          while (1) {
436                    c = *filename++;
437                    if (!c)
438                            break;
439                  if (c == '\\') {                  if (c == '\\') {
440                          switch ((c = *filename++)) {                          c = *filename++;
441                            switch (c) {
442                          case '\\':  /* "\\" */                          case '\\':  /* "\\" */
443                                  continue;                                  continue;
444                          case '$':   /* "\$" */                          case '$':   /* "\$" */
# Line 164  bool IsCorrectPath(const char *filename, Line 451  bool IsCorrectPath(const char *filename,
451                          case 'a':   /* "\a" */                          case 'a':   /* "\a" */
452                          case 'A':   /* "\A" */                          case 'A':   /* "\A" */
453                          case '-':   /* "\-" */                          case '-':   /* "\-" */
454                                  if (pattern_type == -1) break; /* Must not contain pattern */                                  if (pattern_type == -1)
455                                  contains_pattern = 1;                                          break; /* Must not contain pattern */
456                                    contains_pattern = true;
457                                    continue;
458                            case '{':   /* "/\{" */
459                                    if (filename - 3 < start ||
460                                        *(filename - 3) != '/')
461                                            break;
462                                    if (pattern_type == -1)
463                                            break; /* Must not contain pattern */
464                                    contains_pattern = true;
465                                    in_repetition = true;
466                                    continue;
467                            case '}':   /* "\}/" */
468                                    if (*filename != '/')
469                                            break;
470                                    if (!in_repetition)
471                                            break;
472                                    in_repetition = false;
473                                  continue;                                  continue;
474                          case '0':   /* "\ooo" */                          case '0':   /* "\ooo" */
475                          case '1':                          case '1':
476                          case '2':                          case '2':
477                          case '3':                          case '3':
478                                  if ((d = *filename++) >= '0' && d <= '7' && (e = *filename++) >= '0' && e <= '7') {                                  d = *filename++;
479                                          const unsigned char f =                                  if (d < '0' || d > '7')
480                                                  (((unsigned char) (c - '0')) << 6) +                                          break;
481                                                  (((unsigned char) (d - '0')) << 3) +                                  e = *filename++;
482                                                  (((unsigned char) (e - '0')));                                  if (e < '0' || e > '7')
483                                          if (f && (f <= ' ' || f >= 127)) continue; /* pattern is not \000 */                                          break;
484                                  }                                  c = ccs_make_byte(c, d, e);
485                                    if (c && (c <= ' ' || c >= 127))
486                                            continue; /* pattern is not \000 */
487                          }                          }
488                          goto out;                          goto out;
489                    } else if (in_repetition && c == '/') {
490                            goto out;
491                  } else if (c <= ' ' || c >= 127) {                  } else if (c <= ' ' || c >= 127) {
492                          goto out;                          goto out;
493                  }                  }
494          }          }
495          if (pattern_type == 1) { /* Must contain pattern */          if (pattern_type == 1) { /* Must contain pattern */
496                  if (!contains_pattern) goto out;                  if (!contains_pattern)
497                            goto out;
498          }          }
499          return 1;          if (in_repetition)
500                    goto out;
501            return true;
502   out:   out:
503          printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function, original_filename);          return false;
         return 0;  
504  }  }
505    
506  /*  /**
507   *  Check whether the given domainname follows the naming rules.   * ccs_is_correct_domain - Check whether the given domainname follows the naming rules.
508   *  Returns nonzero if follows, zero otherwise.   * @domainname:   The domainname to check.
509     *
510     * Returns true if @domainname follows the naming rules, false otherwise.
511   */   */
512  bool IsCorrectDomain(const unsigned char *domainname, const char *function)  bool ccs_is_correct_domain(const unsigned char *domainname)
513  {  {
514          unsigned char c, d, e;          unsigned char c;
515          const char *org_domainname = domainname;          unsigned char d;
516          if (!domainname || strncmp(domainname, ROOT_NAME, ROOT_NAME_LEN)) goto out;          unsigned char e;
517            if (!domainname || strncmp(domainname, ROOT_NAME, ROOT_NAME_LEN))
518                    goto out;
519          domainname += ROOT_NAME_LEN;          domainname += ROOT_NAME_LEN;
520          if (!*domainname) return 1;          if (!*domainname)
521                    return true;
522          do {          do {
523                  if (*domainname++ != ' ') goto out;                  if (*domainname++ != ' ')
524                  if (*domainname++ != '/') goto out;                          goto out;
525                  while ((c = *domainname) != '\0' && c != ' ') {                  if (*domainname++ != '/')
526                            goto out;
527                    while (1) {
528                            c = *domainname;
529                            if (!c || c == ' ')
530                                    break;
531                          domainname++;                          domainname++;
532                          if (c == '\\') {                          if (c == '\\') {
533                                  switch ((c = *domainname++)) {                                  c = *domainname++;
534                                    switch ((c)) {
535                                  case '\\':  /* "\\" */                                  case '\\':  /* "\\" */
536                                          continue;                                          continue;
537                                  case '0':   /* "\ooo" */                                  case '0':   /* "\ooo" */
538                                  case '1':                                  case '1':
539                                  case '2':                                  case '2':
540                                  case '3':                                  case '3':
541                                          if ((d = *domainname++) >= '0' && d <= '7' && (e = *domainname++) >= '0' && e <= '7') {                                          d = *domainname++;
542                                                  const unsigned char f =                                          if (d < '0' || d > '7')
543                                                          (((unsigned char) (c - '0')) << 6) +                                                  break;
544                                                          (((unsigned char) (d - '0')) << 3) +                                          e = *domainname++;
545                                                          (((unsigned char) (e - '0')));                                          if (e < '0' || e > '7')
546                                                  if (f && (f <= ' ' || f >= 127)) continue; /* pattern is not \000 */                                                  break;
547                                          }                                          c = ccs_make_byte(c, d, e);
548                                            if (c && (c <= ' ' || c >= 127))
549                                                    /* pattern is not \000 */
550                                                    continue;
551                                  }                                  }
552                                  goto out;                                  goto out;
553                          } else if (c < ' ' || c >= 127) {                          } else if (c < ' ' || c >= 127) {
# Line 231  bool IsCorrectDomain(const unsigned char Line 555  bool IsCorrectDomain(const unsigned char
555                          }                          }
556                  }                  }
557          } while (*domainname);          } while (*domainname);
558          return 1;          return true;
559   out:   out:
560          printk(KERN_DEBUG "%s: Invalid domainname '%s'\n", function, org_domainname);          return false;
         return 0;  
561  }  }
562    
563  bool IsDomainDef(const unsigned char *buffer)  /**
564     * ccs_is_domain_def - Check whether the given token can be a domainname.
565     *
566     * @buffer: The token to check.
567     *
568     * Returns true if @buffer possibly be a domainname, false otherwise.
569     */
570    bool ccs_is_domain_def(const unsigned char *buffer)
571  {  {
572          /* while (*buffer && (*buffer <= ' ' || *buffer >= 127)) buffer++; */          return !strncmp(buffer, ROOT_NAME, ROOT_NAME_LEN);
         return strncmp(buffer, ROOT_NAME, ROOT_NAME_LEN) == 0;  
573  }  }
574    
575  struct domain_info *FindDomain(const char *domainname0)  /**
576     * ccs_find_domain - Find a domain by the given name.
577     *
578     * @domainname: The domainname to find.
579     *
580     * Returns pointer to "struct ccs_domain_info" if found, NULL otherwise.
581     *
582     * Caller holds ccs_read_lock().
583     */
584    struct ccs_domain_info *ccs_find_domain(const char *domainname)
585  {  {
586          struct domain_info *domain;          struct ccs_domain_info *domain;
587          struct path_info domainname;          struct ccs_path_info name;
588          domainname.name = domainname0;          name.name = domainname;
589          fill_path_info(&domainname);          ccs_fill_path_info(&name);
590          list1_for_each_entry(domain, &domain_list, list) {          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
591                  if (!domain->is_deleted && !pathcmp(&domainname, domain->domainname)) return domain;                  if (!domain->is_deleted &&
592                        !ccs_pathcmp(&name, domain->domainname))
593                            return domain;
594          }          }
595          return NULL;          return NULL;
596  }  }
597    
598  static int PathDepth(const char *pathname)  /**
599  {   * ccs_const_part_length - Evaluate the initial length without a pattern in a token.
600          int i = 0;   *
601          if (pathname) {   * @filename: The string to evaluate.
602                  char *ep = strchr(pathname, '\0');   *
603                  if (pathname < ep--) {   * Returns the initial length without a pattern in @filename.
604                          if (*ep != '/') i++;   */
605                          while (pathname <= ep) if (*ep-- == '/') i += 2;  static int ccs_const_part_length(const char *filename)
                 }  
         }  
         return i;  
 }  
   
 static int const_part_length(const char *filename)  
606  {  {
607            char c;
608          int len = 0;          int len = 0;
609          if (filename) {          if (!filename)
610                  char c;                  return 0;
611                  while ((c = *filename++) != '\0') {          while (1) {
612                          if (c != '\\') { len++; continue; }                  c = *filename++;
613                          switch (c = *filename++) {                  if (!c)
                         case '\\':  /* "\\" */  
                                 len += 2; continue;  
                         case '0':   /* "\ooo" */  
                         case '1':  
                         case '2':  
                         case '3':  
                                 if ((c = *filename++) >= '0' && c <= '7' && (c = *filename++) >= '0' && c <= '7') { len += 4; continue; }  
                         }  
614                          break;                          break;
615                    if (c != '\\') {
616                            len++;
617                            continue;
618                    }
619                    c = *filename++;
620                    switch (c) {
621                    case '\\':  /* "\\" */
622                            len += 2;
623                            continue;
624                    case '0':   /* "\ooo" */
625                    case '1':
626                    case '2':
627                    case '3':
628                            c = *filename++;
629                            if (c < '0' || c > '7')
630                                    break;
631                            c = *filename++;
632                            if (c < '0' || c > '7')
633                                    break;
634                            len += 4;
635                            continue;
636                  }                  }
637                    break;
638          }          }
639          return len;          return len;
640  }  }
641    
642  void fill_path_info(struct path_info *ptr)  /**
643     * ccs_fill_path_info - Fill in "struct ccs_path_info" members.
644     *
645     * @ptr: Pointer to "struct ccs_path_info" to fill in.
646     *
647     * The caller sets "struct ccs_path_info"->name.
648     */
649    void ccs_fill_path_info(struct ccs_path_info *ptr)
650  {  {
651          const char *name = ptr->name;          const char *name = ptr->name;
652          const int len = strlen(name);          const int len = strlen(name);
653          ptr->total_len = len;          ptr->total_len = len;
654          ptr->const_len = const_part_length(name);          ptr->const_len = ccs_const_part_length(name);
655          ptr->is_dir = len && (name[len - 1] == '/');          ptr->is_dir = len && (name[len - 1] == '/');
656          ptr->is_patterned = (ptr->const_len < len);          ptr->is_patterned = (ptr->const_len < len);
657          ptr->hash = full_name_hash(name, len);          ptr->hash = full_name_hash(name, len);
         ptr->depth = PathDepth(name);  
658  }  }
659    
660  static int FileMatchesToPattern2(const char *filename, const char *filename_end, const char *pattern, const char *pattern_end)  /**
661     * ccs_file_matches_pattern2 - Pattern matching without '/' character
662     * and "\-" pattern.
663     *
664     * @filename:     The start of string to check.
665     * @filename_end: The end of string to check.
666     * @pattern:      The start of pattern to compare.
667     * @pattern_end:  The end of pattern to compare.
668     *
669     * Returns true if @filename matches @pattern, false otherwise.
670     */
671    static bool ccs_file_matches_pattern2(const char *filename,
672                                          const char *filename_end,
673                                          const char *pattern,
674                                          const char *pattern_end)
675  {  {
676          while (filename < filename_end && pattern < pattern_end) {          while (filename < filename_end && pattern < pattern_end) {
677                    char c;
678                  if (*pattern != '\\') {                  if (*pattern != '\\') {
679                          if (*filename++ != *pattern++) return 0;                          if (*filename++ != *pattern++)
680                  } else {                                  return false;
681                          char c = *filename;                          continue;
682                          pattern++;                  }
683                          switch (*pattern) {                  c = *filename;
684                          case '?':                  pattern++;
685                                  if (c == '/') {                  switch (*pattern) {
686                                          return 0;                          int i;
687                                  } else if (c == '\\') {                          int j;
688                                          if ((c = filename[1]) == '\\') {                  case '?':
689                                                  filename++; /* safe because filename is \\ */                          if (c == '/') {
690                                          } else if (c >= '0' && c <= '3' && (c = filename[2]) >= '0' && c <= '7' && (c = filename[3]) >= '0' && c <= '7') {                                  return false;
691                                                  filename += 3; /* safe because filename is \ooo */                          } else if (c == '\\') {
692                                          } else {                                  if (filename[1] == '\\')
693                                                  return 0;                                          filename++;
694                                          }                                  else if (ccs_is_byte_range(filename + 1))
695                                  }                                          filename += 3;
696                                  break;                                  else
697                          case '\\':                                          return false;
698                                  if (c != '\\') return 0;                          }
699                                  if (*++filename != '\\') return 0; /* safe because *filename != '\0' */                          break;
700                                  break;                  case '\\':
701                          case '+':                          if (c != '\\')
702                                  if (c < '0' || c > '9') return 0;                                  return false;
703                                  break;                          if (*++filename != '\\')
704                          case 'x':                                  return false;
705                                  if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) return 0;                          break;
706                                  break;                  case '+':
707                          case 'a':                          if (!ccs_is_decimal(c))
708                                  if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))) return 0;                                  return false;
709                            break;
710                    case 'x':
711                            if (!ccs_is_hexadecimal(c))
712                                    return false;
713                            break;
714                    case 'a':
715                            if (!ccs_is_alphabet_char(c))
716                                    return false;
717                            break;
718                    case '0':
719                    case '1':
720                    case '2':
721                    case '3':
722                            if (c == '\\' && ccs_is_byte_range(filename + 1)
723                                && strncmp(filename + 1, pattern, 3) == 0) {
724                                    filename += 3;
725                                    pattern += 2;
726                                  break;                                  break;
727                          case '0':                          }
728                          case '1':                          return false; /* Not matched. */
729                          case '2':                  case '*':
730                          case '3':                  case '@':
731                                  if (c == '\\' && (c = filename[1]) >= '0' && c <= '3' && c == *pattern                          for (i = 0; i <= filename_end - filename; i++) {
732                                          && (c = filename[2]) >= '0' && c <= '7' && c == pattern[1]                                  if (ccs_file_matches_pattern2(filename + i,
733                                          && (c = filename[3]) >= '0' && c <= '7' && c == pattern[2]) {                                                                filename_end,
734                                          filename += 3; /* safe because filename is \ooo */                                                                pattern + 1,
735                                          pattern += 2; /* safe because pattern is \ooo  */                                                                pattern_end))
736                                            return true;
737                                    c = filename[i];
738                                    if (c == '.' && *pattern == '@')
739                                          break;                                          break;
740                                  }                                  if (c != '\\')
741                                  return 0; /* Not matched. */                                          continue;
742                          case '*':                                  if (filename[i + 1] == '\\')
743                          case '@':                                          i++;
744                                  {                                  else if (ccs_is_byte_range(filename + i + 1))
745                                          int i;                                          i += 3;
746                                          for (i = 0; i <= filename_end - filename; i++) {                                  else
747                                                  if (FileMatchesToPattern2(filename + i, filename_end, pattern + 1, pattern_end)) return 1;                                          break; /* Bad pattern. */
748                                                  if ((c = filename[i]) == '.' && *pattern == '@') break;                          }
749                                                  if (c == '\\') {                          return false; /* Not matched. */
750                                                          if ((c = filename[i + 1]) == '\\') {                  default:
751                                                                  i++; /* safe because filename is \\ */                          j = 0;
752                                                          } else if (c >= '0' && c <= '3' && (c = filename[i + 2]) >= '0' && c <= '7' && (c = filename[i + 3]) >= '0' && c <= '7') {                          c = *pattern;
753                                                                  i += 3; /* safe because filename is \ooo */                          if (c == '$') {
754                                                          } else {                                  while (ccs_is_decimal(filename[j]))
755                                                                  break; /* Bad pattern. */                                          j++;
756                                                          }                          } else if (c == 'X') {
757                                                  }                                  while (ccs_is_hexadecimal(filename[j]))
758                                          }                                          j++;
759                                          return 0; /* Not matched. */                          } else if (c == 'A') {
760                                  }                                  while (ccs_is_alphabet_char(filename[j]))
761                          default:                                          j++;
                                 {  
                                         int i, j = 0;  
                                         if ((c = *pattern) == '$') {  
                                                 while ((c = filename[j]) >= '0' && c <= '9') j++;  
                                         } else if (c == 'X') {  
                                                 while (((c = filename[j]) >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) j++;  
                                         } else if (c == 'A') {  
                                                 while (((c = filename[j]) >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) j++;  
                                         }  
                                         for (i = 1; i <= j; i++) {  
                                                 if (FileMatchesToPattern2(filename + i, filename_end, pattern + 1, pattern_end)) return 1;  
                                         }  
                                 }  
                                 return 0; /* Not matched or bad pattern. */  
762                          }                          }
763                          filename++; /* safe because *filename != '\0' */                          for (i = 1; i <= j; i++) {
764                          pattern++; /* safe because *pattern != '\0' */                                  if (ccs_file_matches_pattern2(filename + i,
765                                                                  filename_end,
766                                                                  pattern + 1,
767                                                                  pattern_end))
768                                            return true;
769                            }
770                            return false; /* Not matched or bad pattern. */
771                  }                  }
772                    filename++;
773                    pattern++;
774          }          }
775          while (*pattern == '\\' && (*(pattern + 1) == '*' || *(pattern + 1) == '@')) pattern += 2;          while (*pattern == '\\' &&
776          return (filename == filename_end && pattern == pattern_end);                 (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
777                    pattern += 2;
778            return filename == filename_end && pattern == pattern_end;
779  }  }
780    
781  static int FileMatchesToPattern(const char *filename, const char *filename_end, const char *pattern, const char *pattern_end)  /**
782     * ccs_file_matches_pattern - Pattern matching without without '/' character.
783     *
784     * @filename:     The start of string to check.
785     * @filename_end: The end of string to check.
786     * @pattern:      The start of pattern to compare.
787     * @pattern_end:  The end of pattern to compare.
788     *
789     * Returns true if @filename matches @pattern, false otherwise.
790     */
791    static bool ccs_file_matches_pattern(const char *filename,
792                                         const char *filename_end,
793                                         const char *pattern,
794                                         const char *pattern_end)
795  {  {
796          const char *pattern_start = pattern;          const char *pattern_start = pattern;
797          int first = 1;          bool first = true;
798          int result;          bool result;
799          while (pattern < pattern_end - 1) {          while (pattern < pattern_end - 1) {
800                  if (*pattern++ != '\\' || *pattern++ != '-') continue;                  /* Split at "\-" pattern. */
801                  result = FileMatchesToPattern2(filename, filename_end, pattern_start, pattern - 2);                  if (*pattern++ != '\\' || *pattern++ != '-')
802                  if (first) result = !result;                          continue;
803                  if (result) return 0;                  result = ccs_file_matches_pattern2(filename, filename_end,
804                  first = 0;                                                     pattern_start, pattern - 2);
805                    if (first)
806                            result = !result;
807                    if (result)
808                            return false;
809                    first = false;
810                  pattern_start = pattern;                  pattern_start = pattern;
811          }          }
812          result = FileMatchesToPattern2(filename, filename_end, pattern_start, pattern_end);          result = ccs_file_matches_pattern2(filename, filename_end,
813                                               pattern_start, pattern_end);
814          return first ? result : !result;          return first ? result : !result;
815  }  }
816    
817  /*  /**
818   *  Check whether the given pathname matches to the given pattern.   * ccs_path_matches_pattern2 - Do pathname pattern matching.
  *  Returns nonzero if matches, zero otherwise.  
819   *   *
820   *  The following patterns are available.   * @f: The start of string to check.
821   *    \\     \ itself.   * @p: The start of pattern to compare.
822   *    \ooo   Octal representation of a byte.   *
823   *    \*     More than or equals to 0 character other than '/'.   * Returns true if @f matches @p, false otherwise.
  *    \@     More than or equals to 0 character other than '/' or '.'.  
  *    \?     1 byte character other than '/'.  
  *    \$     More than or equals to 1 decimal digit.  
  *    \+     1 decimal digit.  
  *    \X     More than or equals to 1 hexadecimal digit.  
  *    \x     1 hexadecimal digit.  
  *    \A     More than or equals to 1 alphabet character.  
  *    \a     1 alphabet character.  
  *    \-     Subtraction operator.  
  */  
   
 int PathMatchesToPattern(const struct path_info *pathname0, const struct path_info *pattern0)  
 {  
         /* if (!pathname || !pattern) return 0; */  
         const char *pathname = pathname0->name, *pattern = pattern0->name;  
         const int len = pattern0->const_len;  
         if (!pattern0->is_patterned) return !pathcmp(pathname0, pattern0);  
         if (pathname0->depth != pattern0->depth) return 0;  
         if (strncmp(pathname, pattern, len)) return 0;  
         pathname += len; pattern += len;  
         while (*pathname && *pattern) {  
                 const char *pathname_delimiter = strchr(pathname, '/'), *pattern_delimiter = strchr(pattern, '/');  
                 if (!pathname_delimiter) pathname_delimiter = strchr(pathname, '\0');  
                 if (!pattern_delimiter) pattern_delimiter = strchr(pattern, '\0');  
                 if (!FileMatchesToPattern(pathname, pathname_delimiter, pattern, pattern_delimiter)) return 0;  
                 pathname = *pathname_delimiter ? pathname_delimiter + 1 : pathname_delimiter;  
                 pattern = *pattern_delimiter ? pattern_delimiter + 1 : pattern_delimiter;  
         }  
         while (*pattern == '\\' && (*(pattern + 1) == '*' || *(pattern + 1) == '@')) pattern += 2;  
         return (!*pathname && !*pattern);  
 }  
   
 /*  
  *  Transactional printf() to struct io_buffer structure.  
  *  snprintf() will truncate, but io_printf() won't.  
  *  Returns zero on success, nonzero otherwise.  
824   */   */
825  int io_printf(struct io_buffer *head, const char *fmt, ...)  static bool ccs_path_matches_pattern2(const char *f, const char *p)
826  {  {
827          va_list args;          const char *f_delimiter;
828          int len, pos = head->read_avail, size = head->readbuf_size - pos;          const char *p_delimiter;
829          if (size <= 0) return -ENOMEM;          while (*f && *p) {
830          va_start(args, fmt);                  f_delimiter = strchr(f, '/');
831          len = vsnprintf(head->read_buf + pos, size, fmt, args);                  if (!f_delimiter)
832          va_end(args);                          f_delimiter = strchr(f, '\0');
833          if (pos + len >= head->readbuf_size) return -ENOMEM;                  p_delimiter = strchr(p, '/');
834          head->read_avail += len;                  if (!p_delimiter)
835          return 0;                          p_delimiter = strchr(p, '\0');
836                    if (*p == '\\' && *(p + 1) == '{')
837                            goto recursive;
838                    if (!ccs_file_matches_pattern(f, f_delimiter, p, p_delimiter))
839                            return false;
840                    f = f_delimiter;
841                    if (*f)
842                            f++;
843                    p = p_delimiter;
844                    if (*p)
845                            p++;
846            }
847            /* Ignore trailing "\*" and "\@" in @pattern. */
848            while (*p == '\\' &&
849                   (*(p + 1) == '*' || *(p + 1) == '@'))
850                    p += 2;
851            return !*f && !*p;
852     recursive:
853            /*
854             * The "\{" pattern is permitted only after '/' character.
855             * This guarantees that below "*(p - 1)" is safe.
856             * Also, the "\}" pattern is permitted only before '/' character
857             * so that "\{" + "\}" pair will not break the "\-" operator.
858             */
859            if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
860                *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
861                    return false; /* Bad pattern. */
862            do {
863                    /* Compare current component with pattern. */
864                    if (!ccs_file_matches_pattern(f, f_delimiter, p + 2,
865                                                  p_delimiter - 2))
866                            break;
867                    /* Proceed to next component. */
868                    f = f_delimiter;
869                    if (*f)
870                            f++;
871                    /* Continue comparison. */
872                    if (ccs_path_matches_pattern2(f, p_delimiter + 1))
873                            return true;
874                    f_delimiter = strchr(f, '/');
875            } while (f_delimiter);
876            return false; /* Not matched. */
877    }
878    
879    /**
880     * ccs_path_matches_pattern - Check whether the given filename matches the given pattern.
881     * @filename: The filename to check.
882     * @pattern:  The pattern to compare.
883     *
884     * Returns true if matches, false otherwise.
885     *
886     * The following patterns are available.
887     *   \\     \ itself.
888     *   \ooo   Octal representation of a byte.
889     *   \*     Zero or more repetitions of characters other than '/'.
890     *   \@     Zero or more repetitions of characters other than '/' or '.'.
891     *   \?     1 byte character other than '/'.
892     *   \$     One or more repetitions of decimal digits.
893     *   \+     1 decimal digit.
894     *   \X     One or more repetitions of hexadecimal digits.
895     *   \x     1 hexadecimal digit.
896     *   \A     One or more repetitions of alphabet characters.
897     *   \a     1 alphabet character.
898     *
899     *   \-     Subtraction operator.
900     *
901     *   /\{dir\}/   One or more repetitions of dir (e.g. /dir/ /dir/dir/
902     *               /dir/dir/dir/ ).
903     */
904    bool ccs_path_matches_pattern(const struct ccs_path_info *filename,
905                                  const struct ccs_path_info *pattern)
906    {
907            /*
908              if (!filename || !pattern)
909              return false;
910            */
911            const char *f = filename->name;
912            const char *p = pattern->name;
913            const int len = pattern->const_len;
914            /* If @pattern doesn't contain pattern, I can use strcmp(). */
915            if (!pattern->is_patterned)
916                    return !ccs_pathcmp(filename, pattern);
917            /* Don't compare directory and non-directory. */
918            if (filename->is_dir != pattern->is_dir)
919                    return false;
920            /* Compare the initial length without patterns. */
921            if (strncmp(f, p, len))
922                    return false;
923            f += len;
924            p += len;
925            return ccs_path_matches_pattern2(f, p);
926  }  }
927    
928  /*  /**
929   * Get realpath() of current process.   * ccs_get_exe - Get ccs_realpath() of current process.
930   * This function uses ccs_alloc(), so caller must ccs_free() if this function didn't return NULL.   *
931     * Returns the ccs_realpath() of current process on success, NULL otherwise.
932     *
933     * This function uses kzalloc(), so the caller must kfree()
934     * if this function didn't return NULL.
935   */   */
936  const char *GetEXE(void)  const char *ccs_get_exe(void)
937  {  {
938          struct mm_struct *mm = current->mm;          struct mm_struct *mm = current->mm;
939          struct vm_area_struct *vma;          struct vm_area_struct *vma;
940          const char *cp = NULL;          const char *cp = NULL;
941          if (!mm) return NULL;          if (!mm)
942                    return NULL;
943          down_read(&mm->mmap_sem);          down_read(&mm->mmap_sem);
944          for (vma = mm->mmap; vma; vma = vma->vm_next) {          for (vma = mm->mmap; vma; vma = vma->vm_next) {
945                  if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {                  if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
946                          cp = realpath_from_dentry(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt);  #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
947                          break;                          struct path path = { vma->vm_file->f_vfsmnt,
948                  }                                               vma->vm_file->f_dentry };
949          }                          cp = ccs_realpath_from_path(&path);
950          up_read(&mm->mmap_sem);  #else
951          return cp;                          cp = ccs_realpath_from_path(&vma->vm_file->f_path);
 }  
   
 const char *GetMSG(const bool is_enforce)  
 {  
         if (is_enforce) return "ERROR"; else return "WARNING";  
 }  
   
 const char *GetAltExec(void)  
 {  
         const u8 profile = current->domain_info->profile;  
         const struct path_info *alt_exec = profile_ptr[profile] ? profile_ptr[profile]->alt_exec : NULL;  
         return alt_exec ? alt_exec->name : NULL;  
 }  
   
 /*************************  DOMAIN POLICY HANDLER  *************************/  
   
 /* Check whether the given access control is enabled. */  
 unsigned int CheckCCSFlags(const u8 index)  
 {  
         const u8 profile = current->domain_info->profile;  
         return sbin_init_started && index < CCS_MAX_CONTROL_INDEX  
 #if MAX_PROFILES != 256  
                 && profile < MAX_PROFILES  
 #endif  
                 && profile_ptr[profile] ? profile_ptr[profile]->value[index] : 0;  
 }  
   
 bool TomoyoVerboseMode(void)  
 {  
         return CheckCCSFlags(CCS_TOMOYO_VERBOSE) != 0;  
 }  
   
 bool CheckDomainQuota(struct domain_info * const domain)  
 {  
         unsigned int count = 0;  
         struct acl_info *ptr;  
         if (!domain) return 1;  
         list1_for_each_entry(ptr, &domain->acl_info_list, list) {  
                 if (!ptr->is_deleted) count++;  
         }  
         if (count < CheckCCSFlags(CCS_TOMOYO_MAX_ACCEPT_ENTRY)) return 1;  
         if (!domain->quota_warned) {  
                 domain->quota_warned = 1;  
                 printk("TOMOYO-WARNING: Domain '%s' has so many ACLs to hold. Stopped learning mode.\n", domain->domainname->name);  
         }  
         return 0;  
 }  
   
 static struct profile *FindOrAssignNewProfile(const unsigned int profile)  
 {  
         static DEFINE_MUTEX(profile_lock);  
         struct profile *ptr = NULL;  
         mutex_lock(&profile_lock);  
         if (profile < MAX_PROFILES && (ptr = profile_ptr[profile]) == NULL) {  
                 if ((ptr = alloc_element(sizeof(*ptr))) != NULL) {  
                         int i;  
                         for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) ptr->value[i] = ccs_control_array[i].current_value;  
                         mb(); /* Avoid out-of-order execution. */  
                         profile_ptr[profile] = ptr;  
                 }  
         }  
         mutex_unlock(&profile_lock);  
         return ptr;  
 }  
   
 /* #define ALT_EXEC */  
   
 static int SetProfile(struct io_buffer *head)  
 {  
         char *data = head->write_buf;  
         unsigned int i, value;  
         char *cp;  
         struct profile *profile;  
         if (!isRoot()) return -EPERM;  
         i = simple_strtoul(data, &cp, 10);  
         if (data != cp) {  
                 if (*cp != '-') return -EINVAL;  
                 data= cp + 1;  
         }  
         profile = FindOrAssignNewProfile(i);  
         if (!profile) return -EINVAL;  
         cp = strchr(data, '=');  
         if (!cp) return -EINVAL;  
         *cp = '\0';  
         UpdateCounter(CCS_UPDATES_COUNTER_PROFILE);  
         if (strcmp(data, ccs_control_array[CCS_PROFILE_COMMENT].keyword) == 0) {  
                 profile->comment = SaveName(cp + 1);  
                 return 0;  
         }  
 #ifdef ALT_EXEC  
 #ifdef CONFIG_TOMOYO  
         if (strcmp(data, ccs_control_array[CCS_TOMOYO_ALT_EXEC].keyword) == 0) {  
                 cp++;  
                 if (*cp && !IsCorrectPath(cp, 1, -1, -1, __FUNCTION__)) cp = "";  
                 profile->alt_exec = SaveName(cp);  
                 return 0;  
         }  
 #endif  
 #endif  
         if (sscanf(cp + 1, "%u", &value) != 1) return -EINVAL;  
 #ifdef CONFIG_TOMOYO  
         if (strncmp(data, KEYWORD_MAC_FOR_CAPABILITY, KEYWORD_MAC_FOR_CAPABILITY_LEN) == 0) {  
                 return SetCapabilityStatus(data + KEYWORD_MAC_FOR_CAPABILITY_LEN, value, i);  
         }  
 #endif  
         for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) {  
                 if (strcmp(data, ccs_control_array[i].keyword)) continue;  
                 if (value > ccs_control_array[i].max_value) value = ccs_control_array[i].max_value;  
                 profile->value[i] = value;  
                 return 0;  
         }  
         return -EINVAL;  
 }  
   
 static int ReadProfile(struct io_buffer *head)  
 {  
         if (!head->read_eof) {  
                 if (!isRoot()) return -EPERM;  
                 if (!head->read_var2) {  
                         int step;  
                         for (step = head->read_step; step < MAX_PROFILES * CCS_MAX_CONTROL_INDEX; step++) {  
                                 const int i = step / CCS_MAX_CONTROL_INDEX, j = step % CCS_MAX_CONTROL_INDEX;  
                                 const struct profile *profile = profile_ptr[i];  
                                 head->read_step = step;  
                                 if (!profile) continue;  
                                 switch (j) {  
                                 case -1: /* Dummy */  
 #ifndef CONFIG_SAKURA  
                                 case CCS_SAKURA_DENY_CONCEAL_MOUNT:  
                                 case CCS_SAKURA_RESTRICT_CHROOT:  
                                 case CCS_SAKURA_RESTRICT_MOUNT:  
                                 case CCS_SAKURA_RESTRICT_UNMOUNT:  
                                 case CCS_SAKURA_RESTRICT_PIVOT_ROOT:  
                                 case CCS_SAKURA_RESTRICT_AUTOBIND:  
 #endif  
 #ifndef CONFIG_TOMOYO  
                                 case CCS_TOMOYO_MAC_FOR_FILE:  
                                 case CCS_TOMOYO_MAC_FOR_ARGV0:  
                                 case CCS_TOMOYO_MAC_FOR_ENV:  
                                 case CCS_TOMOYO_MAC_FOR_NETWORK:  
                                 case CCS_TOMOYO_MAC_FOR_SIGNAL:  
                                 case CCS_TOMOYO_MAX_ACCEPT_ENTRY:  
                                 case CCS_TOMOYO_MAX_GRANT_LOG:  
                                 case CCS_TOMOYO_MAX_REJECT_LOG:  
                                 case CCS_TOMOYO_VERBOSE:  
 #endif  
 #ifndef ALT_EXEC  
                                 case CCS_TOMOYO_ALT_EXEC:  
                                 case CCS_SLEEP_PERIOD:  
 #endif  
                                         continue;  
                                 }  
                                 if (j == CCS_PROFILE_COMMENT) {  
                                         if (io_printf(head, "%u-%s=%s\n", i, ccs_control_array[CCS_PROFILE_COMMENT].keyword, profile->comment ? profile->comment->name : "")) break;  
                                 } else if (j == CCS_TOMOYO_ALT_EXEC) {  
                                         const struct path_info *alt_exec = profile->alt_exec;  
                                         if (io_printf(head, "%u-%s=%s\n", i, ccs_control_array[CCS_TOMOYO_ALT_EXEC].keyword, alt_exec ? alt_exec->name : "")) break;  
                                 } else {  
                                         if (io_printf(head, "%u-%s=%u\n", i, ccs_control_array[j].keyword, profile->value[j])) break;  
                                 }  
                         }  
                         if (step == MAX_PROFILES * CCS_MAX_CONTROL_INDEX) {  
                                 head->read_var2 = (void *) "";  
                                 head->read_step = 0;  
                         }  
                 }  
                 if (head->read_var2) {  
 #ifdef CONFIG_TOMOYO  
                         if (ReadCapabilityStatus(head) == 0)  
952  #endif  #endif
                                 head->read_eof = 1;  
                 }  
         }  
         return 0;  
 }  
   
 /*************************  POLICY MANAGER HANDLER  *************************/  
   
 struct policy_manager_entry {  
         struct list1_head list;  
         const struct path_info *manager;  
         bool is_domain;  
         bool is_deleted;  
 };  
   
 static LIST1_HEAD(policy_manager_list);  
   
 static int AddManagerEntry(const char *manager, const bool is_delete)  
 {  
         struct policy_manager_entry *new_entry, *ptr;  
         static DEFINE_MUTEX(lock);  
         const struct path_info *saved_manager;  
         int error = -ENOMEM;  
         bool is_domain = 0;  
         if (!isRoot()) return -EPERM;  
         if (IsDomainDef(manager)) {  
                 if (!IsCorrectDomain(manager, __FUNCTION__)) return -EINVAL;  
                 is_domain = 1;  
         } else {  
                 if (!IsCorrectPath(manager, 1, -1, -1, __FUNCTION__)) return -EINVAL;  
         }  
         if ((saved_manager = SaveName(manager)) == NULL) return -ENOMEM;  
         mutex_lock(&lock);  
         list1_for_each_entry(ptr, &policy_manager_list, list) {  
                 if (ptr->manager == saved_manager) {  
                         ptr->is_deleted = is_delete;  
                         error = 0;  
                         goto out;  
                 }  
         }  
         if (is_delete) {  
                 error = -ENOENT;  
                 goto out;  
         }  
         if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;  
         new_entry->manager = saved_manager;  
         new_entry->is_domain = is_domain;  
         list1_add_tail_mb(&new_entry->list, &policy_manager_list);  
         error = 0;  
  out:  
         mutex_unlock(&lock);  
         if (!error) UpdateCounter(CCS_UPDATES_COUNTER_MANAGER);  
         return error;  
 }  
   
 static int AddManagerPolicy(struct io_buffer *head)  
 {  
         const char *data = head->write_buf;  
         bool is_delete = 0;  
         if (!isRoot()) return -EPERM;  
         if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {  
                 data += KEYWORD_DELETE_LEN;  
                 is_delete = 1;  
         }  
         return AddManagerEntry(data, is_delete);  
 }  
   
 static int ReadManagerPolicy(struct io_buffer *head)  
 {  
         struct list1_head *pos;  
         if (head->read_eof) return 0;  
         if (!isRoot()) return -EPERM;  
         list1_for_each_cookie(pos, head->read_var2, &policy_manager_list) {  
                 struct policy_manager_entry *ptr;  
                 ptr = list1_entry(pos, struct policy_manager_entry, list);  
                 if (ptr->is_deleted) continue;  
                 if (io_printf(head, "%s\n", ptr->manager->name)) return 0;  
         }  
         head->read_eof = 1;  
         return 0;  
 }  
   
 /* Check whether the current process is a policy manager. */  
 static int IsPolicyManager(void)  
 {  
         struct policy_manager_entry *ptr;  
         const char *exe;  
         const struct path_info *domainname = current->domain_info->domainname;  
         bool found = 0;  
         if (!sbin_init_started) return 1;  
         list1_for_each_entry(ptr, &policy_manager_list, list) {  
                 if (!ptr->is_deleted && ptr->is_domain && !pathcmp(domainname, ptr->manager)) return 1;  
         }  
         if ((exe = GetEXE()) == NULL) return 0;  
         list1_for_each_entry(ptr, &policy_manager_list, list) {  
                 if (!ptr->is_deleted && !ptr->is_domain && !strcmp(exe, ptr->manager->name)) {  
                         found = 1;  
953                          break;                          break;
954                  }                  }
955          }          }
956          if (!found) { /* Reduce error messages. */          up_read(&mm->mmap_sem);
                 static pid_t last_pid = 0;  
                 const pid_t pid = current->pid;  
                 if (last_pid != pid) {  
                         printk("%s ( %s ) is not permitted to update policies.\n", domainname->name, exe);  
                         last_pid = pid;  
                 }  
         }  
         ccs_free(exe);  
         return found;  
 }  
   
 #ifdef CONFIG_TOMOYO  
   
 /*************************  DOMAIN POLICY HANDLER  *************************/  
   
 static char *FindConditionPart(char *data)  
 {  
         char *cp = strstr(data, " if "), *cp2;  
         if (cp) {  
                 while ((cp2 = strstr(cp + 3, " if ")) != NULL) cp = cp2;  
                 *cp++ = '\0';  
         }  
957          return cp;          return cp;
958  }  }
959    
960  static int AddDomainPolicy(struct io_buffer *head)  /**
961     * ccs_get_audit - Get audit mode.
962     *
963     * @profile:    Profile number.
964     * @index:      Index number of functionality.
965     * @is_granted: True if granted log, false otehrwise.
966     *
967     * Returns mode.
968     */
969    bool ccs_get_audit(const u8 profile, const u8 index, const bool is_granted)
970  {  {
971          char *data = head->write_buf;          u8 mode;
972          struct domain_info *domain = head->write_var1;          const u8 category = ccs_index2category[index] + CCS_MAX_MAC_INDEX
973          bool is_delete = 0, is_select = 0, is_undelete = 0;                  + CCS_MAX_CAPABILITY_INDEX;
974          unsigned int profile;          if (!ccs_policy_loaded)
975          const struct condition_list *cond = NULL;                  return false;
976          char *cp;                mode = ccs_profile(profile)->config[index];
977          if (!isRoot()) return -EPERM;          if (mode == CCS_CONFIG_USE_DEFAULT)
978          if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {                  mode = ccs_profile(profile)->config[category];
979                  data += KEYWORD_DELETE_LEN;          if (mode == CCS_CONFIG_USE_DEFAULT)
980                  is_delete = 1;                  mode = ccs_profile(profile)->default_config;
981          } else if (strncmp(data, KEYWORD_SELECT, KEYWORD_SELECT_LEN) == 0) {          if (is_granted)
982                  data += KEYWORD_SELECT_LEN;                  return mode & CCS_CONFIG_WANT_GRANT_LOG;
983                  is_select = 1;          return mode & CCS_CONFIG_WANT_REJECT_LOG;
         } else if (strncmp(data, KEYWORD_UNDELETE, KEYWORD_UNDELETE_LEN) == 0) {  
                 data += KEYWORD_UNDELETE_LEN;  
                 is_undelete = 1;  
         }  
         UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);  
         if (IsDomainDef(data)) {  
                 if (is_delete) {  
                         DeleteDomain(data);  
                         domain = NULL;  
                 } else if (is_select) {  
                         domain = FindDomain(data);  
                 } else if (is_undelete) {  
                         domain = UndeleteDomain(data);  
                 } else {  
                         domain = FindOrAssignNewDomain(data, 0);  
                 }  
                 head->write_var1 = domain;  
                 return 0;  
         }  
         if (!domain) return -EINVAL;  
   
         if (sscanf(data, KEYWORD_USE_PROFILE "%u", &profile) == 1 && profile < MAX_PROFILES) {  
                 if (profile_ptr[profile] || !sbin_init_started) domain->profile = (u8) profile;  
                 return 0;  
         }  
         cp = FindConditionPart(data);  
         if (cp && (cond = FindOrAssignNewCondition(cp)) == NULL) return -EINVAL;  
         if (strncmp(data, KEYWORD_ALLOW_CAPABILITY, KEYWORD_ALLOW_CAPABILITY_LEN) == 0) {  
                 return AddCapabilityPolicy(data + KEYWORD_ALLOW_CAPABILITY_LEN, domain, cond, is_delete);  
         } else if (strncmp(data, KEYWORD_ALLOW_NETWORK, KEYWORD_ALLOW_NETWORK_LEN) == 0) {  
                 return AddNetworkPolicy(data + KEYWORD_ALLOW_NETWORK_LEN, domain, cond, is_delete);  
         } else if (strncmp(data, KEYWORD_ALLOW_SIGNAL, KEYWORD_ALLOW_SIGNAL_LEN) == 0) {  
                 return AddSignalPolicy(data + KEYWORD_ALLOW_SIGNAL_LEN, domain, cond, is_delete);  
         } else if (strncmp(data, KEYWORD_ALLOW_ARGV0, KEYWORD_ALLOW_ARGV0_LEN) == 0) {  
                 return AddArgv0Policy(data + KEYWORD_ALLOW_ARGV0_LEN, domain, cond, is_delete);  
         } else if (strncmp(data, KEYWORD_ALLOW_ENV, KEYWORD_ALLOW_ENV_LEN) == 0) {  
                 return AddEnvPolicy(data + KEYWORD_ALLOW_ENV_LEN, domain, cond, is_delete);  
         } else {  
                 return AddFilePolicy(data, domain, cond, is_delete);  
         }  
         return -EINVAL;  
 }  
   
 static int ReadDomainPolicy(struct io_buffer *head)  
 {  
         struct list1_head *dpos;  
         struct list1_head *apos;  
         if (head->read_eof) return 0;  
         if (head->read_step == 0) {  
                 if (!isRoot()) return -EPERM;  
                 head->read_step = 1;  
         }  
         list1_for_each_cookie(dpos, head->read_var1, &domain_list) {  
                 struct domain_info *domain;  
                 domain = list1_entry(dpos, struct domain_info, list);  
                 if (head->read_step != 1) goto acl_loop;  
                 if (domain->is_deleted) continue;  
                 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;  
                 head->read_step = 2;  
         acl_loop: ;  
                 if (head->read_step == 3) goto tail_mark;  
                 list1_for_each_cookie(apos, head->read_var2, &domain->acl_info_list) {  
                         struct acl_info *ptr;  
                         int pos;  
                         u8 acl_type;  
                         ptr = list1_entry(apos, struct acl_info, list);  
                         if (ptr->is_deleted) continue;  
                         pos = head->read_avail;  
                         acl_type = ptr->type;  
                         if (acl_type == TYPE_SINGLE_PATH_ACL) {  
                                 struct single_acl_record *ptr2 = container_of(ptr, struct single_acl_record, head);  
                                 const bool b = ptr2->u_is_group;  
                                 const u16 perm = ptr2->perm;  
                                 u8 bit = head->read_bit;  
                                 while (bit < MAX_SINGLE_PATH_OPERATION) {  
                                         if (perm & (1 << bit)) {  
                                                 pos = head->read_avail;  
                                                 if (io_printf(head, "allow_%s %s%s ", sp_operation2keyword(bit),  
                                                               b ? "@" : "", b ? ptr2->u.group->group_name->name : ptr2->u.filename->name)  
                                                     || DumpCondition(head, ptr->cond)) {  
                                                         head->read_bit = bit;  
                                                         head->read_avail = pos;  
                                                         return 0;  
                                                 }  
                                         }  
                                         bit++;  
                                 }  
                                 head->read_bit = 0;  
                         } else if (acl_type == TYPE_DOUBLE_PATH_ACL) {  
                                 struct double_acl_record *ptr2 = container_of(ptr, struct double_acl_record, head);  
                                 const bool b0 = ptr2->u1_is_group, b1 = ptr2->u2_is_group;  
                                 const u8 perm = ptr2->perm;  
                                 u8 bit = head->read_bit;  
                                 while (bit < MAX_DOUBLE_PATH_OPERATION) {  
                                         if (perm & (1 << bit)) {  
                                                 pos = head->read_avail;  
                                                 if (io_printf(head, "allow_%s %s%s %s%s", dp_operation2keyword(bit),  
                                                               b0 ? "@" : "", b0 ? ptr2->u1.group1->group_name->name : ptr2->u1.filename1->name,  
                                                               b1 ? "@" : "", b1 ? ptr2->u2.group2->group_name->name : ptr2->u2.filename2->name)  
                                                     || DumpCondition(head, ptr->cond)) {  
                                                         head->read_bit = bit;  
                                                         head->read_avail = pos;  
                                                         return 0;  
                                                 }  
                                         }  
                                         bit++;  
                                 }  
                                 head->read_bit = 0;  
                         } else if (acl_type == TYPE_ARGV0_ACL) {  
                                 struct argv0_acl_record *ptr2 = container_of(ptr, struct argv0_acl_record, head);  
                                 if (io_printf(head, KEYWORD_ALLOW_ARGV0 "%s %s",  
                                               ptr2->filename->name, ptr2->argv0->name)) goto print_acl_rollback;  
                         } else if (acl_type == TYPE_ENV_ACL) {  
                                 struct env_acl_record *ptr2 = container_of(ptr, struct env_acl_record, head);  
                                 if (io_printf(head, KEYWORD_ALLOW_ENV "%s", ptr2->env->name)) goto print_acl_rollback;  
                         } else if (acl_type == TYPE_CAPABILITY_ACL) {  
                                 struct capability_acl_record *ptr2 = container_of(ptr, struct capability_acl_record, head);  
                                 const u32 capability = ptr2->capability;  
                                 u8 bit = head->read_bit;  
                                 while (bit < TOMOYO_MAX_CAPABILITY_INDEX) {  
                                         if (capability & (1 << bit)) {  
                                                 pos = head->read_avail;  
                                                 if (io_printf(head, KEYWORD_ALLOW_CAPABILITY "%s", cap_operation2keyword(bit)) ||  
                                                     DumpCondition(head, ptr->cond)) {  
                                                         head->read_bit = bit;  
                                                         head->read_avail = pos;  
                                                         return 0;  
                                                 }  
                                         }  
                                         bit++;  
                                 }  
                                 head->read_bit = 0;  
                         } else if (acl_type == TYPE_IP_NETWORK_ACL) {  
                                 struct ip_network_acl_record *ptr2 = container_of(ptr, struct ip_network_acl_record, head);  
                                 if (io_printf(head, KEYWORD_ALLOW_NETWORK "%s ", net_operation2keyword(ptr2->operation_type))) goto print_acl_rollback;  
                                 switch (ptr2->record_type) {  
                                 case IP_RECORD_TYPE_ADDRESS_GROUP:  
                                         if (io_printf(head, "@%s", ptr2->u.group->group_name->name)) goto print_acl_rollback;  
                                         break;  
                                 case IP_RECORD_TYPE_IPv4:  
                                         {  
                                                 const u32 min_address = ptr2->u.ipv4.min, max_address = ptr2->u.ipv4.max;  
                                                 if (io_printf(head, "%u.%u.%u.%u", HIPQUAD(min_address))) goto print_acl_rollback;  
                                                 if (min_address != max_address && io_printf(head, "-%u.%u.%u.%u", HIPQUAD(max_address))) goto print_acl_rollback;  
                                         }  
                                         break;  
                                 case IP_RECORD_TYPE_IPv6:  
                                         {  
                                                 char buf[64];  
                                                 const struct in6_addr *min_address = ptr2->u.ipv6.min, *max_address = ptr2->u.ipv6.max;  
                                                 print_ipv6(buf, sizeof(buf), min_address);  
                                                 if (io_printf(head, "%s", buf)) goto print_acl_rollback;  
                                                 if (min_address != max_address) {  
                                                         print_ipv6(buf, sizeof(buf), max_address);  
                                                         if (io_printf(head, "-%s", buf)) goto print_acl_rollback;  
                                                 }  
                                         }  
                                         break;  
                                 }  
                                 {  
                                         const u16 min_port = ptr2->min_port, max_port = ptr2->max_port;  
                                         if (io_printf(head, " %u", min_port)) goto print_acl_rollback;  
                                         if (min_port != max_port && io_printf(head, "-%u", max_port)) goto print_acl_rollback;  
                                 }  
                         } else if (acl_type == TYPE_SIGNAL_ACL) {  
                                 struct signal_acl_record *ptr2 = container_of(ptr, struct signal_acl_record, head);  
                                 if (io_printf(head, KEYWORD_ALLOW_SIGNAL "%u %s", ptr2->sig, ptr2->domainname->name)) goto print_acl_rollback;  
                         } else {  
                                 BUG();  
                         }  
                         if (acl_type != TYPE_SINGLE_PATH_ACL && acl_type != TYPE_DOUBLE_PATH_ACL && acl_type != TYPE_CAPABILITY_ACL && DumpCondition(head, ptr->cond)) {  
                         print_acl_rollback: ;  
                         head->read_avail = pos;  
                         return 0;  
                         }  
                 }  
                 head->read_step = 3;  
         tail_mark: ;  
                 if (io_printf(head, "\n")) return 0;  
                 head->read_step = 1;  
         }  
         head->read_eof = 1;  
         return 0;  
984  }  }
985    
986  #endif  /**
987     * ccs_get_mode - Get MAC mode.
988  static int UpdateDomainProfile(struct io_buffer *head)   *
989     * @profile: Profile number.
990     * @index:   Index number of functionality.
991     *
992     * Returns mode.
993     */
994    int ccs_get_mode(const u8 profile, const u8 index)
995  {  {
996          char *data = head->write_buf;          u8 mode;
997          char *cp = strchr(data, ' ');          const u8 category = ccs_index2category[index] + CCS_MAX_MAC_INDEX
998          struct domain_info *domain;                  + CCS_MAX_CAPABILITY_INDEX;
999          unsigned int profile;          if (!ccs_policy_loaded)
1000          if (!isRoot()) return -EPERM;                  return CCS_CONFIG_DISABLED;
1001          if (!cp) return -EINVAL;          mode = ccs_profile(profile)->config[index];
1002          *cp = '\0';          if (mode == CCS_CONFIG_USE_DEFAULT)
1003          domain = FindDomain(cp + 1);                  mode = ccs_profile(profile)->config[category];
1004          profile = simple_strtoul(data, NULL, 10);          if (mode == CCS_CONFIG_USE_DEFAULT)
1005          if (domain && profile < MAX_PROFILES && (profile_ptr[profile] || !sbin_init_started)) domain->profile = (u8) profile;                  mode = ccs_profile(profile)->default_config;
1006          UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);          return mode & 3;
         return 0;  
 }  
   
 static int ReadDomainProfile(struct io_buffer *head)  
 {  
         struct list1_head *pos;  
         if (head->read_eof) return 0;  
         if (!isRoot()) return -EPERM;  
         list1_for_each_cookie(pos, head->read_var1, &domain_list) {  
                 struct domain_info *domain;  
                 domain = list1_entry(pos, struct domain_info, list);  
                 if (domain->is_deleted) continue;  
                 if (io_printf(head, "%u %s\n", domain->profile, domain->domainname->name)) return 0;  
         }  
         head->read_eof = 1;  
         return 0;  
 }  
   
 static int WritePID(struct io_buffer *head)  
 {  
         head->read_step = (int) simple_strtoul(head->write_buf, NULL, 10);  
         head->read_eof = 0;  
         return 0;  
 }  
   
 static int ReadPID(struct io_buffer *head)  
 {  
         if (head->read_avail == 0 && !head->read_eof) {  
                 const int pid = head->read_step;  
                 struct task_struct *p;  
                 struct domain_info *domain = NULL;  
                 /***** CRITICAL SECTION START *****/  
                 read_lock(&tasklist_lock);  
                 p = find_task_by_pid(pid);  
                 if (p) domain = p->domain_info;  
                 read_unlock(&tasklist_lock);  
                 /***** CRITICAL SECTION END *****/  
                 if (domain) io_printf(head, "%d %u %s", pid, domain->profile, domain->domainname->name);  
                 head->read_eof = 1;  
         }  
         return 0;  
 }  
   
 /*************************  EXCEPTION POLICY HANDLER  *************************/  
   
 #ifdef CONFIG_TOMOYO  
   
 static int AddExceptionPolicy(struct io_buffer *head)  
 {  
         char *data = head->write_buf;  
         bool is_delete = 0;  
         if (!isRoot()) return -EPERM;  
         UpdateCounter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);  
         if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {  
                 data += KEYWORD_DELETE_LEN;  
                 is_delete = 1;  
         }  
         if (strncmp(data, KEYWORD_KEEP_DOMAIN, KEYWORD_KEEP_DOMAIN_LEN) == 0) {  
                 return AddDomainKeeperPolicy(data + KEYWORD_KEEP_DOMAIN_LEN, 0, is_delete);  
         } else if (strncmp(data, KEYWORD_NO_KEEP_DOMAIN, KEYWORD_NO_KEEP_DOMAIN_LEN) == 0) {  
                 return AddDomainKeeperPolicy(data + KEYWORD_NO_KEEP_DOMAIN_LEN, 1, is_delete);  
         } else if (strncmp(data, KEYWORD_INITIALIZE_DOMAIN, KEYWORD_INITIALIZE_DOMAIN_LEN) == 0) {  
                 return AddDomainInitializerPolicy(data + KEYWORD_INITIALIZE_DOMAIN_LEN, 0, is_delete);  
         } else if (strncmp(data, KEYWORD_NO_INITIALIZE_DOMAIN, KEYWORD_NO_INITIALIZE_DOMAIN_LEN) == 0) {  
                 return AddDomainInitializerPolicy(data + KEYWORD_NO_INITIALIZE_DOMAIN_LEN, 1, is_delete);  
         } else if (strncmp(data, KEYWORD_ALIAS, KEYWORD_ALIAS_LEN) == 0) {  
                 return AddAliasPolicy(data + KEYWORD_ALIAS_LEN, is_delete);  
         } else if (strncmp(data, KEYWORD_AGGREGATOR, KEYWORD_AGGREGATOR_LEN) == 0) {  
                 return AddAggregatorPolicy(data + KEYWORD_AGGREGATOR_LEN, is_delete);  
         } else if (strncmp(data, KEYWORD_ALLOW_READ, KEYWORD_ALLOW_READ_LEN) == 0) {  
                 return AddGloballyReadablePolicy(data + KEYWORD_ALLOW_READ_LEN, is_delete);  
         } else if (strncmp(data, KEYWORD_ALLOW_ENV, KEYWORD_ALLOW_ENV_LEN) == 0) {  
                 return AddGloballyUsableEnvPolicy(data + KEYWORD_ALLOW_ENV_LEN, is_delete);  
         } else if (strncmp(data, KEYWORD_FILE_PATTERN, KEYWORD_FILE_PATTERN_LEN) == 0) {  
                 return AddFilePatternPolicy(data + KEYWORD_FILE_PATTERN_LEN, is_delete);  
         } else if (strncmp(data, KEYWORD_PATH_GROUP, KEYWORD_PATH_GROUP_LEN) == 0) {  
                 return AddPathGroupPolicy(data + KEYWORD_PATH_GROUP_LEN, is_delete);  
         } else if (strncmp(data, KEYWORD_DENY_REWRITE, KEYWORD_DENY_REWRITE_LEN) == 0) {  
                 return AddNoRewritePolicy(data + KEYWORD_DENY_REWRITE_LEN, is_delete);  
         } else if (strncmp(data, KEYWORD_ADDRESS_GROUP, KEYWORD_ADDRESS_GROUP_LEN) == 0) {  
                 return AddAddressGroupPolicy(data + KEYWORD_ADDRESS_GROUP_LEN, is_delete);  
         }  
         return -EINVAL;  
 }  
   
 static int ReadExceptionPolicy(struct io_buffer *head)  
 {  
         if (!head->read_eof) {  
                 switch (head->read_step) {  
                 case 0:  
                         if (!isRoot()) return -EPERM;  
                         head->read_var2 = NULL; head->read_step = 1;  
                 case 1:  
                         if (ReadDomainKeeperPolicy(head)) break;  
                         head->read_var2 = NULL; head->read_step = 2;  
                 case 2:  
                         if (ReadGloballyReadablePolicy(head)) break;  
                         head->read_var2 = NULL; head->read_step = 3;  
                 case 3:  
                         if (ReadGloballyUsableEnvPolicy(head)) break;  
                         head->read_var2 = NULL; head->read_step = 4;  
                 case 4:  
                         if (ReadDomainInitializerPolicy(head)) break;  
                         head->read_var2 = NULL; head->read_step = 5;  
                 case 5:  
                         if (ReadAliasPolicy(head)) break;  
                         head->read_var2 = NULL; head->read_step = 6;  
                 case 6:  
                         if (ReadAggregatorPolicy(head)) break;  
                         head->read_var2 = NULL; head->read_step = 7;  
                 case 7:  
                         if (ReadFilePatternPolicy(head)) break;  
                         head->read_var2 = NULL; head->read_step = 8;  
                 case 8:  
                         if (ReadNoRewritePolicy(head)) break;  
                         head->read_var2 = NULL; head->read_step = 9;  
                 case 9:  
                         if (ReadPathGroupPolicy(head)) break;  
                         head->read_var1 = head->read_var2 = NULL; head->read_step = 10;  
                 case 10:  
                         if (ReadAddressGroupPolicy(head)) break;  
                         head->read_eof = 1;  
                         break;  
                 default:  
                         return -EINVAL;  
                 }  
         }  
         return 0;  
1007  }  }
1008    
1009  #endif  /**
1010     * ccs_init_request_info - Initialize "struct ccs_request_info" members.
1011  /*************************  SYSTEM POLICY HANDLER  *************************/   *
1012     * @r:      Pointer to "struct ccs_request_info" to initialize.
1013  #ifdef CONFIG_SAKURA   * @domain: Pointer to "struct ccs_domain_info". NULL for ccs_current_domain().
1014     * @index:  Index number of functionality.
1015  static int AddSystemPolicy(struct io_buffer *head)   *
1016     * Returns mode.
1017     */
1018    int ccs_init_request_info(struct ccs_request_info *r,
1019                              struct ccs_domain_info *domain, const u8 index)
1020  {  {
1021          char *data = head->write_buf;          u8 profile;
1022          bool is_delete = 0;          memset(r, 0, sizeof(*r));
1023          if (!isRoot()) return -EPERM;          if (!domain)
1024          UpdateCounter(CCS_UPDATES_COUNTER_SYSTEM_POLICY);                  domain = ccs_current_domain();
1025          if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {          r->domain = domain;
1026                  data += KEYWORD_DELETE_LEN;          profile = domain->profile;
1027                  is_delete = 1;          r->profile = profile;
1028          }          r->type = index;
1029          if (strncmp(data, KEYWORD_ALLOW_MOUNT, KEYWORD_ALLOW_MOUNT_LEN) == 0)          r->mode = ccs_get_mode(profile, index);
1030                  return AddMountPolicy(data + KEYWORD_ALLOW_MOUNT_LEN, is_delete);          return r->mode;
         if (strncmp(data, KEYWORD_DENY_UNMOUNT, KEYWORD_DENY_UNMOUNT_LEN) == 0)  
                 return AddNoUmountPolicy(data + KEYWORD_DENY_UNMOUNT_LEN, is_delete);  
         if (strncmp(data, KEYWORD_ALLOW_CHROOT, KEYWORD_ALLOW_CHROOT_LEN) == 0)  
                 return AddChrootPolicy(data + KEYWORD_ALLOW_CHROOT_LEN, is_delete);  
         if (strncmp(data, KEYWORD_ALLOW_PIVOT_ROOT, KEYWORD_ALLOW_PIVOT_ROOT_LEN) == 0)  
                 return AddPivotRootPolicy(data + KEYWORD_ALLOW_PIVOT_ROOT_LEN, is_delete);  
         if (strncmp(data, KEYWORD_DENY_AUTOBIND, KEYWORD_DENY_AUTOBIND_LEN) == 0)  
                 return AddReservedPortPolicy(data + KEYWORD_DENY_AUTOBIND_LEN, is_delete);  
         return -EINVAL;  
 }  
   
 static int ReadSystemPolicy(struct io_buffer *head)  
 {  
         if (!head->read_eof) {  
                 switch (head->read_step) {  
                 case 0:  
                         if (!isRoot()) return -EPERM;  
                         head->read_var2 = NULL; head->read_step = 1;  
                 case 1:  
                         if (ReadMountPolicy(head)) break;  
                         head->read_var2 = NULL; head->read_step = 2;  
                 case 2:  
                         if (ReadNoUmountPolicy(head)) break;  
                         head->read_var2 = NULL; head->read_step = 3;  
                 case 3:  
                         if (ReadChrootPolicy(head)) break;  
                         head->read_var2 = NULL; head->read_step = 4;  
                 case 4:  
                         if (ReadPivotRootPolicy(head)) break;  
                         head->read_var2 = NULL; head->read_step = 5;  
                 case 5:  
                         if (ReadReservedPortPolicy(head)) break;  
                         head->read_eof = 1;  
                         break;  
                 default:  
                         return -EINVAL;  
                 }  
         }  
         return 0;  
1031  }  }
1032    
1033  #endif  /**
1034     * ccs_last_word - Get last component of a line.
1035  /*************************  POLICY LOADER  *************************/   *
1036     * @line: A line.
1037  static int profile_loaded = 0;   *
1038     * Returns the last word of a line.
1039  static const char *ccs_loader = NULL;   */
1040    const char *ccs_last_word(const char *name)
 static int __init CCS_loader_Setup(char *str)  
1041  {  {
1042          ccs_loader = str;          const char *cp = strrchr(name, ' ');
1043          return 0;          if (cp)
1044                    return cp + 1;
1045            return name;
1046  }  }
1047    
1048  __setup("CCS_loader=", CCS_loader_Setup);  /**
1049     * ccs_warn_log - Print warning or error message on console.
1050  void CCS_LoadPolicy(const char *filename)   *
1051  {   * @r:   Pointer to "struct ccs_request_info".
1052          if (sbin_init_started) return;   * @fmt: The printf()'s format string, followed by parameters.
1053          /*   */
1054           * Check filename is /sbin/init or /sbin/ccs-start .  void ccs_warn_log(struct ccs_request_info *r, const char *fmt, ...)
          * /sbin/ccs-start is a dummy filename in case where /sbin/init can't be passed.  
          * You can create /sbin/ccs-start by "ln -s /bin/true /sbin/ccs-start", for  
          * only the pathname is needed to activate Mandatory Access Control.  
          */  
         if (strcmp(filename, "/sbin/init") != 0 && strcmp(filename, "/sbin/ccs-start") != 0) return;  
         /*  
          * Don't activate MAC if the path given by 'CCS_loader=' option doesn't exist.  
          * If initrd.img includes /sbin/init but real-root-dev has not mounted on / yet,  
          * activating MAC will block the system since policies are not loaded yet.  
          * So let do_execve() call this function everytime.  
          */  
         {  
                 struct nameidata nd;  
                 if (!ccs_loader) ccs_loader = "/sbin/ccs-init";  
                 if (path_lookup(ccs_loader, lookup_flags, &nd)) {  
                         printk("Not activating Mandatory Access Control now since %s doesn't exist.\n", ccs_loader);  
                         return;  
                 }  
                 path_release(&nd);  
         }  
         if (!profile_loaded) {  
                 char *argv[2], *envp[3];  
                 printk("Calling %s to load policy. Please wait.\n", ccs_loader);  
                 argv[0] = (char *) ccs_loader;  
                 argv[1] = NULL;  
                 envp[0] = "HOME=/";  
                 envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";  
                 envp[2] = NULL;  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)  
                 call_usermodehelper(argv[0], argv, envp, 1);  
 #else  
                 call_usermodehelper(argv[0], argv, envp);  
 #endif  
                 while (!profile_loaded) {  
                         set_current_state(TASK_INTERRUPTIBLE);  
                         schedule_timeout(HZ / 10);  
                 }  
         }  
 #ifdef CONFIG_SAKURA  
         printk("SAKURA: 1.5.3-pre   2008/01/02\n");  
 #endif  
 #ifdef CONFIG_TOMOYO  
         printk("TOMOYO: 1.5.3-pre   2008/01/02\n");  
 #endif  
         //if (!profile_loaded) panic("No profiles loaded. Run policy loader using 'init=' option.\n");  
         printk("Mandatory Access Control activated.\n");  
         sbin_init_started = 1;  
         ccs_log_level = KERN_WARNING;  
         { /* Check all profiles currently assigned to domains are defined. */  
                 struct domain_info *domain;  
                 list1_for_each_entry(domain, &domain_list, list) {  
                         const u8 profile = domain->profile;  
                         if (!profile_ptr[profile]) panic("Profile %u (used by '%s') not defined.\n", profile, domain->domainname->name);  
                 }  
         }  
 }  
   
   
 /*************************  MAC Decision Delayer  *************************/  
   
 static DECLARE_WAIT_QUEUE_HEAD(query_wait);  
   
 static spinlock_t query_lock = SPIN_LOCK_UNLOCKED;  
   
 struct query_entry {  
         struct list_head list;  
         char *query;  
         int query_len;  
         unsigned int serial;  
         int timer;  
         int answer;  
 };  
   
 static LIST_HEAD(query_list);  
 static atomic_t queryd_watcher = ATOMIC_INIT(0);  
   
 int CheckSupervisor(const char *fmt, ...)  
1055  {  {
1056            int len = PAGE_SIZE;
1057          va_list args;          va_list args;
1058          int error = -EPERM;          char *buffer;
1059          int pos, len;          const struct ccs_profile *profile =
1060          static unsigned int serial = 0;                  ccs_profile(r->domain->profile);
1061          struct query_entry *query_entry;          switch (r->mode) {
1062          if (!CheckCCSFlags(CCS_ALLOW_ENFORCE_GRACE) || !atomic_read(&queryd_watcher)) {          case CCS_CONFIG_ENFORCING:
1063  #ifdef ALT_EXEC                  if (!profile->enforcing->enforcing_verbose)
1064                  if ((current->tomoyo_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR) == 0) {                          return;
                         int i;  
                         for (i = 0; i < CheckCCSFlags(CCS_SLEEP_PERIOD); i++) {  
                                 set_current_state(TASK_INTERRUPTIBLE);  
                                 schedule_timeout(HZ / 10);  
                         }  
                 }  
 #endif  
                 return -EPERM;  
         }  
         va_start(args, fmt);  
         len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;  
         va_end(args);  
         if ((query_entry = ccs_alloc(sizeof(*query_entry))) == NULL ||  
                 (query_entry->query = ccs_alloc(len)) == NULL) goto out;  
         INIT_LIST_HEAD(&query_entry->list);  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&query_lock);  
         query_entry->serial = serial++;  
         spin_unlock(&query_lock);  
         /***** CRITICAL SECTION END *****/  
         pos = snprintf(query_entry->query, len - 1, "Q%u\n", query_entry->serial);  
         va_start(args, fmt);  
         vsnprintf(query_entry->query + pos, len - 1 - pos, fmt, args);  
         query_entry->query_len = strlen(query_entry->query) + 1;  
         va_end(args);  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&query_lock);  
         list_add_tail(&query_entry->list, &query_list);  
         spin_unlock(&query_lock);  
         /***** CRITICAL SECTION END *****/  
         UpdateCounter(CCS_UPDATES_COUNTER_QUERY);  
         /* Give 10 seconds for supervisor's opinion. */  
         for (query_entry->timer = 0; atomic_read(&queryd_watcher) && CheckCCSFlags(CCS_ALLOW_ENFORCE_GRACE) && query_entry->timer < 100; query_entry->timer++) {  
                 wake_up(&query_wait);  
                 set_current_state(TASK_INTERRUPTIBLE);  
                 schedule_timeout(HZ / 10);  
                 if (query_entry->answer) break;  
         }  
         UpdateCounter(CCS_UPDATES_COUNTER_QUERY);  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&query_lock);  
         list_del(&query_entry->list);  
         spin_unlock(&query_lock);  
         /***** CRITICAL SECTION END *****/  
         switch (query_entry->answer) {  
         case 1:  
                 /* Granted by administrator. */  
                 error = 0;  
1065                  break;                  break;
1066          case 0:          case CCS_CONFIG_PERMISSIVE:
1067                  /* Timed out. */                  if (!profile->permissive->permissive_verbose)
1068                            return;
1069                  break;                  break;
1070          default:          case CCS_CONFIG_LEARNING:
1071                  /* Rejected by administrator. */                  if (!profile->learning->learning_verbose)
1072                            return;
1073                  break;                  break;
1074          }          }
1075   out: ;          while (1) {
1076          if (query_entry) ccs_free(query_entry->query);                  int len2;
1077          ccs_free(query_entry);                  buffer = kmalloc(len, GFP_KERNEL);
1078          return error;                  if (!buffer)
1079  }                          return;
1080                    va_start(args, fmt);
1081  static int PollQuery(struct file *file, poll_table *wait)                  len2 = vsnprintf(buffer, len - 1, fmt, args);
1082  {                  va_end(args);
1083          int found;                  if (len2 <= len - 1) {
1084          /***** CRITICAL SECTION START *****/                          buffer[len2] = '\0';
         spin_lock(&query_lock);  
         found = !list_empty(&query_list);  
         spin_unlock(&query_lock);  
         /***** CRITICAL SECTION END *****/  
         if (found) return POLLIN | POLLRDNORM;  
         poll_wait(file, &query_wait, wait);  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&query_lock);  
         found = !list_empty(&query_list);  
         spin_unlock(&query_lock);  
         /***** CRITICAL SECTION END *****/  
         if (found) return POLLIN | POLLRDNORM;  
         return 0;  
 }  
   
 static int ReadQuery(struct io_buffer *head)  
 {  
         struct list_head *tmp;  
         int pos = 0, len = 0;  
         char *buf;  
         if (head->read_avail) return 0;  
         if (head->read_buf) {  
                 ccs_free(head->read_buf); head->read_buf = NULL;  
                 head->readbuf_size = 0;  
         }  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&query_lock);  
         list_for_each(tmp, &query_list) {  
                 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);  
                 if (pos++ == head->read_step) {  
                         len = ptr->query_len;  
1085                          break;                          break;
1086                  }                  }
1087                    len = len2 + 1;
1088                    kfree(buffer);
1089          }          }
1090          spin_unlock(&query_lock);          printk(KERN_WARNING "%s: Access %s denied for %s\n",
1091          /***** CRITICAL SECTION END *****/                 r->mode == CCS_CONFIG_ENFORCING ? "ERROR" : "WARNING", buffer,
1092          if (!len) {                 ccs_last_word(r->domain->domainname->name));
1093                  head->read_step = 0;          kfree(buffer);
                 return 0;  
         }  
         if ((buf = ccs_alloc(len)) != NULL) {  
                 pos = 0;  
                 /***** CRITICAL SECTION START *****/  
                 spin_lock(&query_lock);  
                 list_for_each(tmp, &query_list) {  
                         struct query_entry *ptr = list_entry(tmp, struct query_entry, list);  
                         if (pos++ == head->read_step) {  
                                 /* Some query can be skiipped since query_list can change, but I don't care. */  
                                 if (len == ptr->query_len) memmove(buf, ptr->query, len);  
                                 break;  
                         }  
                 }  
                 spin_unlock(&query_lock);  
                 /***** CRITICAL SECTION END *****/  
                 if (buf[0]) {  
                         head->readbuf_size = head->read_avail = len;  
                         head->read_buf = buf;  
                         head->read_step++;  
                 } else {  
                         ccs_free(buf);  
                 }  
         }  
         return 0;  
 }  
   
 static int WriteAnswer(struct io_buffer *head)  
 {  
         char *data = head->write_buf;  
         struct list_head *tmp;  
         unsigned int serial, answer;  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&query_lock);  
         list_for_each(tmp, &query_list) {  
                 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);  
                 ptr->timer = 0;  
         }  
         spin_unlock(&query_lock);  
         /***** CRITICAL SECTION END *****/  
         if (sscanf(data, "A%u=%u", &serial, &answer) != 2) return -EINVAL;  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&query_lock);  
         list_for_each(tmp, &query_list) {  
                 struct query_entry *ptr = list_entry(tmp, struct query_entry, list);  
                 if (ptr->serial != serial) continue;  
                 if (!ptr->answer) ptr->answer = answer;  
                 break;  
         }  
         spin_unlock(&query_lock);  
         /***** CRITICAL SECTION END *****/  
         return 0;  
 }  
   
 /*************************  /proc INTERFACE HANDLER  *************************/  
   
 /* Policy updates counter. */  
 static unsigned int updates_counter[MAX_CCS_UPDATES_COUNTER];  
 static spinlock_t updates_counter_lock = SPIN_LOCK_UNLOCKED;  
   
 void UpdateCounter(const unsigned char index)  
 {  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&updates_counter_lock);  
         if (index < MAX_CCS_UPDATES_COUNTER) updates_counter[index]++;  
         spin_unlock(&updates_counter_lock);  
         /***** CRITICAL SECTION END *****/  
1094  }  }
1095    
1096  static int ReadUpdatesCounter(struct io_buffer *head)  /**
1097  {   * ccs_domain_quota_ok - Check for domain's quota.
1098          if (!head->read_eof) {   *
1099                  unsigned int counter[MAX_CCS_UPDATES_COUNTER];   * @r: Pointer to "struct ccs_request_info".
1100                  /***** CRITICAL SECTION START *****/   *
1101                  spin_lock(&updates_counter_lock);   * Returns true if the domain is not exceeded quota, false otherwise.
1102                  memmove(counter, updates_counter, sizeof(updates_counter));   *
1103                  memset(updates_counter, 0, sizeof(updates_counter));   * Caller holds ccs_read_lock().
1104                  spin_unlock(&updates_counter_lock);   */
1105                  /***** CRITICAL SECTION END *****/  bool ccs_domain_quota_ok(struct ccs_request_info *r)
                 io_printf(head,  
                                   "/proc/ccs/system_policy:    %10u\n"  
                                   "/proc/ccs/domain_policy:    %10u\n"  
                                   "/proc/ccs/exception_policy: %10u\n"  
                                   "/proc/ccs/profile:          %10u\n"  
                                   "/proc/ccs/query:            %10u\n"  
                                   "/proc/ccs/manager:          %10u\n"  
                                   "/proc/ccs/grant_log:        %10u\n"  
                                   "/proc/ccs/reject_log:       %10u\n",  
                                   counter[CCS_UPDATES_COUNTER_SYSTEM_POLICY],  
                                   counter[CCS_UPDATES_COUNTER_DOMAIN_POLICY],  
                                   counter[CCS_UPDATES_COUNTER_EXCEPTION_POLICY],  
                                   counter[CCS_UPDATES_COUNTER_PROFILE],  
                                   counter[CCS_UPDATES_COUNTER_QUERY],  
                                   counter[CCS_UPDATES_COUNTER_MANAGER],  
                                   counter[CCS_UPDATES_COUNTER_GRANT_LOG],  
                                   counter[CCS_UPDATES_COUNTER_REJECT_LOG]);  
                 head->read_eof = 1;  
         }  
         return 0;  
 }  
   
 static int ReadVersion(struct io_buffer *head)  
 {  
         if (!head->read_eof) {  
                 if (io_printf(head, "1.5.3-pre") == 0) head->read_eof = 1;  
         }  
         return 0;  
 }  
   
 static int ReadMemoryCounter(struct io_buffer *head)  
 {  
         if (!head->read_eof) {  
                 const int shared = GetMemoryUsedForSaveName(), private = GetMemoryUsedForElements(), dynamic = GetMemoryUsedForDynamic();  
                 if (io_printf(head, "Shared:  %10u\nPrivate: %10u\nDynamic: %10u\nTotal:   %10u\n", shared, private, dynamic, shared + private + dynamic) == 0) head->read_eof = 1;  
         }  
         return 0;  
 }  
   
 static int ReadSelfDomain(struct io_buffer *head)  
 {  
         if (!head->read_eof) {  
                 io_printf(head, "%s", current->domain_info->domainname->name);  
                 head->read_eof = 1;  
         }  
         return 0;  
 }  
   
 int CCS_OpenControl(const u8 type, struct file *file)  
 {  
         struct io_buffer *head = ccs_alloc(sizeof(*head));  
         if (!head) return -ENOMEM;  
         mutex_init(&head->read_sem);  
         mutex_init(&head->write_sem);  
         switch (type) {  
 #ifdef CONFIG_SAKURA  
         case CCS_SYSTEMPOLICY:  
                 head->write = AddSystemPolicy;  
                 head->read = ReadSystemPolicy;  
                 break;  
 #endif  
 #ifdef CONFIG_TOMOYO  
         case CCS_DOMAINPOLICY:  
                 head->write = AddDomainPolicy;  
                 head->read = ReadDomainPolicy;  
                 break;  
         case CCS_EXCEPTIONPOLICY:  
                 head->write = AddExceptionPolicy;  
                 head->read = ReadExceptionPolicy;  
                 break;  
         case CCS_GRANTLOG:  
                 head->poll = PollGrantLog;  
                 head->read = ReadGrantLog;  
                 break;  
         case CCS_REJECTLOG:  
                 head->poll = PollRejectLog;  
                 head->read = ReadRejectLog;  
                 break;  
 #endif  
         case CCS_SELFDOMAIN:  
                 head->read = ReadSelfDomain;  
                 break;  
         case CCS_DOMAIN_STATUS:  
                 head->write = UpdateDomainProfile;  
                 head->read = ReadDomainProfile;  
                 break;  
         case CCS_PROCESS_STATUS:  
                 head->write = WritePID;  
                 head->read = ReadPID;  
                 break;  
         case CCS_VERSION:  
                 head->read = ReadVersion;  
                 head->readbuf_size = 128;  
                 break;  
         case CCS_MEMINFO:  
                 head->read = ReadMemoryCounter;  
                 head->readbuf_size = 128;  
                 break;  
         case CCS_PROFILE:  
                 head->write = SetProfile;  
                 head->read = ReadProfile;  
                 break;  
         case CCS_QUERY:  
                 head->poll = PollQuery;  
                 head->write = WriteAnswer;  
                 head->read = ReadQuery;  
                 break;  
         case CCS_MANAGER:  
                 head->write = AddManagerPolicy;  
                 head->read = ReadManagerPolicy;  
                 break;  
         case CCS_UPDATESCOUNTER:  
                 head->read = ReadUpdatesCounter;  
                 break;  
         }  
         if (type != CCS_GRANTLOG && type != CCS_REJECTLOG && type != CCS_QUERY) {  
                 if (!head->readbuf_size) head->readbuf_size = PAGE_SIZE * 2;  
                 if ((head->read_buf = ccs_alloc(head->readbuf_size)) == NULL) {  
                         ccs_free(head);  
                         return -ENOMEM;  
                 }  
         }  
         if (head->write) {  
                 head->writebuf_size = PAGE_SIZE * 2;  
                 if ((head->write_buf = ccs_alloc(head->writebuf_size)) == NULL) {  
                         ccs_free(head->read_buf);  
                         ccs_free(head);  
                         return -ENOMEM;  
                 }  
         }  
         file->private_data = head;  
         if (type == CCS_SELFDOMAIN) CCS_ReadControl(file, NULL, 0);  
         else if (head->write == WriteAnswer) atomic_inc(&queryd_watcher);  
         return 0;  
 }  
   
 static int CopyToUser(struct io_buffer *head, char __user * buffer, int buffer_len)  
 {  
         int len = head->read_avail;  
         char *cp = head->read_buf;  
         if (len > buffer_len) len = buffer_len;  
         if (len) {  
                 if (copy_to_user(buffer, cp, len)) return -EFAULT;  
                 head->read_avail -= len;  
                 memmove(cp, cp + len, head->read_avail);  
         }  
         return len;  
 }  
   
 int CCS_PollControl(struct file *file, poll_table *wait)  
 {  
         struct io_buffer *head = file->private_data;  
         if (!head->poll) return -ENOSYS;  
         return head->poll(file, wait);  
 }  
   
 int CCS_ReadControl(struct file *file, char __user *buffer, const int buffer_len)  
 {  
         int len = 0;  
         struct io_buffer *head = file->private_data;  
         if (!head->read) return -ENOSYS;  
         if (!access_ok(VERIFY_WRITE, buffer, buffer_len)) return -EFAULT;  
         if (mutex_lock_interruptible(&head->read_sem)) return -EINTR;  
         len = head->read(head);  
         if (len >= 0) len = CopyToUser(head, buffer, buffer_len);  
         mutex_unlock(&head->read_sem);  
         return len;  
 }  
   
 int CCS_WriteControl(struct file *file, const char __user *buffer, const int buffer_len)  
1106  {  {
1107          struct io_buffer *head = file->private_data;          unsigned int count = 0;
1108          int error = buffer_len;          struct ccs_domain_info *domain = r->domain;
1109          int avail_len = buffer_len;          struct ccs_acl_info *ptr;
1110          char *cp0 = head->write_buf;          if (r->mode != 1)
1111          if (!head->write) return -ENOSYS;                  return false;
1112          if (!access_ok(VERIFY_READ, buffer, buffer_len)) return -EFAULT;          if (!domain)
1113          if (!isRoot()) return -EPERM;                  return true;
1114          if (head->write != WritePID && !IsPolicyManager()) {          list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1115                  return -EPERM; /* Forbid updating policies for non manager programs. */                  if (ptr->is_deleted)
1116          }                          continue;
1117          if (mutex_lock_interruptible(&head->write_sem)) return -EINTR;                  switch (ptr->type) {
1118          while (avail_len > 0) {                          u16 perm;
1119                  char c;                          u8 i;
1120                  if (head->write_avail >= head->writebuf_size - 1) {                  case CCS_TYPE_PATH_ACL:
1121                          error = -ENOMEM;                          perm = container_of(ptr, struct ccs_path_acl, head)->
1122                                    perm;
1123                            for (i = 0; i < CCS_MAX_PATH_OPERATION; i++)
1124                                    if (perm & (1 << i))
1125                                            count++;
1126                            if (perm & (1 << CCS_TYPE_READ_WRITE))
1127                                    count -= 2;
1128                            break;
1129                    case CCS_TYPE_PATH2_ACL:
1130                            perm = container_of(ptr, struct ccs_path2_acl,
1131                                                head)->perm;
1132                            for (i = 0; i < CCS_MAX_PATH2_OPERATION; i++)
1133                                    if (perm & (1 << i))
1134                                            count++;
1135                            break;
1136                    case CCS_TYPE_EXECUTE_HANDLER:
1137                    case CCS_TYPE_DENIED_EXECUTE_HANDLER:
1138                            break;
1139                    case CCS_TYPE_PATH_NUMBER_ACL:
1140                            perm = container_of(ptr, struct ccs_path_number_acl,
1141                                                head)->perm;
1142                            for (i = 0; i < CCS_MAX_PATH_NUMBER_OPERATION; i++)
1143                                    if (perm & (1 << i))
1144                                            count++;
1145                            break;
1146                    case CCS_TYPE_PATH_NUMBER3_ACL:
1147                            perm = container_of(ptr,
1148                                                struct ccs_path_number3_acl,
1149                                                head)->perm;
1150                            for (i = 0; i < CCS_MAX_PATH_NUMBER3_OPERATION;
1151                                 i++)
1152                                    if (perm & (1 << i))
1153                                            count++;
1154                          break;                          break;
1155                  } else if (get_user(c, buffer)) {                  case CCS_TYPE_IP_NETWORK_ACL:
1156                          error = -EFAULT;                          perm = container_of(ptr, struct ccs_ip_network_acl,
1157                                                head)->perm;
1158                            for (i = 0; i < CCS_MAX_NETWORK_OPERATION; i++)
1159                                    if (perm & (1 << i))
1160                                            count++;
1161                          break;                          break;
1162                    default:
1163                            count++;
1164                  }                  }
1165                  buffer++; avail_len--;          }
1166                  cp0[head->write_avail++] = c;          if (count < ccs_profile(domain->profile)->learning->learning_max_entry)
1167                  if (c != '\n') continue;                  return true;
1168                  cp0[head->write_avail - 1] = '\0';          if (!domain->quota_warned) {
1169                  head->write_avail = 0;                  domain->quota_warned = true;
1170                  NormalizeLine(cp0);                  printk(KERN_WARNING "WARNING: "
1171                  head->write(head);                         "Domain '%s' has so many ACLs to hold. "
1172          }                         "Stopped learning mode.\n", domain->domainname->name);
1173          mutex_unlock(&head->write_sem);          }
1174          return error;          return false;
 }  
   
   
 int CCS_CloseControl(struct file *file)  
 {  
         struct io_buffer *head = file->private_data;  
         if (head->write == WriteAnswer) atomic_dec(&queryd_watcher);  
         else if (head->read == ReadMemoryCounter) profile_loaded = 1;  
         ccs_free(head->read_buf); head->read_buf = NULL;  
         ccs_free(head->write_buf); head->write_buf = NULL;  
         ccs_free(head); head = NULL;  
         file->private_data = NULL;  
         return 0;  
1175  }  }

Legend:
Removed from v.853  
changed lines
  Added in v.3014

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