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

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