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

Subversion リポジトリの参照

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

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

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