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

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