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

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