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

Subversion リポジトリの参照

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

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

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