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

Subversion リポジトリの参照

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

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

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