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

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 722 by kumaneko, Thu Nov 22 04:09:54 2007 UTC trunk/1.6.x/ccs-patch/fs/ccs_common.c revision 1798 by kumaneko, Fri Nov 7 08:54:54 2008 UTC
# Line 3  Line 3 
3   *   *
4   * Common functions for SAKURA and TOMOYO.   * Common functions for SAKURA and TOMOYO.
5   *   *
6   * Copyright (C) 2005-2007  NTT DATA CORPORATION   * Copyright (C) 2005-2008  NTT DATA CORPORATION
7   *   *
8   * Version: 1.5.2-pre   2007/11/19   * Version: 1.6.5-rc   2008/11/05
9   *   *
10   * 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.
11   * See README.ccs for ChangeLog.   * See README.ccs for ChangeLog.
12   *   *
13   */   */
14    
15    #include <linux/version.h>
16    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
17    #define __KERNEL_SYSCALLS__
18    #endif
19  #include <linux/string.h>  #include <linux/string.h>
20  #include <linux/mm.h>  #include <linux/mm.h>
21  #include <linux/utime.h>  #include <linux/utime.h>
# Line 20  Line 24 
24  #include <linux/slab.h>  #include <linux/slab.h>
25  #include <asm/uaccess.h>  #include <asm/uaccess.h>
26  #include <stdarg.h>  #include <stdarg.h>
27  #include <linux/version.h>  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)  
28  #include <linux/namei.h>  #include <linux/namei.h>
29  #include <linux/mount.h>  #include <linux/mount.h>
30  static const int lookup_flags = LOOKUP_FOLLOW;  static const int lookup_flags = LOOKUP_FOLLOW;
# Line 32  static const int lookup_flags = LOOKUP_F Line 35  static const int lookup_flags = LOOKUP_F
35  #include <linux/ccs_common.h>  #include <linux/ccs_common.h>
36  #include <linux/ccs_proc.h>  #include <linux/ccs_proc.h>
37  #include <linux/tomoyo.h>  #include <linux/tomoyo.h>
38    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
39  #ifdef CONFIG_TOMOYO_MAX_ACCEPT_ENTRY  #include <linux/unistd.h>
 #define MAX_ACCEPT_ENTRY (CONFIG_TOMOYO_MAX_ACCEPT_ENTRY)  
 #else  
 #define MAX_ACCEPT_ENTRY 2048  
40  #endif  #endif
41  #ifdef CONFIG_TOMOYO_MAX_GRANT_LOG  
42  #define MAX_GRANT_LOG (CONFIG_TOMOYO_MAX_GRANT_LOG)  /* To support PID namespace. */
43  #else  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
44  #define MAX_GRANT_LOG 1024  #define find_task_by_pid find_task_by_vpid
45  #endif  #endif
46  #ifdef CONFIG_TOMOYO_MAX_REJECT_LOG  
47  #define MAX_REJECT_LOG (CONFIG_TOMOYO_MAX_REJECT_LOG)  /* Set default specified by the kernel config. */
48    #ifdef CONFIG_TOMOYO
49    #define MAX_ACCEPT_ENTRY (CONFIG_TOMOYO_MAX_ACCEPT_ENTRY)
50    #define MAX_GRANT_LOG    (CONFIG_TOMOYO_MAX_GRANT_LOG)
51    #define MAX_REJECT_LOG   (CONFIG_TOMOYO_MAX_REJECT_LOG)
52  #else  #else
53  #define MAX_REJECT_LOG 1024  #define MAX_ACCEPT_ENTRY 0
54    #define MAX_GRANT_LOG    0
55    #define MAX_REJECT_LOG   0
56  #endif  #endif
57    
58  /*************************  VARIABLES  *************************/  /* Has /sbin/init started? */
59    bool sbin_init_started;
 /* /sbin/init started? */  
 int sbin_init_started = 0;  
60    
61    /* Log level for SAKURA's printk(). */
62  const char *ccs_log_level = KERN_DEBUG;  const char *ccs_log_level = KERN_DEBUG;
63    
64    /* String table for functionality that takes 4 modes. */
65    static const char *mode_4[4] = {
66            "disabled", "learning", "permissive", "enforcing"
67    };
68    /* String table for functionality that takes 2 modes. */
69    static const char *mode_2[4] = {
70            "disabled", "enabled", "enabled", "enabled"
71    };
72    
73    /* Table for profile. */
74  static struct {  static struct {
75          const char *keyword;          const char *keyword;
76          unsigned int current_value;          unsigned int current_value;
77          const unsigned int max_value;          const unsigned int max_value;
78  } ccs_control_array[CCS_MAX_CONTROL_INDEX] = {  } ccs_control_array[CCS_MAX_CONTROL_INDEX] = {
         [CCS_PROFILE_COMMENT]            = { "COMMENT",             0, 0 }, /* Reserved for string. */  
79          [CCS_TOMOYO_MAC_FOR_FILE]        = { "MAC_FOR_FILE",        0, 3 },          [CCS_TOMOYO_MAC_FOR_FILE]        = { "MAC_FOR_FILE",        0, 3 },
80          [CCS_TOMOYO_MAC_FOR_ARGV0]       = { "MAC_FOR_ARGV0",       0, 3 },          [CCS_TOMOYO_MAC_FOR_ARGV0]       = { "MAC_FOR_ARGV0",       0, 3 },
81          [CCS_TOMOYO_MAC_FOR_ENV]         = { "MAC_FOR_ENV",         0, 3 },          [CCS_TOMOYO_MAC_FOR_ENV]         = { "MAC_FOR_ENV",         0, 3 },
# Line 73  static struct { Line 87  static struct {
87          [CCS_SAKURA_RESTRICT_UNMOUNT]    = { "RESTRICT_UNMOUNT",    0, 3 },          [CCS_SAKURA_RESTRICT_UNMOUNT]    = { "RESTRICT_UNMOUNT",    0, 3 },
88          [CCS_SAKURA_RESTRICT_PIVOT_ROOT] = { "RESTRICT_PIVOT_ROOT", 0, 3 },          [CCS_SAKURA_RESTRICT_PIVOT_ROOT] = { "RESTRICT_PIVOT_ROOT", 0, 3 },
89          [CCS_SAKURA_RESTRICT_AUTOBIND]   = { "RESTRICT_AUTOBIND",   0, 1 },          [CCS_SAKURA_RESTRICT_AUTOBIND]   = { "RESTRICT_AUTOBIND",   0, 1 },
90          [CCS_TOMOYO_MAX_ACCEPT_ENTRY]    = { "MAX_ACCEPT_ENTRY",    MAX_ACCEPT_ENTRY, INT_MAX },          [CCS_TOMOYO_MAX_ACCEPT_ENTRY]
91          [CCS_TOMOYO_MAX_GRANT_LOG]       = { "MAX_GRANT_LOG",       MAX_GRANT_LOG, INT_MAX },          = { "MAX_ACCEPT_ENTRY",    MAX_ACCEPT_ENTRY, INT_MAX },
92          [CCS_TOMOYO_MAX_REJECT_LOG]      = { "MAX_REJECT_LOG",      MAX_REJECT_LOG, INT_MAX },          [CCS_TOMOYO_MAX_GRANT_LOG]
93            = { "MAX_GRANT_LOG",       MAX_GRANT_LOG, INT_MAX },
94            [CCS_TOMOYO_MAX_REJECT_LOG]
95            = { "MAX_REJECT_LOG",      MAX_REJECT_LOG, INT_MAX },
96          [CCS_TOMOYO_VERBOSE]             = { "TOMOYO_VERBOSE",      1, 1 },          [CCS_TOMOYO_VERBOSE]             = { "TOMOYO_VERBOSE",      1, 1 },
97          [CCS_ALLOW_ENFORCE_GRACE]        = { "ALLOW_ENFORCE_GRACE", 0, 1 },          [CCS_SLEEP_PERIOD]
98          [CCS_SLEEP_PERIOD]               = { "SLEEP_PERIOD",        0, 3000 }, /* in 0.1 second */          = { "SLEEP_PERIOD",        0, 3000 }, /* in 0.1 second */
         [CCS_TOMOYO_ALT_EXEC]            = { "ALT_EXEC",            0, 0 }, /* Reserved for string. */  
99  };  };
100    
101  struct profile {  #ifdef CONFIG_TOMOYO
102    /* Capability name used by domain policy. */
103    static const char *capability_control_keyword[TOMOYO_MAX_CAPABILITY_INDEX] = {
104            [TOMOYO_INET_STREAM_SOCKET_CREATE]  = "inet_tcp_create",
105            [TOMOYO_INET_STREAM_SOCKET_LISTEN]  = "inet_tcp_listen",
106            [TOMOYO_INET_STREAM_SOCKET_CONNECT] = "inet_tcp_connect",
107            [TOMOYO_USE_INET_DGRAM_SOCKET]      = "use_inet_udp",
108            [TOMOYO_USE_INET_RAW_SOCKET]        = "use_inet_ip",
109            [TOMOYO_USE_ROUTE_SOCKET]           = "use_route",
110            [TOMOYO_USE_PACKET_SOCKET]          = "use_packet",
111            [TOMOYO_SYS_MOUNT]                  = "SYS_MOUNT",
112            [TOMOYO_SYS_UMOUNT]                 = "SYS_UMOUNT",
113            [TOMOYO_SYS_REBOOT]                 = "SYS_REBOOT",
114            [TOMOYO_SYS_CHROOT]                 = "SYS_CHROOT",
115            [TOMOYO_SYS_KILL]                   = "SYS_KILL",
116            [TOMOYO_SYS_VHANGUP]                = "SYS_VHANGUP",
117            [TOMOYO_SYS_SETTIME]                = "SYS_TIME",
118            [TOMOYO_SYS_NICE]                   = "SYS_NICE",
119            [TOMOYO_SYS_SETHOSTNAME]            = "SYS_SETHOSTNAME",
120            [TOMOYO_USE_KERNEL_MODULE]          = "use_kernel_module",
121            [TOMOYO_CREATE_FIFO]                = "create_fifo",
122            [TOMOYO_CREATE_BLOCK_DEV]           = "create_block_dev",
123            [TOMOYO_CREATE_CHAR_DEV]            = "create_char_dev",
124            [TOMOYO_CREATE_UNIX_SOCKET]         = "create_unix_socket",
125            [TOMOYO_SYS_LINK]                   = "SYS_LINK",
126            [TOMOYO_SYS_SYMLINK]                = "SYS_SYMLINK",
127            [TOMOYO_SYS_RENAME]                 = "SYS_RENAME",
128            [TOMOYO_SYS_UNLINK]                 = "SYS_UNLINK",
129            [TOMOYO_SYS_CHMOD]                  = "SYS_CHMOD",
130            [TOMOYO_SYS_CHOWN]                  = "SYS_CHOWN",
131            [TOMOYO_SYS_IOCTL]                  = "SYS_IOCTL",
132            [TOMOYO_SYS_KEXEC_LOAD]             = "SYS_KEXEC_LOAD",
133            [TOMOYO_SYS_PIVOT_ROOT]             = "SYS_PIVOT_ROOT",
134            [TOMOYO_SYS_PTRACE]                 = "SYS_PTRACE",
135    };
136    #endif
137    
138    /* Profile table. Memory is allocated as needed. */
139    static struct profile {
140          unsigned int value[CCS_MAX_CONTROL_INDEX];          unsigned int value[CCS_MAX_CONTROL_INDEX];
141          const struct path_info *comment;          const struct path_info *comment;
142          const struct path_info *alt_exec;  #ifdef CONFIG_TOMOYO
143  };          unsigned char capability_value[TOMOYO_MAX_CAPABILITY_INDEX];
144    #endif
145    } *profile_ptr[MAX_PROFILES];
146    
147  static struct profile *profile_ptr[MAX_PROFILES];  /* Permit policy management by non-root user? */
148    static bool manage_by_non_root;
149    
150  /*************************  UTILITY FUNCTIONS  *************************/  /* Utility functions. */
151    
152  #ifdef CONFIG_TOMOYO  #ifdef CONFIG_TOMOYO
153  static int __init TOMOYO_Quiet_Setup(char *str)  /**
154     * tomoyo_quiet_setup - Set TOMOYO_VERBOSE=0 by default.
155     *
156     * @str: Unused.
157     *
158     * Returns 0.
159     */
160    static int __init tomoyo_quiet_setup(char *str)
161  {  {
162          ccs_control_array[CCS_TOMOYO_VERBOSE].current_value = 0;          ccs_control_array[CCS_TOMOYO_VERBOSE].current_value = 0;
163          return 0;          return 0;
164  }  }
165    
166  __setup("TOMOYO_QUIET", TOMOYO_Quiet_Setup);  __setup("TOMOYO_QUIET", tomoyo_quiet_setup);
167  #endif  #endif
168    
169  /* Am I root? */  /**
170  static int isRoot(void)   * is_byte_range - Check whether the string isa \ooo style octal value.
171     *
172     * @str: Pointer to the string.
173     *
174     * Returns true if @str is a \ooo style octal value, false otherwise.
175     */
176    static inline bool is_byte_range(const char *str)
177    {
178            return *str >= '0' && *str++ <= '3' &&
179                    *str >= '0' && *str++ <= '7' &&
180                    *str >= '0' && *str <= '7';
181    }
182    
183    /**
184     * is_decimal - Check whether the character is a decimal character.
185     *
186     * @c: The character to check.
187     *
188     * Returns true if @c is a decimal character, false otherwise.
189     */
190    static inline bool is_decimal(const char c)
191    {
192            return c >= '0' && c <= '9';
193    }
194    
195    /**
196     * is_hexadecimal - Check whether the character is a hexadecimal character.
197     *
198     * @c: The character to check.
199     *
200     * Returns true if @c is a hexadecimal character, false otherwise.
201     */
202    static inline bool is_hexadecimal(const char c)
203    {
204            return (c >= '0' && c <= '9') ||
205                    (c >= 'A' && c <= 'F') ||
206                    (c >= 'a' && c <= 'f');
207    }
208    
209    /**
210     * is_alphabet_char - Check whether the character is an alphabet.
211     *
212     * @c: The character to check.
213     *
214     * Returns true if @c is an alphabet character, false otherwise.
215     */
216    static inline bool is_alphabet_char(const char c)
217    {
218            return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
219    }
220    
221    /**
222     * make_byte - Make byte value from three octal characters.
223     *
224     * @c1: The first character.
225     * @c2: The second character.
226     * @c3: The third character.
227     *
228     * Returns byte value.
229     */
230    static inline u8 make_byte(const u8 c1, const u8 c2, const u8 c3)
231    {
232            return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
233    }
234    
235    /**
236     * str_starts - Check whether the given string starts with the given keyword.
237     *
238     * @src:  Pointer to pointer to the string.
239     * @find: Pointer to the keyword.
240     *
241     * Returns true if @src starts with @find, false otherwise.
242     *
243     * The @src is updated to point the first character after the @find
244     * if @src starts with @find.
245     */
246    static bool str_starts(char **src, const char *find)
247  {  {
248          return !current->uid && !current->euid;          const int len = strlen(find);
249            char *tmp = *src;
250            if (strncmp(tmp, find, len))
251                    return false;
252            tmp += len;
253            *src = tmp;
254            return true;
255  }  }
256    
257  /*  /**
258   * Format string.   * normalize_line - Format string.
259     *
260     * @buffer: The line to normalize.
261     *
262   * Leading and trailing whitespaces are removed.   * Leading and trailing whitespaces are removed.
263   * Multiple whitespaces are packed into single space.   * Multiple whitespaces are packed into single space.
264     *
265     * Returns nothing.
266   */   */
267  static void NormalizeLine(unsigned char *buffer)  static void normalize_line(unsigned char *buffer)
268  {  {
269          unsigned char *sp = buffer, *dp = buffer;          unsigned char *sp = buffer;
270          int first = 1;          unsigned char *dp = buffer;
271          while (*sp && (*sp <= ' ' || *sp >= 127)) sp++;          bool first = true;
272            while (*sp && (*sp <= ' ' || *sp >= 127))
273                    sp++;
274          while (*sp) {          while (*sp) {
275                  if (!first) *dp++ = ' ';                  if (!first)
276                  first = 0;                          *dp++ = ' ';
277                  while (*sp > ' ' && *sp < 127) *dp++ = *sp++;                  first = false;
278                  while (*sp && (*sp <= ' ' || *sp >= 127)) sp++;                  while (*sp > ' ' && *sp < 127)
279                            *dp++ = *sp++;
280                    while (*sp && (*sp <= ' ' || *sp >= 127))
281                            sp++;
282          }          }
283          *dp = '\0';          *dp = '\0';
284  }  }
285    
286  /*  /**
287   *  Check whether the given filename follows the naming rules.   * ccs_is_correct_path - Validate a pathname.
288   *  Returns nonzero if follows, zero otherwise.   * @filename:     The pathname to check.
289     * @start_type:   Should the pathname start with '/'?
290     *                1 = must / -1 = must not / 0 = don't care
291     * @pattern_type: Can the pathname contain a wildcard?
292     *                1 = must / -1 = must not / 0 = don't care
293     * @end_type:     Should the pathname end with '/'?
294     *                1 = must / -1 = must not / 0 = don't care
295     * @function:     The name of function calling me.
296     *
297     * Check whether the given filename follows the naming rules.
298     * Returns true if @filename follows the naming rules, false otherwise.
299   */   */
300  bool IsCorrectPath(const char *filename, const int start_type, const int pattern_type, const int end_type, const char *function)  bool ccs_is_correct_path(const char *filename, const s8 start_type,
301  {                           const s8 pattern_type, const s8 end_type,
302          int contains_pattern = 0;                           const char *function)
303          char c, d, e;  {
304            bool contains_pattern = false;
305            unsigned char c;
306            unsigned char d;
307            unsigned char e;
308          const char *original_filename = filename;          const char *original_filename = filename;
309          if (!filename) goto out;          if (!filename)
310                    goto out;
311          c = *filename;          c = *filename;
312          if (start_type == 1) { /* Must start with '/' */          if (start_type == 1) { /* Must start with '/' */
313                  if (c != '/') goto out;                  if (c != '/')
314                            goto out;
315          } else if (start_type == -1) { /* Must not start with '/' */          } else if (start_type == -1) { /* Must not start with '/' */
316                  if (c == '/') goto out;                  if (c == '/')
317                            goto out;
318          }          }
319          if (c) c = * (strchr(filename, '\0') - 1);          if (c)
320                    c = *(filename + strlen(filename) - 1);
321          if (end_type == 1) { /* Must end with '/' */          if (end_type == 1) { /* Must end with '/' */
322                  if (c != '/') goto out;                  if (c != '/')
323                            goto out;
324          } else if (end_type == -1) { /* Must not end with '/' */          } else if (end_type == -1) { /* Must not end with '/' */
325                  if (c == '/') goto out;                  if (c == '/')
326                            goto out;
327          }          }
328          while ((c = *filename++) != '\0') {          while (1) {
329                    c = *filename++;
330                    if (!c)
331                            break;
332                  if (c == '\\') {                  if (c == '\\') {
333                          switch ((c = *filename++)) {                          c = *filename++;
334                            switch (c) {
335                          case '\\':  /* "\\" */                          case '\\':  /* "\\" */
336                                  continue;                                  continue;
337                          case '$':   /* "\$" */                          case '$':   /* "\$" */
# Line 164  bool IsCorrectPath(const char *filename, Line 344  bool IsCorrectPath(const char *filename,
344                          case 'a':   /* "\a" */                          case 'a':   /* "\a" */
345                          case 'A':   /* "\A" */                          case 'A':   /* "\A" */
346                          case '-':   /* "\-" */                          case '-':   /* "\-" */
347                                  if (pattern_type == -1) break; /* Must not contain pattern */                                  if (pattern_type == -1)
348                                  contains_pattern = 1;                                          break; /* Must not contain pattern */
349                                    contains_pattern = true;
350                                  continue;                                  continue;
351                          case '0':   /* "\ooo" */                          case '0':   /* "\ooo" */
352                          case '1':                          case '1':
353                          case '2':                          case '2':
354                          case '3':                          case '3':
355                                  if ((d = *filename++) >= '0' && d <= '7' && (e = *filename++) >= '0' && e <= '7') {                                  d = *filename++;
356                                          const unsigned char f =                                  if (d < '0' || d > '7')
357                                                  (((unsigned char) (c - '0')) << 6) +                                          break;
358                                                  (((unsigned char) (d - '0')) << 3) +                                  e = *filename++;
359                                                  (((unsigned char) (e - '0')));                                  if (e < '0' || e > '7')
360                                          if (f && (f <= ' ' || f >= 127)) continue; /* pattern is not \000 */                                          break;
361                                  }                                  c = make_byte(c, d, e);
362                                    if (c && (c <= ' ' || c >= 127))
363                                            continue; /* pattern is not \000 */
364                          }                          }
365                          goto out;                          goto out;
366                  } else if (c <= ' ' || c >= 127) {                  } else if (c <= ' ' || c >= 127) {
# Line 185  bool IsCorrectPath(const char *filename, Line 368  bool IsCorrectPath(const char *filename,
368                  }                  }
369          }          }
370          if (pattern_type == 1) { /* Must contain pattern */          if (pattern_type == 1) { /* Must contain pattern */
371                  if (!contains_pattern) goto out;                  if (!contains_pattern)
372                            goto out;
373          }          }
374          return 1;          return true;
375   out:   out:
376          printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function, original_filename);          printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function,
377          return 0;                 original_filename);
378            return false;
379  }  }
380    
381  /*  /**
382   *  Check whether the given domainname follows the naming rules.   * ccs_is_correct_domain - Check whether the given domainname follows the naming rules.
383   *  Returns nonzero if follows, zero otherwise.   * @domainname:   The domainname to check.
384     * @function:     The name of function calling me.
385     *
386     * Returns true if @domainname follows the naming rules, false otherwise.
387   */   */
388  bool IsCorrectDomain(const unsigned char *domainname, const char *function)  bool ccs_is_correct_domain(const unsigned char *domainname,
389                               const char *function)
390  {  {
391          unsigned char c, d, e;          unsigned char c;
392            unsigned char d;
393            unsigned char e;
394          const char *org_domainname = domainname;          const char *org_domainname = domainname;
395          if (!domainname || strncmp(domainname, ROOT_NAME, ROOT_NAME_LEN)) goto out;          if (!domainname || strncmp(domainname, ROOT_NAME, ROOT_NAME_LEN))
396                    goto out;
397          domainname += ROOT_NAME_LEN;          domainname += ROOT_NAME_LEN;
398          if (!*domainname) return 1;          if (!*domainname)
399                    return true;
400          do {          do {
401                  if (*domainname++ != ' ') goto out;                  if (*domainname++ != ' ')
402                  if (*domainname++ != '/') goto out;                          goto out;
403                  while ((c = *domainname) != '\0' && c != ' ') {                  if (*domainname++ != '/')
404                            goto out;
405                    while (1) {
406                            c = *domainname;
407                            if (!c || c == ' ')
408                                    break;
409                          domainname++;                          domainname++;
410                          if (c == '\\') {                          if (c == '\\') {
411                                  switch ((c = *domainname++)) {                                  c = *domainname++;
412                                    switch ((c)) {
413                                  case '\\':  /* "\\" */                                  case '\\':  /* "\\" */
414                                          continue;                                          continue;
415                                  case '0':   /* "\ooo" */                                  case '0':   /* "\ooo" */
416                                  case '1':                                  case '1':
417                                  case '2':                                  case '2':
418                                  case '3':                                  case '3':
419                                          if ((d = *domainname++) >= '0' && d <= '7' && (e = *domainname++) >= '0' && e <= '7') {                                          d = *domainname++;
420                                                  const unsigned char f =                                          if (d < '0' || d > '7')
421                                                          (((unsigned char) (c - '0')) << 6) +                                                  break;
422                                                          (((unsigned char) (d - '0')) << 3) +                                          e = *domainname++;
423                                                          (((unsigned char) (e - '0')));                                          if (e < '0' || e > '7')
424                                                  if (f && (f <= ' ' || f >= 127)) continue; /* pattern is not \000 */                                                  break;
425                                          }                                          c = make_byte(c, d, e);
426                                            if (c && (c <= ' ' || c >= 127))
427                                                    /* pattern is not \000 */
428                                                    continue;
429                                  }                                  }
430                                  goto out;                                  goto out;
431                          } else if (c < ' ' || c >= 127) {                          } else if (c < ' ' || c >= 127) {
# Line 231  bool IsCorrectDomain(const unsigned char Line 433  bool IsCorrectDomain(const unsigned char
433                          }                          }
434                  }                  }
435          } while (*domainname);          } while (*domainname);
436          return 1;          return true;
437   out:   out:
438          printk(KERN_DEBUG "%s: Invalid domainname '%s'\n", function, org_domainname);          printk(KERN_DEBUG "%s: Invalid domainname '%s'\n", function,
439          return 0;                 org_domainname);
440            return false;
441  }  }
442    
443  bool IsDomainDef(const unsigned char *buffer)  /**
444     * ccs_is_domain_def - Check whether the given token can be a domainname.
445     *
446     * @buffer: The token to check.
447     *
448     * Returns true if @buffer possibly be a domainname, false otherwise.
449     */
450    bool ccs_is_domain_def(const unsigned char *buffer)
451  {  {
452          /* while (*buffer && (*buffer <= ' ' || *buffer >= 127)) buffer++; */          return !strncmp(buffer, ROOT_NAME, ROOT_NAME_LEN);
         return strncmp(buffer, ROOT_NAME, ROOT_NAME_LEN) == 0;  
453  }  }
454    
455  struct domain_info *FindDomain(const char *domainname0)  /**
456     * ccs_find_domain - Find a domain by the given name.
457     *
458     * @domainname: The domainname to find.
459     *
460     * Returns pointer to "struct domain_info" if found, NULL otherwise.
461     */
462    struct domain_info *ccs_find_domain(const char *domainname)
463  {  {
464          struct domain_info *domain;          struct domain_info *domain;
465          struct path_info domainname;          struct path_info name;
466          domainname.name = domainname0;          name.name = domainname;
467          fill_path_info(&domainname);          ccs_fill_path_info(&name);
468          list1_for_each_entry(domain, &domain_list, list) {          list1_for_each_entry(domain, &domain_list, list) {
469                  if (!domain->is_deleted && !pathcmp(&domainname, domain->domainname)) return domain;                  if (!domain->is_deleted &&
470                        !ccs_pathcmp(&name, domain->domainname))
471                            return domain;
472          }          }
473          return NULL;          return NULL;
474  }  }
475    
476  static int PathDepth(const char *pathname)  /**
477     * path_depth - Evaluate the number of '/' in a string.
478     *
479     * @pathname: The string to evaluate.
480     *
481     * Returns path depth of the string.
482     *
483     * I score 2 for each of the '/' in the @pathname
484     * and score 1 if the @pathname ends with '/'.
485     */
486    static int path_depth(const char *pathname)
487  {  {
488          int i = 0;          int i = 0;
489          if (pathname) {          if (pathname) {
490                  char *ep = strchr(pathname, '\0');                  const char *ep = pathname + strlen(pathname);
491                  if (pathname < ep--) {                  if (pathname < ep--) {
492                          if (*ep != '/') i++;                          if (*ep != '/')
493                          while (pathname <= ep) if (*ep-- == '/') i += 2;                                  i++;
494                            while (pathname <= ep)
495                                    if (*ep-- == '/')
496                                            i += 2;
497                  }                  }
498          }          }
499          return i;          return i;
500  }  }
501    
502    /**
503     * const_part_length - Evaluate the initial length without a pattern in a token.
504     *
505     * @filename: The string to evaluate.
506     *
507     * Returns the initial length without a pattern in @filename.
508     */
509  static int const_part_length(const char *filename)  static int const_part_length(const char *filename)
510  {  {
511            char c;
512          int len = 0;          int len = 0;
513          if (filename) {          if (!filename)
514                  char c;                  return 0;
515                  while ((c = *filename++) != '\0') {          while (1) {
516                          if (c != '\\') { len++; continue; }                  c = *filename++;
517                          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; }  
                         }  
518                          break;                          break;
519                    if (c != '\\') {
520                            len++;
521                            continue;
522                    }
523                    c = *filename++;
524                    switch (c) {
525                    case '\\':  /* "\\" */
526                            len += 2;
527                            continue;
528                    case '0':   /* "\ooo" */
529                    case '1':
530                    case '2':
531                    case '3':
532                            c = *filename++;
533                            if (c < '0' || c > '7')
534                                    break;
535                            c = *filename++;
536                            if (c < '0' || c > '7')
537                                    break;
538                            len += 4;
539                            continue;
540                  }                  }
541                    break;
542          }          }
543          return len;          return len;
544  }  }
545    
546  void fill_path_info(struct path_info *ptr)  /**
547     * ccs_fill_path_info - Fill in "struct path_info" members.
548     *
549     * @ptr: Pointer to "struct path_info" to fill in.
550     *
551     * The caller sets "struct path_info"->name.
552     */
553    void ccs_fill_path_info(struct path_info *ptr)
554  {  {
555          const char *name = ptr->name;          const char *name = ptr->name;
556          const int len = strlen(name);          const int len = strlen(name);
# Line 299  void fill_path_info(struct path_info *pt Line 559  void fill_path_info(struct path_info *pt
559          ptr->is_dir = len && (name[len - 1] == '/');          ptr->is_dir = len && (name[len - 1] == '/');
560          ptr->is_patterned = (ptr->const_len < len);          ptr->is_patterned = (ptr->const_len < len);
561          ptr->hash = full_name_hash(name, len);          ptr->hash = full_name_hash(name, len);
562          ptr->depth = PathDepth(name);          ptr->depth = path_depth(name);
563  }  }
564    
565  static int FileMatchesToPattern2(const char *filename, const char *filename_end, const char *pattern, const char *pattern_end)  /**
566     * file_matches_to_pattern2 - Pattern matching without '/' character
567     * and "\-" pattern.
568     *
569     * @filename:     The start of string to check.
570     * @filename_end: The end of string to check.
571     * @pattern:      The start of pattern to compare.
572     * @pattern_end:  The end of pattern to compare.
573     *
574     * Returns true if @filename matches @pattern, false otherwise.
575     */
576    static bool file_matches_to_pattern2(const char *filename,
577                                         const char *filename_end,
578                                         const char *pattern,
579                                         const char *pattern_end)
580  {  {
581          while (filename < filename_end && pattern < pattern_end) {          while (filename < filename_end && pattern < pattern_end) {
582                    char c;
583                  if (*pattern != '\\') {                  if (*pattern != '\\') {
584                          if (*filename++ != *pattern++) return 0;                          if (*filename++ != *pattern++)
585                  } else {                                  return false;
586                          char c = *filename;                          continue;
587                          pattern++;                  }
588                          switch (*pattern) {                  c = *filename;
589                          case '?':                  pattern++;
590                                  if (c == '/') {                  switch (*pattern) {
591                                          return 0;                          int i;
592                                  } else if (c == '\\') {                          int j;
593                                          if ((c = filename[1]) == '\\') {                  case '?':
594                                                  filename++; /* safe because filename is \\ */                          if (c == '/') {
595                                          } else if (c >= '0' && c <= '3' && (c = filename[2]) >= '0' && c <= '7' && (c = filename[3]) >= '0' && c <= '7') {                                  return false;
596                                                  filename += 3; /* safe because filename is \ooo */                          } else if (c == '\\') {
597                                          } else {                                  if (filename[1] == '\\')
598                                                  return 0;                                          filename++;
599                                          }                                  else if (is_byte_range(filename + 1))
600                                  }                                          filename += 3;
601                                  break;                                  else
602                          case '\\':                                          return false;
603                                  if (c != '\\') return 0;                          }
604                                  if (*++filename != '\\') return 0; /* safe because *filename != '\0' */                          break;
605                                  break;                  case '\\':
606                          case '+':                          if (c != '\\')
607                                  if (c < '0' || c > '9') return 0;                                  return false;
608                                  break;                          if (*++filename != '\\')
609                          case 'x':                                  return false;
610                                  if (!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) return 0;                          break;
611                                  break;                  case '+':
612                          case 'a':                          if (!is_decimal(c))
613                                  if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))) return 0;                                  return false;
614                            break;
615                    case 'x':
616                            if (!is_hexadecimal(c))
617                                    return false;
618                            break;
619                    case 'a':
620                            if (!is_alphabet_char(c))
621                                    return false;
622                            break;
623                    case '0':
624                    case '1':
625                    case '2':
626                    case '3':
627                            if (c == '\\' && is_byte_range(filename + 1)
628                                && strncmp(filename + 1, pattern, 3) == 0) {
629                                    filename += 3;
630                                    pattern += 2;
631                                  break;                                  break;
632                          case '0':                          }
633                          case '1':                          return false; /* Not matched. */
634                          case '2':                  case '*':
635                          case '3':                  case '@':
636                                  if (c == '\\' && (c = filename[1]) >= '0' && c <= '3' && c == *pattern                          for (i = 0; i <= filename_end - filename; i++) {
637                                          && (c = filename[2]) >= '0' && c <= '7' && c == pattern[1]                                  if (file_matches_to_pattern2(filename + i,
638                                          && (c = filename[3]) >= '0' && c <= '7' && c == pattern[2]) {                                                               filename_end,
639                                          filename += 3; /* safe because filename is \ooo */                                                               pattern + 1,
640                                          pattern += 2; /* safe because pattern is \ooo  */                                                               pattern_end))
641                                            return true;
642                                    c = filename[i];
643                                    if (c == '.' && *pattern == '@')
644                                          break;                                          break;
645                                  }                                  if (c != '\\')
646                                  return 0; /* Not matched. */                                          continue;
647                          case '*':                                  if (filename[i + 1] == '\\')
648                          case '@':                                          i++;
649                                  {                                  else if (is_byte_range(filename + i + 1))
650                                          int i;                                          i += 3;
651                                          for (i = 0; i <= filename_end - filename; i++) {                                  else
652                                                  if (FileMatchesToPattern2(filename + i, filename_end, pattern + 1, pattern_end)) return 1;                                          break; /* Bad pattern. */
                                                 if ((c = filename[i]) == '.' && *pattern == '@') break;  
                                                 if (c == '\\') {  
                                                         if ((c = filename[i + 1]) == '\\') {  
                                                                 i++; /* safe because filename is \\ */  
                                                         } else if (c >= '0' && c <= '3' && (c = filename[i + 2]) >= '0' && c <= '7' && (c = filename[i + 3]) >= '0' && c <= '7') {  
                                                                 i += 3; /* safe because filename is \ooo */  
                                                         } else {  
                                                                 break; /* Bad pattern. */  
                                                         }  
                                                 }  
                                         }  
                                         return 0; /* Not matched. */  
                                 }  
                         default:  
                                 {  
                                         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. */  
653                          }                          }
654                          filename++; /* safe because *filename != '\0' */                          return false; /* Not matched. */
655                          pattern++; /* safe because *pattern != '\0' */                  default:
656                            j = 0;
657                            c = *pattern;
658                            if (c == '$') {
659                                    while (is_decimal(filename[j]))
660                                            j++;
661                            } else if (c == 'X') {
662                                    while (is_hexadecimal(filename[j]))
663                                            j++;
664                            } else if (c == 'A') {
665                                    while (is_alphabet_char(filename[j]))
666                                            j++;
667                            }
668                            for (i = 1; i <= j; i++) {
669                                    if (file_matches_to_pattern2(filename + i,
670                                                                 filename_end,
671                                                                 pattern + 1,
672                                                                 pattern_end))
673                                            return true;
674                            }
675                            return false; /* Not matched or bad pattern. */
676                  }                  }
677                    filename++;
678                    pattern++;
679          }          }
680          while (*pattern == '\\' && (*(pattern + 1) == '*' || *(pattern + 1) == '@')) pattern += 2;          while (*pattern == '\\' &&
681          return (filename == filename_end && pattern == pattern_end);                 (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
682                    pattern += 2;
683            return filename == filename_end && pattern == pattern_end;
684  }  }
685    
686  static int FileMatchesToPattern(const char *filename, const char *filename_end, const char *pattern, const char *pattern_end)  /**
687     * file_matches_to_pattern - Pattern matching without without '/' character.
688     *
689     * @filename:     The start of string to check.
690     * @filename_end: The end of string to check.
691     * @pattern:      The start of pattern to compare.
692     * @pattern_end:  The end of pattern to compare.
693     *
694     * Returns true if @filename matches @pattern, false otherwise.
695     */
696    static bool file_matches_to_pattern(const char *filename,
697                                        const char *filename_end,
698                                        const char *pattern,
699                                        const char *pattern_end)
700  {  {
701          const char *pattern_start = pattern;          const char *pattern_start = pattern;
702          int first = 1;          bool first = true;
703          int result;          bool result;
704          while (pattern < pattern_end - 1) {          while (pattern < pattern_end - 1) {
705                  if (*pattern++ != '\\' || *pattern++ != '-') continue;                  /* Split at "\-" pattern. */
706                  result = FileMatchesToPattern2(filename, filename_end, pattern_start, pattern - 2);                  if (*pattern++ != '\\' || *pattern++ != '-')
707                  if (first) result = !result;                          continue;
708                  if (result) return 0;                  result = file_matches_to_pattern2(filename, filename_end,
709                  first = 0;                                                    pattern_start, pattern - 2);
710                    if (first)
711                            result = !result;
712                    if (result)
713                            return false;
714                    first = false;
715                  pattern_start = pattern;                  pattern_start = pattern;
716          }          }
717          result = FileMatchesToPattern2(filename, filename_end, pattern_start, pattern_end);          result = file_matches_to_pattern2(filename, filename_end,
718                                              pattern_start, pattern_end);
719          return first ? result : !result;          return first ? result : !result;
720  }  }
721    
722  /*  /**
723   *  Check whether the given pathname matches to the given pattern.   * ccs_path_matches_pattern - Check whether the given filename matches the given pattern.
724   *  Returns nonzero if matches, zero otherwise.   * @filename: The filename to check.
725   *   * @pattern:  The pattern to compare.
726   *  The following patterns are available.   *
727   *    \\     \ itself.   * Returns true if matches, false otherwise.
728   *    \ooo   Octal representation of a byte.   *
729   *    \*     More than or equals to 0 character other than '/'.   * The following patterns are available.
730   *    \@     More than or equals to 0 character other than '/' or '.'.   *   \\     \ itself.
731   *    \?     1 byte character other than '/'.   *   \ooo   Octal representation of a byte.
732   *    \$     More than or equals to 1 decimal digit.   *   \*     More than or equals to 0 character other than '/'.
733   *    \+     1 decimal digit.   *   \@     More than or equals to 0 character other than '/' or '.'.
734   *    \X     More than or equals to 1 hexadecimal digit.   *   \?     1 byte character other than '/'.
735   *    \x     1 hexadecimal digit.   *   \$     More than or equals to 1 decimal digit.
736   *    \A     More than or equals to 1 alphabet character.   *   \+     1 decimal digit.
737   *    \a     1 alphabet character.   *   \X     More than or equals to 1 hexadecimal digit.
738   *    \-     Subtraction operator.   *   \x     1 hexadecimal digit.
739   */   *   \A     More than or equals to 1 alphabet character.
740     *   \a     1 alphabet character.
741  int PathMatchesToPattern(const struct path_info *pathname0, const struct path_info *pattern0)   *   \-     Subtraction operator.
742  {   */
743          /* if (!pathname || !pattern) return 0; */  bool ccs_path_matches_pattern(const struct path_info *filename,
744          const char *pathname = pathname0->name, *pattern = pattern0->name;                                const struct path_info *pattern)
745          const int len = pattern0->const_len;  {
746          if (!pattern0->is_patterned) return !pathcmp(pathname0, pattern0);          /*
747          if (pathname0->depth != pattern0->depth) return 0;            if (!filename || !pattern)
748          if (strncmp(pathname, pattern, len)) return 0;            return false;
749          pathname += len; pattern += len;          */
750          while (*pathname && *pattern) {          const char *f = filename->name;
751                  const char *pathname_delimiter = strchr(pathname, '/'), *pattern_delimiter = strchr(pattern, '/');          const char *p = pattern->name;
752                  if (!pathname_delimiter) pathname_delimiter = strchr(pathname, '\0');          const int len = pattern->const_len;
753                  if (!pattern_delimiter) pattern_delimiter = strchr(pattern, '\0');          /* If @pattern doesn't contain pattern, I can use strcmp(). */
754                  if (!FileMatchesToPattern(pathname, pathname_delimiter, pattern, pattern_delimiter)) return 0;          if (!pattern->is_patterned)
755                  pathname = *pathname_delimiter ? pathname_delimiter + 1 : pathname_delimiter;                  return !ccs_pathcmp(filename, pattern);
756                  pattern = *pattern_delimiter ? pattern_delimiter + 1 : pattern_delimiter;          /* Dont compare if the number of '/' differs. */
757          }          if (filename->depth != pattern->depth)
758          while (*pattern == '\\' && (*(pattern + 1) == '*' || *(pattern + 1) == '@')) pattern += 2;                  return false;
759          return (!*pathname && !*pattern);          /* Compare the initial length without patterns. */
760  }          if (strncmp(f, p, len))
761                    return false;
762  /*          f += len;
763   *  Transactional printf() to struct io_buffer structure.          p += len;
764   *  snprintf() will truncate, but io_printf() won't.          /* Main loop. Compare each directory component. */
765   *  Returns zero on success, nonzero otherwise.          while (*f && *p) {
766                    const char *f_delimiter = strchr(f, '/');
767                    const char *p_delimiter = strchr(p, '/');
768                    if (!f_delimiter)
769                            f_delimiter = f + strlen(f);
770                    if (!p_delimiter)
771                            p_delimiter = p + strlen(p);
772                    if (!file_matches_to_pattern(f, f_delimiter, p, p_delimiter))
773                            return false;
774                    f = f_delimiter;
775                    if (*f)
776                            f++;
777                    p = p_delimiter;
778                    if (*p)
779                            p++;
780            }
781            /* Ignore trailing "\*" and "\@" in @pattern. */
782            while (*p == '\\' &&
783                   (*(p + 1) == '*' || *(p + 1) == '@'))
784                    p += 2;
785            return !*f && !*p;
786    }
787    
788    /**
789     * ccs_io_printf - Transactional printf() to "struct ccs_io_buffer" structure.
790     *
791     * @head: Pointer to "struct ccs_io_buffer".
792     * @fmt:  The printf()'s format string, followed by parameters.
793     *
794     * Returns true on success, false otherwise.
795     *
796     * The snprintf() will truncate, but ccs_io_printf() won't.
797   */   */
798  int io_printf(struct io_buffer *head, const char *fmt, ...)  bool ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
799  {  {
800          va_list args;          va_list args;
801          int len, pos = head->read_avail, size = head->readbuf_size - pos;          int len;
802          if (size <= 0) return -ENOMEM;          int pos = head->read_avail;
803            int size = head->readbuf_size - pos;
804            if (size <= 0)
805                    return false;
806          va_start(args, fmt);          va_start(args, fmt);
807          len = vsnprintf(head->read_buf + pos, size, fmt, args);          len = vsnprintf(head->read_buf + pos, size, fmt, args);
808          va_end(args);          va_end(args);
809          if (pos + len >= head->readbuf_size) return -ENOMEM;          if (pos + len >= head->readbuf_size)
810                    return false;
811          head->read_avail += len;          head->read_avail += len;
812          return 0;          return true;
813  }  }
814    
815  /*  /**
816   * Get realpath() of current process.   * ccs_get_exe - Get ccs_realpath() of current process.
817   * This function uses ccs_alloc(), so caller must ccs_free() if this function didn't return NULL.   *
818   */   * Returns the ccs_realpath() of current process on success, NULL otherwise.
819  const char *GetEXE(void)   *
820  {   * This function uses ccs_alloc(), so the caller must ccs_free()
821          if (current->mm) {   * if this function didn't return NULL.
822                  struct vm_area_struct *vma;   */
823                  for (vma = current->mm->mmap; vma; vma = vma->vm_next) {  const char *ccs_get_exe(void)
824                          if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {  {
825                                  return realpath_from_dentry(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt);          struct mm_struct *mm = current->mm;
826                          }          struct vm_area_struct *vma;
827            const char *cp = NULL;
828            if (!mm)
829                    return NULL;
830            down_read(&mm->mmap_sem);
831            for (vma = mm->mmap; vma; vma = vma->vm_next) {
832                    if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
833                            cp = ccs_realpath_from_dentry(vma->vm_file->f_dentry,
834                                                          vma->vm_file->f_vfsmnt);
835                            break;
836                  }                  }
837          }          }
838          return NULL;          up_read(&mm->mmap_sem);
839            return cp;
840  }  }
841    
842  const char *GetMSG(const bool is_enforce)  /**
843     * ccs_get_msg - Get warning message.
844     *
845     * @is_enforce: Is it enforcing mode?
846     *
847     * Returns "ERROR" or "WARNING".
848     */
849    const char *ccs_get_msg(const bool is_enforce)
850  {  {
851          if (is_enforce) return "ERROR"; else return "WARNING";          if (is_enforce)
852                    return "ERROR";
853            else
854                    return "WARNING";
855  }  }
856    
857  const char *GetAltExec(void)  /**
858     * ccs_can_sleep - Check whether it is permitted to do operations that may sleep.
859     *
860     * Returns true if it is permitted to do operations that may sleep,
861     * false otherwise.
862     *
863     * TOMOYO Linux supports interactive enforcement that lets processes
864     * wait for the administrator's decision.
865     * All hooks but the one for ccs_may_autobind() are inserted where
866     * it is permitted to do operations that may sleep.
867     * Thus, this warning should not happen.
868     */
869    bool ccs_can_sleep(void)
870  {  {
871          const u8 profile = current->domain_info->profile;          static u8 count = 20;
872          const struct path_info *alt_exec = profile_ptr[profile] ? profile_ptr[profile]->alt_exec : NULL;          if (likely(!in_interrupt()))
873          return alt_exec ? alt_exec->name : NULL;                  return true;
874            if (count) {
875                    count--;
876                    printk(KERN_ERR "BUG: sleeping function called "
877                           "from invalid context.\n");
878                    dump_stack();
879            }
880            return false;
881  }  }
882    
883  /*************************  DOMAIN POLICY HANDLER  *************************/  /**
884     * ccs_check_flags - Check mode for specified functionality.
885  /* Check whether the given access control is enabled. */   *
886  unsigned int CheckCCSFlags(const unsigned int index)   * @domain: Pointer to "struct domain_info". NULL for current->domain_info.
887     * @index:  The functionality to check mode.
888     *
889     * Returns the mode of specified functionality.
890     */
891    unsigned int ccs_check_flags(const struct domain_info *domain, const u8 index)
892  {  {
893          const u8 profile = current->domain_info->profile;          u8 profile;
894            if (!domain)
895                    domain = current->domain_info;
896            profile = domain->profile;
897          return sbin_init_started && index < CCS_MAX_CONTROL_INDEX          return sbin_init_started && index < CCS_MAX_CONTROL_INDEX
898  #if MAX_PROFILES != 256  #if MAX_PROFILES != 256
899                  && profile < MAX_PROFILES                  && profile < MAX_PROFILES
900  #endif  #endif
901                  && profile_ptr[profile] ? profile_ptr[profile]->value[index] : 0;                  && profile_ptr[profile] ?
902                    profile_ptr[profile]->value[index] : 0;
903  }  }
 EXPORT_SYMBOL(CheckCCSFlags);  
904    
905  bool TomoyoVerboseMode(void)  #ifdef CONFIG_TOMOYO
906    /**
907     * ccs_check_capability_flags - Check mode for specified capability.
908     *
909     * @domain: Pointer to "struct domain_info". NULL for current->domain_info.
910     * @index:  The capability to check mode.
911     *
912     * Returns the mode of specified capability.
913     */
914    static u8 ccs_check_capability_flags(const struct domain_info *domain,
915                                         const u8 index)
916    {
917            const u8 profile = domain ? domain->profile :
918                    current->domain_info->profile;
919            return sbin_init_started && index < TOMOYO_MAX_CAPABILITY_INDEX
920    #if MAX_PROFILES != 256
921                    && profile < MAX_PROFILES
922    #endif
923                    && profile_ptr[profile] ?
924                    profile_ptr[profile]->capability_value[index] : 0;
925    }
926    
927    /**
928     * ccs_cap2keyword - Convert capability operation to capability name.
929     *
930     * @operation: The capability index.
931     *
932     * Returns the name of the specified capability's name.
933     */
934    const char *ccs_cap2keyword(const u8 operation)
935  {  {
936          return CheckCCSFlags(CCS_TOMOYO_VERBOSE) != 0;          return operation < TOMOYO_MAX_CAPABILITY_INDEX
937                    ? capability_control_keyword[operation] : NULL;
938  }  }
939    
940  /* Check whether the given access control is enforce mode. */  #endif
941  bool CheckCCSEnforce(const unsigned int index)  
942    /**
943     * ccs_init_request_info - Initialize "struct ccs_request_info" members.
944     *
945     * @r:      Pointer to "struct ccs_request_info" to initialize.
946     * @domain: Pointer to "struct domain_info". NULL for current->domain_info.
947     * @index:  Index number of functionality.
948     */
949    void ccs_init_request_info(struct ccs_request_info *r,
950                               struct domain_info *domain, const u8 index)
951  {  {
952          return CheckCCSFlags(index) == 3;          memset(r, 0, sizeof(*r));
953            if (!domain)
954                    domain = current->domain_info;
955            r->domain = domain;
956            r->profile = domain->profile;
957            if (index < CCS_MAX_CONTROL_INDEX)
958                    r->mode = ccs_check_flags(domain, index);
959    #ifdef CONFIG_TOMOYO
960            else
961                    r->mode = ccs_check_capability_flags(domain, index
962                                                         - CCS_MAX_CONTROL_INDEX);
963    #endif
964  }  }
 EXPORT_SYMBOL(CheckCCSEnforce);  
965    
966  bool CheckDomainQuota(struct domain_info * const domain)  /**
967     * ccs_verbose_mode - Check whether TOMOYO is verbose mode.
968     *
969     * @domain: Pointer to "struct domain_info". NULL for current->domain_info.
970     *
971     * Returns true if domain policy violation warning should be printed to
972     * console.
973     */
974    bool ccs_verbose_mode(const struct domain_info *domain)
975    {
976            return ccs_check_flags(domain, CCS_TOMOYO_VERBOSE) != 0;
977    }
978    
979    /**
980     * ccs_check_domain_quota - Check for domain's quota.
981     *
982     * @domain: Pointer to "struct domain_info".
983     *
984     * Returns true if the domain is not exceeded quota, false otherwise.
985     */
986    bool ccs_check_domain_quota(struct domain_info * const domain)
987  {  {
988          unsigned int count = 0;          unsigned int count = 0;
989          struct acl_info *ptr;          struct acl_info *ptr;
990          if (!domain) return 1;          if (!domain)
991                    return true;
992          list1_for_each_entry(ptr, &domain->acl_info_list, list) {          list1_for_each_entry(ptr, &domain->acl_info_list, list) {
993                  if (!ptr->is_deleted) count++;                  if (ptr->type & ACL_DELETED)
994                            continue;
995                    switch (ccs_acl_type2(ptr)) {
996                            struct single_path_acl_record *acl1;
997                            struct double_path_acl_record *acl2;
998                            u16 perm;
999                    case TYPE_SINGLE_PATH_ACL:
1000                            acl1 = container_of(ptr, struct single_path_acl_record,
1001                                                head);
1002                            perm = acl1->perm;
1003                            if (perm & (1 << TYPE_EXECUTE_ACL))
1004                                    count++;
1005                            if (perm &
1006                                ((1 << TYPE_READ_ACL) | (1 << TYPE_WRITE_ACL)))
1007                                    count++;
1008                            if (perm & (1 << TYPE_CREATE_ACL))
1009                                    count++;
1010                            if (perm & (1 << TYPE_UNLINK_ACL))
1011                                    count++;
1012                            if (perm & (1 << TYPE_MKDIR_ACL))
1013                                    count++;
1014                            if (perm & (1 << TYPE_RMDIR_ACL))
1015                                    count++;
1016                            if (perm & (1 << TYPE_MKFIFO_ACL))
1017                                    count++;
1018                            if (perm & (1 << TYPE_MKSOCK_ACL))
1019                                    count++;
1020                            if (perm & (1 << TYPE_MKBLOCK_ACL))
1021                                    count++;
1022                            if (perm & (1 << TYPE_MKCHAR_ACL))
1023                                    count++;
1024                            if (perm & (1 << TYPE_TRUNCATE_ACL))
1025                                    count++;
1026                            if (perm & (1 << TYPE_SYMLINK_ACL))
1027                                    count++;
1028                            if (perm & (1 << TYPE_REWRITE_ACL))
1029                                    count++;
1030                            break;
1031                    case TYPE_DOUBLE_PATH_ACL:
1032                            acl2 = container_of(ptr, struct double_path_acl_record,
1033                                                head);
1034                            perm = acl2->perm;
1035                            if (perm & (1 << TYPE_LINK_ACL))
1036                                    count++;
1037                            if (perm & (1 << TYPE_RENAME_ACL))
1038                                    count++;
1039                            break;
1040                    case TYPE_EXECUTE_HANDLER:
1041                    case TYPE_DENIED_EXECUTE_HANDLER:
1042                            break;
1043                    default:
1044                            count++;
1045                    }
1046          }          }
1047          if (count < CheckCCSFlags(CCS_TOMOYO_MAX_ACCEPT_ENTRY)) return 1;          if (count < ccs_check_flags(domain, CCS_TOMOYO_MAX_ACCEPT_ENTRY))
1048                    return true;
1049          if (!domain->quota_warned) {          if (!domain->quota_warned) {
1050                  domain->quota_warned = 1;                  domain->quota_warned = true;
1051                  printk("TOMOYO-WARNING: Domain '%s' has so many ACLs to hold. Stopped learning mode.\n", domain->domainname->name);                  printk(KERN_WARNING "TOMOYO-WARNING: "
1052                           "Domain '%s' has so many ACLs to hold. "
1053                           "Stopped learning mode.\n", domain->domainname->name);
1054          }          }
1055          return 0;          return false;
1056  }  }
1057    
1058  /* Check whether the given access control is learning mode. */  /**
1059  bool CheckCCSAccept(const unsigned int index, struct domain_info * const domain)   * ccs_find_or_assign_new_profile - Create a new profile.
1060  {   *
1061          if (CheckCCSFlags(index) != 1) return 0;   * @profile: Profile number to create.
1062          return CheckDomainQuota(domain);   *
1063  }   * Returns pointer to "struct profile" on success, NULL otherwise.
1064  EXPORT_SYMBOL(CheckCCSAccept);   */
1065    static struct profile *ccs_find_or_assign_new_profile(const unsigned int
1066  static struct profile *FindOrAssignNewProfile(const unsigned int profile)                                                        profile)
1067  {  {
1068          static DEFINE_MUTEX(profile_lock);          static DEFINE_MUTEX(lock);
1069          struct profile *ptr = NULL;          struct profile *ptr = NULL;
1070          mutex_lock(&profile_lock);          mutex_lock(&lock);
1071          if (profile < MAX_PROFILES && (ptr = profile_ptr[profile]) == NULL) {          if (profile < MAX_PROFILES) {
1072                  if ((ptr = alloc_element(sizeof(*ptr))) != NULL) {                  ptr = profile_ptr[profile];
1073                    if (ptr)
1074                            goto ok;
1075                    ptr = ccs_alloc_element(sizeof(*ptr));
1076                    if (ptr) {
1077                          int i;                          int i;
1078                          for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) ptr->value[i] = ccs_control_array[i].current_value;                          for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++)
1079                                    ptr->value[i]
1080                                            = ccs_control_array[i].current_value;
1081                            /*
1082                             * Needn't to initialize "ptr->capability_value"
1083                             * because they are always 0.
1084                             */
1085                          mb(); /* Avoid out-of-order execution. */                          mb(); /* Avoid out-of-order execution. */
1086                          profile_ptr[profile] = ptr;                          profile_ptr[profile] = ptr;
1087                  }                  }
1088          }          }
1089          mutex_unlock(&profile_lock);   ok:
1090            mutex_unlock(&lock);
1091          return ptr;          return ptr;
1092  }  }
1093    
1094  static int SetProfile(struct io_buffer *head)  /**
1095     * write_profile - Write profile table.
1096     *
1097     * @head: Pointer to "struct ccs_io_buffer".
1098     *
1099     * Returns 0 on success, negative value otherwise.
1100     */
1101    static int write_profile(struct ccs_io_buffer *head)
1102  {  {
1103          char *data = head->write_buf;          char *data = head->write_buf;
1104          unsigned int i, value;          unsigned int i;
1105            unsigned int value;
1106          char *cp;          char *cp;
1107          struct profile *profile;          struct profile *profile;
         if (!isRoot()) return -EPERM;  
1108          i = simple_strtoul(data, &cp, 10);          i = simple_strtoul(data, &cp, 10);
1109          if (data != cp) {          if (data != cp) {
1110                  if (*cp != '-') return -EINVAL;                  if (*cp != '-')
1111                  data= cp + 1;                          return -EINVAL;
1112                    data = cp + 1;
1113          }          }
1114          profile = FindOrAssignNewProfile(i);          profile = ccs_find_or_assign_new_profile(i);
1115          if (!profile) return -EINVAL;          if (!profile)
1116                    return -EINVAL;
1117          cp = strchr(data, '=');          cp = strchr(data, '=');
1118          if (!cp) return -EINVAL;          if (!cp)
1119                    return -EINVAL;
1120          *cp = '\0';          *cp = '\0';
1121          UpdateCounter(CCS_UPDATES_COUNTER_PROFILE);          ccs_update_counter(CCS_UPDATES_COUNTER_PROFILE);
1122          if (strcmp(data, ccs_control_array[CCS_PROFILE_COMMENT].keyword) == 0) {          if (!strcmp(data, "COMMENT")) {
1123                  profile->comment = SaveName(cp + 1);                  profile->comment = ccs_save_name(cp + 1);
1124                  return 0;                  return 0;
1125          }          }
 #if 0  
1126  #ifdef CONFIG_TOMOYO  #ifdef CONFIG_TOMOYO
1127          if (strcmp(data, ccs_control_array[CCS_TOMOYO_ALT_EXEC].keyword) == 0) {          if (str_starts(&data, KEYWORD_MAC_FOR_CAPABILITY)) {
1128                  cp++;                  if (sscanf(cp + 1, "%u", &value) != 1) {
1129                  if (*cp && !IsCorrectPath(cp, 1, -1, -1, __FUNCTION__)) cp = "";                          for (i = 0; i < 4; i++) {
1130                  profile->alt_exec = SaveName(cp);                                  if (strcmp(cp + 1, mode_4[i]))
1131                  return 0;                                          continue;
1132          }                                  value = i;
1133  #endif                                  break;
1134  #endif                          }
1135          if (sscanf(cp + 1, "%u", &value) != 1) return -EINVAL;                          if (i == 4)
1136  #ifdef CONFIG_TOMOYO                                  return -EINVAL;
1137          if (strncmp(data, KEYWORD_MAC_FOR_CAPABILITY, KEYWORD_MAC_FOR_CAPABILITY_LEN) == 0) {                  }
1138                  return SetCapabilityStatus(data + KEYWORD_MAC_FOR_CAPABILITY_LEN, value, i);                  if (value > 3)
1139                            value = 3;
1140                    for (i = 0; i < TOMOYO_MAX_CAPABILITY_INDEX; i++) {
1141                            if (strcmp(data, capability_control_keyword[i]))
1142                                    continue;
1143                            profile->capability_value[i] = value;
1144                            return 0;
1145                    }
1146                    return -EINVAL;
1147          }          }
1148  #endif  #endif
1149          for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) {          for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) {
1150                  if (strcmp(data, ccs_control_array[i].keyword)) continue;                  if (strcmp(data, ccs_control_array[i].keyword))
1151                  if (value > ccs_control_array[i].max_value) value = ccs_control_array[i].max_value;                          continue;
1152                    if (sscanf(cp + 1, "%u", &value) != 1) {
1153                            int j;
1154                            const char **modes;
1155                            switch (i) {
1156                            case CCS_SAKURA_RESTRICT_AUTOBIND:
1157                            case CCS_TOMOYO_VERBOSE:
1158                                    modes = mode_2;
1159                                    break;
1160                            default:
1161                                    modes = mode_4;
1162                                    break;
1163                            }
1164                            for (j = 0; j < 4; j++) {
1165                                    if (strcmp(cp + 1, modes[j]))
1166                                            continue;
1167                                    value = j;
1168                                    break;
1169                            }
1170                            if (j == 4)
1171                                    return -EINVAL;
1172                    } else if (value > ccs_control_array[i].max_value) {
1173                            value = ccs_control_array[i].max_value;
1174                    }
1175                    switch (i) {
1176                    case CCS_SAKURA_DENY_CONCEAL_MOUNT:
1177                    case CCS_SAKURA_RESTRICT_UNMOUNT:
1178                            if (value == 1)
1179                                    value = 2; /* learning mode is not supported. */
1180                    }
1181                  profile->value[i] = value;                  profile->value[i] = value;
1182                  return 0;                  return 0;
1183          }          }
1184          return -EINVAL;          return -EINVAL;
1185  }  }
1186    
1187  static int ReadProfile(struct io_buffer *head)  /**
1188     * read_profile - Read profile table.
1189     *
1190     * @head: Pointer to "struct ccs_io_buffer".
1191     *
1192     * Returns 0.
1193     */
1194    static int read_profile(struct ccs_io_buffer *head)
1195  {  {
1196          if (!head->read_eof) {          static const int total
1197                  if (!isRoot()) return -EPERM;                  = CCS_MAX_CONTROL_INDEX + TOMOYO_MAX_CAPABILITY_INDEX + 1;
1198                  if (!head->read_var2) {          int step;
1199                          int step;          if (head->read_eof)
1200                          for (step = head->read_step; step < MAX_PROFILES * CCS_MAX_CONTROL_INDEX; step++) {                  return 0;
1201                                  const int i = step / CCS_MAX_CONTROL_INDEX, j = step % CCS_MAX_CONTROL_INDEX;          for (step = head->read_step; step < MAX_PROFILES * total; step++) {
1202                                  const struct profile *profile = profile_ptr[i];                  const u8 index = step / total;
1203                                  head->read_step = step;                  u8 type = step % total;
1204                                  if (!profile) continue;                  const struct profile *profile = profile_ptr[index];
1205                                  switch (j) {                  head->read_step = step;
1206                                  case -1: /* Dummy */                  if (!profile)
1207                            continue;
1208    #if !defined(CONFIG_SAKURA) || !defined(CONFIG_TOMOYO)
1209                    switch (type) {
1210  #ifndef CONFIG_SAKURA  #ifndef CONFIG_SAKURA
1211                                  case CCS_SAKURA_DENY_CONCEAL_MOUNT:                  case CCS_SAKURA_DENY_CONCEAL_MOUNT:
1212                                  case CCS_SAKURA_RESTRICT_CHROOT:                  case CCS_SAKURA_RESTRICT_CHROOT:
1213                                  case CCS_SAKURA_RESTRICT_MOUNT:                  case CCS_SAKURA_RESTRICT_MOUNT:
1214                                  case CCS_SAKURA_RESTRICT_UNMOUNT:                  case CCS_SAKURA_RESTRICT_UNMOUNT:
1215                                  case CCS_SAKURA_RESTRICT_PIVOT_ROOT:                  case CCS_SAKURA_RESTRICT_PIVOT_ROOT:
1216                                  case CCS_SAKURA_RESTRICT_AUTOBIND:                  case CCS_SAKURA_RESTRICT_AUTOBIND:
1217  #endif  #endif
1218  #ifndef CONFIG_TOMOYO  #ifndef CONFIG_TOMOYO
1219                                  case CCS_TOMOYO_MAC_FOR_FILE:                  case CCS_TOMOYO_MAC_FOR_FILE:
1220                                  case CCS_TOMOYO_MAC_FOR_ARGV0:                  case CCS_TOMOYO_MAC_FOR_ARGV0:
1221                                  case CCS_TOMOYO_MAC_FOR_ENV:                  case CCS_TOMOYO_MAC_FOR_ENV:
1222                                  case CCS_TOMOYO_MAC_FOR_NETWORK:                  case CCS_TOMOYO_MAC_FOR_NETWORK:
1223                                  case CCS_TOMOYO_MAC_FOR_SIGNAL:                  case CCS_TOMOYO_MAC_FOR_SIGNAL:
1224                                  case CCS_TOMOYO_MAX_ACCEPT_ENTRY:                  case CCS_TOMOYO_MAX_ACCEPT_ENTRY:
1225                                  case CCS_TOMOYO_MAX_GRANT_LOG:                  case CCS_TOMOYO_MAX_GRANT_LOG:
1226                                  case CCS_TOMOYO_MAX_REJECT_LOG:                  case CCS_TOMOYO_MAX_REJECT_LOG:
1227                                  case CCS_TOMOYO_VERBOSE:                  case CCS_TOMOYO_VERBOSE:
1228  #endif  #endif
1229                                  case CCS_TOMOYO_ALT_EXEC:                          continue;
1230                                  case CCS_SLEEP_PERIOD:                  }
1231                                          continue;  #endif
1232                                  }                  if (!type) { /* Print profile' comment tag. */
1233                                  if (j == CCS_PROFILE_COMMENT) {                          if (!ccs_io_printf(head, "%u-COMMENT=%s\n",
1234                                          if (io_printf(head, "%u-%s=%s\n", i, ccs_control_array[CCS_PROFILE_COMMENT].keyword, profile->comment ? profile->comment->name : "")) break;                                             index, profile->comment ?
1235                                  } else if (j == CCS_TOMOYO_ALT_EXEC) {                                             profile->comment->name : ""))
1236                                          const struct path_info *alt_exec = profile->alt_exec;                                  break;
1237                                          if (io_printf(head, "%u-%s=%s\n", i, ccs_control_array[CCS_TOMOYO_ALT_EXEC].keyword, alt_exec ? alt_exec->name : "")) break;                          continue;
                                 } 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;  
                         }  
1238                  }                  }
1239                  if (head->read_var2) {                  type--;
1240                    if (type >= CCS_MAX_CONTROL_INDEX) {
1241  #ifdef CONFIG_TOMOYO  #ifdef CONFIG_TOMOYO
1242                          if (ReadCapabilityStatus(head) == 0)                          const int i = type - CCS_MAX_CONTROL_INDEX;
1243                            const u8 value = profile->capability_value[i];
1244                            if (!ccs_io_printf(head,
1245                                               "%u-" KEYWORD_MAC_FOR_CAPABILITY
1246                                               "%s=%s\n", index,
1247                                               capability_control_keyword[i],
1248                                               mode_4[value]))
1249                                    break;
1250  #endif  #endif
1251                                  head->read_eof = 1;                  } else {
1252                            const unsigned int value = profile->value[type];
1253                            const char **modes = NULL;
1254                            const char *keyword = ccs_control_array[type].keyword;
1255                            switch (ccs_control_array[type].max_value) {
1256                            case 3:
1257                                    modes = mode_4;
1258                                    break;
1259                            case 1:
1260                                    modes = mode_2;
1261                                    break;
1262                            }
1263                            if (modes) {
1264                                    if (!ccs_io_printf(head, "%u-%s=%s\n", index,
1265                                                       keyword, modes[value]))
1266                                            break;
1267                            } else {
1268                                    if (!ccs_io_printf(head, "%u-%s=%u\n", index,
1269                                                       keyword, value))
1270                                            break;
1271                            }
1272                  }                  }
1273          }          }
1274            if (step == MAX_PROFILES * total)
1275                    head->read_eof = true;
1276          return 0;          return 0;
1277  }  }
1278    
1279  /*************************  POLICY MANAGER HANDLER  *************************/  /* Structure for policy manager. */
   
1280  struct policy_manager_entry {  struct policy_manager_entry {
1281          struct list1_head list;          struct list1_head list;
1282            /* A path to program or a domainname. */
1283          const struct path_info *manager;          const struct path_info *manager;
1284          bool is_domain;          bool is_domain;  /* True if manager is a domainname. */
1285          bool is_deleted;          bool is_deleted; /* True if this entry is deleted. */
1286  };  };
1287    
1288    /* The list for "struct policy_manager_entry". */
1289  static LIST1_HEAD(policy_manager_list);  static LIST1_HEAD(policy_manager_list);
1290    
1291  static int AddManagerEntry(const char *manager, const bool is_delete)  /**
1292     * update_manager_entry - Add a manager entry.
1293     *
1294     * @manager:   The path to manager or the domainnamme.
1295     * @is_delete: True if it is a delete request.
1296     *
1297     * Returns 0 on success, negative value otherwise.
1298     */
1299    static int update_manager_entry(const char *manager, const bool is_delete)
1300  {  {
1301          struct policy_manager_entry *new_entry, *ptr;          struct policy_manager_entry *new_entry;
1302            struct policy_manager_entry *ptr;
1303          static DEFINE_MUTEX(lock);          static DEFINE_MUTEX(lock);
1304          const struct path_info *saved_manager;          const struct path_info *saved_manager;
1305          int error = -ENOMEM;          int error = -ENOMEM;
1306          bool is_domain = 0;          bool is_domain = false;
1307          if (!isRoot()) return -EPERM;          if (ccs_is_domain_def(manager)) {
1308          if (IsDomainDef(manager)) {                  if (!ccs_is_correct_domain(manager, __func__))
1309                  if (!IsCorrectDomain(manager, __FUNCTION__)) return -EINVAL;                          return -EINVAL;
1310                  is_domain = 1;                  is_domain = true;
1311          } else {          } else {
1312                  if (!IsCorrectPath(manager, 1, -1, -1, __FUNCTION__)) return -EINVAL;                  if (!ccs_is_correct_path(manager, 1, -1, -1, __func__))
1313                            return -EINVAL;
1314          }          }
1315          if ((saved_manager = SaveName(manager)) == NULL) return -ENOMEM;          saved_manager = ccs_save_name(manager);
1316            if (!saved_manager)
1317                    return -ENOMEM;
1318          mutex_lock(&lock);          mutex_lock(&lock);
1319          list1_for_each_entry(ptr, &policy_manager_list, list) {          list1_for_each_entry(ptr, &policy_manager_list, list) {
1320                  if (ptr->manager == saved_manager) {                  if (ptr->manager != saved_manager)
1321                          ptr->is_deleted = is_delete;                          continue;
1322                          error = 0;                  ptr->is_deleted = is_delete;
1323                          goto out;                  error = 0;
1324                  }                  goto out;
1325          }          }
1326          if (is_delete) {          if (is_delete) {
1327                  error = -ENOENT;                  error = -ENOENT;
1328                  goto out;                  goto out;
1329          }          }
1330          if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out;          new_entry = ccs_alloc_element(sizeof(*new_entry));
1331            if (!new_entry)
1332                    goto out;
1333          new_entry->manager = saved_manager;          new_entry->manager = saved_manager;
1334          new_entry->is_domain = is_domain;          new_entry->is_domain = is_domain;
1335          list1_add_tail_mb(&new_entry->list, &policy_manager_list);          list1_add_tail_mb(&new_entry->list, &policy_manager_list);
1336          error = 0;          error = 0;
1337   out:   out:
1338          mutex_unlock(&lock);          mutex_unlock(&lock);
1339          if (!error) UpdateCounter(CCS_UPDATES_COUNTER_MANAGER);          if (!error)
1340                    ccs_update_counter(CCS_UPDATES_COUNTER_MANAGER);
1341          return error;          return error;
1342  }  }
1343    
1344  static int AddManagerPolicy(struct io_buffer *head)  /**
1345     * write_manager_policy - Write manager policy.
1346     *
1347     * @head: Pointer to "struct ccs_io_buffer".
1348     *
1349     * Returns 0 on success, negative value otherwise.
1350     */
1351    static int write_manager_policy(struct ccs_io_buffer *head)
1352  {  {
1353          const char *data = head->write_buf;          char *data = head->write_buf;
1354          bool is_delete = 0;          bool is_delete = str_starts(&data, KEYWORD_DELETE);
1355          if (!isRoot()) return -EPERM;          if (!strcmp(data, "manage_by_non_root")) {
1356          if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {                  manage_by_non_root = !is_delete;
1357                  data += KEYWORD_DELETE_LEN;                  return 0;
                 is_delete = 1;  
1358          }          }
1359          return AddManagerEntry(data, is_delete);          return update_manager_entry(data, is_delete);
1360  }  }
1361    
1362  static int ReadManagerPolicy(struct io_buffer *head)  /**
1363     * read_manager_policy - Read manager policy.
1364     *
1365     * @head: Pointer to "struct ccs_io_buffer".
1366     *
1367     * Returns 0.
1368     */
1369    static int read_manager_policy(struct ccs_io_buffer *head)
1370  {  {
1371          struct list1_head *pos;          struct list1_head *pos;
1372          if (head->read_eof) return 0;          if (head->read_eof)
1373          if (!isRoot()) return -EPERM;                  return 0;
1374          list1_for_each_cookie(pos, head->read_var2, &policy_manager_list) {          list1_for_each_cookie(pos, head->read_var2, &policy_manager_list) {
1375                  struct policy_manager_entry *ptr;                  struct policy_manager_entry *ptr;
1376                  ptr = list1_entry(pos, struct policy_manager_entry, list);                  ptr = list1_entry(pos, struct policy_manager_entry, list);
1377                  if (ptr->is_deleted) continue;                  if (ptr->is_deleted)
1378                  if (io_printf(head, "%s\n", ptr->manager->name)) return 0;                          continue;
1379                    if (!ccs_io_printf(head, "%s\n", ptr->manager->name))
1380                            return 0;
1381          }          }
1382          head->read_eof = 1;          head->read_eof = true;
1383          return 0;          return 0;
1384  }  }
1385    
1386  /* Check whether the current process is a policy manager. */  /**
1387  static int IsPolicyManager(void)   * is_policy_manager - Check whether the current process is a policy manager.
1388     *
1389     * Returns true if the current process is permitted to modify policy
1390     * via /proc/ccs/ interface.
1391     */
1392    static bool is_policy_manager(void)
1393  {  {
1394          struct policy_manager_entry *ptr;          struct policy_manager_entry *ptr;
1395          const char *exe;          const char *exe;
1396          const struct path_info *domainname = current->domain_info->domainname;          struct task_struct *task = current;
1397          bool found = 0;          const struct path_info *domainname = task->domain_info->domainname;
1398          if (!sbin_init_started) return 1;          bool found = false;
1399            if (!sbin_init_started)
1400                    return true;
1401            if (task->tomoyo_flags & CCS_TASK_IS_POLICY_MANAGER)
1402                    return true;
1403            if (!manage_by_non_root && (task->uid || task->euid))
1404                    return false;
1405          list1_for_each_entry(ptr, &policy_manager_list, list) {          list1_for_each_entry(ptr, &policy_manager_list, list) {
1406                  if (!ptr->is_deleted && ptr->is_domain && !pathcmp(domainname, ptr->manager)) return 1;                  if (!ptr->is_deleted && ptr->is_domain
1407                        && !ccs_pathcmp(domainname, ptr->manager)) {
1408                            /* Set manager flag. */
1409                            task->tomoyo_flags |= CCS_TASK_IS_POLICY_MANAGER;
1410                            return true;
1411                    }
1412          }          }
1413          if ((exe = GetEXE()) == NULL) return 0;          exe = ccs_get_exe();
1414            if (!exe)
1415                    return false;
1416          list1_for_each_entry(ptr, &policy_manager_list, list) {          list1_for_each_entry(ptr, &policy_manager_list, list) {
1417                  if (!ptr->is_deleted && !ptr->is_domain && !strcmp(exe, ptr->manager->name)) {                  if (!ptr->is_deleted && !ptr->is_domain
1418                          found = 1;                      && !strcmp(exe, ptr->manager->name)) {
1419                            found = true;
1420                            /* Set manager flag. */
1421                            task->tomoyo_flags |= CCS_TASK_IS_POLICY_MANAGER;
1422                          break;                          break;
1423                  }                  }
1424          }          }
1425          if (!found) { /* Reduce error messages. */          if (!found) { /* Reduce error messages. */
1426                  static pid_t last_pid = 0;                  static pid_t last_pid;
1427                  const pid_t pid = current->pid;                  const pid_t pid = current->pid;
1428                  if (last_pid != pid) {                  if (last_pid != pid) {
1429                          printk("%s ( %s ) is not permitted to update policies.\n", domainname->name, exe);                          printk(KERN_WARNING "%s ( %s ) is not permitted to "
1430                                   "update policies.\n", domainname->name, exe);
1431                          last_pid = pid;                          last_pid = pid;
1432                  }                  }
1433          }          }
# Line 778  static int IsPolicyManager(void) Line 1437  static int IsPolicyManager(void)
1437    
1438  #ifdef CONFIG_TOMOYO  #ifdef CONFIG_TOMOYO
1439    
1440  /*************************  DOMAIN POLICY HANDLER  *************************/  /**
1441     * ccs_find_condition_part - Find condition part from the statement.
1442  static char *FindConditionPart(char *data)   *
1443     * @data: String to parse.
1444     *
1445     * Returns pointer to the condition part if it was found in the statement,
1446     * NULL otherwise.
1447     */
1448    static char *ccs_find_condition_part(char *data)
1449  {  {
1450          char *cp = strstr(data, " if "), *cp2;          char *cp = strstr(data, " if ");
1451          if (cp) {          if (cp) {
1452                  while ((cp2 = strstr(cp + 3, " if ")) != NULL) cp = cp2;                  while (1) {
1453                            char *cp2 = strstr(cp + 3, " if ");
1454                            if (!cp2)
1455                                    break;
1456                            cp = cp2;
1457                    }
1458                  *cp++ = '\0';                  *cp++ = '\0';
1459            } else {
1460                    cp = strstr(data, " ; set ");
1461                    if (cp)
1462                            *cp++ = '\0';
1463          }          }
1464          return cp;          return cp;
1465  }  }
1466    
1467  static int AddDomainPolicy(struct io_buffer *head)  /**
1468     * is_select_one - Parse select command.
1469     *
1470     * @head: Pointer to "struct ccs_io_buffer".
1471     * @data: String to parse.
1472     *
1473     * Returns true on success, false otherwise.
1474     */
1475    static bool is_select_one(struct ccs_io_buffer *head, const char *data)
1476    {
1477            unsigned int pid;
1478            struct domain_info *domain = NULL;
1479            if (sscanf(data, "pid=%u", &pid) == 1) {
1480                    struct task_struct *p;
1481                    /***** CRITICAL SECTION START *****/
1482                    read_lock(&tasklist_lock);
1483                    p = find_task_by_pid(pid);
1484                    if (p)
1485                            domain = p->domain_info;
1486                    read_unlock(&tasklist_lock);
1487                    /***** CRITICAL SECTION END *****/
1488            } else if (!strncmp(data, "domain=", 7)) {
1489                    if (ccs_is_domain_def(data + 7))
1490                            domain = ccs_find_domain(data + 7);
1491            } else
1492                    return false;
1493            head->read_avail = 0;
1494            ccs_io_printf(head, "# select %s\n", data);
1495            head->read_single_domain = true;
1496            head->read_eof = !domain;
1497            if (domain) {
1498                    struct domain_info *d;
1499                    head->read_var1 = NULL;
1500                    list1_for_each_entry(d, &domain_list, list) {
1501                            if (d == domain)
1502                                    break;
1503                            head->read_var1 = &d->list;
1504                    }
1505                    head->read_var2 = NULL;
1506                    head->read_bit = 0;
1507                    head->read_step = 0;
1508                    if (domain->is_deleted)
1509                            ccs_io_printf(head, "# This is a deleted domain.\n");
1510            }
1511            head->write_var1 = domain;
1512            return true;
1513    }
1514    
1515    /**
1516     * write_domain_policy - Write domain policy.
1517     *
1518     * @head: Pointer to "struct ccs_io_buffer".
1519     *
1520     * Returns 0 on success, negative value otherwise.
1521     */
1522    static int write_domain_policy(struct ccs_io_buffer *head)
1523  {  {
1524          char *data = head->write_buf;          char *data = head->write_buf;
1525          struct domain_info *domain = head->write_var1;          struct domain_info *domain = head->write_var1;
1526          bool is_delete = 0, is_select = 0, is_undelete = 0;          bool is_delete = false;
1527            bool is_select = false;
1528            bool is_undelete = false;
1529          unsigned int profile;          unsigned int profile;
1530          const struct condition_list *cond = NULL;          const struct condition_list *cond = NULL;
1531          char *cp;                char *cp;
1532          if (!isRoot()) return -EPERM;          if (str_starts(&data, KEYWORD_DELETE))
1533          if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {                  is_delete = true;
1534                  data += KEYWORD_DELETE_LEN;          else if (str_starts(&data, KEYWORD_SELECT))
1535                  is_delete = 1;                  is_select = true;
1536          } else if (strncmp(data, KEYWORD_SELECT, KEYWORD_SELECT_LEN) == 0) {          else if (str_starts(&data, KEYWORD_UNDELETE))
1537                  data += KEYWORD_SELECT_LEN;                  is_undelete = true;
1538                  is_select = 1;          if (is_select && is_select_one(head, data))
1539          } else if (strncmp(data, KEYWORD_UNDELETE, KEYWORD_UNDELETE_LEN) == 0) {                  return 0;
1540                  data += KEYWORD_UNDELETE_LEN;          /* Don't allow updating policies by non manager programs. */
1541                  is_undelete = 1;          if (!is_policy_manager())
1542          }                  return -EPERM;
1543          UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);          if (ccs_is_domain_def(data)) {
1544          if (IsDomainDef(data)) {                  domain = NULL;
1545                  if (is_delete) {                  if (is_delete)
1546                          DeleteDomain(data);                          ccs_delete_domain(data);
1547                          domain = NULL;                  else if (is_select)
1548                  } else if (is_select) {                          domain = ccs_find_domain(data);
1549                          domain = FindDomain(data);                  else if (is_undelete)
1550                  } else if (is_undelete) {                          domain = ccs_undelete_domain(data);
1551                          domain = UndeleteDomain(data);                  else
1552                  } else {                          domain = ccs_find_or_assign_new_domain(data, 0);
                         domain = FindOrAssignNewDomain(data, 0);  
                 }  
1553                  head->write_var1 = domain;                  head->write_var1 = domain;
1554                    ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
1555                  return 0;                  return 0;
1556          }          }
1557          if (!domain) return -EINVAL;          if (!domain)
1558                    return -EINVAL;
1559    
1560          if (sscanf(data, KEYWORD_USE_PROFILE "%u", &profile) == 1 && profile < MAX_PROFILES) {          if (sscanf(data, KEYWORD_USE_PROFILE "%u", &profile) == 1
1561                  if (profile_ptr[profile] || !sbin_init_started) domain->profile = (u8) profile;              && profile < MAX_PROFILES) {
1562                    if (profile_ptr[profile] || !sbin_init_started)
1563                            domain->profile = (u8) profile;
1564                    return 0;
1565            }
1566            if (!strcmp(data, KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) {
1567                    ccs_set_domain_flag(domain, is_delete,
1568                                        DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ);
1569                    return 0;
1570            }
1571            if (!strcmp(data, KEYWORD_IGNORE_GLOBAL_ALLOW_ENV)) {
1572                    ccs_set_domain_flag(domain, is_delete,
1573                                        DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_ENV);
1574                  return 0;                  return 0;
1575          }          }
1576          cp = FindConditionPart(data);          cp = ccs_find_condition_part(data);
1577          if (cp && (cond = FindOrAssignNewCondition(cp)) == NULL) return -EINVAL;          if (cp) {
1578          if (strncmp(data, KEYWORD_ALLOW_CAPABILITY, KEYWORD_ALLOW_CAPABILITY_LEN) == 0) {                  cond = ccs_find_or_assign_new_condition(cp);
1579                  return AddCapabilityPolicy(data + KEYWORD_ALLOW_CAPABILITY_LEN, domain, cond, is_delete);                  if (!cond)
1580          } else if (strncmp(data, KEYWORD_ALLOW_NETWORK, KEYWORD_ALLOW_NETWORK_LEN) == 0) {                          return -EINVAL;
1581                  return AddNetworkPolicy(data + KEYWORD_ALLOW_NETWORK_LEN, domain, cond, is_delete);          }
1582          } else if (strncmp(data, KEYWORD_ALLOW_SIGNAL, KEYWORD_ALLOW_SIGNAL_LEN) == 0) {          if (str_starts(&data, KEYWORD_ALLOW_CAPABILITY))
1583                  return AddSignalPolicy(data + KEYWORD_ALLOW_SIGNAL_LEN, domain, cond, is_delete);                  return ccs_write_capability_policy(data, domain, cond,
1584          } else if (strncmp(data, KEYWORD_ALLOW_ARGV0, KEYWORD_ALLOW_ARGV0_LEN) == 0) {                                                     is_delete);
1585                  return AddArgv0Policy(data + KEYWORD_ALLOW_ARGV0_LEN, domain, cond, is_delete);          else if (str_starts(&data, KEYWORD_ALLOW_NETWORK))
1586          } else if (strncmp(data, KEYWORD_ALLOW_ENV, KEYWORD_ALLOW_ENV_LEN) == 0) {                  return ccs_write_network_policy(data, domain, cond, is_delete);
1587                  return AddEnvPolicy(data + KEYWORD_ALLOW_ENV_LEN, domain, cond, is_delete);          else if (str_starts(&data, KEYWORD_ALLOW_SIGNAL))
1588                    return ccs_write_signal_policy(data, domain, cond, is_delete);
1589            else if (str_starts(&data, KEYWORD_ALLOW_ARGV0))
1590                    return ccs_write_argv0_policy(data, domain, cond, is_delete);
1591            else if (str_starts(&data, KEYWORD_ALLOW_ENV))
1592                    return ccs_write_env_policy(data, domain, cond, is_delete);
1593            else
1594                    return ccs_write_file_policy(data, domain, cond, is_delete);
1595    }
1596    
1597    /**
1598     * print_single_path_acl - Print a single path ACL entry.
1599     *
1600     * @head: Pointer to "struct ccs_io_buffer".
1601     * @ptr:  Pointer to "struct single_path_acl_record".
1602     * @cond: Pointer to "struct condition_list". May be NULL.
1603     *
1604     * Returns true on success, false otherwise.
1605     */
1606    static bool print_single_path_acl(struct ccs_io_buffer *head,
1607                                      struct single_path_acl_record *ptr,
1608                                      const struct condition_list *cond)
1609    {
1610            int pos;
1611            u8 bit;
1612            const char *atmark = "";
1613            const char *filename;
1614            const u16 perm = ptr->perm;
1615            if (ptr->u_is_group) {
1616                    atmark = "@";
1617                    filename = ptr->u.group->group_name->name;
1618          } else {          } else {
1619                  return AddFilePolicy(data, domain, cond, is_delete);                  filename = ptr->u.filename->name;
1620          }          }
1621          return -EINVAL;          for (bit = head->read_bit; bit < MAX_SINGLE_PATH_OPERATION; bit++) {
1622                    const char *msg;
1623                    if (!(perm & (1 << bit)))
1624                            continue;
1625                    /* Print "read/write" instead of "read" and "write". */
1626                    if ((bit == TYPE_READ_ACL || bit == TYPE_WRITE_ACL)
1627                        && (perm & (1 << TYPE_READ_WRITE_ACL)))
1628                            continue;
1629                    msg = ccs_sp2keyword(bit);
1630                    pos = head->read_avail;
1631                    if (!ccs_io_printf(head, "allow_%s %s%s", msg,
1632                                       atmark, filename) ||
1633                        !ccs_print_condition(head, cond))
1634                            goto out;
1635            }
1636            head->read_bit = 0;
1637            return true;
1638     out:
1639            head->read_bit = bit;
1640            head->read_avail = pos;
1641            return false;
1642    }
1643    
1644    /**
1645     * print_double_path_acl - Print a double path ACL entry.
1646     *
1647     * @head: Pointer to "struct ccs_io_buffer".
1648     * @ptr:  Pointer to "struct double_path_acl_record".
1649     * @cond: Pointer to "struct condition_list". May be NULL.
1650     *
1651     * Returns true on success, false otherwise.
1652     */
1653    static bool print_double_path_acl(struct ccs_io_buffer *head,
1654                                      struct double_path_acl_record *ptr,
1655                                      const struct condition_list *cond)
1656    {
1657            int pos;
1658            const char *atmark1 = "";
1659            const char *atmark2 = "";
1660            const char *filename1;
1661            const char *filename2;
1662            const u8 perm = ptr->perm;
1663            u8 bit;
1664            if (ptr->u1_is_group) {
1665                    atmark1 = "@";
1666                    filename1 = ptr->u1.group1->group_name->name;
1667            } else {
1668                    filename1 = ptr->u1.filename1->name;
1669            }
1670            if (ptr->u2_is_group) {
1671                    atmark2 = "@";
1672                    filename2 = ptr->u2.group2->group_name->name;
1673            } else {
1674                    filename2 = ptr->u2.filename2->name;
1675            }
1676            for (bit = head->read_bit; bit < MAX_DOUBLE_PATH_OPERATION; bit++) {
1677                    const char *msg;
1678                    if (!(perm & (1 << bit)))
1679                            continue;
1680                    msg = ccs_dp2keyword(bit);
1681                    pos = head->read_avail;
1682                    if (!ccs_io_printf(head, "allow_%s %s%s %s%s", msg,
1683                                       atmark1, filename1, atmark2, filename2) ||
1684                        !ccs_print_condition(head, cond))
1685                            goto out;
1686            }
1687            head->read_bit = 0;
1688            return true;
1689     out:
1690            head->read_bit = bit;
1691            head->read_avail = pos;
1692            return false;
1693    }
1694    
1695    /**
1696     * print_argv0_acl - Print an argv[0] ACL entry.
1697     *
1698     * @head: Pointer to "struct ccs_io_buffer".
1699     * @ptr:  Pointer to "struct argv0_acl_record".
1700     * @cond: Pointer to "struct condition_list". May be NULL.
1701     *
1702     * Returns true on success, false otherwise.
1703     */
1704    static bool print_argv0_acl(struct ccs_io_buffer *head,
1705                                struct argv0_acl_record *ptr,
1706                                const struct condition_list *cond)
1707    {
1708            int pos = head->read_avail;
1709            if (!ccs_io_printf(head, KEYWORD_ALLOW_ARGV0 "%s %s",
1710                               ptr->filename->name, ptr->argv0->name))
1711                    goto out;
1712            if (!ccs_print_condition(head, cond))
1713                    goto out;
1714            return true;
1715     out:
1716            head->read_avail = pos;
1717            return false;
1718    }
1719    
1720    /**
1721     * print_env_acl - Print an evironment variable name's ACL entry.
1722     *
1723     * @head: Pointer to "struct ccs_io_buffer".
1724     * @ptr:  Pointer to "struct env_acl_record".
1725     * @cond: Pointer to "struct condition_list". May be NULL.
1726     *
1727     * Returns true on success, false otherwise.
1728     */
1729    static bool print_env_acl(struct ccs_io_buffer *head,
1730                              struct env_acl_record *ptr,
1731                              const struct condition_list *cond)
1732    {
1733            int pos = head->read_avail;
1734            if (!ccs_io_printf(head, KEYWORD_ALLOW_ENV "%s", ptr->env->name))
1735                    goto out;
1736            if (!ccs_print_condition(head, cond))
1737                    goto out;
1738            return true;
1739     out:
1740            head->read_avail = pos;
1741            return false;
1742    }
1743    
1744    /**
1745     * print_capability_acl - Print a capability ACL entry.
1746     *
1747     * @head: Pointer to "struct ccs_io_buffer".
1748     * @ptr:  Pointer to "struct capability_acl_record".
1749     * @cond: Pointer to "struct condition_list". May be NULL.
1750     *
1751     * Returns true on success, false otherwise.
1752     */
1753    static bool print_capability_acl(struct ccs_io_buffer *head,
1754                                     struct capability_acl_record *ptr,
1755                                     const struct condition_list *cond)
1756    {
1757            int pos = head->read_avail;
1758            if (!ccs_io_printf(head, KEYWORD_ALLOW_CAPABILITY "%s",
1759                               ccs_cap2keyword(ptr->operation)))
1760                    goto out;
1761            if (!ccs_print_condition(head, cond))
1762                    goto out;
1763            return true;
1764     out:
1765            head->read_avail = pos;
1766            return false;
1767    }
1768    
1769    /**
1770     * print_ipv4_entry - Print IPv4 address of a network ACL entry.
1771     *
1772     * @head: Pointer to "struct ccs_io_buffer".
1773     * @ptr:  Pointer to "struct ip_network_acl_record".
1774     *
1775     * Returns true on success, false otherwise.
1776     */
1777    static bool print_ipv4_entry(struct ccs_io_buffer *head,
1778                                 struct ip_network_acl_record *ptr)
1779    {
1780            const u32 min_address = ptr->u.ipv4.min;
1781            const u32 max_address = ptr->u.ipv4.max;
1782            if (!ccs_io_printf(head, "%u.%u.%u.%u", HIPQUAD(min_address)))
1783                    return false;
1784            if (min_address != max_address
1785                && !ccs_io_printf(head, "-%u.%u.%u.%u", HIPQUAD(max_address)))
1786                    return false;
1787            return true;
1788    }
1789    
1790    /**
1791     * print_ipv6_entry - Print IPv6 address of a network ACL entry.
1792     *
1793     * @head: Pointer to "struct ccs_io_buffer".
1794     * @ptr:  Pointer to "struct ip_network_acl_record".
1795     *
1796     * Returns true on success, false otherwise.
1797     */
1798    static bool print_ipv6_entry(struct ccs_io_buffer *head,
1799                                 struct ip_network_acl_record *ptr)
1800    {
1801            char buf[64];
1802            const struct in6_addr *min_address = ptr->u.ipv6.min;
1803            const struct in6_addr *max_address = ptr->u.ipv6.max;
1804            ccs_print_ipv6(buf, sizeof(buf), min_address);
1805            if (!ccs_io_printf(head, "%s", buf))
1806                    return false;
1807            if (min_address != max_address) {
1808                    ccs_print_ipv6(buf, sizeof(buf), max_address);
1809                    if (!ccs_io_printf(head, "-%s", buf))
1810                            return false;
1811            }
1812            return true;
1813    }
1814    
1815    /**
1816     * print_port_entry - Print port number of a network ACL entry.
1817     *
1818     * @head: Pointer to "struct ccs_io_buffer".
1819     * @ptr:  Pointer to "struct ip_network_acl_record".
1820     *
1821     * Returns true on success, false otherwise.
1822     */
1823    static bool print_port_entry(struct ccs_io_buffer *head,
1824                                 struct ip_network_acl_record *ptr)
1825    {
1826            const u16 min_port = ptr->min_port, max_port = ptr->max_port;
1827            if (!ccs_io_printf(head, " %u", min_port))
1828                    return false;
1829            if (min_port != max_port && !ccs_io_printf(head, "-%u", max_port))
1830                    return false;
1831            return true;
1832    }
1833    
1834    /**
1835     * print_network_acl - Print a network ACL entry.
1836     *
1837     * @head: Pointer to "struct ccs_io_buffer".
1838     * @ptr:  Pointer to "struct ip_network_acl_record".
1839     * @cond: Pointer to "struct condition_list". May be NULL.
1840     *
1841     * Returns true on success, false otherwise.
1842     */
1843    static bool print_network_acl(struct ccs_io_buffer *head,
1844                                  struct ip_network_acl_record *ptr,
1845                                  const struct condition_list *cond)
1846    {
1847            int pos = head->read_avail;
1848            if (!ccs_io_printf(head, KEYWORD_ALLOW_NETWORK "%s ",
1849                               ccs_net2keyword(ptr->operation_type)))
1850                    goto out;
1851            switch (ptr->record_type) {
1852            case IP_RECORD_TYPE_ADDRESS_GROUP:
1853                    if (!ccs_io_printf(head, "@%s", ptr->u.group->group_name->name))
1854                            goto out;
1855                    break;
1856            case IP_RECORD_TYPE_IPv4:
1857                    if (!print_ipv4_entry(head, ptr))
1858                            goto out;
1859                    break;
1860            case IP_RECORD_TYPE_IPv6:
1861                    if (!print_ipv6_entry(head, ptr))
1862                            goto out;
1863                    break;
1864            }
1865            if (!print_port_entry(head, ptr))
1866                    goto out;
1867            if (!ccs_print_condition(head, cond))
1868                    goto out;
1869            return true;
1870     out:
1871            head->read_avail = pos;
1872            return false;
1873  }  }
1874    
1875  static int ReadDomainPolicy(struct io_buffer *head)  /**
1876     * print_signal_acl - Print a signal ACL entry.
1877     *
1878     * @head: Pointer to "struct ccs_io_buffer".
1879     * @ptr:  Pointer to "struct signale_acl_record".
1880     * @cond: Pointer to "struct condition_list". May be NULL.
1881     *
1882     * Returns true on success, false otherwise.
1883     */
1884    static bool print_signal_acl(struct ccs_io_buffer *head,
1885                                 struct signal_acl_record *ptr,
1886                                 const struct condition_list *cond)
1887    {
1888            int pos = head->read_avail;
1889            if (!ccs_io_printf(head, KEYWORD_ALLOW_SIGNAL "%u %s",
1890                               ptr->sig, ptr->domainname->name))
1891                    goto out;
1892            if (!ccs_print_condition(head, cond))
1893                    goto out;
1894            return true;
1895     out:
1896            head->read_avail = pos;
1897            return false;
1898    }
1899    
1900    /**
1901     * print_execute_handler_record - Print an execute handler ACL entry.
1902     *
1903     * @head:    Pointer to "struct ccs_io_buffer".
1904     * @keyword: Name of the keyword.
1905     * @ptr:     Pointer to "struct execute_handler_record".
1906     *
1907     * Returns true on success, false otherwise.
1908     */
1909    static bool print_execute_handler_record(struct ccs_io_buffer *head,
1910                                             const char *keyword,
1911                                             struct execute_handler_record *ptr)
1912    {
1913            return ccs_io_printf(head, "%s %s\n", keyword, ptr->handler->name);
1914    }
1915    
1916    /**
1917     * print_entry - Print an ACL entry.
1918     *
1919     * @head: Pointer to "struct ccs_io_buffer".
1920     * @ptr:  Pointer to an ACL entry.
1921     *
1922     * Returns true on success, false otherwise.
1923     */
1924    static bool print_entry(struct ccs_io_buffer *head, struct acl_info *ptr)
1925    {
1926            const struct condition_list *cond = ccs_get_condition_part(ptr);
1927            const u8 acl_type = ccs_acl_type2(ptr);
1928            if (acl_type & ACL_DELETED)
1929                    return true;
1930            if (acl_type == TYPE_SINGLE_PATH_ACL) {
1931                    struct single_path_acl_record *acl
1932                            = container_of(ptr, struct single_path_acl_record,
1933                                           head);
1934                    return print_single_path_acl(head, acl, cond);
1935            }
1936            if (acl_type == TYPE_DOUBLE_PATH_ACL) {
1937                    struct double_path_acl_record *acl
1938                            = container_of(ptr, struct double_path_acl_record,
1939                                           head);
1940                    return print_double_path_acl(head, acl, cond);
1941            }
1942            if (acl_type == TYPE_ARGV0_ACL) {
1943                    struct argv0_acl_record *acl
1944                            = container_of(ptr, struct argv0_acl_record, head);
1945                    return print_argv0_acl(head, acl, cond);
1946            }
1947            if (acl_type == TYPE_ENV_ACL) {
1948                    struct env_acl_record *acl
1949                            = container_of(ptr, struct env_acl_record, head);
1950                    return print_env_acl(head, acl, cond);
1951            }
1952            if (acl_type == TYPE_CAPABILITY_ACL) {
1953                    struct capability_acl_record *acl
1954                            = container_of(ptr, struct capability_acl_record, head);
1955                    return print_capability_acl(head, acl, cond);
1956            }
1957            if (acl_type == TYPE_IP_NETWORK_ACL) {
1958                    struct ip_network_acl_record *acl
1959                            = container_of(ptr, struct ip_network_acl_record, head);
1960                    return print_network_acl(head, acl, cond);
1961            }
1962            if (acl_type == TYPE_SIGNAL_ACL) {
1963                    struct signal_acl_record *acl
1964                            = container_of(ptr, struct signal_acl_record, head);
1965                    return print_signal_acl(head, acl, cond);
1966            }
1967            if (acl_type == TYPE_EXECUTE_HANDLER) {
1968                    struct execute_handler_record *acl
1969                            = container_of(ptr, struct execute_handler_record,
1970                                           head);
1971                    const char *keyword = KEYWORD_EXECUTE_HANDLER;
1972                    return print_execute_handler_record(head, keyword, acl);
1973            }
1974            if (acl_type == TYPE_DENIED_EXECUTE_HANDLER) {
1975                    struct execute_handler_record *acl
1976                            = container_of(ptr, struct execute_handler_record,
1977                                           head);
1978                    const char *keyword = KEYWORD_DENIED_EXECUTE_HANDLER;
1979                    return print_execute_handler_record(head, keyword, acl);
1980            }
1981            /* Workaround for gcc 3.2.2's inline bug. */
1982            if (acl_type & ACL_DELETED)
1983                    return true;
1984            BUG(); /* This must not happen. */
1985            return false;
1986    }
1987    
1988    /**
1989     * read_domain_policy - Read domain policy.
1990     *
1991     * @head: Pointer to "struct ccs_io_buffer".
1992     *
1993     * Returns 0.
1994     */
1995    static int read_domain_policy(struct ccs_io_buffer *head)
1996  {  {
1997          struct list1_head *dpos;          struct list1_head *dpos;
1998          struct list1_head *apos;          struct list1_head *apos;
1999          if (head->read_eof) return 0;          if (head->read_eof)
2000          if (head->read_step == 0) {                  return 0;
2001                  if (!isRoot()) return -EPERM;          if (head->read_step == 0)
2002                  head->read_step = 1;                  head->read_step = 1;
         }  
2003          list1_for_each_cookie(dpos, head->read_var1, &domain_list) {          list1_for_each_cookie(dpos, head->read_var1, &domain_list) {
2004                  struct domain_info *domain;                  struct domain_info *domain;
2005                    const char *quota_exceeded = "";
2006                    const char *transition_failed = "";
2007                    const char *ignore_global_allow_read = "";
2008                    const char *ignore_global_allow_env = "";
2009                  domain = list1_entry(dpos, struct domain_info, list);                  domain = list1_entry(dpos, struct domain_info, list);
2010                  if (head->read_step != 1) goto acl_loop;                  if (head->read_step != 1)
2011                  if (domain->is_deleted) continue;                          goto acl_loop;
2012                  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;                  if (domain->is_deleted && !head->read_single_domain)
2013                  head->read_step = 2;                          continue;
2014          acl_loop: ;                  /* Print domainname and flags. */
2015                  if (head->read_step == 3) goto tail_mark;                  if (domain->quota_warned)
2016                  list1_for_each_cookie(apos, head->read_var2, &domain->acl_info_list) {                          quota_exceeded = "quota_exceeded\n";
2017                          struct acl_info *ptr;                  if (domain->flags & DOMAIN_FLAGS_TRANSITION_FAILED)
2018                          int pos;                          transition_failed = "transition_failed\n";
2019                          u8 acl_type;                  if (domain->flags & DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ)
2020                          ptr = list1_entry(apos, struct acl_info, list);                          ignore_global_allow_read
2021                          if (ptr->is_deleted) continue;                                  = KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n";
2022                          pos = head->read_avail;                  if (domain->flags & DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_ENV)
2023                          acl_type = ptr->type;                          ignore_global_allow_env
2024                          if (acl_type == TYPE_FILE_ACL) {                                  = KEYWORD_IGNORE_GLOBAL_ALLOW_ENV "\n";
2025                                  struct file_acl_record *ptr2 = container_of(ptr, struct file_acl_record, head);                  if (!ccs_io_printf(head, "%s\n" KEYWORD_USE_PROFILE "%u\n"
2026                                  const unsigned char b = ptr2->u_is_group;                                     "%s%s%s%s\n", domain->domainname->name,
2027                                  if (io_printf(head, "%d %s%s", ptr2->perm,                                     domain->profile, quota_exceeded,
2028                                                b ? "@" : "",                                     transition_failed,
2029                                                b ? ptr2->u.group->group_name->name : ptr2->u.filename->name)) goto print_acl_rollback;                                     ignore_global_allow_read,
2030                          } else if (acl_type == TYPE_ARGV0_ACL) {                                     ignore_global_allow_env))
                                 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);  
                                 if (io_printf(head, KEYWORD_ALLOW_CAPABILITY "%s", capability2keyword(ptr2->capability))) goto print_acl_rollback;  
                         } 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 ", network2keyword(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 {  
                                 const char *keyword = acltype2keyword(acl_type);  
                                 if (!keyword) continue;  
                                 if (acltype2paths(acl_type) == 2) {  
                                         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;  
                                         if (io_printf(head, "allow_%s %s%s %s%s", keyword,  
                                                       b0 ? "@" : "", b0 ? ptr2->u1.group1->group_name->name : ptr2->u1.filename1->name,  
                                                       b1 ? "@" : "", b1 ? ptr2->u2.group2->group_name->name : ptr2->u2.filename2->name)) goto print_acl_rollback;  
                                 } else {  
                                         struct single_acl_record *ptr2 = container_of(ptr, struct single_acl_record, head);  
                                         const bool b = ptr2->u_is_group;  
                                         if (io_printf(head, "allow_%s %s%s", keyword,  
                                                       b ? "@" : "", b ? ptr2->u.group->group_name->name : ptr2->u.filename->name)) goto print_acl_rollback;  
                                 }  
                         }  
                         if (DumpCondition(head, ptr->cond)) {  
                         print_acl_rollback: ;  
                         head->read_avail = pos;  
2031                          return 0;                          return 0;
2032                          }                  head->read_step = 2;
2033     acl_loop:
2034                    if (head->read_step == 3)
2035                            goto tail_mark;
2036                    /* Print ACL entries in the domain. */
2037                    list1_for_each_cookie(apos, head->read_var2,
2038                                          &domain->acl_info_list) {
2039                            struct acl_info *ptr
2040                                    = list1_entry(apos, struct acl_info, list);
2041                            if (!print_entry(head, ptr))
2042                                    return 0;
2043                  }                  }
2044                  head->read_step = 3;                  head->read_step = 3;
2045          tail_mark: ;   tail_mark:
2046                  if (io_printf(head, "\n")) return 0;                  if (!ccs_io_printf(head, "\n"))
2047                            return 0;
2048                  head->read_step = 1;                  head->read_step = 1;
2049                    if (head->read_single_domain)
2050                            break;
2051          }          }
2052          head->read_eof = 1;          head->read_eof = true;
2053          return 0;          return 0;
2054  }  }
2055    
2056  #endif  #endif
2057    
2058  static int UpdateDomainProfile(struct io_buffer *head)  /**
2059     * write_domain_profile - Assign profile for specified domain.
2060     *
2061     * @head: Pointer to "struct ccs_io_buffer".
2062     *
2063     * Returns 0 on success, -EINVAL otherwise.
2064     *
2065     * This is equivalent to doing
2066     *
2067     *     ( echo "select " $domainname; echo "use_profile " $profile ) |
2068     *     /usr/lib/ccs/loadpolicy -d
2069     */
2070    static int write_domain_profile(struct ccs_io_buffer *head)
2071  {  {
2072          char *data = head->write_buf;          char *data = head->write_buf;
2073          char *cp = strchr(data, ' ');          char *cp = strchr(data, ' ');
2074          struct domain_info *domain;          struct domain_info *domain;
2075          unsigned int profile;          unsigned int profile;
2076          if (!isRoot()) return -EPERM;          if (!cp)
2077          if (!cp) return -EINVAL;                  return -EINVAL;
2078          *cp = '\0';          *cp = '\0';
2079          domain = FindDomain(cp + 1);          domain = ccs_find_domain(cp + 1);
2080          profile = simple_strtoul(data, NULL, 10);          profile = simple_strtoul(data, NULL, 10);
2081          if (domain && profile < MAX_PROFILES && (profile_ptr[profile] || !sbin_init_started)) domain->profile = (u8) profile;          if (domain && profile < MAX_PROFILES
2082          UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);              && (profile_ptr[profile] || !sbin_init_started))
2083                    domain->profile = (u8) profile;
2084            ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
2085          return 0;          return 0;
2086  }  }
2087    
2088  static int ReadDomainProfile(struct io_buffer *head)  /**
2089     * read_domain_profile - Read only domainname and profile.
2090     *
2091     * @head: Pointer to "struct ccs_io_buffer".
2092     *
2093     * Returns list of profile number and domainname pairs.
2094     *
2095     * This is equivalent to doing
2096     *
2097     *     grep -A 1 '^<kernel>' /proc/ccs/domain_policy |
2098     *     awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
2099     *     domainname = $0; } else if ( $1 == "use_profile" ) {
2100     *     print $2 " " domainname; domainname = ""; } } ; '
2101     */
2102    static int read_domain_profile(struct ccs_io_buffer *head)
2103  {  {
2104          struct list1_head *pos;          struct list1_head *pos;
2105          if (head->read_eof) return 0;          if (head->read_eof)
2106          if (!isRoot()) return -EPERM;                  return 0;
2107          list1_for_each_cookie(pos, head->read_var1, &domain_list) {          list1_for_each_cookie(pos, head->read_var1, &domain_list) {
2108                  struct domain_info *domain;                  struct domain_info *domain;
2109                  domain = list1_entry(pos, struct domain_info, list);                  domain = list1_entry(pos, struct domain_info, list);
2110                  if (domain->is_deleted) continue;                  if (domain->is_deleted)
2111                  if (io_printf(head, "%u %s\n", domain->profile, domain->domainname->name)) return 0;                          continue;
2112                    if (!ccs_io_printf(head, "%u %s\n", domain->profile,
2113                                       domain->domainname->name))
2114                            return 0;
2115          }          }
2116          head->read_eof = 1;          head->read_eof = true;
2117          return 0;          return 0;
2118  }  }
2119    
2120  static int WritePID(struct io_buffer *head)  /**
2121     * write_pid: Specify PID to obtain domainname.
2122     *
2123     * @head: Pointer to "struct ccs_io_buffer".
2124     *
2125     * Returns 0.
2126     */
2127    static int write_pid(struct ccs_io_buffer *head)
2128  {  {
2129          head->read_step = (int) simple_strtoul(head->write_buf, NULL, 10);          head->read_eof = false;
         head->read_eof = 0;  
2130          return 0;          return 0;
2131  }  }
2132    
2133  static int ReadPID(struct io_buffer *head)  /**
2134     * read_pid - Read information of a process.
2135     *
2136     * @head: Pointer to "struct ccs_io_buffer".
2137     *
2138     * Returns the domainname which the specified PID is in or
2139     * process information of the specified PID on success,
2140     * empty string otherwise.
2141     */
2142    static int read_pid(struct ccs_io_buffer *head)
2143  {  {
2144          if (head->read_avail == 0 && !head->read_eof) {          /* Accessing write_buf is safe because head->io_sem is held. */
2145                  const int pid = head->read_step;          char *buf = head->write_buf;
2146                  struct task_struct *p;          bool task_info = false;
2147                  struct domain_info *domain = NULL;          unsigned int pid;
2148                  /***** CRITICAL SECTION START *****/          struct task_struct *p;
2149                  read_lock(&tasklist_lock);          struct domain_info *domain = NULL;
2150                  p = find_task_by_pid(pid);          u32 tomoyo_flags = 0;
2151                  if (p) domain = p->domain_info;          if (head->read_avail || head->read_eof)
2152                  read_unlock(&tasklist_lock);                  goto done;
2153                  /***** CRITICAL SECTION END *****/          head->read_eof = true;
2154                  if (domain) io_printf(head, "%d %u %s", pid, domain->profile, domain->domainname->name);          if (str_starts(&buf, "info "))
2155                  head->read_eof = 1;                  task_info = true;
2156            pid = (unsigned int) simple_strtoul(buf, NULL, 10);
2157            /***** CRITICAL SECTION START *****/
2158            read_lock(&tasklist_lock);
2159            p = find_task_by_pid(pid);
2160            if (p) {
2161                    domain = p->domain_info;
2162                    tomoyo_flags = p->tomoyo_flags;
2163          }          }
2164            read_unlock(&tasklist_lock);
2165            /***** CRITICAL SECTION END *****/
2166            if (!domain)
2167                    goto done;
2168            if (!task_info)
2169                    ccs_io_printf(head, "%u %u %s", pid, domain->profile,
2170                                  domain->domainname->name);
2171            else
2172                    ccs_io_printf(head, "%u manager=%s execute_handler=%s "
2173                                  "state[0]=%u state[1]=%u state[2]=%u", pid,
2174                                  tomoyo_flags & CCS_TASK_IS_POLICY_MANAGER ?
2175                                  "yes" : "no",
2176                                  tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER ?
2177                                  "yes" : "no",
2178                                  (u8) (tomoyo_flags >> 24),
2179                                  (u8) (tomoyo_flags >> 16),
2180                                  (u8) (tomoyo_flags >> 8));
2181     done:
2182          return 0;          return 0;
2183  }  }
2184    
 /*************************  EXCEPTION POLICY HANDLER  *************************/  
   
2185  #ifdef CONFIG_TOMOYO  #ifdef CONFIG_TOMOYO
2186    
2187  static int AddExceptionPolicy(struct io_buffer *head)  /**
2188     * write_exception_policy - Write exception policy.
2189     *
2190     * @head: Pointer to "struct ccs_io_buffer".
2191     *
2192     * Returns 0 on success, negative value otherwise.
2193     */
2194    static int write_exception_policy(struct ccs_io_buffer *head)
2195  {  {
2196          char *data = head->write_buf;          char *data = head->write_buf;
2197          bool is_delete = 0;          bool is_delete = str_starts(&data, KEYWORD_DELETE);
2198          if (!isRoot()) return -EPERM;          if (str_starts(&data, KEYWORD_KEEP_DOMAIN))
2199          UpdateCounter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);                  return ccs_write_domain_keeper_policy(data, false, is_delete);
2200          if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {          if (str_starts(&data, KEYWORD_NO_KEEP_DOMAIN))
2201                  data += KEYWORD_DELETE_LEN;                  return ccs_write_domain_keeper_policy(data, true, is_delete);
2202                  is_delete = 1;          if (str_starts(&data, KEYWORD_INITIALIZE_DOMAIN))
2203          }                  return ccs_write_domain_initializer_policy(data, false,
2204          if (strncmp(data, KEYWORD_KEEP_DOMAIN, KEYWORD_KEEP_DOMAIN_LEN) == 0) {                                                             is_delete);
2205                  return AddDomainKeeperPolicy(data + KEYWORD_KEEP_DOMAIN_LEN, 0, is_delete);          if (str_starts(&data, KEYWORD_NO_INITIALIZE_DOMAIN))
2206          } else if (strncmp(data, KEYWORD_NO_KEEP_DOMAIN, KEYWORD_NO_KEEP_DOMAIN_LEN) == 0) {                  return ccs_write_domain_initializer_policy(data, true,
2207                  return AddDomainKeeperPolicy(data + KEYWORD_NO_KEEP_DOMAIN_LEN, 1, is_delete);                                                             is_delete);
2208          } else if (strncmp(data, KEYWORD_INITIALIZE_DOMAIN, KEYWORD_INITIALIZE_DOMAIN_LEN) == 0) {          if (str_starts(&data, KEYWORD_ALIAS))
2209                  return AddDomainInitializerPolicy(data + KEYWORD_INITIALIZE_DOMAIN_LEN, 0, is_delete);                  return ccs_write_alias_policy(data, is_delete);
2210          } else if (strncmp(data, KEYWORD_NO_INITIALIZE_DOMAIN, KEYWORD_NO_INITIALIZE_DOMAIN_LEN) == 0) {          if (str_starts(&data, KEYWORD_AGGREGATOR))
2211                  return AddDomainInitializerPolicy(data + KEYWORD_NO_INITIALIZE_DOMAIN_LEN, 1, is_delete);                  return ccs_write_aggregator_policy(data, is_delete);
2212          } else if (strncmp(data, KEYWORD_ALIAS, KEYWORD_ALIAS_LEN) == 0) {          if (str_starts(&data, KEYWORD_ALLOW_READ))
2213                  return AddAliasPolicy(data + KEYWORD_ALIAS_LEN, is_delete);                  return ccs_write_globally_readable_policy(data, is_delete);
2214          } else if (strncmp(data, KEYWORD_AGGREGATOR, KEYWORD_AGGREGATOR_LEN) == 0) {          if (str_starts(&data, KEYWORD_ALLOW_ENV))
2215                  return AddAggregatorPolicy(data + KEYWORD_AGGREGATOR_LEN, is_delete);                  return ccs_write_globally_usable_env_policy(data, is_delete);
2216          } else if (strncmp(data, KEYWORD_ALLOW_READ, KEYWORD_ALLOW_READ_LEN) == 0) {          if (str_starts(&data, KEYWORD_FILE_PATTERN))
2217                  return AddGloballyReadablePolicy(data + KEYWORD_ALLOW_READ_LEN, is_delete);                  return ccs_write_pattern_policy(data, is_delete);
2218          } else if (strncmp(data, KEYWORD_ALLOW_ENV, KEYWORD_ALLOW_ENV_LEN) == 0) {          if (str_starts(&data, KEYWORD_PATH_GROUP))
2219                  return AddGloballyUsableEnvPolicy(data + KEYWORD_ALLOW_ENV_LEN, is_delete);                  return ccs_write_path_group_policy(data, is_delete);
2220          } else if (strncmp(data, KEYWORD_FILE_PATTERN, KEYWORD_FILE_PATTERN_LEN) == 0) {          if (str_starts(&data, KEYWORD_DENY_REWRITE))
2221                  return AddPatternPolicy(data + KEYWORD_FILE_PATTERN_LEN, is_delete);                  return ccs_write_no_rewrite_policy(data, is_delete);
2222          } else if (strncmp(data, KEYWORD_PATH_GROUP, KEYWORD_PATH_GROUP_LEN) == 0) {          if (str_starts(&data, KEYWORD_ADDRESS_GROUP))
2223                  return AddPathGroupPolicy(data + KEYWORD_PATH_GROUP_LEN, is_delete);                  return ccs_write_address_group_policy(data, 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);  
         }  
2224          return -EINVAL;          return -EINVAL;
2225  }  }
2226    
2227  static int ReadExceptionPolicy(struct io_buffer *head)  /**
2228     * read_exception_policy - Read exception policy.
2229     *
2230     * @head: Pointer to "struct ccs_io_buffer".
2231     *
2232     * Returns 0 on success, -EINVAL otherwise.
2233     */
2234    static int read_exception_policy(struct ccs_io_buffer *head)
2235  {  {
2236          if (!head->read_eof) {          if (!head->read_eof) {
2237                  switch (head->read_step) {                  switch (head->read_step) {
2238                  case 0:                  case 0:
2239                          if (!isRoot()) return -EPERM;                          head->read_var2 = NULL;
2240                          head->read_var2 = NULL; head->read_step = 1;                          head->read_step = 1;
2241                  case 1:                  case 1:
2242                          if (ReadDomainKeeperPolicy(head)) break;                          if (!ccs_read_domain_keeper_policy(head))
2243                          head->read_var2 = NULL; head->read_step = 2;                                  break;
2244                            head->read_var2 = NULL;
2245                            head->read_step = 2;
2246                  case 2:                  case 2:
2247                          if (ReadGloballyReadablePolicy(head)) break;                          if (!ccs_read_globally_readable_policy(head))
2248                          head->read_var2 = NULL; head->read_step = 3;                                  break;
2249                            head->read_var2 = NULL;
2250                            head->read_step = 3;
2251                  case 3:                  case 3:
2252                          if (ReadGloballyUsableEnvPolicy(head)) break;                          if (!ccs_read_globally_usable_env_policy(head))
2253                          head->read_var2 = NULL; head->read_step = 4;                                  break;
2254                            head->read_var2 = NULL;
2255                            head->read_step = 4;
2256                  case 4:                  case 4:
2257                          if (ReadDomainInitializerPolicy(head)) break;                          if (!ccs_read_domain_initializer_policy(head))
2258                          head->read_var2 = NULL; head->read_step = 5;                                  break;
2259                            head->read_var2 = NULL;
2260                            head->read_step = 5;
2261                  case 5:                  case 5:
2262                          if (ReadAliasPolicy(head)) break;                          if (!ccs_read_alias_policy(head))
2263                          head->read_var2 = NULL; head->read_step = 6;                                  break;
2264                            head->read_var2 = NULL;
2265                            head->read_step = 6;
2266                  case 6:                  case 6:
2267                          if (ReadAggregatorPolicy(head)) break;                          if (!ccs_read_aggregator_policy(head))
2268                          head->read_var2 = NULL; head->read_step = 7;                                  break;
2269                            head->read_var2 = NULL;
2270                            head->read_step = 7;
2271                  case 7:                  case 7:
2272                          if (ReadPatternPolicy(head)) break;                          if (!ccs_read_file_pattern(head))
2273                          head->read_var2 = NULL; head->read_step = 8;                                  break;
2274                            head->read_var2 = NULL;
2275                            head->read_step = 8;
2276                  case 8:                  case 8:
2277                          if (ReadNoRewritePolicy(head)) break;                          if (!ccs_read_no_rewrite_policy(head))
2278                          head->read_var2 = NULL; head->read_step = 9;                                  break;
2279                            head->read_var2 = NULL;
2280                            head->read_step = 9;
2281                  case 9:                  case 9:
2282                          if (ReadPathGroupPolicy(head)) break;                          if (!ccs_read_path_group_policy(head))
2283                          head->read_var1 = head->read_var2 = NULL; head->read_step = 10;                                  break;
2284                            head->read_var1 = NULL;
2285                            head->read_var2 = NULL;
2286                            head->read_step = 10;
2287                  case 10:                  case 10:
2288                          if (ReadAddressGroupPolicy(head)) break;                          if (!ccs_read_address_group_policy(head))
2289                          head->read_eof = 1;                                  break;
2290                            head->read_eof = true;
2291                          break;                          break;
2292                  default:                  default:
2293                          return -EINVAL;                          return -EINVAL;
# Line 1103  static int ReadExceptionPolicy(struct io Line 2298  static int ReadExceptionPolicy(struct io
2298    
2299  #endif  #endif
2300    
 /*************************  SYSTEM POLICY HANDLER  *************************/  
   
2301  #ifdef CONFIG_SAKURA  #ifdef CONFIG_SAKURA
2302    
2303  static int AddSystemPolicy(struct io_buffer *head)  /**
2304     * write_system_policy - Write system policy.
2305     *
2306     * @head: Pointer to "struct ccs_io_buffer".
2307     *
2308     * Returns 0 on success, negative value otherwise.
2309     */
2310    static int write_system_policy(struct ccs_io_buffer *head)
2311  {  {
2312          char *data = head->write_buf;          char *data = head->write_buf;
2313          bool is_delete = 0;          bool is_delete = false;
2314          if (!isRoot()) return -EPERM;          if (str_starts(&data, KEYWORD_DELETE))
2315          UpdateCounter(CCS_UPDATES_COUNTER_SYSTEM_POLICY);                  is_delete = true;
2316          if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {          if (str_starts(&data, KEYWORD_ALLOW_MOUNT))
2317                  data += KEYWORD_DELETE_LEN;                  return ccs_write_mount_policy(data, is_delete);
2318                  is_delete = 1;          if (str_starts(&data, KEYWORD_DENY_UNMOUNT))
2319          }                  return ccs_write_no_umount_policy(data, is_delete);
2320          if (strncmp(data, KEYWORD_ALLOW_MOUNT, KEYWORD_ALLOW_MOUNT_LEN) == 0)          if (str_starts(&data, KEYWORD_ALLOW_CHROOT))
2321                  return AddMountPolicy(data + KEYWORD_ALLOW_MOUNT_LEN, is_delete);                  return ccs_write_chroot_policy(data, is_delete);
2322          if (strncmp(data, KEYWORD_DENY_UNMOUNT, KEYWORD_DENY_UNMOUNT_LEN) == 0)          if (str_starts(&data, KEYWORD_ALLOW_PIVOT_ROOT))
2323                  return AddNoUmountPolicy(data + KEYWORD_DENY_UNMOUNT_LEN, is_delete);                  return ccs_write_pivot_root_policy(data, is_delete);
2324          if (strncmp(data, KEYWORD_ALLOW_CHROOT, KEYWORD_ALLOW_CHROOT_LEN) == 0)          if (str_starts(&data, KEYWORD_DENY_AUTOBIND))
2325                  return AddChrootPolicy(data + KEYWORD_ALLOW_CHROOT_LEN, is_delete);                  return ccs_write_reserved_port_policy(data, 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);  
2326          return -EINVAL;          return -EINVAL;
2327  }  }
2328    
2329  static int ReadSystemPolicy(struct io_buffer *head)  /**
2330     * read_system_policy - Read system policy.
2331     *
2332     * @head: Pointer to "struct ccs_io_buffer".
2333     *
2334     * Returns 0 on success, -EINVAL otherwise.
2335     */
2336    static int read_system_policy(struct ccs_io_buffer *head)
2337  {  {
2338          if (!head->read_eof) {          if (!head->read_eof) {
2339                  switch (head->read_step) {                  switch (head->read_step) {
2340                  case 0:                  case 0:
2341                          if (!isRoot()) return -EPERM;                          head->read_var2 = NULL;
2342                          head->read_var2 = NULL; head->read_step = 1;                          head->read_step = 1;
2343                  case 1:                  case 1:
2344                          if (ReadMountPolicy(head)) break;                          if (!ccs_read_mount_policy(head))
2345                          head->read_var2 = NULL; head->read_step = 2;                                  break;
2346                            head->read_var2 = NULL;
2347                            head->read_step = 2;
2348                  case 2:                  case 2:
2349                          if (ReadNoUmountPolicy(head)) break;                          if (!ccs_read_no_umount_policy(head))
2350                          head->read_var2 = NULL; head->read_step = 3;                                  break;
2351                            head->read_var2 = NULL;
2352                            head->read_step = 3;
2353                  case 3:                  case 3:
2354                          if (ReadChrootPolicy(head)) break;                          if (!ccs_read_chroot_policy(head))
2355                          head->read_var2 = NULL; head->read_step = 4;                                  break;
2356                            head->read_var2 = NULL;
2357                            head->read_step = 4;
2358                  case 4:                  case 4:
2359                          if (ReadPivotRootPolicy(head)) break;                          if (!ccs_read_pivot_root_policy(head))
2360                          head->read_var2 = NULL; head->read_step = 5;                                  break;
2361                            head->read_var2 = NULL;
2362                            head->read_step = 5;
2363                  case 5:                  case 5:
2364                          if (ReadReservedPortPolicy(head)) break;                          if (!ccs_read_reserved_port_policy(head))
2365                          head->read_eof = 1;                                  break;
2366                            head->read_eof = true;
2367                          break;                          break;
2368                  default:                  default:
2369                          return -EINVAL;                          return -EINVAL;
# Line 1162  static int ReadSystemPolicy(struct io_bu Line 2374  static int ReadSystemPolicy(struct io_bu
2374    
2375  #endif  #endif
2376    
2377  /*************************  POLICY LOADER  *************************/  /* Path to the policy loader. The default is /sbin/ccs-init. */
2378    static const char *ccs_loader;
 static int profile_loaded = 0;  
2379    
2380  static const char *ccs_loader = NULL;  /**
2381     * loader_setup - Specify the policy loader to use.
2382  static int __init CCS_loader_Setup(char *str)   *
2383     * @str: Path to the policy loader.
2384     *
2385     * Returns 0.
2386     */
2387    static int __init loader_setup(char *str)
2388  {  {
2389          ccs_loader = str;          ccs_loader = str;
2390          return 0;          return 0;
2391  }  }
2392    
2393  __setup("CCS_loader=", CCS_loader_Setup);  __setup("CCS_loader=", loader_setup);
2394    
2395  void CCS_LoadPolicy(const char *filename)  /**
2396     * policy_loader_exists - Check whether /sbin/ccs-init exists.
2397     *
2398     * Returns true if /sbin/ccs-init exists, false otherwise.
2399     */
2400    static bool policy_loader_exists(void)
2401  {  {
         if (sbin_init_started) return;  
2402          /*          /*
2403           * Check filename is /sbin/init or /sbin/ccs-start .           * Don't activate MAC if the path given by 'CCS_loader=' option doesn't
2404           * /sbin/ccs-start is a dummy filename in case where /sbin/init can't be passed.           * exist. If the initrd includes /sbin/init but real-root-dev has not
2405           * You can create /sbin/ccs-start by "ln -s /bin/true /sbin/ccs-start", for           * mounted on / yet, activating MAC will block the system since
2406           * only the pathname is needed to activate Mandatory Access Control.           * policies are not loaded yet.
2407             * Thus, let do_execve() call this function everytime.
2408           */           */
2409          if (strcmp(filename, "/sbin/init") != 0 && strcmp(filename, "/sbin/ccs-start") != 0) return;          struct nameidata nd;
2410            if (!ccs_loader)
2411                    ccs_loader = "/sbin/ccs-init";
2412            if (path_lookup(ccs_loader, lookup_flags, &nd)) {
2413                    printk(KERN_INFO "Not activating Mandatory Access Control now "
2414                           "since %s doesn't exist.\n", ccs_loader);
2415                    return false;
2416            }
2417    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
2418            path_put(&nd.path);
2419    #else
2420            path_release(&nd);
2421    #endif
2422            return true;
2423    }
2424    
2425    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
2426    /**
2427     * run_ccs_loader - Start /sbin/ccs-init .
2428     *
2429     * @unused: Not used.
2430     *
2431     * Returns PID of /sbin/ccs-init on success, negative value otherwise.
2432     */
2433    static int run_ccs_loader(void *unused)
2434    {
2435            char *argv[2];
2436            char *envp[3];
2437            printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
2438                   ccs_loader);
2439            argv[0] = (char *) ccs_loader;
2440            argv[1] = NULL;
2441            envp[0] = "HOME=/";
2442            envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
2443            envp[2] = NULL;
2444            return exec_usermodehelper(argv[0], argv, envp);
2445    }
2446    #endif
2447    
2448    /**
2449     * ccs_load_policy - Run external policy loader to load policy.
2450     *
2451     * @filename: The program about to start.
2452     *
2453     * This function checks whether @filename is /sbin/init , and if so
2454     * invoke /sbin/ccs-init and wait for the termination of /sbin/ccs-init
2455     * and then continues invocation of /sbin/init.
2456     * /sbin/ccs-init reads policy files in /etc/ccs/ directory and
2457     * writes to /proc/ccs/ interfaces.
2458     *
2459     * Returns nothing.
2460     */
2461    void ccs_load_policy(const char *filename)
2462    {
2463            if (sbin_init_started)
2464                    return;
2465          /*          /*
2466           * Don't activate MAC if the path given by 'CCS_loader=' option doesn't exist.           * Check filename is /sbin/init or /sbin/ccs-start.
2467           * If initrd.img includes /sbin/init but real-root-dev has not mounted on / yet,           * /sbin/ccs-start is a dummy filename in case where /sbin/init can't
2468           * activating MAC will block the system since policies are not loaded yet.           * be passed.
2469           * So let do_execve() call this function everytime.           * You can create /sbin/ccs-start by "ln -s /bin/true /sbin/ccs-start".
2470           */           */
2471            if (strcmp(filename, "/sbin/init") &&
2472                strcmp(filename, "/sbin/ccs-start"))
2473                    return;
2474            if (!policy_loader_exists())
2475                    return;
2476    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
2477          {          {
2478                  struct nameidata nd;                  char *argv[2];
2479                  if (!ccs_loader) ccs_loader = "/sbin/ccs-init";                  char *envp[3];
2480                  if (path_lookup(ccs_loader, lookup_flags, &nd)) {                  printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
2481                          printk("Not activating Mandatory Access Control now since %s doesn't exist.\n", ccs_loader);                         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);  
2482                  argv[0] = (char *) ccs_loader;                  argv[0] = (char *) ccs_loader;
2483                  argv[1] = NULL;                  argv[1] = NULL;
2484                  envp[0] = "HOME=/";                  envp[0] = "HOME=/";
2485                  envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";                  envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
2486                  envp[2] = NULL;                  envp[2] = NULL;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)  
2487                  call_usermodehelper(argv[0], argv, envp, 1);                  call_usermodehelper(argv[0], argv, envp, 1);
2488            }
2489    #elif defined(TASK_DEAD)
2490            {
2491                    /* Copied from kernel/kmod.c */
2492                    struct task_struct *task = current;
2493                    pid_t pid = kernel_thread(run_ccs_loader, NULL, 0);
2494                    sigset_t tmpsig;
2495                    spin_lock_irq(&task->sighand->siglock);
2496                    tmpsig = task->blocked;
2497                    siginitsetinv(&task->blocked,
2498                                  sigmask(SIGKILL) | sigmask(SIGSTOP));
2499                    recalc_sigpending();
2500                    spin_unlock_irq(&current->sighand->siglock);
2501                    if (pid >= 0)
2502                            waitpid(pid, NULL, __WCLONE);
2503                    spin_lock_irq(&task->sighand->siglock);
2504                    task->blocked = tmpsig;
2505                    recalc_sigpending();
2506                    spin_unlock_irq(&task->sighand->siglock);
2507            }
2508  #else  #else
2509                  call_usermodehelper(argv[0], argv, envp);          {
2510  #endif                  /* Copied from kernel/kmod.c */
2511                  while (!profile_loaded) {                  struct task_struct *task = current;
2512                          set_current_state(TASK_INTERRUPTIBLE);                  pid_t pid = kernel_thread(run_ccs_loader, NULL, 0);
2513                          schedule_timeout(HZ / 10);                  sigset_t tmpsig;
2514                  }                  spin_lock_irq(&task->sigmask_lock);
2515                    tmpsig = task->blocked;
2516                    siginitsetinv(&task->blocked,
2517                                  sigmask(SIGKILL) | sigmask(SIGSTOP));
2518                    recalc_sigpending(task);
2519                    spin_unlock_irq(&task->sigmask_lock);
2520                    if (pid >= 0)
2521                            waitpid(pid, NULL, __WCLONE);
2522                    spin_lock_irq(&task->sigmask_lock);
2523                    task->blocked = tmpsig;
2524                    recalc_sigpending(task);
2525                    spin_unlock_irq(&task->sigmask_lock);
2526          }          }
2527    #endif
2528  #ifdef CONFIG_SAKURA  #ifdef CONFIG_SAKURA
2529          printk("SAKURA: 1.5.2-pre   2007/11/19\n");          printk(KERN_INFO "SAKURA: 1.6.5-rc   2008/11/05\n");
2530  #endif  #endif
2531  #ifdef CONFIG_TOMOYO  #ifdef CONFIG_TOMOYO
2532          printk("TOMOYO: 1.5.2-pre   2007/11/19\n");          printk(KERN_INFO "TOMOYO: 1.6.5-rc   2008/11/05\n");
2533  #endif  #endif
2534          //if (!profile_loaded) panic("No profiles loaded. Run policy loader using 'init=' option.\n");          printk(KERN_INFO "Mandatory Access Control activated.\n");
2535          printk("Mandatory Access Control activated.\n");          sbin_init_started = true;
         sbin_init_started = 1;  
2536          ccs_log_level = KERN_WARNING;          ccs_log_level = KERN_WARNING;
2537          { /* Check all profiles currently assigned to domains are defined. */          { /* Check all profiles currently assigned to domains are defined. */
2538                  struct domain_info *domain;                  struct domain_info *domain;
2539                  list1_for_each_entry(domain, &domain_list, list) {                  list1_for_each_entry(domain, &domain_list, list) {
2540                          const u8 profile = domain->profile;                          const u8 profile = domain->profile;
2541                          if (!profile_ptr[profile]) panic("Profile %u (used by '%s') not defined.\n", profile, domain->domainname->name);                          if (profile_ptr[profile])
2542                                    continue;
2543                            panic("Profile %u (used by '%s') not defined.\n",
2544                                  profile, domain->domainname->name);
2545                  }                  }
2546          }          }
2547  }  }
2548    
2549    /* Wait queue for query_list. */
 /*************************  MAC Decision Delayer  *************************/  
   
2550  static DECLARE_WAIT_QUEUE_HEAD(query_wait);  static DECLARE_WAIT_QUEUE_HEAD(query_wait);
2551    
2552  static spinlock_t query_lock = SPIN_LOCK_UNLOCKED;  /* Lock for manipulating query_list. */
2553    static DEFINE_SPINLOCK(query_list_lock);
2554    
2555    /* Structure for query. */
2556  struct query_entry {  struct query_entry {
2557          struct list_head list;          struct list_head list;
2558          char *query;          char *query;
# Line 1254  struct query_entry { Line 2562  struct query_entry {
2562          int answer;          int answer;
2563  };  };
2564    
2565    /* The list for "struct query_entry". */
2566  static LIST_HEAD(query_list);  static LIST_HEAD(query_list);
2567    
2568    /* Number of "struct file" referring /proc/ccs/query interface. */
2569  static atomic_t queryd_watcher = ATOMIC_INIT(0);  static atomic_t queryd_watcher = ATOMIC_INIT(0);
2570    
2571  int CheckSupervisor(const char *fmt, ...)  /**
2572     * ccs_check_supervisor - Ask for the supervisor's decision.
2573     *
2574     * @r:       Pointer to "struct ccs_request_info".
2575     * @fmt:     The printf()'s format string, followed by parameters.
2576     *
2577     * Returns 0 if the supervisor decided to permit the access request which
2578     * violated the policy in enforcing mode, 1 if the supervisor decided to
2579     * retry the access request which violated the policy in enforcing mode,
2580     * -EPERM otherwise.
2581     */
2582    int ccs_check_supervisor(struct ccs_request_info *r, const char *fmt, ...)
2583  {  {
2584          va_list args;          va_list args;
2585          int error = -EPERM;          int error = -EPERM;
2586          int pos, len;          int pos;
2587          static unsigned int serial = 0;          int len;
2588          struct query_entry *query_entry;          static unsigned int serial;
2589          if (!CheckCCSFlags(CCS_ALLOW_ENFORCE_GRACE) || !atomic_read(&queryd_watcher)) {          struct query_entry *query_entry = NULL;
2590  #if 0          char *header;
2591                  if ((current->tomoyo_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR) == 0) {          if (!r->domain)
2592                          int i;                  r->domain = current->domain_info;
2593                          for (i = 0; i < CheckCCSFlags(CCS_SLEEP_PERIOD); i++) {          if (!atomic_read(&queryd_watcher)) {
2594                                  set_current_state(TASK_INTERRUPTIBLE);                  int i;
2595                                  schedule_timeout(HZ / 10);                  if (current->tomoyo_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR)
2596                          }                          return -EPERM;
2597                    for (i = 0; i < ccs_check_flags(r->domain, CCS_SLEEP_PERIOD);
2598                         i++) {
2599                            set_current_state(TASK_INTERRUPTIBLE);
2600                            schedule_timeout(HZ / 10);
2601                  }                  }
 #endif  
2602                  return -EPERM;                  return -EPERM;
2603          }          }
2604          va_start(args, fmt);          va_start(args, fmt);
2605          len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;          len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;
2606          va_end(args);          va_end(args);
2607          if ((query_entry = ccs_alloc(sizeof(*query_entry))) == NULL ||  #ifdef CONFIG_TOMOYO
2608                  (query_entry->query = ccs_alloc(len)) == NULL) goto out;          header = ccs_init_audit_log(&len, r);
2609    #else
2610            header = ccs_alloc(1);
2611    #endif
2612            if (!header)
2613                    goto out;
2614            query_entry = ccs_alloc(sizeof(*query_entry));
2615            if (!query_entry)
2616                    goto out;
2617            query_entry->query = ccs_alloc(len);
2618            if (!query_entry->query)
2619                    goto out;
2620          INIT_LIST_HEAD(&query_entry->list);          INIT_LIST_HEAD(&query_entry->list);
2621          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
2622          spin_lock(&query_lock);          spin_lock(&query_list_lock);
2623          query_entry->serial = serial++;          query_entry->serial = serial++;
2624          spin_unlock(&query_lock);          spin_unlock(&query_list_lock);
2625          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
2626          pos = snprintf(query_entry->query, len - 1, "Q%u\n", query_entry->serial);          pos = snprintf(query_entry->query, len - 1, "Q%u-%hu\n%s",
2627                           query_entry->serial, r->retry, header);
2628            ccs_free(header);
2629            header = NULL;
2630          va_start(args, fmt);          va_start(args, fmt);
2631          vsnprintf(query_entry->query + pos, len - 1 - pos, fmt, args);          vsnprintf(query_entry->query + pos, len - 1 - pos, fmt, args);
2632          query_entry->query_len = strlen(query_entry->query) + 1;          query_entry->query_len = strlen(query_entry->query) + 1;
2633          va_end(args);          va_end(args);
2634          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
2635          spin_lock(&query_lock);          spin_lock(&query_list_lock);
2636          list_add_tail(&query_entry->list, &query_list);          list_add_tail(&query_entry->list, &query_list);
2637          spin_unlock(&query_lock);          spin_unlock(&query_list_lock);
2638          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
2639          UpdateCounter(CCS_UPDATES_COUNTER_QUERY);          ccs_update_counter(CCS_UPDATES_COUNTER_QUERY);
2640          /* Give 10 seconds for supervisor's opinion. */          /* Give 10 seconds for supervisor's opinion. */
2641          for (query_entry->timer = 0; atomic_read(&queryd_watcher) && CheckCCSFlags(CCS_ALLOW_ENFORCE_GRACE) && query_entry->timer < 100; query_entry->timer++) {          for (query_entry->timer = 0; atomic_read(&queryd_watcher)