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

Subversion リポジトリの参照

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

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

trunk/1.5.x/ccs-patch/fs/ccs_common.c revision 853 by kumaneko, Wed Jan 2 07:32:11 2008 UTC trunk/1.6.x/ccs-patch/fs/ccs_common.c revision 1191 by kumaneko, Fri May 9 01:46:04 2008 UTC
# Line 5  Line 5 
5   *   *
6   * Copyright (C) 2005-2008  NTT DATA CORPORATION   * Copyright (C) 2005-2008  NTT DATA CORPORATION
7   *   *
8   * Version: 1.5.3-pre   2008/01/02   * Version: 1.6.1   2008/05/10
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;
# Line 33  static const int lookup_flags = LOOKUP_F Line 33  static const int lookup_flags = LOOKUP_F
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  bool 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 },          [CCS_TOMOYO_MAC_FOR_ENV]         = { "MAC_FOR_ENV",         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]               = { "SLEEP_PERIOD",        0, 3000 }, /* in 0.1 second */          [CCS_SLEEP_PERIOD]
87          [CCS_TOMOYO_ALT_EXEC]            = { "ALT_EXEC",            0, 0 }, /* Reserved for string. */          = { "SLEEP_PERIOD",        0, 3000 }, /* in 0.1 second */
88  };  };
89    
90  struct profile {  #ifdef CONFIG_TOMOYO
91    /* Capability name used by domain policy. */
92    static 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          const struct path_info *alt_exec;  #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 !current->uid && !current->euid;          return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
222  }  }
223    
224  /*  /**
225   * Format string.   * 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            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     * 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  bool IsCorrectPath(const char *filename, const s8 start_type, const s8 pattern_type, const s8 end_type, const char *function)  bool ccs_is_correct_path(const char *filename, const s8 start_type,
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 164  bool IsCorrectPath(const char *filename, Line 329  bool 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 185  bool IsCorrectPath(const char *filename, Line 353  bool 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  bool 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 231  bool IsCorrectDomain(const unsigned char Line 415  bool 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  bool IsDomainDef(const unsigned char *buffer)  /**
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          /* while (*buffer && (*buffer <= ' ' || *buffer >= 127)) buffer++; */          return !strncmp(buffer, ROOT_NAME, ROOT_NAME_LEN);
         return strncmp(buffer, ROOT_NAME, ROOT_NAME_LEN) == 0;  
435  }  }
436    
437  struct domain_info *FindDomain(const char *domainname0)  /**
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;          struct domain_info *domain;
447          struct path_info domainname;          struct path_info name;
448          domainname.name = domainname0;          name.name = domainname;
449          fill_path_info(&domainname);          ccs_fill_path_info(&name);
450          list1_for_each_entry(domain, &domain_list, list) {          list1_for_each_entry(domain, &domain_list, list) {
451                  if (!domain->is_deleted && !pathcmp(&domainname, domain->domainname)) return domain;                  if (!domain->is_deleted &&
452                        !ccs_pathcmp(&name, domain->domainname))
453                            return domain;
454          }          }
455          return NULL;          return NULL;
456  }  }
457    
458  static int PathDepth(const char *pathname)  /**
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 299  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. */
                                                 if ((c = filename[i]) == '.' && *pattern == '@') break;  
                                                 if (c == '\\') {  
                                                         if ((c = filename[i + 1]) == '\\') {  
                                                                 i++; /* safe because filename is \\ */  
                                                         } else if (c >= '0' && c <= '3' && (c = filename[i + 2]) >= '0' && c <= '7' && (c = filename[i + 3]) >= '0' && c <= '7') {  
                                                                 i += 3; /* safe because filename is \ooo */  
                                                         } else {  
                                                                 break; /* Bad pattern. */  
                                                         }  
                                                 }  
                                         }  
                                         return 0; /* Not matched. */  
                                 }  
                         default:  
                                 {  
                                         int i, j = 0;  
                                         if ((c = *pattern) == '$') {  
                                                 while ((c = filename[j]) >= '0' && c <= '9') j++;  
                                         } else if (c == 'X') {  
                                                 while (((c = filename[j]) >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) j++;  
                                         } else if (c == 'A') {  
                                                 while (((c = filename[j]) >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) j++;  
                                         }  
                                         for (i = 1; i <= j; i++) {  
                                                 if (FileMatchesToPattern2(filename + i, filename_end, pattern + 1, pattern_end)) return 1;  
                                         }  
                                 }  
                                 return 0; /* Not matched or bad pattern. */  
632                          }                          }
633                          filename++; /* safe because *filename != '\0' */                          return false; /* Not matched. */
634                          pattern++; /* safe because *pattern != '\0' */                  default:
635                            j = 0;
636                            c = *pattern;
637                            if (c == '$') {
638                                    while (is_decimal(filename[j]))
639                                            j++;
640                            } else if (c == 'X') {
641                                    while (is_hexadecimal(filename[j]))
642                                            j++;
643                            } else if (c == 'A') {
644                                    while (is_alphabet_char(filename[j]))
645                                            j++;
646                            }
647                            for (i = 1; i <= j; i++) {
648                                    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     *
799     * This function uses ccs_alloc(), so the caller must ccs_free()
800     * if this function didn't return NULL.
801   */   */
802  const char *GetEXE(void)  const char *ccs_get_exe(void)
803  {  {
804          struct mm_struct *mm = current->mm;          struct mm_struct *mm = current->mm;
805          struct vm_area_struct *vma;          struct vm_area_struct *vma;
806          const char *cp = NULL;          const char *cp = NULL;
807          if (!mm) return NULL;          if (!mm)
808                    return NULL;
809          down_read(&mm->mmap_sem);          down_read(&mm->mmap_sem);
810          for (vma = mm->mmap; vma; vma = vma->vm_next) {          for (vma = mm->mmap; vma; vma = vma->vm_next) {
811                  if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {                  if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
812                          cp = realpath_from_dentry(vma->vm_file->f_dentry, vma->vm_file->f_vfsmnt);                          cp = ccs_realpath_from_dentry(vma->vm_file->f_dentry,
813                                                          vma->vm_file->f_vfsmnt);
814                          break;                          break;
815                  }                  }
816          }          }
# Line 488  const char *GetEXE(void) Line 818  const char *GetEXE(void)
818          return cp;          return cp;
819  }  }
820    
821  const char *GetMSG(const bool 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  const char *GetAltExec(void)  /**
837     * ccs_check_flags_no_sleep_check - Check mode for specified functionality.
838     *
839     * @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          const struct path_info *alt_exec = profile_ptr[profile] ? profile_ptr[profile]->alt_exec : NULL;          return sbin_init_started && index < CCS_MAX_CONTROL_INDEX
847          return alt_exec ? alt_exec->name : NULL;  #if MAX_PROFILES != 256
848                    && profile < MAX_PROFILES
849    #endif
850                    && profile_ptr[profile] ?
851                    profile_ptr[profile]->value[index] : 0;
852  }  }
853    
854  /*************************  DOMAIN POLICY HANDLER  *************************/  /**
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            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    /**
881     * 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 sleep_check() ? ccs_check_flags_no_sleep_check(index) : 0;
890    }
891    
892  /* Check whether the given access control is enabled. */  #ifdef CONFIG_TOMOYO
893  unsigned int CheckCCSFlags(const u8 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          const u8 profile = current->domain_info->profile;          const u8 profile = current->domain_info->profile;
903          return sbin_init_started && index < CCS_MAX_CONTROL_INDEX          return sbin_init_started && index < TOMOYO_MAX_CAPABILITY_INDEX
904  #if MAX_PROFILES != 256  #if MAX_PROFILES != 256
905                  && profile < MAX_PROFILES                  && profile < MAX_PROFILES
906  #endif  #endif
907                  && profile_ptr[profile] ? profile_ptr[profile]->value[index] : 0;                  && sleep_check()
908                    && profile_ptr[profile] ?
909                    profile_ptr[profile]->capability_value[index] : 0;
910  }  }
911    
912  bool TomoyoVerboseMode(void)  /**
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          return CheckCCSFlags(CCS_TOMOYO_VERBOSE) != 0;          return operation < TOMOYO_MAX_CAPABILITY_INDEX
922                    ? capability_control_keyword[operation] : NULL;
923  }  }
924    
925  bool CheckDomainQuota(struct domain_info * const domain)  #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;          unsigned int count = 0;
948          struct acl_info *ptr;          struct acl_info *ptr;
949          if (!domain) return 1;          if (!domain)
950                    return true;
951          list1_for_each_entry(ptr, &domain->acl_info_list, list) {          list1_for_each_entry(ptr, &domain->acl_info_list, list) {
952                  if (!ptr->is_deleted) count++;                  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 < CheckCCSFlags(CCS_TOMOYO_MAX_ACCEPT_ENTRY)) return 1;          if (count < ccs_check_flags(CCS_TOMOYO_MAX_ACCEPT_ENTRY))
1007                    return true;
1008          if (!domain->quota_warned) {          if (!domain->quota_warned) {
1009                  domain->quota_warned = 1;                  domain->quota_warned = true;
1010                  printk("TOMOYO-WARNING: Domain '%s' has so many ACLs to hold. Stopped learning mode.\n", domain->domainname->name);                  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 0;          return false;
1015  }  }
1016    
1017  static struct profile *FindOrAssignNewProfile(const unsigned int profile)  /**
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);          static DEFINE_MUTEX(profile_lock);
1028          struct profile *ptr = NULL;          struct profile *ptr = NULL;
1029          mutex_lock(&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                                    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. */                          mb(); /* Avoid out-of-order execution. */
1045                          profile_ptr[profile] = ptr;                          profile_ptr[profile] = ptr;
1046                  }                  }
1047          }          }
1048     ok:
1049          mutex_unlock(&profile_lock);          mutex_unlock(&profile_lock);
1050          return ptr;          return ptr;
1051  }  }
1052    
1053  /* #define ALT_EXEC */  /**
1054     * write_profile - Write profile table.
1055  static int SetProfile(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          UpdateCounter(CCS_UPDATES_COUNTER_PROFILE);          ccs_update_counter(CCS_UPDATES_COUNTER_PROFILE);
1081          if (strcmp(data, ccs_control_array[CCS_PROFILE_COMMENT].keyword) == 0) {          if (!strcmp(data, "COMMENT")) {
1082                  profile->comment = SaveName(cp + 1);                  profile->comment = ccs_save_name(cp + 1);
1083                  return 0;                  return 0;
1084          }          }
 #ifdef ALT_EXEC  
1085  #ifdef CONFIG_TOMOYO  #ifdef CONFIG_TOMOYO
1086          if (strcmp(data, ccs_control_array[CCS_TOMOYO_ALT_EXEC].keyword) == 0) {          if (str_starts(&data, KEYWORD_MAC_FOR_CAPABILITY)) {
1087                  cp++;                  if (sscanf(cp + 1, "%u", &value) != 1) {
1088                  if (*cp && !IsCorrectPath(cp, 1, -1, -1, __FUNCTION__)) cp = "";                          for (i = 0; i < 4; i++) {
1089                  profile->alt_exec = SaveName(cp);                                  if (strcmp(cp + 1, mode_4[i]))
1090                  return 0;                                          continue;
1091          }                                  value = i;
1092  #endif                                  break;
1093  #endif                          }
1094          if (sscanf(cp + 1, "%u", &value) != 1) return -EINVAL;                          if (i == 4)
1095  #ifdef CONFIG_TOMOYO                                  return -EINVAL;
1096          if (strncmp(data, KEYWORD_MAC_FOR_CAPABILITY, KEYWORD_MAC_FOR_CAPABILITY_LEN) == 0) {                  }
1097                  return SetCapabilityStatus(data + KEYWORD_MAC_FOR_CAPABILITY_LEN, value, i);                  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 ReadProfile(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                            continue;
1168    #if !defined(CONFIG_SAKURA) || !defined(CONFIG_TOMOYO)
1169                    switch (type) {
1170  #ifndef CONFIG_SAKURA  #ifndef CONFIG_SAKURA
1171                                  case CCS_SAKURA_DENY_CONCEAL_MOUNT:                  case CCS_SAKURA_DENY_CONCEAL_MOUNT:
1172                                  case CCS_SAKURA_RESTRICT_CHROOT:                  case CCS_SAKURA_RESTRICT_CHROOT:
1173                                  case CCS_SAKURA_RESTRICT_MOUNT:                  case CCS_SAKURA_RESTRICT_MOUNT:
1174                                  case CCS_SAKURA_RESTRICT_UNMOUNT:                  case CCS_SAKURA_RESTRICT_UNMOUNT:
1175                                  case CCS_SAKURA_RESTRICT_PIVOT_ROOT:                  case CCS_SAKURA_RESTRICT_PIVOT_ROOT:
1176                                  case CCS_SAKURA_RESTRICT_AUTOBIND:                  case CCS_SAKURA_RESTRICT_AUTOBIND:
1177  #endif  #endif
1178  #ifndef CONFIG_TOMOYO  #ifndef CONFIG_TOMOYO
1179                                  case CCS_TOMOYO_MAC_FOR_FILE:                  case CCS_TOMOYO_MAC_FOR_FILE:
1180                                  case CCS_TOMOYO_MAC_FOR_ARGV0:                  case CCS_TOMOYO_MAC_FOR_ARGV0:
1181                                  case CCS_TOMOYO_MAC_FOR_ENV:                  case CCS_TOMOYO_MAC_FOR_ENV:
1182                                  case CCS_TOMOYO_MAC_FOR_NETWORK:                  case CCS_TOMOYO_MAC_FOR_NETWORK:
1183                                  case CCS_TOMOYO_MAC_FOR_SIGNAL:                  case CCS_TOMOYO_MAC_FOR_SIGNAL:
1184                                  case CCS_TOMOYO_MAX_ACCEPT_ENTRY:                  case CCS_TOMOYO_MAX_ACCEPT_ENTRY:
1185                                  case CCS_TOMOYO_MAX_GRANT_LOG:                  case CCS_TOMOYO_MAX_GRANT_LOG:
1186                                  case CCS_TOMOYO_MAX_REJECT_LOG:                  case CCS_TOMOYO_MAX_REJECT_LOG:
1187                                  case CCS_TOMOYO_VERBOSE:                  case CCS_TOMOYO_VERBOSE:
1188  #endif  #endif
1189  #ifndef ALT_EXEC                          continue;
1190                                  case CCS_TOMOYO_ALT_EXEC:                  }
1191                                  case CCS_SLEEP_PERIOD:  #endif
1192  #endif                  if (!type) { /* Print profile' comment tag. */
1193                                          continue;                          if (!ccs_io_printf(head, "%u-COMMENT=%s\n",
1194                                  }                                             index, profile->comment ?
1195                                  if (j == CCS_PROFILE_COMMENT) {                                             profile->comment->name : ""))
1196                                          if (io_printf(head, "%u-%s=%s\n", i, ccs_control_array[CCS_PROFILE_COMMENT].keyword, profile->comment ? profile->comment->name : "")) break;                                  break;
1197                                  } else if (j == CCS_TOMOYO_ALT_EXEC) {                          continue;
                                         const struct path_info *alt_exec = profile->alt_exec;  
                                         if (io_printf(head, "%u-%s=%s\n", i, ccs_control_array[CCS_TOMOYO_ALT_EXEC].keyword, alt_exec ? alt_exec->name : "")) break;  
                                 } else {  
                                         if (io_printf(head, "%u-%s=%u\n", i, ccs_control_array[j].keyword, profile->value[j])) break;  
                                 }  
                         }  
                         if (step == MAX_PROFILES * CCS_MAX_CONTROL_INDEX) {  
                                 head->read_var2 = (void *) "";  
                                 head->read_step = 0;  
                         }  
1198                  }                  }
1199                  if (head->read_var2) {                  type--;
1200                    if (type >= CCS_MAX_CONTROL_INDEX) {
1201  #ifdef CONFIG_TOMOYO  #ifdef CONFIG_TOMOYO
1202                          if (ReadCapabilityStatus(head) == 0)                          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                                  head->read_eof = 1;                  } else {
1212                            const unsigned int value = profile->value[type];
1213                            const char **modes = NULL;
1214                            const char *keyword = ccs_control_array[type].keyword;
1215                            switch (ccs_control_array[type].max_value) {
1216                            case 3:
1217                                    modes = mode_4;
1218                                    break;
1219                            case 1:
1220                                    modes = mode_2;
1221                                    break;
1222                            }
1223                            if (modes) {
1224                                    if (!ccs_io_printf(head, "%u-%s=%s\n", index,
1225                                                       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                  }                  }
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 list1_head list;          struct list1_head list;
1242            /* A path to program or a domainname. */
1243          const struct path_info *manager;          const struct path_info *manager;
1244          bool is_domain;          bool is_domain;  /* True if manager is a domainname. */
1245          bool is_deleted;          bool is_deleted; /* True if this entry is deleted. */
1246  };  };
1247    
1248    /* The list for "struct policy_manager_entry". */
1249  static LIST1_HEAD(policy_manager_list);  static LIST1_HEAD(policy_manager_list);
1250    
1251  static int AddManagerEntry(const char *manager, const bool 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            struct policy_manager_entry *ptr;
1263          static DEFINE_MUTEX(lock);          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          bool 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            if (!saved_manager)
1277                    return -ENOMEM;
1278          mutex_lock(&lock);          mutex_lock(&lock);
1279          list1_for_each_entry(ptr, &policy_manager_list, list) {          list1_for_each_entry(ptr, &policy_manager_list, list) {
1280                  if (ptr->manager == saved_manager) {                  if (ptr->manager != saved_manager)
1281                          ptr->is_deleted = is_delete;                          continue;
1282                          error = 0;                  ptr->is_deleted = is_delete;
1283                          goto out;                  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          list1_add_tail_mb(&new_entry->list, &policy_manager_list);          list1_add_tail_mb(&new_entry->list, &policy_manager_list);
1296          error = 0;          error = 0;
1297   out:   out:
1298          mutex_unlock(&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          bool 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          struct list1_head *pos;          struct list1_head *pos;
1332          if (head->read_eof) return 0;          if (head->read_eof)
1333          if (!isRoot()) return -EPERM;                  return 0;
1334          list1_for_each_cookie(pos, head->read_var2, &policy_manager_list) {          list1_for_each_cookie(pos, head->read_var2, &policy_manager_list) {
1335                  struct policy_manager_entry *ptr;                  struct policy_manager_entry *ptr;
1336                  ptr = list1_entry(pos, struct policy_manager_entry, list);                  ptr = list1_entry(pos, struct policy_manager_entry, list);
1337                  if (ptr->is_deleted) continue;                  if (ptr->is_deleted)
1338                  if (io_printf(head, "%s\n", ptr->manager->name)) return 0;                          continue;
1339                    if (!ccs_io_printf(head, "%s\n", ptr->manager->name))
1340                            return 0;
1341          }          }
1342          head->read_eof = 1;          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          bool found = 0;          const struct path_info *domainname = task->domain_info->domainname;
1358          if (!sbin_init_started) return 1;          bool found = false;
1359            if (!sbin_init_started)
1360                    return true;
1361            if (!manage_by_non_root && (task->uid || task->euid))
1362                    return false;
1363          list1_for_each_entry(ptr, &policy_manager_list, list) {          list1_for_each_entry(ptr, &policy_manager_list, list) {
1364                  if (!ptr->is_deleted && ptr->is_domain && !pathcmp(domainname, ptr->manager)) return 1;                  if (!ptr->is_deleted && ptr->is_domain
1365          }                      && !ccs_pathcmp(domainname, ptr->manager))
1366          if ((exe = GetEXE()) == NULL) return 0;                          return true;
1367            }
1368            exe = ccs_get_exe();
1369            if (!exe)
1370                    return false;
1371          list1_for_each_entry(ptr, &policy_manager_list, list) {          list1_for_each_entry(ptr, &policy_manager_list, list) {
1372                  if (!ptr->is_deleted && !ptr->is_domain && !strcmp(exe, ptr->manager->name)) {                  if (!ptr->is_deleted && !ptr->is_domain
1373                          found = 1;                      && !strcmp(exe, ptr->manager->name)) {
1374                            found = true;
1375                          break;                          break;
1376                  }                  }
1377          }          }
1378          if (!found) { /* 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          }          }
# Line 770  static int IsPolicyManager(void) Line 1390  static int IsPolicyManager(void)
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  static char *FindConditionPart(char *data)   *
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 "), *cp2;          char *cp = strstr(data, " if ");
1404          if (cp) {          if (cp) {
1405                  while ((cp2 = strstr(cp + 3, " if ")) != NULL) cp = cp2;                  char *cp2;
1406                    while ((cp2 = strstr(cp + 3, " if ")) != NULL)
1407                            cp = cp2;
1408                  *cp++ = '\0';                  *cp++ = '\0';
1409            } else {
1410                    cp = strstr(data, " ; set ");
1411                    if (cp)
1412                            *cp++ = '\0';
1413          }          }
1414          return cp;          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          bool 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          const struct condition_list *cond = NULL;          const struct condition_list *cond = NULL;
1433          char *cp;                char *cp;
1434          if (!isRoot()) return -EPERM;          if (str_starts(&data, KEYWORD_DELETE))
1435          if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {                  is_delete = true;
1436                  data += KEYWORD_DELETE_LEN;          else if (str_starts(&data, KEYWORD_SELECT))
1437                  is_delete = 1;                  is_select = true;
1438          } else if (strncmp(data, KEYWORD_SELECT, KEYWORD_SELECT_LEN) == 0) {          else if (str_starts(&data, KEYWORD_UNDELETE))
1439                  data += KEYWORD_SELECT_LEN;                  is_undelete = true;
1440                  is_select = 1;          if (ccs_is_domain_def(data)) {
1441          } else if (strncmp(data, KEYWORD_UNDELETE, KEYWORD_UNDELETE_LEN) == 0) {                  domain = NULL;
1442                  data += KEYWORD_UNDELETE_LEN;                  if (is_delete)
1443                  is_undelete = 1;                          ccs_delete_domain(data);
1444          }                  else if (is_select)
1445          UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);                          domain = ccs_find_domain(data);
1446          if (IsDomainDef(data)) {                  else if (is_undelete)
1447                  if (is_delete) {                          domain = ccs_undelete_domain(data);
1448                          DeleteDomain(data);                  else
1449                          domain = NULL;                          domain = ccs_find_or_assign_new_domain(data, 0);
                 } else if (is_select) {  
                         domain = FindDomain(data);  
                 } 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                    return -EINVAL;
1456    
1457          if (sscanf(data, KEYWORD_USE_PROFILE "%u", &profile) == 1 && profile < MAX_PROFILES) {          if (sscanf(data, KEYWORD_USE_PROFILE "%u", &profile) == 1
1458                  if (profile_ptr[profile] || !sbin_init_started) domain->profile = (u8) profile;              && profile < MAX_PROFILES) {
1459                    if (profile_ptr[profile] || !sbin_init_started)
1460                            domain->profile = (u8) profile;
1461                    return 0;
1462            }
1463            if (!strcmp(data, KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) {
1464                    ccs_set_domain_flag(domain, is_delete,
1465                                        DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ);
1466                    return 0;
1467            }
1468            if (!strcmp(data, KEYWORD_IGNORE_GLOBAL_ALLOW_ENV)) {
1469                    ccs_set_domain_flag(domain, is_delete,
1470                                        DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_ENV);
1471                  return 0;                  return 0;
1472          }          }
1473          cp = FindConditionPart(data);          cp = ccs_find_condition_part(data);
1474          if (cp && (cond = FindOrAssignNewCondition(cp)) == NULL) return -EINVAL;          if (cp) {
1475          if (strncmp(data, KEYWORD_ALLOW_CAPABILITY, KEYWORD_ALLOW_CAPABILITY_LEN) == 0) {                  cond = ccs_find_or_assign_new_condition(cp);
1476                  return AddCapabilityPolicy(data + KEYWORD_ALLOW_CAPABILITY_LEN, domain, cond, is_delete);                  if (!cond)
1477          } else if (strncmp(data, KEYWORD_ALLOW_NETWORK, KEYWORD_ALLOW_NETWORK_LEN) == 0) {                          return -EINVAL;
1478                  return AddNetworkPolicy(data + KEYWORD_ALLOW_NETWORK_LEN, domain, cond, is_delete);          }
1479          } else if (strncmp(data, KEYWORD_ALLOW_SIGNAL, KEYWORD_ALLOW_SIGNAL_LEN) == 0) {          if (str_starts(&data, KEYWORD_ALLOW_CAPABILITY))
1480                  return AddSignalPolicy(data + KEYWORD_ALLOW_SIGNAL_LEN, domain, cond, is_delete);                  return ccs_write_capability_policy(data, domain, cond,
1481          } else if (strncmp(data, KEYWORD_ALLOW_ARGV0, KEYWORD_ALLOW_ARGV0_LEN) == 0) {                                                     is_delete);
1482                  return AddArgv0Policy(data + KEYWORD_ALLOW_ARGV0_LEN, domain, cond, is_delete);          else if (str_starts(&data, KEYWORD_ALLOW_NETWORK))
1483          } else if (strncmp(data, KEYWORD_ALLOW_ENV, KEYWORD_ALLOW_ENV_LEN) == 0) {                  return ccs_write_network_policy(data, domain, cond, is_delete);
1484                  return AddEnvPolicy(data + KEYWORD_ALLOW_ENV_LEN, domain, cond, is_delete);          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                  return AddFilePolicy(data, domain, cond, is_delete);                  filename = ptr->u.filename->name;
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    /**
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            int pos = head->read_avail;
1631            if (!ccs_io_printf(head, KEYWORD_ALLOW_ENV "%s", ptr->env->name))
1632                    goto out;
1633            if (!ccs_print_condition(head, cond))
1634                    goto out;
1635            return true;
1636     out:
1637            head->read_avail = pos;
1638            return false;
1639    }
1640    
1641    /**
1642     * print_capability_acl - Print a capability ACL entry.
1643     *
1644     * @head: Pointer to "struct ccs_io_buffer".
1645     * @ptr:  Pointer to "struct capability_acl_record".
1646     * @cond: Pointer to "struct condition_list". May be NULL.
1647     *
1648     * Returns true on success, false otherwise.
1649     */
1650    static bool print_capability_acl(struct ccs_io_buffer *head,
1651                                     struct capability_acl_record *ptr,
1652                                     const struct condition_list *cond)
1653    {
1654            int pos = head->read_avail;
1655            if (!ccs_io_printf(head, KEYWORD_ALLOW_CAPABILITY "%s",
1656                               ccs_cap2keyword(ptr->operation)))
1657                    goto out;
1658            if (!ccs_print_condition(head, cond))
1659                    goto out;
1660            return true;
1661     out:
1662            head->read_avail = pos;
1663            return false;
1664    }
1665    
1666    /**
1667     * print_ipv4_entry - Print IPv4 address of a network ACL entry.
1668     *
1669     * @head: Pointer to "struct ccs_io_buffer".
1670     * @ptr:  Pointer to "struct ip_network_acl_record".
1671     *
1672     * Returns true on success, false otherwise.
1673     */
1674    static bool print_ipv4_entry(struct ccs_io_buffer *head,
1675                                 struct ip_network_acl_record *ptr)
1676    {
1677            const u32 min_address = ptr->u.ipv4.min;
1678            const u32 max_address = ptr->u.ipv4.max;
1679            if (!ccs_io_printf(head, "%u.%u.%u.%u", HIPQUAD(min_address)))
1680                    return false;
1681            if (min_address != max_address
1682                && !ccs_io_printf(head, "-%u.%u.%u.%u", HIPQUAD(max_address)))
1683                    return false;
1684            return true;
1685    }
1686    
1687    /**
1688     * print_ipv6_entry - Print IPv6 address of a network ACL entry.
1689     *
1690     * @head: Pointer to "struct ccs_io_buffer".
1691     * @ptr:  Pointer to "struct ip_network_acl_record".
1692     *
1693     * Returns true on success, false otherwise.
1694     */
1695    static bool print_ipv6_entry(struct ccs_io_buffer *head,
1696                                 struct ip_network_acl_record *ptr)
1697    {
1698            char buf[64];
1699            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            if (!ccs_io_printf(head, "%s", buf))
1703                    return false;
1704            if (min_address != max_address) {
1705                    ccs_print_ipv6(buf, sizeof(buf), max_address);
1706                    if (!ccs_io_printf(head, "-%s", buf))
1707                            return false;
1708            }
1709            return true;
1710  }  }
1711    
1712  static int ReadDomainPolicy(struct io_buffer *head)  /**
1713     * print_port_entry - Print port number of a network ACL entry.
1714     *
1715     * @head: Pointer to "struct ccs_io_buffer".
1716     * @ptr:  Pointer to "struct ip_network_acl_record".
1717     *
1718     * Returns true on success, false otherwise.
1719     */
1720    static bool print_port_entry(struct ccs_io_buffer *head,
1721                                 struct ip_network_acl_record *ptr)
1722    {
1723            const u16 min_port = ptr->min_port, max_port = ptr->max_port;
1724            if (!ccs_io_printf(head, " %u", min_port))
1725                    return false;
1726            if (min_port != max_port && !ccs_io_printf(head, "-%u", max_port))
1727                    return false;
1728            return true;
1729    }
1730    
1731    /**
1732     * print_network_acl - Print a network ACL entry.
1733     *
1734     * @head: Pointer to "struct ccs_io_buffer".
1735     * @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     */
1740    static bool print_network_acl(struct ccs_io_buffer *head,
1741                                  struct ip_network_acl_record *ptr,
1742                                  const struct condition_list *cond)
1743    {
1744            int pos = head->read_avail;
1745            if (!ccs_io_printf(head, KEYWORD_ALLOW_NETWORK "%s ",
1746                               ccs_net2keyword(ptr->operation_type)))
1747                    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            /* Workaround for gcc 3.2.2's inline bug. */
1879            if (acl_type & ACL_DELETED)
1880                    return true;
1881            BUG(); /* This must not happen. */
1882            return false;
1883    }
1884    
1885    /**
1886     * read_domain_policy - Read domain policy.
1887     *
1888     * @head: Pointer to "struct ccs_io_buffer".
1889     *
1890     * Returns 0.
1891     */
1892    static int read_domain_policy(struct ccs_io_buffer *head)
1893  {  {
1894          struct list1_head *dpos;          struct list1_head *dpos;
1895          struct list1_head *apos;          struct list1_head *apos;
1896          if (head->read_eof) return 0;          if (head->read_eof)
1897          if (head->read_step == 0) {                  return 0;
1898                  if (!isRoot()) return -EPERM;          if (head->read_step == 0)
1899                  head->read_step = 1;                  head->read_step = 1;
         }  
1900          list1_for_each_cookie(dpos, head->read_var1, &domain_list) {          list1_for_each_cookie(dpos, head->read_var1, &domain_list) {
1901                  struct domain_info *domain;                  struct domain_info *domain;
1902                    const char *quota_exceeded = "";
1903                    const char *transition_failed = "";
1904                    const char *ignore_global_allow_read = "";
1905                    const char *ignore_global_allow_env = "";
1906                  domain = list1_entry(dpos, struct domain_info, list);                  domain = list1_entry(dpos, struct domain_info, list);
1907                  if (head->read_step != 1) goto acl_loop;                  if (head->read_step != 1)
1908                  if (domain->is_deleted) continue;                          goto acl_loop;
1909                  if (io_printf(head, "%s\n" KEYWORD_USE_PROFILE "%u\n%s\n", domain->domainname->name, domain->profile, domain->quota_warned ? "quota_exceeded\n" : "")) return 0;                  if (domain->is_deleted)
1910                  head->read_step = 2;                          continue;
1911          acl_loop: ;                  /* Print domainname and flags. */
1912                  if (head->read_step == 3) goto tail_mark;                  if (domain->quota_warned)
1913                  list1_for_each_cookie(apos, head->read_var2, &domain->acl_info_list) {                          quota_exceeded = "quota_exceeded\n";
1914                          struct acl_info *ptr;                  if (domain->flags & DOMAIN_FLAGS_TRANSITION_FAILED)
1915                          int pos;                          transition_failed = "transition_failed\n";
1916                          u8 acl_type;                  if (domain->flags & DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ)
1917                          ptr = list1_entry(apos, struct acl_info, list);                          ignore_global_allow_read
1918                          if (ptr->is_deleted) continue;                                  = KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n";
1919                          pos = head->read_avail;                  if (domain->flags & DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_ENV)
1920                          acl_type = ptr->type;                          ignore_global_allow_env
1921                          if (acl_type == TYPE_SINGLE_PATH_ACL) {                                  = KEYWORD_IGNORE_GLOBAL_ALLOW_ENV "\n";
1922                                  struct single_acl_record *ptr2 = container_of(ptr, struct single_acl_record, head);                  if (!ccs_io_printf(head, "%s\n" KEYWORD_USE_PROFILE "%u\n"
1923                                  const bool b = ptr2->u_is_group;                                     "%s%s%s%s\n", domain->domainname->name,
1924                                  const u16 perm = ptr2->perm;                                     domain->profile, quota_exceeded,
1925                                  u8 bit = head->read_bit;                                     transition_failed,
1926                                  while (bit < MAX_SINGLE_PATH_OPERATION) {                                     ignore_global_allow_read,
1927                                          if (perm & (1 << bit)) {                                     ignore_global_allow_env))
                                                 pos = head->read_avail;  
                                                 if (io_printf(head, "allow_%s %s%s ", sp_operation2keyword(bit),  
                                                               b ? "@" : "", b ? ptr2->u.group->group_name->name : ptr2->u.filename->name)  
                                                     || DumpCondition(head, ptr->cond)) {  
                                                         head->read_bit = bit;  
                                                         head->read_avail = pos;  
                                                         return 0;  
                                                 }  
                                         }  
                                         bit++;  
                                 }  
                                 head->read_bit = 0;  
                         } else if (acl_type == TYPE_DOUBLE_PATH_ACL) {  
                                 struct double_acl_record *ptr2 = container_of(ptr, struct double_acl_record, head);  
                                 const bool b0 = ptr2->u1_is_group, b1 = ptr2->u2_is_group;  
                                 const u8 perm = ptr2->perm;  
                                 u8 bit = head->read_bit;  
                                 while (bit < MAX_DOUBLE_PATH_OPERATION) {  
                                         if (perm & (1 << bit)) {  
                                                 pos = head->read_avail;  
                                                 if (io_printf(head, "allow_%s %s%s %s%s", dp_operation2keyword(bit),  
                                                               b0 ? "@" : "", b0 ? ptr2->u1.group1->group_name->name : ptr2->u1.filename1->name,  
                                                               b1 ? "@" : "", b1 ? ptr2->u2.group2->group_name->name : ptr2->u2.filename2->name)  
                                                     || DumpCondition(head, ptr->cond)) {  
                                                         head->read_bit = bit;  
                                                         head->read_avail = pos;  
                                                         return 0;  
                                                 }  
                                         }  
                                         bit++;  
                                 }  
                                 head->read_bit = 0;  
                         } else if (acl_type == TYPE_ARGV0_ACL) {  
                                 struct argv0_acl_record *ptr2 = container_of(ptr, struct argv0_acl_record, head);  
                                 if (io_printf(head, KEYWORD_ALLOW_ARGV0 "%s %s",  
                                               ptr2->filename->name, ptr2->argv0->name)) goto print_acl_rollback;  
                         } else if (acl_type == TYPE_ENV_ACL) {  
                                 struct env_acl_record *ptr2 = container_of(ptr, struct env_acl_record, head);  
                                 if (io_printf(head, KEYWORD_ALLOW_ENV "%s", ptr2->env->name)) goto print_acl_rollback;  
                         } else if (acl_type == TYPE_CAPABILITY_ACL) {  
                                 struct capability_acl_record *ptr2 = container_of(ptr, struct capability_acl_record, head);  
                                 const u32 capability = ptr2->capability;  
                                 u8 bit = head->read_bit;  
                                 while (bit < TOMOYO_MAX_CAPABILITY_INDEX) {  
                                         if (capability & (1 << bit)) {  
                                                 pos = head->read_avail;  
                                                 if (io_printf(head, KEYWORD_ALLOW_CAPABILITY "%s", cap_operation2keyword(bit)) ||  
                                                     DumpCondition(head, ptr->cond)) {  
                                                         head->read_bit = bit;  
                                                         head->read_avail = pos;  
                                                         return 0;  
                                                 }  
                                         }  
                                         bit++;  
                                 }  
                                 head->read_bit = 0;  
                         } else if (acl_type == TYPE_IP_NETWORK_ACL) {  
                                 struct ip_network_acl_record *ptr2 = container_of(ptr, struct ip_network_acl_record, head);  
                                 if (io_printf(head, KEYWORD_ALLOW_NETWORK "%s ", net_operation2keyword(ptr2->operation_type))) goto print_acl_rollback;  
                                 switch (ptr2->record_type) {  
                                 case IP_RECORD_TYPE_ADDRESS_GROUP:  
                                         if (io_printf(head, "@%s", ptr2->u.group->group_name->name)) goto print_acl_rollback;  
                                         break;  
                                 case IP_RECORD_TYPE_IPv4:  
                                         {  
                                                 const u32 min_address = ptr2->u.ipv4.min, max_address = ptr2->u.ipv4.max;  
                                                 if (io_printf(head, "%u.%u.%u.%u", HIPQUAD(min_address))) goto print_acl_rollback;  
                                                 if (min_address != max_address && io_printf(head, "-%u.%u.%u.%u", HIPQUAD(max_address))) goto print_acl_rollback;  
                                         }  
                                         break;  
                                 case IP_RECORD_TYPE_IPv6:  
                                         {  
                                                 char buf[64];  
                                                 const struct in6_addr *min_address = ptr2->u.ipv6.min, *max_address = ptr2->u.ipv6.max;  
                                                 print_ipv6(buf, sizeof(buf), min_address);  
                                                 if (io_printf(head, "%s", buf)) goto print_acl_rollback;  
                                                 if (min_address != max_address) {  
                                                         print_ipv6(buf, sizeof(buf), max_address);  
                                                         if (io_printf(head, "-%s", buf)) goto print_acl_rollback;  
                                                 }  
                                         }  
                                         break;  
                                 }  
                                 {  
                                         const u16 min_port = ptr2->min_port, max_port = ptr2->max_port;  
                                         if (io_printf(head, " %u", min_port)) goto print_acl_rollback;  
                                         if (min_port != max_port && io_printf(head, "-%u", max_port)) goto print_acl_rollback;  
                                 }  
                         } else if (acl_type == TYPE_SIGNAL_ACL) {  
                                 struct signal_acl_record *ptr2 = container_of(ptr, struct signal_acl_record, head);  
                                 if (io_printf(head, KEYWORD_ALLOW_SIGNAL "%u %s", ptr2->sig, ptr2->domainname->name)) goto print_acl_rollback;  
                         } else {  
                                 BUG();  
                         }  
                         if (acl_type != TYPE_SINGLE_PATH_ACL && acl_type != TYPE_DOUBLE_PATH_ACL && acl_type != TYPE_CAPABILITY_ACL && DumpCondition(head, ptr->cond)) {  
                         print_acl_rollback: ;  
                         head->read_avail = pos;  
1928                          return 0;                          return 0;
1929                          }                  head->read_step = 2;
1930     acl_loop:
1931                    if (head->read_step == 3)
1932                            goto tail_mark;
1933                    /* Print ACL entries in the domain. */
1934                    list1_for_each_cookie(apos, head->read_var2,
1935                                          &domain->acl_info_list) {
1936                            struct acl_info *ptr
1937                                    = list1_entry(apos, struct acl_info, list);
1938                            if (!print_entry(head, ptr))
1939                                    return 0;
1940                  }                  }
1941                  head->read_step = 3;                  head->read_step = 3;
1942          tail_mark: ;   tail_mark:
1943                  if (io_printf(head, "\n")) return 0;                  if (!ccs_io_printf(head, "\n"))
1944                            return 0;
1945                  head->read_step = 1;                  head->read_step = 1;
1946          }          }
1947          head->read_eof = 1;          head->read_eof = true;
1948          return 0;          return 0;
1949  }  }
1950    
1951  #endif  #endif
1952    
1953  static int UpdateDomainProfile(struct io_buffer *head)  /**
1954     * write_domain_profile - Assign profile for specified domain.
1955     *
1956     * @head: Pointer to "struct ccs_io_buffer".
1957     *
1958     * Returns 0 on success, -EINVAL otherwise.
1959     *
1960     * This is equivalent to doing
1961     *
1962     *     ( echo "select " $domainname; echo "use_profile " $profile ) |
1963     *     /usr/lib/ccs/loadpolicy -d
1964     */
1965    static int write_domain_profile(struct ccs_io_buffer *head)
1966  {  {
1967          char *data = head->write_buf;          char *data = head->write_buf;
1968          char *cp = strchr(data, ' ');          char *cp = strchr(data, ' ');
1969          struct domain_info *domain;          struct domain_info *domain;
1970          unsigned int profile;          unsigned int profile;
1971          if (!isRoot()) return -EPERM;          if (!cp)
1972          if (!cp) return -EINVAL;                  return -EINVAL;
1973          *cp = '\0';          *cp = '\0';
1974          domain = FindDomain(cp + 1);          domain = ccs_find_domain(cp + 1);
1975          profile = simple_strtoul(data, NULL, 10);          profile = simple_strtoul(data, NULL, 10);
1976          if (domain && profile < MAX_PROFILES && (profile_ptr[profile] || !sbin_init_started)) domain->profile = (u8) profile;          if (domain && profile < MAX_PROFILES
1977          UpdateCounter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);              && (profile_ptr[profile] || !sbin_init_started))
1978                    domain->profile = (u8) profile;
1979            ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY);
1980          return 0;          return 0;
1981  }  }
1982    
1983  static int ReadDomainProfile(struct io_buffer *head)  /**
1984     * read_domain_profile - Read only domainname and profile.
1985     *
1986     * @head: Pointer to "struct ccs_io_buffer".
1987     *
1988     * Returns list of profile number and domainname pairs.
1989     *
1990     * This is equivalent to doing
1991     *
1992     *     grep -A 1 '^<kernel>' /proc/ccs/domain_policy |
1993     *     awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
1994     *     domainname = $0; } else if ( $1 == "use_profile" ) {
1995     *     print $2 " " domainname; domainname = ""; } } ; '
1996     */
1997    static int read_domain_profile(struct ccs_io_buffer *head)
1998  {  {
1999          struct list1_head *pos;          struct list1_head *pos;
2000          if (head->read_eof) return 0;          if (head->read_eof)
2001          if (!isRoot()) return -EPERM;                  return 0;
2002          list1_for_each_cookie(pos, head->read_var1, &domain_list) {          list1_for_each_cookie(pos, head->read_var1, &domain_list) {
2003                  struct domain_info *domain;                  struct domain_info *domain;
2004                  domain = list1_entry(pos, struct domain_info, list);                  domain = list1_entry(pos, struct domain_info, list);
2005                  if (domain->is_deleted) continue;                  if (domain->is_deleted)
2006                  if (io_printf(head, "%u %s\n", domain->profile, domain->domainname->name)) return 0;                          continue;
2007                    if (!ccs_io_printf(head, "%u %s\n", domain->profile,
2008                                       domain->domainname->name))
2009                            return 0;
2010          }          }
2011          head->read_eof = 1;          head->read_eof = true;
2012          return 0;          return 0;
2013  }  }
2014    
2015  static int WritePID(struct io_buffer *head)  /**
2016     * write_pid: Specify PID to obtain domainname.
2017     *
2018     * @head: Pointer to "struct ccs_io_buffer".
2019     *
2020     * Returns 0.
2021     */
2022    static int write_pid(struct ccs_io_buffer *head)
2023  {  {
2024          head->read_step = (int) simple_strtoul(head->write_buf, NULL, 10);          head->read_step = (int) simple_strtoul(head->write_buf, NULL, 10);
2025          head->read_eof = 0;          head->read_eof = false;
2026          return 0;          return 0;
2027  }  }
2028    
2029  static int ReadPID(struct io_buffer *head)  /**
2030     * read_pid - Get domainname of the specified PID.
2031     *
2032     * @head: Pointer to "struct ccs_io_buffer".
2033     *
2034     * Returns the domainname which the specified PID is in on success,
2035     * empty string otherwise.
2036     * The PID is specified by write_pid() so that the user can obtain
2037     * using read()/write() interface rather than sysctl() interface.
2038     */
2039    static int read_pid(struct ccs_io_buffer *head)
2040  {  {
2041          if (head->read_avail == 0 && !head->read_eof) {          if (head->read_avail == 0 && !head->read_eof) {
2042                  const int pid = head->read_step;                  const int pid = head->read_step;
# Line 1031  static int ReadPID(struct io_buffer *hea Line 2045  static int ReadPID(struct io_buffer *hea
2045                  /***** CRITICAL SECTION START *****/                  /***** CRITICAL SECTION START *****/
2046                  read_lock(&tasklist_lock);                  read_lock(&tasklist_lock);
2047                  p = find_task_by_pid(pid);                  p = find_task_by_pid(pid);
2048                  if (p) domain = p->domain_info;                  if (p)
2049                            domain = p->domain_info;
2050                  read_unlock(&tasklist_lock);                  read_unlock(&tasklist_lock);
2051                  /***** CRITICAL SECTION END *****/                  /***** CRITICAL SECTION END *****/
2052                  if (domain) io_printf(head, "%d %u %s", pid, domain->profile, domain->domainname->name);                  if (domain)
2053                  head->read_eof = 1;                          ccs_io_printf(head, "%d %u %s", pid, domain->profile,
2054                                          domain->domainname->name);
2055                    head->read_eof = true;
2056          }          }
2057          return 0;          return 0;
2058  }  }
2059    
 /*************************  EXCEPTION POLICY HANDLER  *************************/  
   
2060  #ifdef CONFIG_TOMOYO  #ifdef CONFIG_TOMOYO
2061    
2062  static int AddExceptionPolicy(struct io_buffer *head)  /**
2063     * write_exception_policy - Write exception policy.
2064     *
2065     * @head: Pointer to "struct ccs_io_buffer".
2066     *
2067     * Returns 0 on success, negative value otherwise.
2068     */
2069    static int write_exception_policy(struct ccs_io_buffer *head)
2070  {  {
2071          char *data = head->write_buf;          char *data = head->write_buf;
2072          bool is_delete = 0;          bool is_delete = str_starts(&data, KEYWORD_DELETE);
2073          if (!isRoot()) return -EPERM;          if (str_starts(&data, KEYWORD_KEEP_DOMAIN))
2074          UpdateCounter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY);                  return ccs_write_domain_keeper_policy(data, false, is_delete);
2075          if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {          if (str_starts(&data, KEYWORD_NO_KEEP_DOMAIN))
2076                  data += KEYWORD_DELETE_LEN;                  return ccs_write_domain_keeper_policy(data, true, is_delete);
2077                  is_delete = 1;          if (str_starts(&data, KEYWORD_INITIALIZE_DOMAIN))
2078          }                  return ccs_write_domain_initializer_policy(data, false,
2079          if (strncmp(data, KEYWORD_KEEP_DOMAIN, KEYWORD_KEEP_DOMAIN_LEN) == 0) {                                                             is_delete);
2080                  return AddDomainKeeperPolicy(data + KEYWORD_KEEP_DOMAIN_LEN, 0, is_delete);          if (str_starts(&data, KEYWORD_NO_INITIALIZE_DOMAIN))
2081          } else if (strncmp(data, KEYWORD_NO_KEEP_DOMAIN, KEYWORD_NO_KEEP_DOMAIN_LEN) == 0) {                  return ccs_write_domain_initializer_policy(data, true,
2082                  return AddDomainKeeperPolicy(data + KEYWORD_NO_KEEP_DOMAIN_LEN, 1, is_delete);                                                             is_delete);
2083          } else if (strncmp(data, KEYWORD_INITIALIZE_DOMAIN, KEYWORD_INITIALIZE_DOMAIN_LEN) == 0) {          if (str_starts(&data, KEYWORD_ALIAS))
2084                  return AddDomainInitializerPolicy(data + KEYWORD_INITIALIZE_DOMAIN_LEN, 0, is_delete);                  return ccs_write_alias_policy(data, is_delete);
2085          } else if (strncmp(data, KEYWORD_NO_INITIALIZE_DOMAIN, KEYWORD_NO_INITIALIZE_DOMAIN_LEN) == 0) {          if (str_starts(&data, KEYWORD_AGGREGATOR))
2086                  return AddDomainInitializerPolicy(data + KEYWORD_NO_INITIALIZE_DOMAIN_LEN, 1, is_delete);                  return ccs_write_aggregator_policy(data, is_delete);
2087          } else if (strncmp(data, KEYWORD_ALIAS, KEYWORD_ALIAS_LEN) == 0) {          if (str_starts(&data, KEYWORD_ALLOW_READ))
2088                  return AddAliasPolicy(data + KEYWORD_ALIAS_LEN, is_delete);                  return ccs_write_globally_readable_policy(data, is_delete);
2089          } else if (strncmp(data, KEYWORD_AGGREGATOR, KEYWORD_AGGREGATOR_LEN) == 0) {          if (str_starts(&data, KEYWORD_ALLOW_ENV))
2090                  return AddAggregatorPolicy(data + KEYWORD_AGGREGATOR_LEN, is_delete);                  return ccs_write_globally_usable_env_policy(data, is_delete);
2091          } else if (strncmp(data, KEYWORD_ALLOW_READ, KEYWORD_ALLOW_READ_LEN) == 0) {          if (str_starts(&data, KEYWORD_FILE_PATTERN))
2092                  return AddGloballyReadablePolicy(data + KEYWORD_ALLOW_READ_LEN, is_delete);                  return ccs_write_pattern_policy(data, is_delete);
2093          } else if (strncmp(data, KEYWORD_ALLOW_ENV, KEYWORD_ALLOW_ENV_LEN) == 0) {          if (str_starts(&data, KEYWORD_PATH_GROUP))
2094                  return AddGloballyUsableEnvPolicy(data + KEYWORD_ALLOW_ENV_LEN, is_delete);                  return ccs_write_path_group_policy(data, is_delete);
2095          } else if (strncmp(data, KEYWORD_FILE_PATTERN, KEYWORD_FILE_PATTERN_LEN) == 0) {          if (str_starts(&data, KEYWORD_DENY_REWRITE))
2096                  return AddFilePatternPolicy(data + KEYWORD_FILE_PATTERN_LEN, is_delete);                  return ccs_write_no_rewrite_policy(data, is_delete);
2097          } else if (strncmp(data, KEYWORD_PATH_GROUP, KEYWORD_PATH_GROUP_LEN) == 0) {          if (str_starts(&data, KEYWORD_ADDRESS_GROUP))
2098                  return AddPathGroupPolicy(data + KEYWORD_PATH_GROUP_LEN, is_delete);                  return ccs_write_address_group_policy(data, is_delete);
         } else if (strncmp(data, KEYWORD_DENY_REWRITE, KEYWORD_DENY_REWRITE_LEN) == 0) {  
                 return AddNoRewritePolicy(data + KEYWORD_DENY_REWRITE_LEN, is_delete);  
         } else if (strncmp(data, KEYWORD_ADDRESS_GROUP, KEYWORD_ADDRESS_GROUP_LEN) == 0) {  
                 return AddAddressGroupPolicy(data + KEYWORD_ADDRESS_GROUP_LEN, is_delete);  
         }  
2099          return -EINVAL;          return -EINVAL;
2100  }  }
2101    
2102  static int ReadExceptionPolicy(struct io_buffer *head)  /**
2103     * read_exception_policy - Read exception policy.
2104     *
2105     * @head: Pointer to "struct ccs_io_buffer".
2106     *
2107     * Returns 0 on success, -EINVAL otherwise.
2108     */
2109    static int read_exception_policy(struct ccs_io_buffer *head)
2110  {  {
2111          if (!head->read_eof) {          if (!head->read_eof) {
2112                  switch (head->read_step) {                  switch (head->read_step) {
2113                  case 0:                  case 0:
2114                          if (!isRoot()) return -EPERM;                          head->read_var2 = NULL;
2115                          head->read_var2 = NULL; head->read_step = 1;                          head->read_step = 1;
2116                  case 1:                  case 1:
2117                          if (ReadDomainKeeperPolicy(head)) break;                          if (!ccs_read_domain_keeper_policy(head))
2118                          head->read_var2 = NULL; head->read_step = 2;                                  break;
2119                            head->read_var2 = NULL;
2120                            head->read_step = 2;
2121                  case 2:                  case 2:
2122                          if (ReadGloballyReadablePolicy(head)) break;                          if (!ccs_read_globally_readable_policy(head))
2123                          head->read_var2 = NULL; head->read_step = 3;                                  break;
2124                            head->read_var2 = NULL;
2125                            head->read_step = 3;
2126                  case 3:                  case 3:
2127                          if (ReadGloballyUsableEnvPolicy(head)) break;                          if (!ccs_read_globally_usable_env_policy(head))
2128                          head->read_var2 = NULL; head->read_step = 4;                                  break;
2129                            head->read_var2 = NULL;
2130                            head->read_step = 4;
2131                  case 4:                  case 4:
2132                          if (ReadDomainInitializerPolicy(head)) break;                          if (!ccs_read_domain_initializer_policy(head))
2133                          head->read_var2 = NULL; head->read_step = 5;                                  break;
2134                            head->read_var2 = NULL;
2135                            head->read_step = 5;
2136                  case 5:                  case 5:
2137                          if (ReadAliasPolicy(head)) break;                          if (!ccs_read_alias_policy(head))
2138                          head->read_var2 = NULL; head->read_step = 6;                                  break;
2139                            head->read_var2 = NULL;
2140                            head->read_step = 6;
2141                  case 6:                  case 6:
2142                          if (ReadAggregatorPolicy(head)) break;                          if (!ccs_read_aggregator_policy(head))
2143                          head->read_var2 = NULL; head->read_step = 7;                                  break;
2144                            head->read_var2 = NULL;
2145                            head->read_step = 7;
2146                  case 7:                  case 7:
2147                          if (ReadFilePatternPolicy(head)) break;                          if (!ccs_read_file_pattern(head))
2148                          head->read_var2 = NULL; head->read_step = 8;                                  break;
2149                            head->read_var2 = NULL;
2150                            head->read_step = 8;
2151                  case 8:                  case 8:
2152                          if (ReadNoRewritePolicy(head)) break;                          if (!ccs_read_no_rewrite_policy(head))
2153                          head->read_var2 = NULL; head->read_step = 9;                                  break;
2154                            head->read_var2 = NULL;
2155                            head->read_step = 9;
2156                  case 9:                  case 9:
2157                          if (ReadPathGroupPolicy(head)) break;                          if (!ccs_read_path_group_policy(head))
2158                          head->read_var1 = head->read_var2 = NULL; head->read_step = 10;                                  break;
2159                            head->read_var1 = NULL;
2160                            head->read_var2 = NULL;
2161                            head->read_step = 10;
2162                  case 10:                  case 10:
2163                          if (ReadAddressGroupPolicy(head)) break;                          if (!ccs_read_address_group_policy(head))
2164                          head->read_eof = 1;                                  break;
2165                            head->read_eof = true;
2166                          break;                          break;
2167                  default:                  default:
2168                          return -EINVAL;                          return -EINVAL;
# Line 1129  static int ReadExceptionPolicy(struct io Line 2173  static int ReadExceptionPolicy(struct io
2173    
2174  #endif  #endif
2175    
 /*************************  SYSTEM POLICY HANDLER  *************************/  
   
2176  #ifdef CONFIG_SAKURA  #ifdef CONFIG_SAKURA
2177    
2178  static int AddSystemPolicy(struct io_buffer *head)  /**
2179     * write_system_policy - Write system policy.
2180     *
2181     * @head: Pointer to "struct ccs_io_buffer".
2182     *
2183     * Returns 0 on success, negative value otherwise.
2184     */
2185    static int write_system_policy(struct ccs_io_buffer *head)
2186  {  {
2187          char *data = head->write_buf;          char *data = head->write_buf;
2188          bool is_delete = 0;          bool is_delete = false;
2189          if (!isRoot()) return -EPERM;          if (str_starts(&data, KEYWORD_DELETE))
2190          UpdateCounter(CCS_UPDATES_COUNTER_SYSTEM_POLICY);                  is_delete = true;
2191          if (strncmp(data, KEYWORD_DELETE, KEYWORD_DELETE_LEN) == 0) {          if (str_starts(&data, KEYWORD_ALLOW_MOUNT))
2192                  data += KEYWORD_DELETE_LEN;                  return ccs_write_mount_policy(data, is_delete);
2193                  is_delete = 1;          if (str_starts(&data, KEYWORD_DENY_UNMOUNT))
2194          }                  return ccs_write_no_umount_policy(data, is_delete);
2195          if (strncmp(data, KEYWORD_ALLOW_MOUNT, KEYWORD_ALLOW_MOUNT_LEN) == 0)          if (str_starts(&data, KEYWORD_ALLOW_CHROOT))
2196                  return AddMountPolicy(data + KEYWORD_ALLOW_MOUNT_LEN, is_delete);                  return ccs_write_chroot_policy(data, is_delete);
2197          if (strncmp(data, KEYWORD_DENY_UNMOUNT, KEYWORD_DENY_UNMOUNT_LEN) == 0)          if (str_starts(&data, KEYWORD_ALLOW_PIVOT_ROOT))
2198                  return AddNoUmountPolicy(data + KEYWORD_DENY_UNMOUNT_LEN, is_delete);                  return ccs_write_pivot_root_policy(data, is_delete);
2199          if (strncmp(data, KEYWORD_ALLOW_CHROOT, KEYWORD_ALLOW_CHROOT_LEN) == 0)          if (str_starts(&data, KEYWORD_DENY_AUTOBIND))
2200                  return AddChrootPolicy(data + KEYWORD_ALLOW_CHROOT_LEN, is_delete);                  return ccs_write_reserved_port_policy(data, is_delete);
         if (strncmp(data, KEYWORD_ALLOW_PIVOT_ROOT, KEYWORD_ALLOW_PIVOT_ROOT_LEN) == 0)  
                 return AddPivotRootPolicy(data + KEYWORD_ALLOW_PIVOT_ROOT_LEN, is_delete);  
         if (strncmp(data, KEYWORD_DENY_AUTOBIND, KEYWORD_DENY_AUTOBIND_LEN) == 0)  
                 return AddReservedPortPolicy(data + KEYWORD_DENY_AUTOBIND_LEN, is_delete);  
2201          return -EINVAL;          return -EINVAL;
2202  }  }
2203    
2204  static int ReadSystemPolicy(struct io_buffer *head)  /**
2205     * read_system_policy - Read system policy.
2206     *
2207     * @head: Pointer to "struct ccs_io_buffer".
2208     *
2209     * Returns 0 on success, -EINVAL otherwise.
2210     */
2211    static int read_system_policy(struct ccs_io_buffer *head)
2212  {  {
2213          if (!head->read_eof) {          if (!head->read_eof) {
2214                  switch (head->read_step) {                  switch (head->read_step) {
2215                  case 0:                  case 0:
2216                          if (!isRoot()) return -EPERM;                          head->read_var2 = NULL;
2217                          head->read_var2 = NULL; head->read_step = 1;                          head->read_step = 1;
2218                  case 1:                  case 1:
2219                          if (ReadMountPolicy(head)) break;                          if (!ccs_read_mount_policy(head))
2220                          head->read_var2 = NULL; head->read_step = 2;                                  break;
2221                            head->read_var2 = NULL;
2222                            head->read_step = 2;
2223                  case 2:                  case 2:
2224                          if (ReadNoUmountPolicy(head)) break;                          if (!ccs_read_no_umount_policy(head))
2225                          head->read_var2 = NULL; head->read_step = 3;                                  break;
2226                            head->read_var2 = NULL;
2227                            head->read_step = 3;
2228                  case 3:                  case 3:
2229                          if (ReadChrootPolicy(head)) break;                          if (!ccs_read_chroot_policy(head))
2230                          head->read_var2 = NULL; head->read_step = 4;                                  break;
2231                            head->read_var2 = NULL;
2232                            head->read_step = 4;
2233                  case 4:                  case 4:
2234                          if (ReadPivotRootPolicy(head)) break;                          if (!ccs_read_pivot_root_policy(head))
2235                          head->read_var2 = NULL; head->read_step = 5;                                  break;
2236                            head->read_var2 = NULL;
2237                            head->read_step = 5;
2238                  case 5:                  case 5:
2239                          if (ReadReservedPortPolicy(head)) break;                          if (!ccs_read_reserved_port_policy(head))
2240                          head->read_eof = 1;                                  break;
2241                            head->read_eof = true;
2242                          break;                          break;
2243                  default:                  default:
2244                          return -EINVAL;                          return -EINVAL;
# Line 1188  static int ReadSystemPolicy(struct io_bu Line 2249  static int ReadSystemPolicy(struct io_bu
2249    
2250  #endif  #endif
2251    
2252  /*************************  POLICY LOADER  *************************/  /* Profile loaded by policy loader? */
2253    static bool profile_loaded = false;
 static int profile_loaded = 0;  
2254    
2255  static const char *ccs_loader = NULL;  /* Path to the policy loader. The default is /sbin/ccs-init. */
2256    static const char *ccs_loader;
2257    
2258  static int __init CCS_loader_Setup(char *str)  /**
2259     * loader_setup - Specify the policy loader to use.
2260     *
2261     * @str: Path to the policy loader.
2262     *
2263     * Returns 0.
2264     */
2265    static int __init loader_setup(char *str)
2266  {  {
2267          ccs_loader = str;          ccs_loader = str;
2268          return 0;          return 0;
2269  }  }
2270    
2271  __setup("CCS_loader=", CCS_loader_Setup);  __setup("CCS_loader=", loader_setup);
2272    
2273  void CCS_LoadPolicy(const char *filename)  /**
2274     * policy_loader_exists - Check whether /sbin/ccs-init exists.
2275     *
2276     * Returns true if /sbin/ccs-init exists, false otherwise.
2277     */
2278    static bool policy_loader_exists(void)
2279  {  {
         if (sbin_init_started) return;  
2280          /*          /*
2281           * Check filename is /sbin/init or /sbin/ccs-start .           * Don't activate MAC if the path given by 'CCS_loader=' option doesn't
2282           * /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
2283           * 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
2284           * only the pathname is needed to activate Mandatory Access Control.           * policies are not loaded yet.
2285             * Thus, let do_execve() call this function everytime.
2286           */           */
2287          if (strcmp(filename, "/sbin/init") != 0 && strcmp(filename, "/sbin/ccs-start") != 0) return;          struct nameidata nd;
2288            if (!ccs_loader)
2289                    ccs_loader = "/sbin/ccs-init";
2290            if (path_lookup(ccs_loader, lookup_flags, &nd)) {
2291                    printk(KERN_INFO "Not activating Mandatory Access Control now "
2292                           "since %s doesn't exist.\n", ccs_loader);
2293                    return false;
2294            }
2295    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
2296            path_put(&nd.path);
2297    #else
2298            path_release(&nd);
2299    #endif
2300            return true;
2301    }
2302    
2303    /**
2304     * ccs_load_policy - Run external policy loader to load policy.
2305     *
2306     * @filename: The program about to start.
2307     *
2308     * This function checks whether @filename is /sbin/init , and if so
2309     * invoke /sbin/ccs-init and wait for the termination of /sbin/ccs-init
2310     * and then continues invocation of /sbin/init.
2311     * /sbin/ccs-init reads policy files in /etc/ccs/ directory and
2312     * writes to /proc/ccs/ interfaces.
2313     *
2314     * Returns nothing.
2315     */
2316    void ccs_load_policy(const char *filename)
2317    {
2318            if (sbin_init_started)
2319                    return;
2320          /*          /*
2321           * Don't activate MAC if the path given by 'CCS_loader=' option doesn't exist.           * Check filename is /sbin/init or /sbin/ccs-start.
2322           * 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
2323           * activating MAC will block the system since policies are not loaded yet.           * be passed.
2324           * So let do_execve() call this function everytime.           * You can create /sbin/ccs-start by "ln -s /bin/true /sbin/ccs-start".
2325           */           */
2326          {          if (strcmp(filename, "/sbin/init") &&
2327                  struct nameidata nd;              strcmp(filename, "/sbin/ccs-start"))
2328                  if (!ccs_loader) ccs_loader = "/sbin/ccs-init";                  return;
2329                  if (path_lookup(ccs_loader, lookup_flags, &nd)) {          if (!policy_loader_exists())
2330                          printk("Not activating Mandatory Access Control now since %s doesn't exist.\n", ccs_loader);                  return;
                         return;  
                 }  
                 path_release(&nd);  
         }  
2331          if (!profile_loaded) {          if (!profile_loaded) {
2332                  char *argv[2], *envp[3];                  char *argv[2];
2333                  printk("Calling %s to load policy. Please wait.\n", ccs_loader);                  char *envp[3];
2334                    printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
2335                           ccs_loader);
2336                  argv[0] = (char *) ccs_loader;                  argv[0] = (char *) ccs_loader;
2337                  argv[1] = NULL;                  argv[1] = NULL;
2338                  envp[0] = "HOME=/";                  envp[0] = "HOME=/";
2339                  envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";                  envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
2340                  envp[2] = NULL;                  envp[2] = NULL;
2341  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
2342                  call_usermodehelper(argv[0], argv, envp, 1);                  call_usermodehelper(argv[0], argv, envp, 1);
2343  #else  #else
2344                  call_usermodehelper(argv[0], argv, envp);                  call_usermodehelper(argv[0], argv, envp);
# Line 1246  void CCS_LoadPolicy(const char *filename Line 2349  void CCS_LoadPolicy(const char *filename
2349                  }                  }
2350          }          }
2351  #ifdef CONFIG_SAKURA  #ifdef CONFIG_SAKURA
2352          printk("SAKURA: 1.5.3-pre   2008/01/02\n");          printk(KERN_INFO "SAKURA: 1.6.1   2008/05/10\n");
2353  #endif  #endif
2354  #ifdef CONFIG_TOMOYO  #ifdef CONFIG_TOMOYO
2355          printk("TOMOYO: 1.5.3-pre   2008/01/02\n");          printk(KERN_INFO "TOMOYO: 1.6.1   2008/05/10\n");
2356  #endif  #endif
2357          //if (!profile_loaded) panic("No profiles loaded. Run policy loader using 'init=' option.\n");          printk(KERN_INFO "Mandatory Access Control activated.\n");
2358          printk("Mandatory Access Control activated.\n");          sbin_init_started = true;
         sbin_init_started = 1;  
2359          ccs_log_level = KERN_WARNING;          ccs_log_level = KERN_WARNING;
2360          { /* Check all profiles currently assigned to domains are defined. */          { /* Check all profiles currently assigned to domains are defined. */
2361                  struct domain_info *domain;                  struct domain_info *domain;
2362                  list1_for_each_entry(domain, &domain_list, list) {                  list1_for_each_entry(domain, &domain_list, list) {
2363                          const u8 profile = domain->profile;                          const u8 profile = domain->profile;
2364                          if (!profile_ptr[profile]) panic("Profile %u (used by '%s') not defined.\n", profile, domain->domainname->name);                          if (profile_ptr[profile])
2365                                    continue;
2366                            panic("Profile %u (used by '%s') not defined.\n",
2367                                  profile, domain->domainname->name);
2368                  }                  }
2369          }          }
2370  }  }
2371    
2372    /* Wait queue for query_list. */
 /*************************  MAC Decision Delayer  *************************/  
   
2373  static DECLARE_WAIT_QUEUE_HEAD(query_wait);  static DECLARE_WAIT_QUEUE_HEAD(query_wait);
2374    
2375  static spinlock_t query_lock = SPIN_LOCK_UNLOCKED;  /* Lock for manipurating query_list. */
2376    static DEFINE_SPINLOCK(query_lock);
2377    
2378    /* Structure for query. */
2379  struct query_entry {  struct query_entry {
2380          struct list_head list;          struct list_head list;
2381          char *query;          char *query;
# Line 1280  struct query_entry { Line 2385  struct query_entry {
2385          int answer;          int answer;
2386  };  };
2387    
2388    /* The list for "struct query_entry". */
2389  static LIST_HEAD(query_list);  static LIST_HEAD(query_list);
2390    
2391    /* Number of "struct file" referring /proc/ccs/query interface. */
2392  static atomic_t queryd_watcher = ATOMIC_INIT(0);  static atomic_t queryd_watcher = ATOMIC_INIT(0);
2393    
2394  int CheckSupervisor(const char *fmt, ...)  /**
2395     * ccs_check_supervisor - Ask for the supervisor's decision.
2396     *
2397     * @fmt: The printf()'s format string, followed by parameters.
2398     *
2399     * Returns 0 if the supervisor decided to permit the access request which
2400     * violated the policy in enforcing mode, -EPERM otherwise.
2401     */
2402    int ccs_check_supervisor(const char *fmt, ...)
2403  {  {
2404          va_list args;          va_list args;
2405          int error = -EPERM;          int error = -EPERM;
2406          int pos, len;          int pos;
2407          static unsigned int serial = 0;          int len;
2408            static unsigned int serial;
2409          struct query_entry *query_entry;          struct query_entry *query_entry;
2410          if (!CheckCCSFlags(CCS_ALLOW_ENFORCE_GRACE) || !atomic_read(&queryd_watcher)) {          if (!ccs_check_flags(CCS_ALLOW_ENFORCE_GRACE)
2411  #ifdef ALT_EXEC              || !atomic_read(&queryd_watcher)) {
2412                  if ((current->tomoyo_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR) == 0) {                  int i;
2413                          int i;                  if (current->tomoyo_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR)
2414                          for (i = 0; i < CheckCCSFlags(CCS_SLEEP_PERIOD); i++) {                          return -EPERM;
2415                                  set_current_state(TASK_INTERRUPTIBLE);                  for (i = 0; i < ccs_check_flags(CCS_SLEEP_PERIOD); i++) {
2416                                  schedule_timeout(HZ / 10);                          set_current_state(TASK_INTERRUPTIBLE);
2417                          }                          schedule_timeout(HZ / 10);
2418                  }                  }
 #endif  
2419                  return -EPERM;                  return -EPERM;
2420          }          }
2421          va_start(args, fmt);          va_start(args, fmt);
2422          len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;          len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;
2423          va_end(args);          va_end(args);
2424          if ((query_entry = ccs_alloc(sizeof(*query_entry))) == NULL ||          query_entry = ccs_alloc(sizeof(*query_entry));
2425                  (query_entry->query = ccs_alloc(len)) == NULL) goto out;          if (!query_entry)
2426                    goto out;
2427            query_entry->query = ccs_alloc(len);
2428            if (!query_entry->query)
2429                    goto out;
2430          INIT_LIST_HEAD(&query_entry->list);          INIT_LIST_HEAD(&query_entry->list);
2431          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
2432          spin_lock(&query_lock);          spin_lock(&query_lock);
2433          query_entry->serial = serial++;          query_entry->serial = serial++;
2434          spin_unlock(&query_lock);          spin_unlock(&query_lock);
2435          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
2436          pos = snprintf(query_entry->query, len - 1, "Q%u\n", query_entry->serial);          pos = snprintf(query_entry->query, len - 1, "Q%u\n",
2437                           query_entry->serial);
2438          va_start(args, fmt);          va_start(args, fmt);
2439          vsnprintf(query_entry->query + pos, len - 1 - pos, fmt, args);          vsnprintf(query_entry->query + pos, len - 1 - pos, fmt, args);
2440          query_entry->query_len = strlen(query_entry->query) + 1;          query_entry->query_len = strlen(query_entry->query) + 1;
# Line 1323  int CheckSupervisor(const char *fmt, ... Line 2444  int CheckSupervisor(const char *fmt, ...
2444          list_add_tail(&query_entry->list, &query_list);          list_add_tail(&query_entry->list, &query_list);
2445          spin_unlock(&query_lock);          spin_unlock(&query_lock);
2446          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
2447          UpdateCounter(CCS_UPDATES_COUNTER_QUERY);          ccs_update_counter(CCS_UPDATES_COUNTER_QUERY);
2448          /* Give 10 seconds for supervisor's opinion. */          /* Give 10 seconds for supervisor's opinion. */
2449          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)
2450                         && ccs_check_flags(CCS_ALLOW_ENFORCE_GRACE)
2451                         && query_entry->timer < 100; query_entry->timer++) {
2452                  wake_up(&query_wait);                  wake_up(&query_wait);
2453                  set_current_state(TASK_INTERRUPTIBLE);                  set_current_state(TASK_INTERRUPTIBLE);
2454                  schedule_timeout(HZ / 10);                  schedule_timeout(HZ / 10);
2455                  if (query_entry->answer) break;                  if (query_entry->answer)
2456                            break;
2457          }          }
2458          UpdateCounter(CCS_UPDATES_COUNTER_QUERY);          ccs_update_counter(CCS_UPDATES_COUNTER_QUERY);
2459          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
2460          spin_lock(&query_lock);          spin_lock(&query_lock);
2461          list_del(&query_entry->list);          list_del(&query_entry->list);
# Line 1349  int CheckSupervisor(const char *fmt, ... Line 2473  int CheckSupervisor(const char *fmt, ...
2473                  /* Rejected by administrator. */                  /* Rejected by administrator. */
2474                  break;                  break;
2475          }          }
2476   out: ;   out:
2477          if (query_entry) ccs_free(query_entry->query);          if (query_entry)
2478                    ccs_free(query_entry->query);
2479          ccs_free(query_entry);          ccs_free(query_entry);
2480          return error;          return error;
2481  }  }
2482    
2483  static int PollQuery(struct file *file, poll_table *wait)  /**
2484     * poll_query - poll() for /proc/ccs/query.
2485     *
2486     * @file: Pointer to "struct file".
2487     * @wait: Pointer to "poll_table".
2488     *
2489     * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise.
2490     *
2491     * Waits for access requests which violated policy in enforcing mode.
2492     */
2493    static int poll_query(struct file *file, poll_table *wait)
2494  {  {
2495          int found;          bool found;
2496          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
2497          spin_lock(&query_lock);          spin_lock(&query_lock);
2498          found = !list_empty(&query_list);          found = !list_empty(&query_list);
2499          spin_unlock(&query_lock);          spin_unlock(&query_lock);
2500          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
2501          if (found) return POLLIN | POLLRDNORM;          if (found)
2502                    return POLLIN | POLLRDNORM;
2503          poll_wait(file, &query_wait, wait);          poll_wait(file, &query_wait, wait);
2504          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
2505          spin_lock(&query_lock);          spin_lock(&query_lock);
2506          found = !list_empty(&query_list);          found = !list_empty(&query_list);
2507          spin_unlock(&query_lock);          spin_unlock(&query_lock);
2508          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
2509          if (found) return POLLIN | POLLRDNORM;          if (found)
2510                    return POLLIN | POLLRDNORM;
2511          return 0;          return 0;
2512  }  }
2513    
2514  static int ReadQuery(struct io_buffer *head)  /**
2515     * read_query - Read access requests which violated policy in enforcing mode.
2516     *
2517     * @head: Pointer to "struct ccs_io_buffer".
2518     *
2519     * Returns 0.
2520     */
2521    static int read_query(struct ccs_io_buffer *head)
2522  {  {
2523          struct list_head *tmp;          struct list_head *tmp;
2524          int pos = 0, len = 0;          int pos = 0;
2525            int len = 0;
2526          char *buf;          char *buf;
2527          if (head->read_avail) return 0;          if (head->read_avail)
2528                    return 0;
2529          if (head->read_buf) {          if (head->read_buf) {
2530                  ccs_free(head->read_buf); head->read_buf = NULL;                  ccs_free(head->read_buf);
2531                    head->read_buf = NULL;
2532                  head->readbuf_size = 0;                  head->readbuf_size = 0;
2533          }          }
2534          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
2535          spin_lock(&query_lock);          spin_lock(&query_lock);
2536          list_for_each(tmp, &query_list) {          list_for_each(tmp, &query_list) {
2537                  struct query_entry *ptr = list_entry(tmp, struct query_entry, list);                  struct query_entry *ptr
2538                  if (pos++ == head->read_step) {                          = list_entry(tmp, struct query_entry, list);
2539                          len = ptr->query_len;                  if (pos++ != head->read_step)
2540                          break;                          continue;
2541                  }                  len = ptr->query_len;
2542                    break;
2543          }          }
2544          spin_unlock(&query_lock);          spin_unlock(&query_lock);
2545          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
# Line 1399  static int ReadQuery(struct io_buffer *h Line 2547  static int ReadQuery(struct io_buffer *h
2547                  head->read_step = 0;                  head->read_step = 0;
2548                  return 0;                  return 0;
2549          }          }
2550          if ((buf = ccs_alloc(len)) != NULL) {          buf = ccs_alloc(len);
2551            if (buf) {
2552                  pos = 0;                  pos = 0;
2553                  /***** CRITICAL SECTION START *****/                  /***** CRITICAL SECTION START *****/
2554                  spin_lock(&query_lock);                  spin_lock(&query_lock);
2555                  list_for_each(tmp, &query_list) {                  list_for_each(tmp, &query_list) {
2556                          struct query_entry *ptr = list_entry(tmp, struct query_entry, list);                          struct query_entry *ptr
2557                          if (pos++ == head->read_step) {                                  = list_entry(tmp, struct query_entry, list);
2558                                  /* Some query can be skiipped since query_list can change, but I don't care. */                          if (pos++ != head->read_step)
2559                                  if (len == ptr->query_len) memmove(buf, ptr->query, len);                                  continue;
2560                                  break;                          /*
2561                          }                           * Some query can be skipped because query_list
2562                             * can change, but I don't care.
2563                             */
2564                            if (len == ptr->query_len)
2565                                    memmove(buf, ptr->query, len);
2566                            break;
2567                  }                  }
2568                  spin_unlock(&query_lock);                  spin_unlock(&query_lock);
2569                  /***** CRITICAL SECTION END *****/                  /***** CRITICAL SECTION END *****/
2570                  if (buf[0]) {                  if (buf[0]) {
2571                          head->readbuf_size = head->read_avail = len;                          head->read_avail = len;
2572                            head->readbuf_size = head->read_avail;
2573                          head->read_buf = buf;                          head->read_buf = buf;
2574                          head->read_step++;                          head->read_step++;
2575                  } else {                  } else {
# Line 1424  static int ReadQuery(struct io_buffer *h Line 2579  static int ReadQuery(struct io_buffer *h
2579          return 0;          return 0;
2580  }  }
2581    
2582  static int WriteAnswer(struct io_buffer *head)  /**
2583     * write_answer - Write the supervisor's decision.
2584     *
2585     * @head: Pointer to "struct ccs_io_buffer".
2586     *
2587     * Returns 0 on success, -EINVAL otherwise.
2588     */
2589    static int write_answer(struct ccs_io_buffer *head)
2590  {  {
2591          char *data = head->write_buf;          char *data = head->write_buf;
2592          struct list_head *tmp;          struct list_head *tmp;
2593          unsigned int serial, answer;          unsigned int serial;
2594            unsigned int answer;
2595          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
2596          spin_lock(&query_lock);          spin_lock(&query_lock);
2597          list_for_each(tmp, &query_list) {          list_for_each(tmp, &query_list) {
2598                  struct query_entry *ptr = list_entry(tmp, struct query_entry, list);                  struct query_entry *ptr
2599                            = list_entry(tmp, struct query_entry, list);
2600                  ptr->timer = 0;                  ptr->timer = 0;
2601          }          }
2602          spin_unlock(&query_lock);          spin_unlock(&query_lock);
2603          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
2604          if (sscanf(data, "A%u=%u", &serial, &answer) != 2) return -EINVAL;          if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
2605                    return -EINVAL;
2606          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
2607          spin_lock(&query_lock);          spin_lock(&query_lock);
2608          list_for_each(tmp, &query_list) {          list_for_each(tmp, &query_list) {
2609                  struct query_entry *ptr = list_entry(tmp, struct query_entry, list);                  struct query_entry *ptr
2610                  if (ptr->serial != serial) continue;                          = list_entry(tmp, struct query_entry, list);
2611                  if (!ptr->answer) ptr->answer = answer;                  if (ptr->serial != serial)
2612                            continue;
2613                    if (!ptr->answer)
2614                            ptr->answer = answer;
2615                  break;                  break;
2616          }          }
2617          spin_unlock(&query_lock);          spin_unlock(&query_lock);
# Line 1451  static int WriteAnswer(struct io_buffer Line 2619  static int WriteAnswer(struct io_buffer
2619          return 0;          return 0;
2620  }  }
2621    
 /*************************  /proc INTERFACE HANDLER  *************************/  
   
2622  /* Policy updates counter. */  /* Policy updates counter. */
2623  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;  
2624    
2625  void UpdateCounter(const unsigned char index)  /* Policy updates counter lock. */
2626    static DEFINE_SPINLOCK(updates_counter_lock);
2627    
2628    /**
2629     * ccs_update_counter - Increment policy change counter.
2630     *