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

Subversion リポジトリの参照

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

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

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