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

Subversion リポジトリの参照

Diff of /trunk/1.8.x/ccs-patch/security/ccsecurity/policy_io.c

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

branches/ccs-patch/security/ccsecurity/policy_io.c revision 2888 by kumaneko, Mon Aug 10 07:31:29 2009 UTC trunk/1.8.x/ccs-patch/security/ccsecurity/policy_io.c revision 4056 by kumaneko, Sat Oct 9 23:48:20 2010 UTC
# Line 1  Line 1 
1  /*  /*
2   * security/ccsecurity/policy_io.c   * security/ccsecurity/policy_io.c
3   *   *
4   * Copyright (C) 2005-2009  NTT DATA CORPORATION   * Copyright (C) 2005-2010  NTT DATA CORPORATION
5   *   *
6   * Version: 1.7.0-pre   2009/08/08   * Version: 1.8.0-pre   2010/10/10
7   *   *
8   * 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.
9   * See README.ccs for ChangeLog.   * See README.ccs for ChangeLog.
# Line 12  Line 12 
12    
13  #include "internal.h"  #include "internal.h"
14    
15  /* Lock for protecting ccs_profile->comment  */  /* Profile version. Currently only 20100903 is defined. */
16  static DEFINE_SPINLOCK(ccs_profile_comment_lock);  static unsigned int ccs_profile_version;
17    
18  static bool ccs_profile_entry_used[CCS_MAX_CONTROL_INDEX +  /* Profile table. Memory is allocated as needed. */
19                                     CCS_MAX_CAPABILITY_INDEX + 1];  static struct ccs_profile *ccs_profile_ptr[CCS_MAX_PROFILES];
20    
21  /* String table for functionality that takes 4 modes. */  /* String table for functionality that takes 4 modes. */
22  static const char *ccs_mode_4[4] = {  const char * const ccs_mode[CCS_CONFIG_MAX_MODE] = {
23          "disabled", "learning", "permissive", "enforcing"          [CCS_CONFIG_DISABLED]   = "disabled",
24            [CCS_CONFIG_LEARNING]   = "learning",
25            [CCS_CONFIG_PERMISSIVE] = "permissive",
26            [CCS_CONFIG_ENFORCING]  = "enforcing"
27  };  };
28  /* String table for functionality that takes 2 modes. */  
29  static const char *ccs_mode_2[4] = {  /* String table for /proc/ccs/profile */
30          "disabled", "enabled", "enabled", "enabled"  const char * const ccs_mac_keywords[CCS_MAX_MAC_INDEX
31                                        + CCS_MAX_MAC_CATEGORY_INDEX] = {
32            [CCS_MAC_FILE_EXECUTE]    = "execute",
33            [CCS_MAC_FILE_OPEN]       = "open",
34            [CCS_MAC_FILE_CREATE]     = "create",
35            [CCS_MAC_FILE_UNLINK]     = "unlink",
36            [CCS_MAC_FILE_MKDIR]      = "mkdir",
37            [CCS_MAC_FILE_RMDIR]      = "rmdir",
38            [CCS_MAC_FILE_MKFIFO]     = "mkfifo",
39            [CCS_MAC_FILE_MKSOCK]     = "mksock",
40            [CCS_MAC_FILE_TRUNCATE]   = "truncate",
41            [CCS_MAC_FILE_SYMLINK]    = "symlink",
42            [CCS_MAC_FILE_MKBLOCK]    = "mkblock",
43            [CCS_MAC_FILE_MKCHAR]     = "mkchar",
44            [CCS_MAC_FILE_LINK]       = "link",
45            [CCS_MAC_FILE_RENAME]     = "rename",
46            [CCS_MAC_FILE_CHMOD]      = "chmod",
47            [CCS_MAC_FILE_CHOWN]      = "chown",
48            [CCS_MAC_FILE_CHGRP]      = "chgrp",
49            [CCS_MAC_FILE_IOCTL]      = "ioctl",
50            [CCS_MAC_FILE_CHROOT]     = "chroot",
51            [CCS_MAC_FILE_MOUNT]      = "mount",
52            [CCS_MAC_FILE_UMOUNT]     = "unmount",
53            [CCS_MAC_FILE_PIVOT_ROOT] = "pivot_root",
54            [CCS_MAC_ENVIRON] = "env",
55            [CCS_MAC_NETWORK_INET_STREAM_BIND]       = "inet_stream_bind",
56            [CCS_MAC_NETWORK_INET_STREAM_LISTEN]     = "inet_stream_listen",
57            [CCS_MAC_NETWORK_INET_STREAM_CONNECT]    = "inet_stream_connect",
58            [CCS_MAC_NETWORK_INET_STREAM_ACCEPT]     = "inet_stream_accept",
59            [CCS_MAC_NETWORK_INET_DGRAM_BIND]        = "inet_dgram_bind",
60            [CCS_MAC_NETWORK_INET_DGRAM_SEND]        = "inet_dgram_send",
61            [CCS_MAC_NETWORK_INET_DGRAM_RECV]        = "inet_dgram_recv",
62            [CCS_MAC_NETWORK_INET_RAW_BIND]          = "inet_raw_bind",
63            [CCS_MAC_NETWORK_INET_RAW_SEND]          = "inet_raw_send",
64            [CCS_MAC_NETWORK_INET_RAW_RECV]          = "inet_raw_recv",
65            [CCS_MAC_NETWORK_UNIX_STREAM_BIND]       = "unix_stream_bind",
66            [CCS_MAC_NETWORK_UNIX_STREAM_LISTEN]     = "unix_stream_listen",
67            [CCS_MAC_NETWORK_UNIX_STREAM_CONNECT]    = "unix_stream_connect",
68            [CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT]     = "unix_stream_accept",
69            [CCS_MAC_NETWORK_UNIX_DGRAM_BIND]        = "unix_dgram_bind",
70            [CCS_MAC_NETWORK_UNIX_DGRAM_SEND]        = "unix_dgram_send",
71            [CCS_MAC_NETWORK_UNIX_DGRAM_RECV]        = "unix_dgram_recv",
72            [CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND]    = "unix_seqpacket_bind",
73            [CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN]  = "unix_seqpacket_listen",
74            [CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
75            [CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT]  = "unix_seqpacket_accept",
76            [CCS_MAC_SIGNAL] = "signal",
77            [CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET]  = "use_route",
78            [CCS_MAC_CAPABILITY_USE_PACKET_SOCKET] = "use_packet",
79            [CCS_MAC_CAPABILITY_SYS_REBOOT]        = "SYS_REBOOT",
80            [CCS_MAC_CAPABILITY_SYS_VHANGUP]       = "SYS_VHANGUP",
81            [CCS_MAC_CAPABILITY_SYS_SETTIME]       = "SYS_TIME",
82            [CCS_MAC_CAPABILITY_SYS_NICE]          = "SYS_NICE",
83            [CCS_MAC_CAPABILITY_SYS_SETHOSTNAME]   = "SYS_SETHOSTNAME",
84            [CCS_MAC_CAPABILITY_USE_KERNEL_MODULE] = "use_kernel_module",
85            [CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD]    = "SYS_KEXEC_LOAD",
86            [CCS_MAC_CAPABILITY_SYS_PTRACE]        = "SYS_PTRACE",
87            [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_FILE]       = "file",
88            [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_NETWORK]    = "network",
89            [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_MISC]       = "misc",
90            [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_IPC]        = "ipc",
91            [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_CAPABILITY] = "capability",
92  };  };
93    
94  /* Table for profile. */  const char * const ccs_path_keyword[CCS_MAX_PATH_OPERATION] = {
95  static struct {          [CCS_TYPE_EXECUTE]    = "execute",
96          const char *keyword;          [CCS_TYPE_READ]       = "read",
97          unsigned int current_value;          [CCS_TYPE_WRITE]      = "write",
98          const unsigned int max_value;          [CCS_TYPE_APPEND]     = "append",
99  } ccs_control_array[CCS_MAX_CONTROL_INDEX] = {          [CCS_TYPE_UNLINK]     = "unlink",
100          [CCS_MAC_FOR_FILE]        = { "MAC_FOR_FILE",        0, 3 },          [CCS_TYPE_RMDIR]      = "rmdir",
101          [CCS_MAC_FOR_IOCTL]       = { "MAC_FOR_IOCTL",       0, 3 },          [CCS_TYPE_TRUNCATE]   = "truncate",
102          [CCS_MAC_FOR_FILEATTR]    = { "MAC_FOR_FILEATTR",    0, 3 },          [CCS_TYPE_SYMLINK]    = "symlink",
103          [CCS_MAC_FOR_ARGV0]       = { "MAC_FOR_ARGV0",       0, 3 },          [CCS_TYPE_CHROOT]     = "chroot",
104          [CCS_MAC_FOR_ENV]         = { "MAC_FOR_ENV",         0, 3 },          [CCS_TYPE_UMOUNT]     = "unmount",
105          [CCS_MAC_FOR_NETWORK]     = { "MAC_FOR_NETWORK",     0, 3 },  };
106          [CCS_MAC_FOR_SIGNAL]      = { "MAC_FOR_SIGNAL",      0, 3 },  
107          [CCS_MAC_FOR_NAMESPACE]   = { "MAC_FOR_NAMESPACE",   0, 3 },  static const char * const ccs_category_keywords[CCS_MAX_MAC_CATEGORY_INDEX] = {
108          [CCS_RESTRICT_AUTOBIND]   = { "RESTRICT_AUTOBIND",   0, 1 },          [CCS_MAC_CATEGORY_FILE]       = "file",
109          [CCS_MAX_ACCEPT_ENTRY]          [CCS_MAC_CATEGORY_NETWORK]    = "network",
110          = { "MAX_ACCEPT_ENTRY", CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY, INT_MAX },          [CCS_MAC_CATEGORY_MISC]       = "misc",
111  #ifdef CONFIG_CCSECURITY_AUDIT          [CCS_MAC_CATEGORY_IPC]        = "ipc",
112          [CCS_MAX_GRANT_LOG]          [CCS_MAC_CATEGORY_CAPABILITY] = "capability",
113          = { "MAX_GRANT_LOG", CONFIG_CCSECURITY_MAX_GRANT_LOG, INT_MAX },  };
114          [CCS_MAX_REJECT_LOG]  
115          = { "MAX_REJECT_LOG", CONFIG_CCSECURITY_MAX_REJECT_LOG, INT_MAX },  const char * const ccs_condition_keyword[CCS_MAX_CONDITION_KEYWORD] = {
116  #endif          [CCS_TASK_UID]             = "task.uid",
117          [CCS_VERBOSE]             = { "TOMOYO_VERBOSE",      1, 1 },          [CCS_TASK_EUID]            = "task.euid",
118          [CCS_SLEEP_PERIOD]          [CCS_TASK_SUID]            = "task.suid",
119          = { "SLEEP_PERIOD",        0, 3000 }, /* in 0.1 second */          [CCS_TASK_FSUID]           = "task.fsuid",
120            [CCS_TASK_GID]             = "task.gid",
121            [CCS_TASK_EGID]            = "task.egid",
122            [CCS_TASK_SGID]            = "task.sgid",
123            [CCS_TASK_FSGID]           = "task.fsgid",
124            [CCS_TASK_PID]             = "task.pid",
125            [CCS_TASK_PPID]            = "task.ppid",
126            [CCS_EXEC_ARGC]            = "exec.argc",
127            [CCS_EXEC_ENVC]            = "exec.envc",
128            [CCS_TYPE_IS_SOCKET]       = "socket",
129            [CCS_TYPE_IS_SYMLINK]      = "symlink",
130            [CCS_TYPE_IS_FILE]         = "file",
131            [CCS_TYPE_IS_BLOCK_DEV]    = "block",
132            [CCS_TYPE_IS_DIRECTORY]    = "directory",
133            [CCS_TYPE_IS_CHAR_DEV]     = "char",
134            [CCS_TYPE_IS_FIFO]         = "fifo",
135            [CCS_MODE_SETUID]          = "setuid",
136            [CCS_MODE_SETGID]          = "setgid",
137            [CCS_MODE_STICKY]          = "sticky",
138            [CCS_MODE_OWNER_READ]      = "owner_read",
139            [CCS_MODE_OWNER_WRITE]     = "owner_write",
140            [CCS_MODE_OWNER_EXECUTE]   = "owner_execute",
141            [CCS_MODE_GROUP_READ]      = "group_read",
142            [CCS_MODE_GROUP_WRITE]     = "group_write",
143            [CCS_MODE_GROUP_EXECUTE]   = "group_execute",
144            [CCS_MODE_OTHERS_READ]     = "others_read",
145            [CCS_MODE_OTHERS_WRITE]    = "others_write",
146            [CCS_MODE_OTHERS_EXECUTE]  = "others_execute",
147            [CCS_TASK_TYPE]            = "task.type",
148            [CCS_TASK_EXECUTE_HANDLER] = "execute_handler",
149            [CCS_EXEC_REALPATH]        = "exec.realpath",
150            [CCS_SYMLINK_TARGET]       = "symlink.target",
151            [CCS_PATH1_UID]            = "path1.uid",
152            [CCS_PATH1_GID]            = "path1.gid",
153            [CCS_PATH1_INO]            = "path1.ino",
154            [CCS_PATH1_MAJOR]          = "path1.major",
155            [CCS_PATH1_MINOR]          = "path1.minor",
156            [CCS_PATH1_PERM]           = "path1.perm",
157            [CCS_PATH1_TYPE]           = "path1.type",
158            [CCS_PATH1_DEV_MAJOR]      = "path1.dev_major",
159            [CCS_PATH1_DEV_MINOR]      = "path1.dev_minor",
160            [CCS_PATH2_UID]            = "path2.uid",
161            [CCS_PATH2_GID]            = "path2.gid",
162            [CCS_PATH2_INO]            = "path2.ino",
163            [CCS_PATH2_MAJOR]          = "path2.major",
164            [CCS_PATH2_MINOR]          = "path2.minor",
165            [CCS_PATH2_PERM]           = "path2.perm",
166            [CCS_PATH2_TYPE]           = "path2.type",
167            [CCS_PATH2_DEV_MAJOR]      = "path2.dev_major",
168            [CCS_PATH2_DEV_MINOR]      = "path2.dev_minor",
169            [CCS_PATH1_PARENT_UID]     = "path1.parent.uid",
170            [CCS_PATH1_PARENT_GID]     = "path1.parent.gid",
171            [CCS_PATH1_PARENT_INO]     = "path1.parent.ino",
172            [CCS_PATH1_PARENT_PERM]    = "path1.parent.perm",
173            [CCS_PATH2_PARENT_UID]     = "path2.parent.uid",
174            [CCS_PATH2_PARENT_GID]     = "path2.parent.gid",
175            [CCS_PATH2_PARENT_INO]     = "path2.parent.ino",
176            [CCS_PATH2_PARENT_PERM]    = "path2.parent.perm",
177    };
178    
179    static const char * const ccs_pref_keywords[CCS_MAX_PREF] = {
180            [CCS_PREF_MAX_GRANT_LOG]      = "max_grant_log",
181            [CCS_PREF_MAX_REJECT_LOG]     = "max_reject_log",
182            [CCS_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry",
183            [CCS_PREF_ENFORCING_PENALTY]  = "enforcing_penalty",
184  };  };
185    
186  /* Permit policy management by non-root user? */  /* Permit policy management by non-root user? */
187  static bool ccs_manage_by_non_root;  static bool ccs_manage_by_non_root;
188    
189  /**  /**
190   * ccs_quiet_setup - Set CCS_VERBOSE=0 by default.   * ccs_yesno - Return "yes" or "no".
191   *   *
192   * @str: Unused.   * @value: Bool value.
193     */
194    static const char *ccs_yesno(const unsigned int value)
195    {
196            return value ? "yes" : "no";
197    }
198    
199    static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)
200         __attribute__ ((format(printf, 3, 4)));
201    
202    static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)
203    {
204            va_list args;
205            const int pos = strlen(buffer);
206            va_start(args, fmt);
207            vsnprintf(buffer + pos, len - pos - 1, fmt, args);
208            va_end(args);
209    }
210    
211    /**
212     * ccs_flush - Flush queued string to userspace's buffer.
213   *   *
214   * Returns 0.   * @head:   Pointer to "struct ccs_io_buffer".
215     *
216     * Returns true if all data was flushed, false otherwise.
217   */   */
218  static int __init ccs_quiet_setup(char *str)  static bool ccs_flush(struct ccs_io_buffer *head)
219  {  {
220          ccs_control_array[CCS_VERBOSE].current_value = 0;          while (head->r.w_pos) {
221          return 0;                  const char *w = head->r.w[0];
222                    int len = strlen(w);
223                    if (len) {
224                            if (len > head->read_user_buf_avail)
225                                    len = head->read_user_buf_avail;
226                            if (!len)
227                                    return false;
228                            if (copy_to_user(head->read_user_buf, w, len))
229                                    return false;
230                            head->read_user_buf_avail -= len;
231                            head->read_user_buf += len;
232                            w += len;
233                    }
234                    if (*w) {
235                            head->r.w[0] = w;
236                            return false;
237                    }
238                    /* Add '\0' for audit logs and query. */
239                    if (head->poll) {
240                            if (!head->read_user_buf_avail ||
241                                copy_to_user(head->read_user_buf, "", 1))
242                                    return false;
243                            head->read_user_buf_avail--;
244                            head->read_user_buf++;
245                    }
246                    head->r.w_pos--;
247                    for (len = 0; len < head->r.w_pos; len++)
248                            head->r.w[len] = head->r.w[len + 1];
249            }
250            head->r.avail = 0;
251            return true;
252  }  }
253    
254  __setup("CCS_QUIET", ccs_quiet_setup);  /**
255     * ccs_set_string - Queue string to "struct ccs_io_buffer" structure.
256     *
257     * @head:   Pointer to "struct ccs_io_buffer".
258     * @string: String to print.
259     *
260     * Note that @string has to be kept valid until @head is kfree()d.
261     * This means that char[] allocated on stack memory cannot be passed to
262     * this function. Use ccs_io_printf() for char[] allocated on stack memory.
263     */
264    static void ccs_set_string(struct ccs_io_buffer *head, const char *string)
265    {
266            if (head->r.w_pos < CCS_MAX_IO_READ_QUEUE) {
267                    head->r.w[head->r.w_pos++] = string;
268                    ccs_flush(head);
269            } else
270                    printk(KERN_WARNING "Too many words in a line.\n");
271    }
272    
273  /**  /**
274   * ccs_io_printf - Transactional printf() to "struct ccs_io_buffer" structure.   * ccs_io_printf - printf() to "struct ccs_io_buffer" structure.
275   *   *
276   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
277   * @fmt:  The printf()'s format string, followed by parameters.   * @fmt:  The printf()'s format string, followed by parameters.
  *  
  * Returns true on success, false otherwise.  
  *  
  * The snprintf() will truncate, but ccs_io_printf() won't.  
278   */   */
279  bool ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)  void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
280  {  {
281          va_list args;          va_list args;
282          int len;          int len;
283          int pos = head->read_avail;          int pos = head->r.avail;
284          int size = head->readbuf_size - pos;          int size = head->readbuf_size - pos;
285          if (size <= 0)          if (size <= 0)
286                  return false;                  return;
287          va_start(args, fmt);          va_start(args, fmt);
288          len = vsnprintf(head->read_buf + pos, size, fmt, args);          len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
289          va_end(args);          va_end(args);
290          if (pos + len >= head->readbuf_size)          if (pos + len >= head->readbuf_size) {
291                  return false;                  printk(KERN_WARNING "Too many words in a line.\n");
292          head->read_avail += len;                  return;
293          return true;          }
294            head->r.avail += len;
295            ccs_set_string(head, head->read_buf + pos);
296    }
297    
298    static void ccs_set_space(struct ccs_io_buffer *head)
299    {
300            ccs_set_string(head, " ");
301    }
302    
303    static bool ccs_set_lf(struct ccs_io_buffer *head)
304    {
305            ccs_set_string(head, "\n");
306            return !head->r.w_pos;
307  }  }
308    
309  /**  /**
310   * ccs_find_or_assign_new_profile - Create a new profile.   * ccs_assign_profile - Create a new profile.
311   *   *
312   * @profile: Profile number to create.   * @profile: Profile number to create.
313   *   *
314   * Returns pointer to "struct ccs_profile" on success, NULL otherwise.   * Returns pointer to "struct ccs_profile" on success, NULL otherwise.
315   */   */
316  struct ccs_profile *ccs_find_or_assign_new_profile(const unsigned int  static struct ccs_profile *ccs_assign_profile(const unsigned int profile)
                                                    profile)  
317  {  {
318          struct ccs_profile *ptr;          struct ccs_profile *ptr;
319          struct ccs_profile *entry;          struct ccs_profile *entry;
320          int i;          if (profile >= CCS_MAX_PROFILES)
         if (profile >= MAX_PROFILES)  
321                  return NULL;                  return NULL;
322          ptr = ccs_profile_ptr[profile];          ptr = ccs_profile_ptr[profile];
323          if (ptr)          if (ptr)
324                  return ptr;                  return ptr;
325          entry = kzalloc(sizeof(*entry), GFP_KERNEL);          entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
326          mutex_lock(&ccs_policy_lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
327                    goto out;
328          ptr = ccs_profile_ptr[profile];          ptr = ccs_profile_ptr[profile];
329          if (!ptr && ccs_memory_ok(entry, sizeof(*entry))) {          if (!ptr && ccs_memory_ok(entry, sizeof(*entry))) {
330                  ptr = entry;                  ptr = entry;
331                  for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++)                  ptr->default_config = CCS_CONFIG_DISABLED |
332                          ptr->value[i] = ccs_control_array[i].current_value;                          CCS_CONFIG_WANT_GRANT_LOG | CCS_CONFIG_WANT_REJECT_LOG;
333                  /*                  memset(ptr->config, CCS_CONFIG_USE_DEFAULT,
334                   * Needn't to initialize "ptr->capability_value"                         sizeof(ptr->config));
335                   * because they are always 0.                  ptr->pref[CCS_PREF_MAX_GRANT_LOG] =
336                   */                          CONFIG_CCSECURITY_MAX_GRANT_LOG;
337                    ptr->pref[CCS_PREF_MAX_REJECT_LOG] =
338                            CONFIG_CCSECURITY_MAX_REJECT_LOG;
339                    ptr->pref[CCS_PREF_MAX_LEARNING_ENTRY] =
340                            CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY;
341                  mb(); /* Avoid out-of-order execution. */                  mb(); /* Avoid out-of-order execution. */
342                  ccs_profile_ptr[profile] = ptr;                  ccs_profile_ptr[profile] = ptr;
343                  entry = NULL;                  entry = NULL;
344          }          }
345          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
346    out:
347          kfree(entry);          kfree(entry);
348          return ptr;          return ptr;
349  }  }
350    
351  /**  /**
352     * ccs_check_profile - Check all profiles currently assigned to domains are defined.
353     */
354    static void ccs_check_profile(void)
355    {
356            struct ccs_domain_info *domain;
357            const int idx = ccs_read_lock();
358            ccs_policy_loaded = true;
359            list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
360                    const u8 profile = domain->profile;
361                    if (ccs_profile_ptr[profile])
362                            continue;
363                    printk(KERN_ERR "You need to define profile %u before using it.\n",
364                           profile);
365                    printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/1.8/ "
366                           "for more information.\n");
367                    panic("Profile %u (used by '%s') not defined.\n",
368                          profile, domain->domainname->name);
369            }
370            ccs_read_unlock(idx);
371            if (ccs_profile_version != 20100903) {
372                    printk(KERN_ERR "You need to install userland programs for "
373                           "TOMOYO 1.8 and initialize policy configuration.\n");
374                    printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/1.8/ "
375                           "for more information.\n");
376                    panic("Profile version %u is not supported.\n",
377                          ccs_profile_version);
378            }
379            printk(KERN_INFO "CCSecurity: 1.8.0-pre   2010/10/10\n");
380            printk(KERN_INFO "Mandatory Access Control activated.\n");
381    }
382    
383    /**
384     * ccs_profile - Find a profile.
385     *
386     * @profile: Profile number to find.
387     *
388     * Returns pointer to "struct ccs_profile".
389     */
390    struct ccs_profile *ccs_profile(const u8 profile)
391    {
392            static struct ccs_profile ccs_null_profile;
393            struct ccs_profile *ptr = ccs_profile_ptr[profile];
394            if (!ptr)
395                    ptr = &ccs_null_profile;
396            return ptr;
397    }
398    
399    static s8 ccs_find_yesno(const char *string, const char *find)
400    {
401            const char *cp = strstr(string, find);
402            if (cp) {
403                    cp += strlen(find);
404                    if (!strncmp(cp, "=yes", 4))
405                            return 1;
406                    else if (!strncmp(cp, "=no", 3))
407                            return 0;
408            }
409            return -1;
410    }
411    
412    static void ccs_set_uint(unsigned int *i, const char *string, const char *find)
413    {
414            const char *cp = strstr(string, find);
415            if (cp)
416                    sscanf(cp + strlen(find), "=%u", i);
417    }
418    
419    static int ccs_set_mode(char *name, const char *value,
420                            struct ccs_profile *profile)
421    {
422            u8 i;
423            u8 config;
424            if (!strcmp(name, "CONFIG")) {
425                    i = CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
426                    config = profile->default_config;
427            } else if (ccs_str_starts(&name, "CONFIG::")) {
428                    config = 0;
429                    for (i = 0; i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
430                         i++) {
431                            int len = 0;
432                            if (i < CCS_MAX_MAC_INDEX) {
433                                    const u8 c = ccs_index2category[i];
434                                    const char *category =
435                                            ccs_category_keywords[c];
436                                    len = strlen(category);
437                                    if (strncmp(name, category, len) ||
438                                        name[len++] != ':' || name[len++] != ':')
439                                            continue;
440                            }
441                            if (strcmp(name + len, ccs_mac_keywords[i]))
442                                    continue;
443                            config = profile->config[i];
444                            break;
445                    }
446                    if (i == CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
447                            return -EINVAL;
448            } else {
449                    return -EINVAL;
450            }
451            if (strstr(value, "use_default")) {
452                    config = CCS_CONFIG_USE_DEFAULT;
453            } else {
454                    u8 mode;
455                    for (mode = 0; mode < CCS_CONFIG_MAX_MODE; mode++)
456                            if (strstr(value, ccs_mode[mode]))
457                                    /*
458                                     * Update lower 3 bits in order to distinguish
459                                     * 'config' from 'CCS_CONFIG_USE_DEAFULT'.
460                                     */
461                                    config = (config & ~7) | mode;
462                    if (config != CCS_CONFIG_USE_DEFAULT) {
463                            switch (ccs_find_yesno(value, "grant_log")) {
464                            case 1:
465                                    config |= CCS_CONFIG_WANT_GRANT_LOG;
466                                    break;
467                            case 0:
468                                    config &= ~CCS_CONFIG_WANT_GRANT_LOG;
469                                    break;
470                            }
471                            switch (ccs_find_yesno(value, "reject_log")) {
472                            case 1:
473                                    config |= CCS_CONFIG_WANT_REJECT_LOG;
474                                    break;
475                            case 0:
476                                    config &= ~CCS_CONFIG_WANT_REJECT_LOG;
477                                    break;
478                            }
479                    }
480            }
481            if (i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
482                    profile->config[i] = config;
483            else if (config != CCS_CONFIG_USE_DEFAULT)
484                    profile->default_config = config;
485            return 0;
486    }
487    
488    /**
489   * ccs_write_profile - Write profile table.   * ccs_write_profile - Write profile table.
490   *   *
491   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
# Line 149  static int ccs_write_profile(struct ccs_ Line 496  static int ccs_write_profile(struct ccs_
496  {  {
497          char *data = head->write_buf;          char *data = head->write_buf;
498          unsigned int i;          unsigned int i;
         unsigned int value;  
499          char *cp;          char *cp;
500          struct ccs_profile *ccs_profile;          struct ccs_profile *profile;
501            if (sscanf(data, "PROFILE_VERSION=%u", &ccs_profile_version) == 1)
502                    return 0;
503          i = simple_strtoul(data, &cp, 10);          i = simple_strtoul(data, &cp, 10);
504          if (data != cp) {          if (*cp != '-')
505                  if (*cp != '-')                  return -EINVAL;
506                          return -EINVAL;          data = cp + 1;
507                  data = cp + 1;          profile = ccs_assign_profile(i);
508          }          if (!profile)
         ccs_profile = ccs_find_or_assign_new_profile(i);  
         if (!ccs_profile)  
509                  return -EINVAL;                  return -EINVAL;
510          cp = strchr(data, '=');          cp = strchr(data, '=');
511          if (!cp)          if (!cp)
512                  return -EINVAL;                  return -EINVAL;
513          *cp = '\0';          *cp++ = '\0';
514          if (!strcmp(data, "COMMENT")) {          if (!strcmp(data, "COMMENT")) {
515                  const struct ccs_path_info *new_comment                  const struct ccs_path_info *old_comment = profile->comment;
516                          = ccs_get_name(cp + 1);                  profile->comment = ccs_get_name(cp);
                 const struct ccs_path_info *old_comment;  
                 /* Protect reader from ccs_put_name(). */  
                 /***** CRITICAL SECTION START *****/  
                 spin_lock(&ccs_profile_comment_lock);  
                 old_comment = ccs_profile->comment;  
                 ccs_profile->comment = new_comment;  
                 spin_unlock(&ccs_profile_comment_lock);  
                 /***** CRITICAL SECTION END *****/  
517                  ccs_put_name(old_comment);                  ccs_put_name(old_comment);
                 ccs_profile_entry_used[0] = true;  
518                  return 0;                  return 0;
519          }          }
520          if (ccs_str_starts(&data, KEYWORD_MAC_FOR_CAPABILITY)) {          if (!strcmp(data, "PREFERENCE")) {
521                  if (sscanf(cp + 1, "%u", &value) != 1) {                  for (i = 0; i < CCS_MAX_PREF; i++)
522                          for (i = 0; i < 4; i++) {                          ccs_set_uint(&profile->pref[i], cp,
523                                  if (strcmp(cp + 1, ccs_mode_4[i]))                                       ccs_pref_keywords[i]);
                                         continue;  
                                 value = i;  
                                 break;  
                         }  
                         if (i == 4)  
                                 return -EINVAL;  
                 }  
                 if (value > 3)  
                         value = 3;  
                 for (i = 0; i < CCS_MAX_CAPABILITY_INDEX; i++) {  
                         if (strcmp(data, ccs_capability_control_keyword[i]))  
                                 continue;  
                         ccs_profile->capability_value[i] = value;  
                         ccs_profile_entry_used[i + 1 + CCS_MAX_CONTROL_INDEX]  
                                 = true;  
                         return 0;  
                 }  
                 return -EINVAL;  
         }  
         for (i = 0; i < CCS_MAX_CONTROL_INDEX; i++) {  
                 if (strcmp(data, ccs_control_array[i].keyword))  
                         continue;  
                 if (sscanf(cp + 1, "%u", &value) != 1) {  
                         int j;  
                         const char **modes;  
                         switch (i) {  
                         case CCS_RESTRICT_AUTOBIND:  
                         case CCS_VERBOSE:  
                                 modes = ccs_mode_2;  
                                 break;  
                         default:  
                                 modes = ccs_mode_4;  
                                 break;  
                         }  
                         for (j = 0; j < 4; j++) {  
                                 if (strcmp(cp + 1, modes[j]))  
                                         continue;  
                                 value = j;  
                                 break;  
                         }  
                         if (j == 4)  
                                 return -EINVAL;  
                 } else if (value > ccs_control_array[i].max_value) {  
                         value = ccs_control_array[i].max_value;  
                 }  
                 ccs_profile->value[i] = value;  
                 ccs_profile_entry_used[i + 1] = true;  
524                  return 0;                  return 0;
525          }          }
526          return -EINVAL;          return ccs_set_mode(data, cp, profile);
527    }
528    
529    static void ccs_print_config(struct ccs_io_buffer *head, const u8 config)
530    {
531            ccs_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n",
532                          ccs_mode[config & 3],
533                          ccs_yesno(config & CCS_CONFIG_WANT_GRANT_LOG),
534                          ccs_yesno(config & CCS_CONFIG_WANT_REJECT_LOG));
535  }  }
536    
537  /**  /**
538   * ccs_read_profile - Read profile table.   * ccs_read_profile - Read profile table.
539   *   *
540   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
  *  
  * Returns 0.  
541   */   */
542  static int ccs_read_profile(struct ccs_io_buffer *head)  static void ccs_read_profile(struct ccs_io_buffer *head)
543  {  {
544          static const int ccs_total          u8 index;
545                  = CCS_MAX_CONTROL_INDEX + CCS_MAX_CAPABILITY_INDEX + 1;          const struct ccs_profile *profile;
546          int step;  next:
547          if (head->read_eof)          index = head->r.index;
548                  return 0;          profile = ccs_profile_ptr[index];
549          for (step = head->read_step; step < MAX_PROFILES * ccs_total; step++) {          switch (head->r.step) {
550                  const u8 index = step / ccs_total;          case 0:
551                  u8 type = step % ccs_total;                  ccs_io_printf(head, "PROFILE_VERSION=%s\n", "20100903");
552                  const struct ccs_profile *ccs_profile = ccs_profile_ptr[index];                  head->r.step++;
553                  head->read_step = step;                  break;
554                  if (!ccs_profile)          case 1:
555                          continue;                  for ( ; head->r.index < CCS_MAX_PROFILES;
556                  if (!ccs_profile_entry_used[type])                        head->r.index++)
557                          continue;                          if (ccs_profile_ptr[head->r.index])
558                  if (!type) { /* Print profile' comment tag. */                                  break;
559                          bool done;                  if (head->r.index == CCS_MAX_PROFILES)
560                          /***** CRITICAL SECTION START *****/                          return;
561                          spin_lock(&ccs_profile_comment_lock);                  head->r.step++;
562                          done = ccs_io_printf(head, "%u-COMMENT=%s\n",                  break;
563                                               index, ccs_profile->comment ?          case 2:
564                                               ccs_profile->comment->name : "");                  {
565                          spin_unlock(&ccs_profile_comment_lock);                          u8 i;
566                          /***** CRITICAL SECTION END *****/                          const struct ccs_path_info *comment = profile->comment;
567                          if (!done)                          ccs_io_printf(head, "%u-COMMENT=", index);
568                                  break;                          ccs_set_string(head, comment ? comment->name : "");
569                          continue;                          ccs_set_lf(head);
570                            ccs_io_printf(head, "%u-PREFERENCE={ ", index);
571                            for (i = 0; i < CCS_MAX_PREF; i++)
572                                    ccs_io_printf(head, "%s=%u ",
573                                                  ccs_pref_keywords[i],
574                                                  profile->pref[i]);
575                            ccs_set_string(head, " }\n");
576                            head->r.step++;
577                  }                  }
578                  type--;                  break;
579                  if (type >= CCS_MAX_CONTROL_INDEX) {          case 3:
580                          const int i = type - CCS_MAX_CONTROL_INDEX;                  {
581                          const u8 value = ccs_profile->capability_value[i];                          ccs_io_printf(head, "%u-%s", index, "CONFIG");
582                          if (!ccs_io_printf(head,                          ccs_print_config(head, profile->default_config);
583                                             "%u-" KEYWORD_MAC_FOR_CAPABILITY                          head->r.bit = 0;
584                                             "%s=%s\n", index,                          head->r.step++;
585                                             ccs_capability_control_keyword[i],                  }
586                                             ccs_mode_4[value]))                  break;
587                                  break;          case 4:
588                  } else {                  for ( ; head->r.bit < CCS_MAX_MAC_INDEX
589                          const unsigned int value = ccs_profile->value[type];                                + CCS_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
590                          const char **modes = NULL;                          const u8 i = head->r.bit;
591                          const char *keyword = ccs_control_array[type].keyword;                          const u8 config = profile->config[i];
592                          switch (ccs_control_array[type].max_value) {                          if (config == CCS_CONFIG_USE_DEFAULT)
593                          case 3:                                  continue;
594                                  modes = ccs_mode_4;                          if (i < CCS_MAX_MAC_INDEX)
595                                  break;                                  ccs_io_printf(head, "%u-CONFIG::%s::%s", index,
596                          case 1:                                                ccs_category_keywords
597                                  modes = ccs_mode_2;                                                [ccs_index2category[i]],
598                                  break;                                                ccs_mac_keywords[i]);
599                          }                          else
600                          if (modes) {                                  ccs_io_printf(head, "%u-CONFIG::%s", index,
601                                  if (!ccs_io_printf(head, "%u-%s=%s\n", index,                                                ccs_mac_keywords[i]);
602                                                     keyword, modes[value]))                          ccs_print_config(head, config);
603                                          break;                          head->r.bit++;
604                          } else {                          break;
605                                  if (!ccs_io_printf(head, "%u-%s=%u\n", index,                  }
606                                                     keyword, value))                  if (head->r.bit == CCS_MAX_MAC_INDEX
607                                          break;                      + CCS_MAX_MAC_CATEGORY_INDEX) {
608                          }                          head->r.index++;
609                            head->r.step = 1;
610                  }                  }
611                    break;
612          }          }
613          if (step == MAX_PROFILES * ccs_total)          if (ccs_flush(head))
614                  head->read_eof = true;                  goto next;
         return 0;  
615  }  }
616    
617  /* The list for "struct ccs_policy_manager_entry". */  static bool ccs_same_manager(const struct ccs_acl_head *a,
618  LIST_HEAD(ccs_policy_manager_list);                               const struct ccs_acl_head *b)
619    {
620            return container_of(a, struct ccs_manager, head)->manager
621                    == container_of(b, struct ccs_manager, head)->manager;
622    }
623    
624  /**  /**
625   * ccs_update_manager_entry - Add a manager entry.   * ccs_update_manager_entry - Add a manager entry.
# Line 323  LIST_HEAD(ccs_policy_manager_list); Line 631  LIST_HEAD(ccs_policy_manager_list);
631   */   */
632  static int ccs_update_manager_entry(const char *manager, const bool is_delete)  static int ccs_update_manager_entry(const char *manager, const bool is_delete)
633  {  {
634          struct ccs_policy_manager_entry *entry = NULL;          struct ccs_manager e = { };
         struct ccs_policy_manager_entry *ptr;  
         const struct ccs_path_info *saved_manager;  
635          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
636          bool is_domain = false;          if (ccs_domain_def(manager)) {
637          if (ccs_is_domain_def(manager)) {                  if (!ccs_correct_domain(manager))
                 if (!ccs_is_correct_domain(manager))  
638                          return -EINVAL;                          return -EINVAL;
639                  is_domain = true;                  e.is_domain = true;
640          } else {          } else {
641                  if (!ccs_is_correct_path(manager, 1, -1, -1))                  if (!ccs_correct_path(manager))
642                          return -EINVAL;                          return -EINVAL;
643          }          }
644          saved_manager = ccs_get_name(manager);          e.manager = ccs_get_name(manager);
645          if (!saved_manager)          if (!e.manager)
646                  return -ENOMEM;                  return error;
647          if (!is_delete)          error = ccs_update_policy(&e.head, sizeof(e), is_delete,
648                  entry = kzalloc(sizeof(*entry), GFP_KERNEL);                                    &ccs_policy_list[CCS_ID_MANAGER],
649          mutex_lock(&ccs_policy_lock);                                    ccs_same_manager);
650          list_for_each_entry_rcu(ptr, &ccs_policy_manager_list, list) {          ccs_put_name(e.manager);
                 if (ptr->manager != saved_manager)  
                         continue;  
                 ptr->is_deleted = is_delete;  
                 error = 0;  
                 break;  
         }  
         if (!is_delete && error && ccs_memory_ok(entry, sizeof(*entry))) {  
                 entry->manager = saved_manager;  
                 saved_manager = NULL;  
                 entry->is_domain = is_domain;  
                 list_add_tail_rcu(&entry->list, &ccs_policy_manager_list);  
                 entry = NULL;  
                 error = 0;  
         }  
         mutex_unlock(&ccs_policy_lock);  
         ccs_put_name(saved_manager);  
         kfree(entry);  
651          return error;          return error;
652  }  }
653    
654  /**  /**
655   * ccs_write_manager_policy - Write manager policy.   * ccs_write_manager - Write manager policy.
656   *   *
657   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
658   *   *
659   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
660   */   */
661  static int ccs_write_manager_policy(struct ccs_io_buffer *head)  static int ccs_write_manager(struct ccs_io_buffer *head)
662  {  {
663          char *data = head->write_buf;          char *data = head->write_buf;
664          bool is_delete = ccs_str_starts(&data, KEYWORD_DELETE);          bool is_delete = ccs_str_starts(&data, "delete ");
665          if (!strcmp(data, "manage_by_non_root")) {          if (!strcmp(data, "manage_by_non_root")) {
666                  ccs_manage_by_non_root = !is_delete;                  ccs_manage_by_non_root = !is_delete;
667                  return 0;                  return 0;
# Line 382  static int ccs_write_manager_policy(stru Line 670  static int ccs_write_manager_policy(stru
670  }  }
671    
672  /**  /**
673   * ccs_read_manager_policy - Read manager policy.   * ccs_read_manager - Read manager policy.
674   *   *
675   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
676   *   *
  * Returns 0.  
  *  
677   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
678   */   */
679  static int ccs_read_manager_policy(struct ccs_io_buffer *head)  static void ccs_read_manager(struct ccs_io_buffer *head)
680  {  {
681          struct list_head *pos;          if (head->r.eof)
682          ccs_check_read_lock();                  return;
683          if (head->read_eof)          list_for_each_cookie(head->r.acl, &ccs_policy_list[CCS_ID_MANAGER]) {
684                  return 0;                  struct ccs_manager *ptr =
685          list_for_each_cookie(pos, head->read_var2, &ccs_policy_manager_list) {                          list_entry(head->r.acl, typeof(*ptr), head.list);
686                  struct ccs_policy_manager_entry *ptr;                  if (ptr->head.is_deleted)
                 ptr = list_entry(pos, struct ccs_policy_manager_entry, list);  
                 if (ptr->is_deleted)  
687                          continue;                          continue;
688                  if (!ccs_io_printf(head, "%s\n", ptr->manager->name))                  if (!ccs_flush(head))
689                          return 0;                          return;
690                    ccs_set_string(head, ptr->manager->name);
691                    ccs_set_lf(head);
692          }          }
693          head->read_eof = true;          head->r.eof = true;
         return 0;  
694  }  }
695    
696  /**  /**
697   * ccs_is_policy_manager - Check whether the current process is a policy manager.   * ccs_manager - Check whether the current process is a policy manager.
698   *   *
699   * Returns true if the current process is permitted to modify policy   * Returns true if the current process is permitted to modify policy
700   * via /proc/ccs/ interface.   * via /proc/ccs/ interface.
701   *   *
702   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
703   */   */
704  static bool ccs_is_policy_manager(void)  static bool ccs_manager(void)
705  {  {
706          struct ccs_policy_manager_entry *ptr;          struct ccs_manager *ptr;
707          const char *exe;          const char *exe;
708          struct task_struct *task = current;          struct ccs_security *task = ccs_current_security();
709          const struct ccs_path_info *domainname          const struct ccs_path_info *domainname
710                  = ccs_current_domain()->domainname;                  = ccs_current_domain()->domainname;
711          bool found = false;          bool found = false;
         ccs_check_read_lock();  
712          if (!ccs_policy_loaded)          if (!ccs_policy_loaded)
713                  return true;                  return true;
714          if (task->ccs_flags & CCS_TASK_IS_POLICY_MANAGER)          if (task->ccs_flags & CCS_TASK_IS_MANAGER)
715                  return true;                  return true;
716          if (!ccs_manage_by_non_root && (current_uid() || current_euid()))          if (!ccs_manage_by_non_root && (current_uid() || current_euid()))
717                  return false;                  return false;
         list_for_each_entry_rcu(ptr, &ccs_policy_manager_list, list) {  
                 if (!ptr->is_deleted && ptr->is_domain  
                     && !ccs_pathcmp(domainname, ptr->manager)) {  
                         /* Set manager flag. */  
                         task->ccs_flags |= CCS_TASK_IS_POLICY_MANAGER;  
                         return true;  
                 }  
         }  
718          exe = ccs_get_exe();          exe = ccs_get_exe();
719          if (!exe)          list_for_each_entry_srcu(ptr, &ccs_policy_list[CCS_ID_MANAGER],
720                  return false;                                   head.list, &ccs_ss) {
721          list_for_each_entry_rcu(ptr, &ccs_policy_manager_list, list) {                  if (ptr->head.is_deleted)
722                  if (!ptr->is_deleted && !ptr->is_domain                          continue;
723                      && !strcmp(exe, ptr->manager->name)) {                  if (ptr->is_domain) {
724                          found = true;                          if (ccs_pathcmp(domainname, ptr->manager))
725                          /* Set manager flag. */                                  continue;
726                          task->ccs_flags |= CCS_TASK_IS_POLICY_MANAGER;                  } else {
727                          break;                          if (!exe || strcmp(exe, ptr->manager->name))
728                                    continue;
729                  }                  }
730                    /* Set manager flag. */
731                    task->ccs_flags |= CCS_TASK_IS_MANAGER;
732                    found = true;
733                    break;
734          }          }
735          if (!found) { /* Reduce error messages. */          if (!found) { /* Reduce error messages. */
736                  static pid_t ccs_last_pid;                  static pid_t ccs_last_pid;
# Line 465  static bool ccs_is_policy_manager(void) Line 746  static bool ccs_is_policy_manager(void)
746  }  }
747    
748  /**  /**
749   * ccs_find_condition_part - Find condition part from the statement.   * ccs_select_one - Parse select command.
  *  
  * @data: String to parse.  
  *  
  * Returns pointer to the condition part if it was found in the statement,  
  * NULL otherwise.  
  */  
 static char *ccs_find_condition_part(char *data)  
 {  
         char *cp = strstr(data, " if ");  
         if (cp) {  
                 while (1) {  
                         char *cp2 = strstr(cp + 3, " if ");  
                         if (!cp2)  
                                 break;  
                         cp = cp2;  
                 }  
                 *cp++ = '\0';  
         } else {  
                 cp = strstr(data, " ; set ");  
                 if (cp)  
                         *cp++ = '\0';  
         }  
         return cp;  
 }  
   
 /**  
  * ccs_is_select_one - Parse select command.  
750   *   *
751   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
752   * @data: String to parse.   * @data: String to parse.
# Line 501  static char *ccs_find_condition_part(cha Line 755  static char *ccs_find_condition_part(cha
755   *   *
756   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
757   */   */
758  static bool ccs_is_select_one(struct ccs_io_buffer *head, const char *data)  static bool ccs_select_one(struct ccs_io_buffer *head, const char *data)
759  {  {
760          unsigned int pid;          unsigned int pid;
761          struct ccs_domain_info *domain = NULL;          struct ccs_domain_info *domain = NULL;
762          ccs_check_read_lock();          bool global_pid = false;
763          if (!strcmp(data, "allow_execute")) {          if (!strcmp(data, "execute")) {
764                  head->read_execute_only = true;                  head->r.print_execute_only = true;
765                  return true;                  return true;
766          }          }
767          if (sscanf(data, "pid=%u", &pid) == 1) {          if (sscanf(data, "pid=%u", &pid) == 1 ||
768                (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
769                  struct task_struct *p;                  struct task_struct *p;
770                  /***** CRITICAL SECTION START *****/                  ccs_tasklist_lock();
771                  read_lock(&tasklist_lock);  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
772                    if (global_pid)
773                            p = ccsecurity_exports.find_task_by_pid_ns(pid,
774                                                                   &init_pid_ns);
775                    else
776                            p = ccsecurity_exports.find_task_by_vpid(pid);
777    #else
778                  p = find_task_by_pid(pid);                  p = find_task_by_pid(pid);
779    #endif
780                  if (p)                  if (p)
781                          domain = ccs_task_domain(p);                          domain = ccs_task_domain(p);
782                  read_unlock(&tasklist_lock);                  ccs_tasklist_unlock();
                 /***** CRITICAL SECTION END *****/  
783          } else if (!strncmp(data, "domain=", 7)) {          } else if (!strncmp(data, "domain=", 7)) {
784                  if (ccs_is_domain_def(data + 7))                  if (ccs_domain_def(data + 7))
785                          domain = ccs_find_domain(data + 7);                          domain = ccs_find_domain(data + 7);
786          } else          } else
787                  return false;                  return false;
788          head->write_var1 = domain;          head->w.domain = domain;
789          /* Accessing read_buf is safe because head->io_sem is held. */          /* Accessing read_buf is safe because head->io_sem is held. */
790          if (!head->read_buf)          if (!head->read_buf)
791                  return true; /* Do nothing if open(O_WRONLY). */                  return true; /* Do nothing if open(O_WRONLY). */
792          head->read_avail = 0;          memset(&head->r, 0, sizeof(head->r));
793            head->r.print_this_domain_only = true;
794            if (domain)
795                    head->r.domain = &domain->list;
796            else
797                    head->r.eof = true;
798          ccs_io_printf(head, "# select %s\n", data);          ccs_io_printf(head, "# select %s\n", data);
799          head->read_single_domain = true;          if (domain && domain->is_deleted)
800          head->read_eof = !domain;                  ccs_set_string(head, "# This is a deleted domain.\n");
         if (domain) {  
                 struct ccs_domain_info *d;  
                 head->read_var1 = NULL;  
                 list_for_each_entry_rcu(d, &ccs_domain_list, list) {  
                         if (d == domain)  
                                 break;  
                         head->read_var1 = &d->list;  
                 }  
                 head->read_var2 = NULL;  
                 head->read_bit = 0;  
                 head->read_step = 0;  
                 if (domain->is_deleted)  
                         ccs_io_printf(head, "# This is a deleted domain.\n");  
         }  
801          return true;          return true;
802  }  }
803    
804    static bool ccs_same_handler_acl(const struct ccs_acl_info *a,
805                                     const struct ccs_acl_info *b)
806    {
807            const struct ccs_handler_acl *p1 = container_of(a, typeof(*p1), head);
808            const struct ccs_handler_acl *p2 = container_of(b, typeof(*p2), head);
809            return p1->handler == p2->handler;
810    }
811    
812    static bool ccs_same_task_acl(const struct ccs_acl_info *a,
813                                  const struct ccs_acl_info *b)
814    {
815            const struct ccs_task_acl *p1 = container_of(a, typeof(*p1), head);
816            const struct ccs_task_acl *p2 = container_of(b, typeof(*p2), head);
817            return p1->domainname == p2->domainname;
818    }
819    
820    /**
821     * ccs_write_task - Update task related list.
822     *
823     * @param: Pointer to "struct ccs_acl_param".
824     *
825     * Returns 0 on success, negative value otherwise.
826     */
827    static int ccs_write_task(struct ccs_acl_param *param)
828    {
829            int error;
830            const bool is_auto = ccs_str_starts(&param->data,
831                                                "auto_domain_transition ");
832            if (!is_auto && !ccs_str_starts(&param->data,
833                                            "manual_domain_transition ")) {
834                    struct ccs_handler_acl e = { };
835                    char *handler;
836                    if (ccs_str_starts(&param->data, "auto_execute_handler "))
837                            e.head.type = CCS_TYPE_AUTO_EXECUTE_HANDLER;
838                    else if (ccs_str_starts(&param->data,
839                                            "denied_execute_handler "))
840                            e.head.type = CCS_TYPE_DENIED_EXECUTE_HANDLER;
841                    else
842                            return -EINVAL;
843                    handler = ccs_read_token(param);
844                    if (!ccs_correct_path(handler))
845                            return -EINVAL;
846                    e.handler = ccs_get_name(handler);
847                    if (!e.handler)
848                            return -ENOMEM;
849                    if (e.handler->is_patterned)
850                            error = -EINVAL; /* No patterns allowed. */
851                    else
852                            error = ccs_update_domain(&e.head, sizeof(e), param,
853                                                      ccs_same_handler_acl, NULL);
854                    ccs_put_name(e.handler);
855            } else {
856                    struct ccs_task_acl e = {
857                            .head.type = is_auto ?
858                            CCS_TYPE_AUTO_TASK_ACL : CCS_TYPE_MANUAL_TASK_ACL,
859                            .domainname = ccs_get_domainname(param),
860                    };
861                    if (!e.domainname)
862                            error = -EINVAL;
863                    else
864                            error = ccs_update_domain(&e.head, sizeof(e), param,
865                                                      ccs_same_task_acl, NULL);
866                    ccs_put_name(e.domainname);
867            }
868            return error;
869    }
870    
871    static int ccs_write_domain2(char *data, struct ccs_domain_info *domain,
872                                 const bool is_delete)
873    {
874            struct ccs_acl_param param = {
875                    .data = data,
876                    .domain = domain,
877                    .is_delete = is_delete,
878            };
879            static const struct {
880                    const char *keyword;
881                    int (*write) (struct ccs_acl_param *);
882            } ccs_callback[7] = {
883                    { "file ", ccs_write_file },
884                    { "network inet ", ccs_write_inet_network },
885                    { "network unix ", ccs_write_unix_network },
886                    { "misc ", ccs_write_misc },
887                    { "capability ", ccs_write_capability },
888                    { "ipc ", ccs_write_ipc },
889                    { "task ", ccs_write_task },
890            };
891            u8 i;
892            for (i = 0; i < 7; i++) {
893                    if (!ccs_str_starts(&param.data, ccs_callback[i].keyword))
894                            continue;
895                    return ccs_callback[i].write(&param);
896            }
897            return -EINVAL;
898    }
899    
900    const char * const ccs_dif[CCS_MAX_DOMAIN_INFO_FLAGS] = {
901            [CCS_DIF_QUOTA_WARNED]      = "quota_exceeded\n",
902            [CCS_DIF_TRANSITION_FAILED] = "transition_failed\n",
903    };
904    
905  /**  /**
906   * ccs_write_domain_policy - Write domain policy.   * ccs_write_domain - Write domain policy.
907   *   *
908   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
909   *   *
910   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
911   */   */
912  static int ccs_write_domain_policy(struct ccs_io_buffer *head)  static int ccs_write_domain(struct ccs_io_buffer *head)
913  {  {
914          char *data = head->write_buf;          char *data = head->write_buf;
915          struct ccs_domain_info *domain = head->write_var1;          struct ccs_domain_info *domain = head->w.domain;
916          bool is_delete = false;          bool is_delete = false;
917          bool is_select = false;          bool is_select = false;
918          unsigned int profile;          unsigned int profile;
919          struct ccs_condition *cond = NULL;          if (ccs_str_starts(&data, "delete "))
         char *cp;  
         int error;  
         if (ccs_str_starts(&data, KEYWORD_DELETE))  
920                  is_delete = true;                  is_delete = true;
921          else if (ccs_str_starts(&data, KEYWORD_SELECT))          else if (ccs_str_starts(&data, "select "))
922                  is_select = true;                  is_select = true;
923          if (is_select && ccs_is_select_one(head, data))          if (is_select && ccs_select_one(head, data))
924                  return 0;                  return 0;
925          /* Don't allow updating policies by non manager programs. */          /* Don't allow updating policies by non manager programs. */
926          if (!ccs_is_policy_manager())          if (!ccs_manager())
927                  return -EPERM;                  return -EPERM;
928          if (ccs_is_domain_def(data)) {          if (ccs_domain_def(data)) {
929                  domain = NULL;                  domain = NULL;
930                  if (is_delete)                  if (is_delete)
931                          ccs_delete_domain(data);                          ccs_delete_domain(data);
932                  else if (is_select)                  else if (is_select)
933                          domain = ccs_find_domain(data);                          domain = ccs_find_domain(data);
934                  else                  else
935                          domain = ccs_find_or_assign_new_domain(data, 0);                          domain = ccs_assign_domain(data, 0, 0, false);
936                  head->write_var1 = domain;                  head->w.domain = domain;
937                  return 0;                  return 0;
938          }          }
939          if (!domain)          if (!domain)
940                  return -EINVAL;                  return -EINVAL;
941    
942          if (sscanf(data, KEYWORD_USE_PROFILE "%u", &profile) == 1          if (sscanf(data, "use_profile %u\n", &profile) == 1
943              && profile < MAX_PROFILES) {              && profile < CCS_MAX_PROFILES) {
944                  if (ccs_profile_ptr[profile] || !ccs_policy_loaded)                  if (!ccs_policy_loaded || ccs_profile_ptr[(u8) profile])
945                          domain->profile = (u8) profile;                          domain->profile = (u8) profile;
946                  return 0;                  return 0;
947          }          }
948          if (!strcmp(data, KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) {          if (sscanf(data, "use_group %u\n", &profile) == 1
949                  domain->ignore_global_allow_read = !is_delete;              && profile < CCS_MAX_ACL_GROUPS) {
950                  return 0;                  domain->group = (u8) profile;
         }  
         if (!strcmp(data, KEYWORD_IGNORE_GLOBAL_ALLOW_ENV)) {  
                 domain->ignore_global_allow_env = !is_delete;  
951                  return 0;                  return 0;
952          }          }
953          cp = ccs_find_condition_part(data);          for (profile = 0; profile < CCS_MAX_DOMAIN_INFO_FLAGS; profile++) {
954          if (cp) {                  const char *cp = ccs_dif[profile];
955                  cond = ccs_get_condition(cp);                  if (strncmp(data, cp, strlen(cp) - 1))
                 if (!cond)  
                         return -EINVAL;  
         }  
         if (ccs_str_starts(&data, KEYWORD_ALLOW_CAPABILITY))  
                 error = ccs_write_capability_policy(data, domain, cond,  
                                                     is_delete);  
         else if (ccs_str_starts(&data, KEYWORD_ALLOW_NETWORK))  
                 error = ccs_write_network_policy(data, domain, cond, is_delete);  
         else if (ccs_str_starts(&data, KEYWORD_ALLOW_SIGNAL))  
                 error = ccs_write_signal_policy(data, domain, cond, is_delete);  
         else if (ccs_str_starts(&data, KEYWORD_ALLOW_ARGV0))  
                 error = ccs_write_argv0_policy(data, domain, cond, is_delete);  
         else if (ccs_str_starts(&data, KEYWORD_ALLOW_ENV))  
                 error = ccs_write_env_policy(data, domain, cond, is_delete);  
         else if (ccs_str_starts(&data, KEYWORD_ALLOW_MOUNT))  
                 error = ccs_write_mount_policy(data, domain, cond, is_delete);  
         else if (ccs_str_starts(&data, KEYWORD_ALLOW_UNMOUNT))  
                 error = ccs_write_umount_policy(data, domain, cond, is_delete);  
         else if (ccs_str_starts(&data, KEYWORD_ALLOW_CHROOT))  
                 error = ccs_write_chroot_policy(data, domain, cond, is_delete);  
         else if (ccs_str_starts(&data, KEYWORD_ALLOW_PIVOT_ROOT))  
                 error = ccs_write_pivot_root_policy(data, domain, cond,  
                                                     is_delete);  
         else  
                 error = ccs_write_file_policy(data, domain, cond, is_delete);  
         if (cond)  
                 ccs_put_condition(cond);  
         return error;  
 }  
   
 static bool ccs_print_name_union(struct ccs_io_buffer *head,  
                                  struct ccs_name_union *ptr)  
 {  
         const int pos = head->read_avail;  
         if (pos && head->read_buf[pos - 1] == ' ')  
                 head->read_avail--;  
         if (ptr->is_group)  
                 return ccs_io_printf(head, " @%s",  
                                      ptr->group->group_name->name);  
         return ccs_io_printf(head, " %s", ptr->filename->name);  
 }  
   
 static bool ccs_print_number_union(struct ccs_io_buffer *head,  
                                    struct ccs_number_union *ptr)  
 {  
         unsigned long min;  
         unsigned long max;  
         if (ptr->is_group)  
                 return ccs_io_printf(head, " @%s",  
                                      ptr->group->group_name->name);  
         min = ptr->values[0];  
         max = ptr->values[1];  
         if (min == max)  
                 return ccs_io_printf(head, " %lu", min);  
         return ccs_io_printf(head, " %lu-%lu", min, max);  
 }  
   
 /**  
  * ccs_print_single_path_acl - Print a single path ACL entry.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  * @ptr:  Pointer to "struct ccs_single_path_acl_record".  
  * @cond: Pointer to "struct ccs_condition". May be NULL.  
  *  
  * Returns true on success, false otherwise.  
  */  
 static bool ccs_print_single_path_acl(struct ccs_io_buffer *head,  
                                       struct ccs_single_path_acl_record *ptr,  
                                       const struct ccs_condition *cond)  
 {  
         int pos;  
         u8 bit;  
         const u16 perm = ptr->perm;  
         for (bit = head->read_bit; bit < MAX_SINGLE_PATH_OPERATION; bit++) {  
                 const char *msg;  
                 if (!(perm & (1 << bit)))  
                         continue;  
                 if (head->read_execute_only && bit != TYPE_EXECUTE_ACL)  
                         continue;  
                 /* Print "read/write" instead of "read" and "write". */  
                 if ((bit == TYPE_READ_ACL || bit == TYPE_WRITE_ACL)  
                     && (perm & (1 << TYPE_READ_WRITE_ACL)))  
956                          continue;                          continue;
957                  msg = ccs_sp2keyword(bit);                  domain->flags[profile] = !is_delete;
958                  pos = head->read_avail;                  return 0;
                 if (!ccs_io_printf(head, "allow_%s", msg) ||  
                     !ccs_print_name_union(head, &ptr->name) ||  
                     !ccs_print_condition(head, cond))  
                         goto out;  
959          }          }
960          head->read_bit = 0;          return ccs_write_domain2(data, domain, is_delete);
         return true;  
  out:  
         head->read_bit = bit;  
         head->read_avail = pos;  
         return false;  
961  }  }
962    
963  /**  /**
964   * ccs_print_mkdev_acl - Print a mkdev ACL entry.   * ccs_print_name_union - Print a ccs_name_union.
965   *   *
966   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
967   * @ptr:  Pointer to "struct ccs_mkdev_acl_record".   * @ptr:  Pointer to "struct ccs_name_union".
  * @cond: Pointer to "struct ccs_condition". May be NULL.  
  *  
  * Returns true on success, false otherwise.  
968   */   */
969  static bool ccs_print_mkdev_acl(struct ccs_io_buffer *head,  static void ccs_print_name_union(struct ccs_io_buffer *head,
970                                  struct ccs_mkdev_acl_record *ptr,                                   const struct ccs_name_union *ptr)
                                 const struct ccs_condition *cond)  
971  {  {
972          int pos;          const bool cond = head->r.print_cond_part;
973          u8 bit;          if (!cond)
974          const u16 perm = ptr->perm;                  ccs_set_space(head);
975          for (bit = head->read_bit; bit < MAX_MKDEV_OPERATION; bit++) {          if (ptr->is_group) {
976                  const char *msg;                  ccs_set_string(head, "@");
977                  if (!(perm & (1 << bit)))                  ccs_set_string(head, ptr->group->group_name->name);
978                          continue;          } else {
979                  msg = ccs_mkdev2keyword(bit);                  if (cond)
980                  pos = head->read_avail;                          ccs_set_string(head, "\"");
981                  if (!ccs_io_printf(head, "allow_%s", msg) ||                  ccs_set_string(head, ptr->filename->name);
982                      !ccs_print_name_union(head, &ptr->name) ||                  if (cond)
983                      !ccs_print_number_union(head, &ptr->major) ||                          ccs_set_string(head, "\"");
                     !ccs_print_number_union(head, &ptr->minor) ||  
                     !ccs_print_condition(head, cond))  
                         goto out;  
         }  
         head->read_bit = 0;  
         return true;  
  out:  
         head->read_bit = bit;  
         head->read_avail = pos;  
         return false;  
 }  
   
 /**  
  * ccs_print_double_path_acl - Print a double path ACL entry.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  * @ptr:  Pointer to "struct ccs_double_path_acl_record".  
  * @cond: Pointer to "struct ccs_condition". May be NULL.  
  *  
  * Returns true on success, false otherwise.  
  */  
 static bool ccs_print_double_path_acl(struct ccs_io_buffer *head,  
                                       struct ccs_double_path_acl_record *ptr,  
                                       const struct ccs_condition *cond)  
 {  
         int pos;  
         u8 bit;  
         const u8 perm = ptr->perm;  
         for (bit = head->read_bit; bit < MAX_DOUBLE_PATH_OPERATION; bit++) {  
                 const char *msg;  
                 if (!(perm & (1 << bit)))  
                         continue;  
                 msg = ccs_dp2keyword(bit);  
                 pos = head->read_avail;  
                 if (!ccs_io_printf(head, "allow_%s", msg) ||  
                     !ccs_print_name_union(head, &ptr->name1) ||  
                     !ccs_print_name_union(head, &ptr->name2) ||  
                     !ccs_print_condition(head, cond))  
                         goto out;  
984          }          }
         head->read_bit = 0;  
         return true;  
  out:  
         head->read_bit = bit;  
         head->read_avail = pos;  
         return false;  
985  }  }
986    
987  /**  /**
988   * ccs_print_path_number_acl - Print an ioctl/chmod/chown/chgrp ACL entry.   * ccs_print_number_union - Print a ccs_number_union.
989   *   *
990   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
991   * @ptr:  Pointer to "struct ccs_path_number_acl_record".   * @ptr:  Pointer to "struct ccs_number_union".
  * @cond: Pointer to "struct ccs_condition". May be NULL.  
  *  
  * Returns true on success, false otherwise.  
992   */   */
993  static bool ccs_print_path_number_acl(struct ccs_io_buffer *head,  static void ccs_print_number_union(struct ccs_io_buffer *head,
994                                        struct ccs_path_number_acl_record *ptr,                                     const struct ccs_number_union *ptr)
                                       const struct ccs_condition *cond)  
995  {  {
996          int pos;          if (!head->r.print_cond_part)
997          u8 bit;                  ccs_set_space(head);
998          const u8 perm = ptr->perm;          if (ptr->is_group) {
999          for (bit = head->read_bit; bit < MAX_PATH_NUMBER_OPERATION; bit++) {                  ccs_set_string(head, "@");
1000                  const char *msg;                  ccs_set_string(head, ptr->group->group_name->name);
1001                  if (!(perm & (1 << bit)))          } else {
1002                          continue;                  int i;
1003                  msg = ccs_path_number2keyword(bit);                  unsigned long min = ptr->values[0];
1004                  pos = head->read_avail;                  const unsigned long max = ptr->values[1];
1005                  if (!ccs_io_printf(head, "allow_%s", msg) ||                  u8 min_type = ptr->value_type[0];
1006                      !ccs_print_name_union(head, &ptr->name) ||                  const u8 max_type = ptr->value_type[1];
1007                      !ccs_print_number_union(head, &ptr->number) ||                  char buffer[128];
1008                      !ccs_print_condition(head, cond))                  buffer[0] = '\0';
1009                          goto out;                  for (i = 0; i < 2; i++) {
1010                            switch (min_type) {
1011                            case CCS_VALUE_TYPE_HEXADECIMAL:
1012                                    ccs_addprintf(buffer, sizeof(buffer), "0x%lX",
1013                                                  min);
1014                                    break;
1015                            case CCS_VALUE_TYPE_OCTAL:
1016                                    ccs_addprintf(buffer, sizeof(buffer), "0%lo",
1017                                                  min);
1018                                    break;
1019                            default:
1020                                    ccs_addprintf(buffer, sizeof(buffer), "%lu",
1021                                                  min);
1022                                    break;
1023                            }
1024                            if (min == max && min_type == max_type)
1025                                    break;
1026                            ccs_addprintf(buffer, sizeof(buffer), "-");
1027                            min_type = max_type;
1028                            min = max;
1029                    }
1030                    ccs_io_printf(head, "%s", buffer);
1031          }          }
         head->read_bit = 0;  
         return true;  
  out:  
         head->read_bit = bit;  
         head->read_avail = pos;  
         return false;  
1032  }  }
1033    
1034  /**  /**
1035   * ccs_print_argv0_acl - Print an argv[0] ACL entry.   * ccs_print_condition - Print condition part.
1036   *   *
1037   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
1038   * @ptr:  Pointer to "struct ccs_argv0_acl_record".   * @cond: Pointer to "struct ccs_condition".
  * @cond: Pointer to "struct ccs_condition". May be NULL.  
1039   *   *
1040   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
1041   */   */
1042  static bool ccs_print_argv0_acl(struct ccs_io_buffer *head,  static bool ccs_print_condition(struct ccs_io_buffer *head,
                                 struct ccs_argv0_acl_record *ptr,  
1043                                  const struct ccs_condition *cond)                                  const struct ccs_condition *cond)
1044  {  {
1045          int pos = head->read_avail;          switch (head->r.cond_step) {
1046          if (!ccs_io_printf(head, KEYWORD_ALLOW_ARGV0 "%s %s",          case 0:
1047                             ptr->filename->name, ptr->argv0->name))                  head->r.cond_index = 0;
1048                  goto out;                  head->r.cond_step++;
1049          if (!ccs_print_condition(head, cond))                  /* fall through */
1050                  goto out;          case 1:
1051          return true;                  {
1052   out:                          const u16 condc = cond->condc;
1053          head->read_avail = pos;                          const struct ccs_condition_element *condp =
1054                                    (typeof(condp)) (cond + 1);
1055                            const struct ccs_number_union *numbers_p =
1056                                    (typeof(numbers_p)) (condp + condc);
1057                            const struct ccs_name_union *names_p =
1058                                    (typeof(names_p))
1059                                    (numbers_p + cond->numbers_count);
1060                            const struct ccs_argv *argv =
1061                                    (typeof(argv)) (names_p + cond->names_count);
1062                            const struct ccs_envp *envp =
1063                                    (typeof(envp)) (argv + cond->argc);
1064                            u16 skip;
1065                            for (skip = 0; skip < head->r.cond_index; skip++) {
1066                                    const u8 left = condp->left;
1067                                    const u8 right = condp->right;
1068                                    condp++;
1069                                    switch (left) {
1070                                    case CCS_ARGV_ENTRY:
1071                                            argv++;
1072                                            continue;
1073                                    case CCS_ENVP_ENTRY:
1074                                            envp++;
1075                                            continue;
1076                                    case CCS_NUMBER_UNION:
1077                                            numbers_p++;
1078                                            break;
1079                                    }
1080                                    switch (right) {
1081                                    case CCS_NAME_UNION:
1082                                            names_p++;
1083                                            break;
1084                                    case CCS_NUMBER_UNION:
1085                                            numbers_p++;
1086                                            break;
1087                                    }
1088                            }
1089                            while (head->r.cond_index < condc) {
1090                                    const u8 match = condp->equals;
1091                                    const u8 left = condp->left;
1092                                    const u8 right = condp->right;
1093                                    if (!ccs_flush(head))
1094                                            return false;
1095                                    condp++;
1096                                    head->r.cond_index++;
1097                                    ccs_set_space(head);
1098                                    switch (left) {
1099                                    case CCS_ARGV_ENTRY:
1100                                            ccs_io_printf(head,
1101                                                          "exec.argv[%u]%s\"%s\"",
1102                                                          argv->index,
1103                                                          argv->is_not ?
1104                                                          "!=" : "=",
1105                                                          argv->value->name);
1106                                            argv++;
1107                                            continue;
1108                                    case CCS_ENVP_ENTRY:
1109                                            ccs_io_printf(head,
1110                                                          "exec.envp[\"%s\"]%s",
1111                                                          envp->name->name,
1112                                                          envp->is_not ?
1113                                                          "!=" : "=");
1114                                            if (envp->value) {
1115                                                    ccs_set_string(head, "\"");
1116                                                    ccs_set_string(head, envp->
1117                                                                   value->name);
1118                                                    ccs_set_string(head, "\"");
1119                                            } else {
1120                                                    ccs_set_string(head, "NULL");
1121                                            }
1122                                            envp++;
1123                                            continue;
1124                                    case CCS_NUMBER_UNION:
1125                                            ccs_print_number_union(head,
1126                                                                   numbers_p++);
1127                                            break;
1128                                    default:
1129                                            ccs_set_string(head,
1130                                                   ccs_condition_keyword[left]);
1131                                            break;
1132                                    }
1133                                    ccs_set_string(head, match ? "=" : "!=");
1134                                    switch (right) {
1135                                    case CCS_NAME_UNION:
1136                                            ccs_print_name_union(head, names_p++);
1137                                            break;
1138                                    case CCS_NUMBER_UNION:
1139                                            ccs_print_number_union(head,
1140                                                                   numbers_p++);
1141                                            break;
1142                                    default:
1143                                            ccs_set_string(head,
1144                                                   ccs_condition_keyword[right]);
1145                                            break;
1146                                    }
1147                            }
1148                    }
1149                    head->r.cond_step++;
1150                    /* fall through */
1151            case 2:
1152                    if (!ccs_flush(head))
1153                            break;
1154                    head->r.cond_step++;
1155                    /* fall through */
1156            case 3:
1157                    if (cond->grant_log)
1158                            ccs_io_printf(head, " grant_log=%s",
1159                                          ccs_yesno(cond->grant_log == 2));
1160                    if (cond->transit) {
1161                            ccs_set_string(head, " auto_domain_transitition=\"");
1162                            ccs_set_string(head, cond->transit->name);
1163                            ccs_set_string(head, "\"");
1164                    }
1165                    ccs_set_lf(head);
1166                    return true;
1167            }
1168          return false;          return false;
1169  }  }
1170    
1171  /**  /**
1172   * ccs_print_env_acl - Print an evironment variable name's ACL entry.   * ccs_fns - Find next set bit.
1173   *   *
1174   * @head: Pointer to "struct ccs_io_buffer".   * @perm: 8 bits value.
1175   * @ptr:  Pointer to "struct ccs_env_acl_record".   * @bit:  First bit to find.
  * @cond: Pointer to "struct ccs_condition". May be NULL.  
1176   *   *
1177   * Returns true on success, false otherwise.   * Returns next set bit on success, 8 otherwise.
1178   */   */
1179  static bool ccs_print_env_acl(struct ccs_io_buffer *head,  static u8 ccs_fns(const u8 perm, u8 bit)
                               struct ccs_env_acl_record *ptr,  
                               const struct ccs_condition *cond)  
1180  {  {
1181          int pos = head->read_avail;          for ( ; bit < 8; bit++)
1182          if (!ccs_io_printf(head, KEYWORD_ALLOW_ENV "%s", ptr->env->name))                  if (perm & (1 << bit))
1183                  goto out;                          break;
1184          if (!ccs_print_condition(head, cond))          return bit;
                 goto out;  
         return true;  
  out:  
         head->read_avail = pos;  
         return false;  
 }  
   
 /**  
  * ccs_print_capability_acl - Print a capability ACL entry.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  * @ptr:  Pointer to "struct ccs_capability_acl_record".  
  * @cond: Pointer to "struct ccs_condition". May be NULL.  
  *  
  * Returns true on success, false otherwise.  
  */  
 static bool ccs_print_capability_acl(struct ccs_io_buffer *head,  
                                      struct ccs_capability_acl_record *ptr,  
                                      const struct ccs_condition *cond)  
 {  
         int pos = head->read_avail;  
         if (!ccs_io_printf(head, KEYWORD_ALLOW_CAPABILITY "%s",  
                            ccs_cap2keyword(ptr->operation)))  
                 goto out;  
         if (!ccs_print_condition(head, cond))  
                 goto out;  
         return true;  
  out:  
         head->read_avail = pos;  
         return false;  
1185  }  }
1186    
1187  /**  static void ccs_set_group(struct ccs_io_buffer *head)
  * ccs_print_ipv4_entry - Print IPv4 address of a network ACL entry.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  * @ptr:  Pointer to "struct ccs_ip_network_acl_record".  
  *  
  * Returns true on success, false otherwise.  
  */  
 static bool ccs_print_ipv4_entry(struct ccs_io_buffer *head,  
                                  struct ccs_ip_network_acl_record *ptr)  
1188  {  {
1189          const u32 min_address = ptr->address.ipv4.min;          if (head->type == CCS_EXCEPTIONPOLICY)
1190          const u32 max_address = ptr->address.ipv4.max;                  ccs_io_printf(head, "acl_group %u ", head->r.group_index);
         if (!ccs_io_printf(head, "%u.%u.%u.%u", HIPQUAD(min_address)))  
                 return false;  
         if (min_address != max_address  
             && !ccs_io_printf(head, "-%u.%u.%u.%u", HIPQUAD(max_address)))  
                 return false;  
         return true;  
1191  }  }
1192    
1193  /**  /**
1194   * ccs_print_ipv6_entry - Print IPv6 address of a network ACL entry.   * ccs_print_entry - Print an ACL entry.
1195   *   *
1196   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
1197   * @ptr:  Pointer to "struct ccs_ip_network_acl_record".   * @acl:  Pointer to an ACL entry.
1198   *   *
1199   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
1200   */   */
1201  static bool ccs_print_ipv6_entry(struct ccs_io_buffer *head,  static bool ccs_print_entry(struct ccs_io_buffer *head,
1202                                   struct ccs_ip_network_acl_record *ptr)                              const struct ccs_acl_info *acl)
1203  {  {
1204          char buf[64];          const u8 acl_type = acl->type;
1205          const struct in6_addr *min_address = ptr->address.ipv6.min;          u8 bit;
1206          const struct in6_addr *max_address = ptr->address.ipv6.max;          if (head->r.print_cond_part)
1207          ccs_print_ipv6(buf, sizeof(buf), min_address);                  goto print_cond_part;
1208          if (!ccs_io_printf(head, "%s", buf))          if (acl->is_deleted)
1209                    return true;
1210    next:
1211            bit = head->r.bit;
1212            if (!ccs_flush(head))
1213                  return false;                  return false;
1214          if (min_address != max_address) {          else if (acl_type == CCS_TYPE_PATH_ACL) {
1215                  ccs_print_ipv6(buf, sizeof(buf), max_address);                  struct ccs_path_acl *ptr
1216                  if (!ccs_io_printf(head, "-%s", buf))                          = container_of(acl, typeof(*ptr), head);
1217                    const u16 perm = ptr->perm;
1218                    for ( ; bit < CCS_MAX_PATH_OPERATION; bit++) {
1219                            if (!(perm & (1 << bit)))
1220                                    continue;
1221                            if (head->r.print_execute_only &&
1222                                bit != CCS_TYPE_EXECUTE
1223                                /* && bit != CCS_TYPE_TRANSIT */)
1224                                    continue;
1225                            break;
1226                    }
1227                    if (bit >= CCS_MAX_PATH_OPERATION)
1228                            goto done;
1229                    ccs_set_group(head);
1230                    ccs_set_string(head, "file ");
1231                    ccs_set_string(head, ccs_path_keyword[bit]);
1232                    ccs_print_name_union(head, &ptr->name);
1233            } else if (acl_type == CCS_TYPE_AUTO_EXECUTE_HANDLER ||
1234                       acl_type == CCS_TYPE_DENIED_EXECUTE_HANDLER) {
1235                    struct ccs_handler_acl *ptr
1236                            = container_of(acl, typeof(*ptr), head);
1237                    ccs_set_group(head);
1238                    ccs_set_string(head, "task ");
1239                    ccs_set_string(head, acl_type == CCS_TYPE_AUTO_EXECUTE_HANDLER
1240                                   ? "auto_execute_handler " :
1241                                   "denied_execute_handler ");
1242                    ccs_set_string(head, ptr->handler->name);
1243            } else if (acl_type == CCS_TYPE_AUTO_TASK_ACL ||
1244                       acl_type == CCS_TYPE_MANUAL_TASK_ACL) {
1245                    struct ccs_task_acl *ptr =
1246                            container_of(acl, typeof(*ptr), head);
1247                    ccs_set_group(head);
1248                    ccs_set_string(head, "task ");
1249                    ccs_set_string(head, acl_type == CCS_TYPE_AUTO_TASK_ACL ?
1250                                   "auto_domain_transition " :
1251                                   "manual_domain_transition ");
1252                    ccs_set_string(head, ptr->domainname->name);
1253            } else if (head->r.print_execute_only) {
1254                    return true;
1255            } else if (acl_type == CCS_TYPE_MKDEV_ACL) {
1256                    struct ccs_mkdev_acl *ptr =
1257                            container_of(acl, typeof(*ptr), head);
1258                    bit = ccs_fns(ptr->perm, bit);
1259                    if (bit >= CCS_MAX_MKDEV_OPERATION)
1260                            goto done;
1261                    ccs_set_group(head);
1262                    ccs_set_string(head, "file ");
1263                    ccs_set_string(head, ccs_mac_keywords[ccs_pnnn2mac[bit]]);
1264                    ccs_print_name_union(head, &ptr->name);
1265                    ccs_print_number_union(head, &ptr->mode);
1266                    ccs_print_number_union(head, &ptr->major);
1267                    ccs_print_number_union(head, &ptr->minor);
1268            } else if (acl_type == CCS_TYPE_PATH2_ACL) {
1269                    struct ccs_path2_acl *ptr =
1270                            container_of(acl, typeof(*ptr), head);
1271                    bit = ccs_fns(ptr->perm, bit);
1272                    if (bit >= CCS_MAX_PATH2_OPERATION)
1273                            goto done;
1274                    ccs_set_group(head);
1275                    ccs_set_string(head, "file ");
1276                    ccs_set_string(head, ccs_mac_keywords[ccs_pp2mac[bit]]);
1277                    ccs_print_name_union(head, &ptr->name1);
1278                    ccs_print_name_union(head, &ptr->name2);
1279            } else if (acl_type == CCS_TYPE_PATH_NUMBER_ACL) {
1280                    struct ccs_path_number_acl *ptr =
1281                            container_of(acl, typeof(*ptr), head);
1282                    bit = ccs_fns(ptr->perm, bit);
1283                    if (bit >= CCS_MAX_PATH_NUMBER_OPERATION)
1284                            goto done;
1285                    ccs_set_group(head);
1286                    ccs_set_string(head, "file ");
1287                    ccs_set_string(head, ccs_mac_keywords[ccs_pn2mac[bit]]);
1288                    ccs_print_name_union(head, &ptr->name);
1289                    ccs_print_number_union(head, &ptr->number);
1290            } else if (acl_type == CCS_TYPE_ENV_ACL) {
1291                    struct ccs_env_acl *ptr =
1292                            container_of(acl, typeof(*ptr), head);
1293                    ccs_set_group(head);
1294                    ccs_set_string(head, "misc env ");
1295                    ccs_set_string(head, ptr->env->name);
1296            } else if (acl_type == CCS_TYPE_CAPABILITY_ACL) {
1297                    struct ccs_capability_acl *ptr =
1298                            container_of(acl, typeof(*ptr), head);
1299                    ccs_set_group(head);
1300                    ccs_set_string(head, "capability ");
1301                    ccs_set_string(head,
1302                                   ccs_mac_keywords[ccs_c2mac[ptr->operation]]);
1303            } else if (acl_type == CCS_TYPE_INET_ACL) {
1304                    struct ccs_inet_acl *ptr =
1305                            container_of(acl, typeof(*ptr), head);
1306                    bit = ccs_fns(ptr->perm, bit);
1307                    if (bit >= CCS_MAX_NETWORK_OPERATION)
1308                            goto done;
1309                    ccs_set_group(head);
1310                    ccs_set_string(head, "network inet ");
1311                    ccs_set_string(head, ccs_proto_keyword[ptr->protocol]);
1312                    ccs_set_space(head);
1313                    ccs_set_string(head, ccs_socket_keyword[bit]);
1314                    ccs_set_space(head);
1315                    switch (ptr->address_type) {
1316                            char buf[128];
1317                    case CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP:
1318                            ccs_set_string(head, "@");
1319                            ccs_set_string(head,
1320                                           ptr->address.group->group_name->name);
1321                            break;
1322                    case CCS_IP_ADDRESS_TYPE_IPv4:
1323                            ccs_print_ipv4(buf, sizeof(buf), ptr->address.ipv4.min,
1324                                           ptr->address.ipv4.max);
1325                            ccs_io_printf(head, "%s", buf);
1326                            break;
1327                    case CCS_IP_ADDRESS_TYPE_IPv6:
1328                            ccs_print_ipv6(buf, sizeof(buf), ptr->address.ipv6.min,
1329                                           ptr->address.ipv6.max);
1330                            ccs_io_printf(head, "%s", buf);
1331                            break;
1332                    }
1333                    ccs_print_number_union(head, &ptr->port);
1334            } else if (acl_type == CCS_TYPE_UNIX_ACL) {
1335                    struct ccs_unix_acl *ptr =
1336                            container_of(acl, typeof(*ptr), head);
1337                    bit = ccs_fns(ptr->perm, bit);
1338                    if (bit >= CCS_MAX_NETWORK_OPERATION)
1339                            goto done;
1340                    ccs_set_group(head);
1341                    ccs_set_string(head, "network unix ");
1342                    ccs_set_string(head, ccs_proto_keyword[ptr->protocol]);
1343                    ccs_set_space(head);
1344                    ccs_set_string(head, ccs_socket_keyword[bit]);
1345                    ccs_print_name_union(head, &ptr->name);
1346            } else if (acl_type == CCS_TYPE_SIGNAL_ACL) {
1347                    struct ccs_signal_acl *ptr =
1348                            container_of(acl, typeof(*ptr), head);
1349                    ccs_set_group(head);
1350                    ccs_set_string(head, "ipc signal ");
1351                    ccs_io_printf(head, "%u ", ptr->sig);
1352                    ccs_set_string(head, ptr->domainname->name);
1353            } else if (acl_type == CCS_TYPE_MOUNT_ACL) {
1354                    struct ccs_mount_acl *ptr =
1355                            container_of(acl, typeof(*ptr), head);
1356                    ccs_set_group(head);
1357                    ccs_io_printf(head, "file mount");
1358                    ccs_print_name_union(head, &ptr->dev_name);
1359                    ccs_print_name_union(head, &ptr->dir_name);
1360                    ccs_print_name_union(head, &ptr->fs_type);
1361                    ccs_print_number_union(head, &ptr->flags);
1362            }
1363            head->r.bit = bit + 1;
1364            if (acl->cond) {
1365                    head->r.print_cond_part = true;
1366                    head->r.cond_step = 0;
1367                    if (!ccs_flush(head))
1368                            return false;
1369    print_cond_part:
1370                    if (!ccs_print_condition(head, acl->cond))
1371                          return false;                          return false;
1372                    head->r.print_cond_part = false;
1373            } else {
1374                    ccs_set_lf(head);
1375          }          }
1376          return true;          switch (acl_type) {
1377  }          case CCS_TYPE_PATH_ACL:
1378            case CCS_TYPE_MKDEV_ACL:
1379  /**          case CCS_TYPE_PATH2_ACL:
1380   * ccs_print_network_acl - Print a network ACL entry.          case CCS_TYPE_PATH_NUMBER_ACL:
1381   *          case CCS_TYPE_INET_ACL:
1382   * @head: Pointer to "struct ccs_io_buffer".          case CCS_TYPE_UNIX_ACL:
1383   * @ptr:  Pointer to "struct ccs_ip_network_acl_record".                  goto next;
  * @cond: Pointer to "struct ccs_condition". May be NULL.  
  *  
  * Returns true on success, false otherwise.  
  */  
 static bool ccs_print_network_acl(struct ccs_io_buffer *head,  
                                   struct ccs_ip_network_acl_record *ptr,  
                                   const struct ccs_condition *cond)  
 {  
         int pos = head->read_avail;  
         if (!ccs_io_printf(head, KEYWORD_ALLOW_NETWORK "%s ",  
                            ccs_net2keyword(ptr->operation_type)))  
                 goto out;  
         switch (ptr->record_type) {  
         case IP_RECORD_TYPE_ADDRESS_GROUP:  
                 if (!ccs_io_printf(head, "@%s",  
                                    ptr->address.group->group_name->name))  
                         goto out;  
                 break;  
         case IP_RECORD_TYPE_IPv4:  
                 if (!ccs_print_ipv4_entry(head, ptr))  
                         goto out;  
                 break;  
         case IP_RECORD_TYPE_IPv6:  
                 if (!ccs_print_ipv6_entry(head, ptr))  
                         goto out;  
                 break;  
1384          }          }
1385          if (!ccs_print_number_union(head, &ptr->port) ||  done:
1386              !ccs_print_condition(head, cond))          head->r.bit = 0;
                 goto out;  
1387          return true;          return true;
  out:  
         head->read_avail = pos;  
         return false;  
1388  }  }
1389    
1390  /**  /**
1391   * ccs_print_signal_acl - Print a signal ACL entry.   * ccs_read_domain2 - Read domain policy.
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  * @ptr:  Pointer to "struct signale_acl_record".  
  * @cond: Pointer to "struct ccs_condition". May be NULL.  
1392   *   *
1393   * Returns true on success, false otherwise.   * @head:   Pointer to "struct ccs_io_buffer".
1394   */   * @domain: Pointer to "struct ccs_domain_info".
1395  static bool ccs_print_signal_acl(struct ccs_io_buffer *head,   * @index:  Index number.
                                  struct ccs_signal_acl_record *ptr,  
                                  const struct ccs_condition *cond)  
 {  
         int pos = head->read_avail;  
         if (!ccs_io_printf(head, KEYWORD_ALLOW_SIGNAL "%u %s",  
                            ptr->sig, ptr->domainname->name))  
                 goto out;  
         if (!ccs_print_condition(head, cond))  
                 goto out;  
         return true;  
  out:  
         head->read_avail = pos;  
         return false;  
 }  
   
 /**  
  * ccs_print_execute_handler_record - Print an execute handler ACL entry.  
1396   *   *
1397   * @head:    Pointer to "struct ccs_io_buffer".   * Caller holds ccs_read_lock().
  * @keyword: Name of the keyword.  
  * @ptr:     Pointer to "struct ccs_execute_handler_record".  
  *  
  * Returns true on success, false otherwise.  
  */  
 static bool ccs_print_execute_handler_record(struct ccs_io_buffer *head,  
                                              const char *keyword,  
                                              struct ccs_execute_handler_record *  
                                              ptr)  
 {  
         return ccs_io_printf(head, "%s %s\n", keyword, ptr->handler->name);  
 }  
   
 /**  
  * ccs_print_mount_acl - Print a mount ACL entry.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  * @ptr:  Pointer to "struct ccs_mount_acl_record".  
  * @cond: Pointer to "struct ccs_condition". May be NULL.  
  *  
  * Returns true on success, false otherwise.  
  */  
 static bool ccs_print_mount_acl(struct ccs_io_buffer *head,  
                                 struct ccs_mount_acl_record *ptr,  
                                 const struct ccs_condition *cond)  
 {  
         int pos = head->read_avail;  
         if (!ccs_io_printf(head, KEYWORD_ALLOW_MOUNT "%s %s %s 0x%lX\n",  
                            ptr->dev_name->name, ptr->dir_name->name,  
                            ptr->fs_type->name, ptr->flags))  
                 goto out;  
         if (!ccs_print_condition(head, cond))  
                 goto out;  
         return true;  
  out:  
         head->read_avail = pos;  
         return false;  
 }  
   
 /**  
  * ccs_print_umount_acl - Print a mount ACL entry.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  * @ptr:  Pointer to "struct ccs_umount_acl_record".  
  * @cond: Pointer to "struct ccs_condition". May be NULL.  
  *  
  * Returns true on success, false otherwise.  
  */  
 static bool ccs_print_umount_acl(struct ccs_io_buffer *head,  
                                  struct ccs_umount_acl_record *ptr,  
                                  const struct ccs_condition *cond)  
 {  
         int pos = head->read_avail;  
         if (!ccs_io_printf(head, KEYWORD_ALLOW_UNMOUNT "%s\n",  
                            ptr->dir->name))  
                 goto out;  
         if (!ccs_print_condition(head, cond))  
                 goto out;  
         return true;  
  out:  
         head->read_avail = pos;  
         return false;  
 }  
   
 /**  
  * ccs_print_chroot_acl - Print a chroot ACL entry.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  * @ptr:  Pointer to "struct ccs_chroot_acl_record".  
  * @cond: Pointer to "struct ccs_condition". May be NULL.  
  *  
  * Returns true on success, false otherwise.  
  */  
 static bool ccs_print_chroot_acl(struct ccs_io_buffer *head,  
                                  struct ccs_chroot_acl_record *ptr,  
                                  const struct ccs_condition *cond)  
 {  
         int pos = head->read_avail;  
         if (!ccs_io_printf(head, KEYWORD_ALLOW_CHROOT "%s\n",  
                            ptr->dir->name))  
                 goto out;  
         if (!ccs_print_condition(head, cond))  
                 goto out;  
         return true;  
  out:  
         head->read_avail = pos;  
         return false;  
 }  
   
 /**  
  * ccs_print_pivot_root_acl - Print a pivot_root ACL entry.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  * @ptr:  Pointer to "struct ccs_pivot_root_acl_record".  
  * @cond: Pointer to "struct ccs_condition". May be NULL.  
  *  
  * Returns true on success, false otherwise.  
  */  
 static bool ccs_print_pivot_root_acl(struct ccs_io_buffer *head,  
                                      struct ccs_pivot_root_acl_record *ptr,  
                                      const struct ccs_condition *cond)  
 {  
         int pos = head->read_avail;  
         if (!ccs_io_printf(head, KEYWORD_ALLOW_PIVOT_ROOT "%s %s\n",  
                            ptr->new_root->name, ptr->old_root->name))  
                 goto out;  
         if (!ccs_print_condition(head, cond))  
                 goto out;  
         return true;  
  out:  
         head->read_avail = pos;  
         return false;  
 }  
   
 /**  
  * ccs_print_entry - Print an ACL entry.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  * @ptr:  Pointer to an ACL entry.  
1398   *   *
1399   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
1400   */   */
1401  static bool ccs_print_entry(struct ccs_io_buffer *head,  static bool ccs_read_domain2(struct ccs_io_buffer *head,
1402                              struct ccs_acl_info *ptr)                               struct ccs_domain_info *domain,
1403  {                               const u8 index)
1404          const struct ccs_condition *cond = ptr->cond;  {
1405          const u8 acl_type = ccs_acl_type2(ptr);          list_for_each_cookie(head->r.acl, &domain->acl_info_list[index]) {
1406          if (acl_type & ACL_DELETED)                  struct ccs_acl_info *ptr =
1407                  return true;                          list_entry(head->r.acl, typeof(*ptr), list);
1408          if (acl_type == TYPE_SINGLE_PATH_ACL) {                  if (!ccs_print_entry(head, ptr))
1409                  struct ccs_single_path_acl_record *acl                          return false;
                         = container_of(ptr, struct ccs_single_path_acl_record,  
                                        head);  
                 return ccs_print_single_path_acl(head, acl, cond);  
         }  
         if (acl_type == TYPE_EXECUTE_HANDLER) {  
                 struct ccs_execute_handler_record *acl  
                         = container_of(ptr, struct ccs_execute_handler_record,  
                                        head);  
                 const char *keyword = KEYWORD_EXECUTE_HANDLER;  
                 return ccs_print_execute_handler_record(head, keyword, acl);  
         }  
         if (acl_type == TYPE_DENIED_EXECUTE_HANDLER) {  
                 struct ccs_execute_handler_record *acl  
                         = container_of(ptr, struct ccs_execute_handler_record,  
                                        head);  
                 const char *keyword = KEYWORD_DENIED_EXECUTE_HANDLER;  
                 return ccs_print_execute_handler_record(head, keyword, acl);  
         }  
         if (head->read_execute_only)  
                 return true;  
         if (acl_type == TYPE_MKDEV_ACL) {  
                 struct ccs_mkdev_acl_record *acl  
                         = container_of(ptr, struct ccs_mkdev_acl_record, head);  
                 return ccs_print_mkdev_acl(head, acl, cond);  
         }  
         if (acl_type == TYPE_DOUBLE_PATH_ACL) {  
                 struct ccs_double_path_acl_record *acl  
                         = container_of(ptr, struct ccs_double_path_acl_record,  
                                        head);  
                 return ccs_print_double_path_acl(head, acl, cond);  
         }  
         if (acl_type == TYPE_PATH_NUMBER_ACL) {  
                 struct ccs_path_number_acl_record *acl  
                         = container_of(ptr, struct ccs_path_number_acl_record,  
                                        head);  
                 return ccs_print_path_number_acl(head, acl, cond);  
         }  
         if (acl_type == TYPE_ARGV0_ACL) {  
                 struct ccs_argv0_acl_record *acl  
                         = container_of(ptr, struct ccs_argv0_acl_record, head);  
                 return ccs_print_argv0_acl(head, acl, cond);  
         }  
         if (acl_type == TYPE_ENV_ACL) {  
                 struct ccs_env_acl_record *acl  
                         = container_of(ptr, struct ccs_env_acl_record, head);  
                 return ccs_print_env_acl(head, acl, cond);  
         }  
         if (acl_type == TYPE_CAPABILITY_ACL) {  
                 struct ccs_capability_acl_record *acl  
                         = container_of(ptr, struct ccs_capability_acl_record,  
                                        head);  
                 return ccs_print_capability_acl(head, acl, cond);  
         }  
         if (acl_type == TYPE_IP_NETWORK_ACL) {  
                 struct ccs_ip_network_acl_record *acl  
                         = container_of(ptr, struct ccs_ip_network_acl_record,  
                                        head);  
                 return ccs_print_network_acl(head, acl, cond);  
         }  
         if (acl_type == TYPE_SIGNAL_ACL) {  
                 struct ccs_signal_acl_record *acl  
                         = container_of(ptr, struct ccs_signal_acl_record, head);  
                 return ccs_print_signal_acl(head, acl, cond);  
         }  
         if (acl_type == TYPE_MOUNT_ACL) {  
                 struct ccs_mount_acl_record *acl  
                         = container_of(ptr, struct ccs_mount_acl_record, head);  
                 return ccs_print_mount_acl(head, acl, cond);  
         }  
         if (acl_type == TYPE_UMOUNT_ACL) {  
                 struct ccs_umount_acl_record *acl  
                         = container_of(ptr, struct ccs_umount_acl_record, head);  
                 return ccs_print_umount_acl(head, acl, cond);  
         }  
         if (acl_type == TYPE_CHROOT_ACL) {  
                 struct ccs_chroot_acl_record *acl  
                         = container_of(ptr, struct ccs_chroot_acl_record, head);  
                 return ccs_print_chroot_acl(head, acl, cond);  
         }  
         if (acl_type == TYPE_PIVOT_ROOT_ACL) {  
                 struct ccs_pivot_root_acl_record *acl  
                         = container_of(ptr, struct ccs_pivot_root_acl_record,  
                                        head);  
                 return ccs_print_pivot_root_acl(head, acl, cond);  
1410          }          }
1411          /* Workaround for gcc 3.2.2's inline bug. */          head->r.acl = NULL;
1412          if (acl_type & ACL_DELETED)          return true;
                 return true;  
         BUG(); /* This must not happen. */  
         return false;  
1413  }  }
1414    
1415  /**  /**
1416   * ccs_read_domain_policy - Read domain policy.   * ccs_read_domain - Read domain policy.
1417   *   *
1418   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
1419   *   *
  * Returns 0.  
  *  
1420   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
1421   */   */
1422  static int ccs_read_domain_policy(struct ccs_io_buffer *head)  static void ccs_read_domain(struct ccs_io_buffer *head)
1423  {  {
1424          struct list_head *dpos;          if (head->r.eof)
1425          struct list_head *apos;                  return;
1426          ccs_check_read_lock();          list_for_each_cookie(head->r.domain, &ccs_domain_list) {
1427          if (head->read_eof)                  struct ccs_domain_info *domain =
1428                  return 0;                          list_entry(head->r.domain, typeof(*domain), list);
1429          if (head->read_step == 0)                  switch (head->r.step) {
1430                  head->read_step = 1;                          u8 i;
1431          list_for_each_cookie(dpos, head->read_var1, &ccs_domain_list) {                  case 0:
1432                  struct ccs_domain_info *domain;                          if (domain->is_deleted &&
1433                  const char *quota_exceeded = "";                              !head->r.print_this_domain_only)
1434                  const char *transition_failed = "";                                  continue;
1435                  const char *ignore_global_allow_read = "";                          /* Print domainname and flags. */
1436                  const char *ignore_global_allow_env = "";                          ccs_set_string(head, domain->domainname->name);
1437                  domain = list_entry(dpos, struct ccs_domain_info, list);                          ccs_set_lf(head);
1438                  if (head->read_step != 1)                          ccs_io_printf(head, "use_profile %u\n",
1439                          goto acl_loop;                                        domain->profile);
1440                  if (domain->is_deleted && !head->read_single_domain)                          ccs_io_printf(head, "use_group %u\n", domain->group);
1441                          continue;                          for (i = 0; i < CCS_MAX_DOMAIN_INFO_FLAGS; i++)
1442                  /* Print domainname and flags. */                                  if (domain->flags[i])
1443                  if (domain->quota_warned)                                          ccs_set_string(head, ccs_dif[i]);
1444                          quota_exceeded = "quota_exceeded\n";                          head->r.step++;
1445                  if (domain->domain_transition_failed)                          ccs_set_lf(head);
1446                          transition_failed = "transition_failed\n";                          /* fall through */
1447                  if (domain->ignore_global_allow_read)                  case 1:
1448                          ignore_global_allow_read                          if (!ccs_read_domain2(head, domain, 0))
1449                                  = KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n";                                  return;
1450                  if (domain->ignore_global_allow_env)                          head->r.step++;
1451                          ignore_global_allow_env                          /* fall through */
1452                                  = KEYWORD_IGNORE_GLOBAL_ALLOW_ENV "\n";                  case 2:
1453                  if (!ccs_io_printf(head, "%s\n" KEYWORD_USE_PROFILE "%u\n"                          if (!ccs_read_domain2(head, domain, 1))
1454                                     "%s%s%s%s\n", domain->domainname->name,                                  return;
1455                                     domain->profile, quota_exceeded,                          head->r.step++;
1456                                     transition_failed,                          if (!ccs_set_lf(head))
1457                                     ignore_global_allow_read,                                  return;
1458                                     ignore_global_allow_env))                          /* fall through */
1459                          return 0;                  case 3:
1460                  head->read_step = 2;                          head->r.step = 0;
1461   acl_loop:                          if (head->r.print_this_domain_only)
1462                  if (head->read_step == 3)                                  goto done;
1463                          goto tail_mark;                  }
                 /* Print ACL entries in the domain. */  
                 list_for_each_cookie(apos, head->read_var2,  
                                      &domain->acl_info_list) {  
                         struct ccs_acl_info *ptr  
                                 = list_entry(apos, struct ccs_acl_info, list);  
                         if (!ccs_print_entry(head, ptr))  
                                 return 0;  
                 }  
                 head->read_step = 3;  
  tail_mark:  
                 if (!ccs_io_printf(head, "\n"))  
                         return 0;  
                 head->read_step = 1;  
                 if (head->read_single_domain)  
                         break;  
1464          }          }
1465          head->read_eof = true;  done:
1466          return 0;          head->r.eof = true;
1467  }  }
1468    
1469  /**  /**
# Line 1307  static int ccs_read_domain_policy(struct Line 1476  static int ccs_read_domain_policy(struct
1476   * This is equivalent to doing   * This is equivalent to doing
1477   *   *
1478   *     ( echo "select " $domainname; echo "use_profile " $profile ) |   *     ( echo "select " $domainname; echo "use_profile " $profile ) |
1479   *     /usr/lib/ccs/loadpolicy -d   *     /usr/sbin/ccs-loadpolicy -d
1480   *   *
1481   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
1482   */   */
# Line 1317  static int ccs_write_domain_profile(stru Line 1486  static int ccs_write_domain_profile(stru
1486          char *cp = strchr(data, ' ');          char *cp = strchr(data, ' ');
1487          struct ccs_domain_info *domain;          struct ccs_domain_info *domain;
1488          unsigned int profile;          unsigned int profile;
         ccs_check_read_lock();  
1489          if (!cp)          if (!cp)
1490                  return -EINVAL;                  return -EINVAL;
1491          *cp = '\0';          *cp = '\0';
1492          profile = simple_strtoul(data, NULL, 10);          profile = simple_strtoul(data, NULL, 10);
1493          if (profile >= MAX_PROFILES)          if (profile >= CCS_MAX_PROFILES)
1494                  return -EINVAL;                  return -EINVAL;
1495          domain = ccs_find_domain(cp + 1);          domain = ccs_find_domain(cp + 1);
1496          if (domain && (ccs_profile_ptr[profile] || !ccs_policy_loaded))          if (domain && (!ccs_policy_loaded || ccs_profile_ptr[(u8) profile]))
1497                  domain->profile = (u8) profile;                  domain->profile = (u8) profile;
1498          return 0;          return 0;
1499  }  }
# Line 1335  static int ccs_write_domain_profile(stru Line 1503  static int ccs_write_domain_profile(stru
1503   *   *
1504   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
1505   *   *
  * Returns list of profile number and domainname pairs.  
  *  
1506   * This is equivalent to doing   * This is equivalent to doing
1507   *   *
1508   *     grep -A 1 '^<kernel>' /proc/ccs/domain_policy |   *     grep -A 1 '^<kernel>' /proc/ccs/domain_policy |
# Line 1346  static int ccs_write_domain_profile(stru Line 1512  static int ccs_write_domain_profile(stru
1512   *   *
1513   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
1514   */   */
1515  static int ccs_read_domain_profile(struct ccs_io_buffer *head)  static void ccs_read_domain_profile(struct ccs_io_buffer *head)
1516  {  {
1517          struct list_head *pos;          if (head->r.eof)
1518          ccs_check_read_lock();                  return;
1519          if (head->read_eof)          list_for_each_cookie(head->r.domain, &ccs_domain_list) {
1520                  return 0;                  struct ccs_domain_info *domain =
1521          list_for_each_cookie(pos, head->read_var1, &ccs_domain_list) {                          list_entry(head->r.domain, typeof(*domain), list);
                 struct ccs_domain_info *domain;  
                 domain = list_entry(pos, struct ccs_domain_info, list);  
1522                  if (domain->is_deleted)                  if (domain->is_deleted)
1523                          continue;                          continue;
1524                  if (!ccs_io_printf(head, "%u %s\n", domain->profile,                  if (!ccs_flush(head))
1525                                     domain->domainname->name))                          return;
1526                          return 0;                  ccs_io_printf(head, "%u ", domain->profile);
1527                    ccs_set_string(head, domain->domainname->name);
1528                    ccs_set_lf(head);
1529          }          }
1530          head->read_eof = true;          head->r.eof = true;
         return 0;  
1531  }  }
1532    
1533  /**  /**
# Line 1374  static int ccs_read_domain_profile(struc Line 1539  static int ccs_read_domain_profile(struc
1539   */   */
1540  static int ccs_write_pid(struct ccs_io_buffer *head)  static int ccs_write_pid(struct ccs_io_buffer *head)
1541  {  {
1542          head->read_eof = false;          head->r.eof = false;
1543          return 0;          return 0;
1544  }  }
1545    
# Line 1389  static int ccs_write_pid(struct ccs_io_b Line 1554  static int ccs_write_pid(struct ccs_io_b
1554   *   *
1555   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
1556   */   */
1557  static int ccs_read_pid(struct ccs_io_buffer *head)  static void ccs_read_pid(struct ccs_io_buffer *head)
1558  {  {
1559          char *buf = head->write_buf;          char *buf = head->write_buf;
1560          bool task_info = false;          bool task_info = false;
1561            bool global_pid = false;
1562          unsigned int pid;          unsigned int pid;
1563          struct task_struct *p;          struct task_struct *p;
1564          struct ccs_domain_info *domain = NULL;          struct ccs_domain_info *domain = NULL;
1565          u32 ccs_flags = 0;          u32 ccs_flags = 0;
         ccs_check_read_lock();  
1566          /* Accessing write_buf is safe because head->io_sem is held. */          /* Accessing write_buf is safe because head->io_sem is held. */
1567          if (!buf)          if (!buf) {
1568                  goto done; /* Do nothing if open(O_RDONLY). */                  head->r.eof = true;
1569          if (head->read_avail || head->read_eof)                  return; /* Do nothing if open(O_RDONLY). */
1570                  goto done;          }
1571          head->read_eof = true;          if (head->r.w_pos || head->r.eof)
1572                    return;
1573            head->r.eof = true;
1574          if (ccs_str_starts(&buf, "info "))          if (ccs_str_starts(&buf, "info "))
1575                  task_info = true;                  task_info = true;
1576            if (ccs_str_starts(&buf, "global-pid "))
1577                    global_pid = true;
1578          pid = (unsigned int) simple_strtoul(buf, NULL, 10);          pid = (unsigned int) simple_strtoul(buf, NULL, 10);
1579          /***** CRITICAL SECTION START *****/          ccs_tasklist_lock();
1580          read_lock(&tasklist_lock);  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1581            if (global_pid)
1582                    p = ccsecurity_exports.find_task_by_pid_ns(pid, &init_pid_ns);
1583            else
1584                    p = ccsecurity_exports.find_task_by_vpid(pid);
1585    #else
1586          p = find_task_by_pid(pid);          p = find_task_by_pid(pid);
1587    #endif
1588          if (p) {          if (p) {
1589                  domain = ccs_task_domain(p);                  domain = ccs_task_domain(p);
1590                  ccs_flags = p->ccs_flags;                  ccs_flags = ccs_task_flags(p);
1591          }          }
1592          read_unlock(&tasklist_lock);          ccs_tasklist_unlock();
         /***** CRITICAL SECTION END *****/  
1593          if (!domain)          if (!domain)
1594                  goto done;                  return;
1595          if (!task_info)          if (!task_info) {
1596                  ccs_io_printf(head, "%u %u %s", pid, domain->profile,                  ccs_io_printf(head, "%u %u ", pid, domain->profile);
1597                                domain->domainname->name);                  ccs_set_string(head, domain->domainname->name);
1598          else          } else {
1599                  ccs_io_printf(head, "%u manager=%s execute_handler=%s "                  ccs_io_printf(head, "%u manager=%s execute_handler=%s ", pid,
1600                                "state[0]=%u state[1]=%u state[2]=%u", pid,                                ccs_yesno(ccs_flags &
1601                                ccs_flags & CCS_TASK_IS_POLICY_MANAGER ?                                          CCS_TASK_IS_MANAGER),
1602                                "yes" : "no",                                ccs_yesno(ccs_flags &
1603                                ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER ?                                          CCS_TASK_IS_EXECUTE_HANDLER));
1604                                "yes" : "no",          }
                               (u8) (ccs_flags >> 24),  
                               (u8) (ccs_flags >> 16),  
                               (u8) (ccs_flags >> 8));  
  done:  
         return 0;  
1605  }  }
1606    
1607    static const char * const ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = {
1608            [CCS_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
1609            [CCS_TRANSITION_CONTROL_INITIALIZE]    = "initialize_domain ",
1610            [CCS_TRANSITION_CONTROL_NO_KEEP]       = "no_keep_domain ",
1611            [CCS_TRANSITION_CONTROL_KEEP]          = "keep_domain ",
1612    };
1613    
1614    static const char * const ccs_group_name[CCS_MAX_GROUP] = {
1615            [CCS_PATH_GROUP]    = "path_group ",
1616            [CCS_NUMBER_GROUP]  = "number_group ",
1617            [CCS_ADDRESS_GROUP] = "address_group ",
1618    };
1619    
1620  /**  /**
1621   * ccs_write_exception_policy - Write exception policy.   * ccs_write_exception - Write exception policy.
1622   *   *
1623   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
1624   *   *
1625   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
1626   */   */
1627  static int ccs_write_exception_policy(struct ccs_io_buffer *head)  static int ccs_write_exception(struct ccs_io_buffer *head)
1628  {  {
1629          char *data = head->write_buf;          char *data = head->write_buf;
1630          bool is_delete = ccs_str_starts(&data, KEYWORD_DELETE);          const bool is_delete = ccs_str_starts(&data, "delete ");
1631          if (ccs_str_starts(&data, KEYWORD_KEEP_DOMAIN))          u8 i;
1632                  return ccs_write_domain_keeper_policy(data, false, is_delete);          static const struct {
1633          if (ccs_str_starts(&data, KEYWORD_NO_KEEP_DOMAIN))                  const char *keyword;
1634                  return ccs_write_domain_keeper_policy(data, true, is_delete);                  int (*write) (char *, const bool);
1635          if (ccs_str_starts(&data, KEYWORD_INITIALIZE_DOMAIN))          } ccs_callback[2] = {
1636                  return ccs_write_domain_initializer_policy(data, false,                  { "aggregator ",    ccs_write_aggregator },
1637                                                             is_delete);                  { "deny_autobind ", ccs_write_reserved_port },
1638          if (ccs_str_starts(&data, KEYWORD_NO_INITIALIZE_DOMAIN))          };
1639                  return ccs_write_domain_initializer_policy(data, true,          for (i = 0; i < 2; i++)
1640                                                             is_delete);                  if (ccs_str_starts(&data, ccs_callback[i].keyword))
1641          if (ccs_str_starts(&data, KEYWORD_AGGREGATOR))                          return ccs_callback[i].write(data, is_delete);
1642                  return ccs_write_aggregator_policy(data, is_delete);          for (i = 0; i < CCS_MAX_TRANSITION_TYPE; i++)
1643          if (ccs_str_starts(&data, KEYWORD_ALLOW_READ))                  if (ccs_str_starts(&data, ccs_transition_type[i]))
1644                  return ccs_write_globally_readable_policy(data, is_delete);                          return ccs_write_transition_control(data, is_delete,
1645          if (ccs_str_starts(&data, KEYWORD_ALLOW_ENV))                                                              i);
1646                  return ccs_write_globally_usable_env_policy(data, is_delete);          for (i = 0; i < CCS_MAX_GROUP; i++)
1647          if (ccs_str_starts(&data, KEYWORD_FILE_PATTERN))                  if (ccs_str_starts(&data, ccs_group_name[i]))
1648                  return ccs_write_pattern_policy(data, is_delete);                          return ccs_write_group(data, is_delete, i);
1649          if (ccs_str_starts(&data, KEYWORD_PATH_GROUP))          if (ccs_str_starts(&data, "acl_group ")) {
1650                  return ccs_write_path_group_policy(data, is_delete);                  unsigned int group;
1651          if (ccs_str_starts(&data, KEYWORD_NUMBER_GROUP))                  if (sscanf(data, "%u", &group) == 1 &&
1652                  return ccs_write_number_group_policy(data, is_delete);                      group < CCS_MAX_ACL_GROUPS) {
1653          if (ccs_str_starts(&data, KEYWORD_DENY_REWRITE))                          data = strchr(data, ' ');
1654                  return ccs_write_no_rewrite_policy(data, is_delete);                          if (data)
1655          if (ccs_str_starts(&data, KEYWORD_ADDRESS_GROUP))                                  return ccs_write_domain2(data + 1,
1656                  return ccs_write_address_group_policy(data, is_delete);                                                           &ccs_acl_group[group],
1657          if (ccs_str_starts(&data, KEYWORD_DENY_AUTOBIND))                                                           is_delete);
1658                  return ccs_write_reserved_port_policy(data, is_delete);                  }
1659            }
1660          return -EINVAL;          return -EINVAL;
1661  }  }
1662    
1663  /**  /**
1664   * ccs_read_exception_policy - Read exception policy.   * ccs_read_group - Read "struct ccs_path_group"/"struct ccs_number_group"/"struct ccs_address_group" list.
1665   *   *
1666   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
1667     * @idx:  Index number.
1668   *   *
1669   * Returns 0 on success, -EINVAL otherwise.   * Returns true on success, false otherwise.
1670   *   *
1671   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
1672   */   */
1673  static int ccs_read_exception_policy(struct ccs_io_buffer *head)  static bool ccs_read_group(struct ccs_io_buffer *head, const int idx)
1674  {  {
1675          ccs_check_read_lock();          list_for_each_cookie(head->r.group, &ccs_group_list[idx]) {
1676          if (!head->read_eof) {                  struct ccs_group *group =
1677                  switch (head->read_step) {                          list_entry(head->r.group, typeof(*group), head.list);
1678                  case 0:                  list_for_each_cookie(head->r.acl, &group->member_list) {
1679                          head->read_var2 = NULL;                          struct ccs_acl_head *ptr =
1680                          head->read_step = 1;                                  list_entry(head->r.acl, typeof(*ptr), list);
1681                  case 1:                          if (ptr->is_deleted)
1682                          if (!ccs_read_domain_keeper_policy(head))                                  continue;
1683                                  break;                          if (!ccs_flush(head))
1684                          head->read_var2 = NULL;                                  return false;
1685                          head->read_step = 2;                          ccs_set_string(head, ccs_group_name[idx]);
1686                  case 2:                          ccs_set_string(head, group->group_name->name);
1687                          if (!ccs_read_globally_readable_policy(head))                          if (idx == CCS_PATH_GROUP) {
1688                                  break;                                  ccs_set_space(head);
1689                          head->read_var2 = NULL;                                  ccs_set_string(head, container_of
1690                          head->read_step = 3;                                                 (ptr, struct ccs_path_group,
1691                  case 3:                                                  head)->member_name->name);
1692                          if (!ccs_read_globally_usable_env_policy(head))                          } else if (idx == CCS_NUMBER_GROUP) {
1693                                  break;                                  ccs_print_number_union(head, &container_of
1694                          head->read_var2 = NULL;                                                 (ptr, struct ccs_number_group,
1695                          head->read_step = 4;                                                  head)->number);
1696                  case 4:                          } else if (idx == CCS_ADDRESS_GROUP) {
1697                          if (!ccs_read_domain_initializer_policy(head))                                  char buffer[128];
1698                                  break;                                  struct ccs_address_group *member =
1699                          head->read_var2 = NULL;                                          container_of(ptr, typeof(*member),
1700                          head->read_step = 6;                                                       head);
1701                  case 6:                                  if (member->is_ipv6)
1702                          if (!ccs_read_aggregator_policy(head))                                          ccs_print_ipv6(buffer, sizeof(buffer),
1703                                  break;                                                         member->min.ipv6,
1704                          head->read_var2 = NULL;                                                         member->max.ipv6);
1705                          head->read_step = 7;                                  else
1706                  case 7:                                          ccs_print_ipv4(buffer, sizeof(buffer),
1707                          if (!ccs_read_file_pattern(head))                                                         member->min.ipv4,
1708                                  break;                                                         member->max.ipv4);
1709                          head->read_var2 = NULL;                                  ccs_io_printf(head, " %s", buffer);
1710                          head->read_step = 8;                          }
1711                  case 8:                          ccs_set_lf(head);
1712                          if (!ccs_read_no_rewrite_policy(head))                  }
1713                                  break;                  head->r.acl = NULL;
1714                          head->read_var2 = NULL;          }
1715                          head->read_step = 9;          head->r.group = NULL;
1716                  case 9:          return true;
1717                          if (!ccs_read_path_group_policy(head))  }
1718                                  break;  
1719                          head->read_var1 = NULL;  /**
1720                          head->read_var2 = NULL;   * ccs_read_policy - Read "struct ccs_..._entry" list.
1721                          head->read_step = 10;   *
1722                  case 10:   * @head: Pointer to "struct ccs_io_buffer".
1723                          if (!ccs_read_number_group_policy(head))   * @idx:  Index number.
1724                                  break;   *
1725                          head->read_var1 = NULL;   * Returns true on success, false otherwise.
1726                          head->read_var2 = NULL;   *
1727                          head->read_step = 11;   * Caller holds ccs_read_lock().
1728                  case 11:   */
1729                          if (!ccs_read_address_group_policy(head))  static bool ccs_read_policy(struct ccs_io_buffer *head, const int idx)
1730                                  break;  {
1731                          head->read_var2 = NULL;          list_for_each_cookie(head->r.acl, &ccs_policy_list[idx]) {
1732                          head->read_step = 12;                  struct ccs_acl_head *acl =
1733                  case 12:                          container_of(head->r.acl, typeof(*acl), list);
1734                          if (!ccs_read_reserved_port_policy(head))                  if (acl->is_deleted)
1735                                  break;                          continue;
1736                          head->read_eof = true;                  if (!ccs_flush(head))
1737                            return false;
1738                    switch (idx) {
1739                    case CCS_ID_TRANSITION_CONTROL:
1740                            {
1741                                    struct ccs_transition_control *ptr =
1742                                            container_of(acl, typeof(*ptr), head);
1743                                    ccs_set_string(head,
1744                                                   ccs_transition_type[ptr->type]);
1745                                    ccs_set_string(head, ptr->program ?
1746                                                   ptr->program->name : "any");
1747                                    ccs_set_string(head, " from ");
1748                                    ccs_set_string(head, ptr->domainname ?
1749                                                   ptr->domainname->name : "any");
1750                            }
1751                            break;
1752                    case CCS_ID_AGGREGATOR:
1753                            {
1754                                    struct ccs_aggregator *ptr =
1755                                            container_of(acl, typeof(*ptr), head);
1756                                    ccs_set_string(head, "aggregator ");
1757                                    ccs_set_string(head, ptr->original_name->name);
1758                                    ccs_set_space(head);
1759                                    ccs_set_string(head,
1760                                                   ptr->aggregated_name->name);
1761                            }
1762                            break;
1763                    case CCS_ID_RESERVEDPORT:
1764                            {
1765                                    struct ccs_reserved *ptr =
1766                                            container_of(acl, typeof(*ptr), head);
1767                                    const u16 min_port = ptr->min_port;
1768                                    const u16 max_port = ptr->max_port;
1769                                    ccs_set_string(head, "deny_autobind ");
1770                                    ccs_io_printf(head, "%u", min_port);
1771                                    if (min_port != max_port)
1772                                            ccs_io_printf(head, "-%u", max_port);
1773                            }
1774                          break;                          break;
1775                  default:                  default:
1776                          return -EINVAL;                          continue;
1777                  }                  }
1778                    ccs_set_lf(head);
1779          }          }
1780          return 0;          head->r.acl = NULL;
1781            return true;
1782    }
1783    
1784    /**
1785     * ccs_read_exception - Read exception policy.
1786     *
1787     * @head: Pointer to "struct ccs_io_buffer".
1788     *
1789     * Caller holds ccs_read_lock().
1790     */
1791    static void ccs_read_exception(struct ccs_io_buffer *head)
1792    {
1793            if (head->r.eof)
1794                    return;
1795            while (head->r.step < CCS_MAX_POLICY &&
1796                   ccs_read_policy(head, head->r.step))
1797                    head->r.step++;
1798            if (head->r.step < CCS_MAX_POLICY)
1799                    return;
1800            while (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP &&
1801                   ccs_read_group(head, head->r.step - CCS_MAX_POLICY))
1802                    head->r.step++;
1803            if (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP)
1804                    return;
1805            while (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP
1806                   + CCS_MAX_ACL_GROUPS * 2) {
1807                    head->r.group_index = (head->r.step - CCS_MAX_POLICY
1808                                           - CCS_MAX_GROUP) / 2;
1809                    if (!ccs_read_domain2(head,
1810                                          &ccs_acl_group[head->r.group_index],
1811                                          head->r.step & 1))
1812                            return;
1813                    head->r.step++;
1814            }
1815            head->r.eof = true;
1816  }  }
1817    
1818  /* Wait queue for ccs_query_list. */  /* Wait queue for ccs_query_list. */
1819  static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait);  static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait);
1820    static DECLARE_WAIT_QUEUE_HEAD(ccs_answer_wait);
1821    
1822  /* Lock for manipulating ccs_query_list. */  /* Lock for manipulating ccs_query_list. */
1823  static DEFINE_SPINLOCK(ccs_query_list_lock);  static DEFINE_SPINLOCK(ccs_query_list_lock);
1824    
1825  /* Structure for query. */  /* Structure for query. */
1826  struct ccs_query_entry {  struct ccs_query {
1827          struct list_head list;          struct list_head list;
1828          char *query;          char *query;
1829          int query_len;          int query_len;
1830          unsigned int serial;          unsigned int serial;
1831          int timer;          int timer;
1832          int answer;          int answer;
1833            u8 retry;
1834  };  };
1835    
1836  /* The list for "struct ccs_query_entry". */  /* The list for "struct ccs_query". */
1837  static LIST_HEAD(ccs_query_list);  static LIST_HEAD(ccs_query_list);
1838    
1839  /* Number of "struct file" referring /proc/ccs/query interface. */  /* Number of "struct file" referring /proc/ccs/query interface. */
1840  static atomic_t ccs_query_observers = ATOMIC_INIT(0);  static atomic_t ccs_query_observers = ATOMIC_INIT(0);
1841    
1842    static int ccs_truncate(char *str)
1843    {
1844            char *start = str;
1845            while (*(unsigned char *) str > (unsigned char) ' ')
1846                    str++;
1847            *str = '\0';
1848            return strlen(start) + 1;
1849    }
1850    
1851    static void ccs_add_entry(char *header)
1852    {
1853            char *buffer;
1854            char *realpath = NULL;
1855            char *argv0 = NULL;
1856            char *symlink = NULL;
1857            char *handler;
1858            char *cp = strchr(header, '\n');
1859            int len;
1860            if (!cp)
1861                    return;
1862            cp = strchr(cp + 1, '\n');
1863            if (!cp)
1864                    return;
1865            *cp++ = '\0';
1866            len = strlen(cp) + 1;
1867            /* strstr() will return NULL if ordering is wrong. */
1868            if (*cp == 'f') {
1869                    argv0 = strstr(header, " argv[]={ \"");
1870                    if (argv0) {
1871                            argv0 += 10;
1872                            len += ccs_truncate(argv0) + 14;
1873                    }
1874                    realpath = strstr(header, " exec={ realpath=\"");
1875                    if (realpath) {
1876                            realpath += 8;
1877                            len += ccs_truncate(realpath) + 6;
1878                    }
1879                    symlink = strstr(header, " symlink.target=\"");
1880                    if (symlink)
1881                            len += ccs_truncate(symlink + 1) + 1;
1882            }
1883            handler = strstr(header, "type=execute_handler");
1884            if (handler)
1885                    len += ccs_truncate(handler) + 6;
1886            buffer = kmalloc(len, CCS_GFP_FLAGS);
1887            if (!buffer)
1888                    return;
1889            snprintf(buffer, len - 1, "%s", cp);
1890            if (handler)
1891                    ccs_addprintf(buffer, len, " task.%s", handler);
1892            if (realpath)
1893                    ccs_addprintf(buffer, len, " exec.%s", realpath);
1894            if (argv0)
1895                    ccs_addprintf(buffer, len, " exec.argv[0]=%s", argv0);
1896            if (symlink)
1897                    ccs_addprintf(buffer, len, "%s", symlink);
1898            ccs_normalize_line(buffer);
1899            if (!ccs_write_domain2(buffer, ccs_current_domain(), false))
1900                    ccs_update_stat(CCS_STAT_POLICY_UPDATES);
1901            kfree(buffer);
1902    }
1903    
1904  /**  /**
1905   * ccs_check_supervisor - Ask for the supervisor's decision.   * ccs_supervisor - Ask for the supervisor's decision.
1906   *   *
1907   * @r:       Pointer to "struct ccs_request_info".   * @r:   Pointer to "struct ccs_request_info".
1908   * @fmt:     The printf()'s format string, followed by parameters.   * @fmt: The printf()'s format string, followed by parameters.
1909   *   *
1910   * Returns 0 if the supervisor decided to permit the access request which   * Returns 0 if the supervisor decided to permit the access request which
1911   * violated the policy in enforcing mode, 1 if the supervisor decided to   * violated the policy in enforcing mode, CCS_RETRY_REQUEST if the supervisor
1912   * retry the access request which violated the policy in enforcing mode,   * decided to retry the access request which violated the policy in enforcing
1913   * -EPERM otherwise.   * mode, 0 if it is not in enforcing mode, -EPERM otherwise.
1914   */   */
1915  int ccs_check_supervisor(struct ccs_request_info *r, const char *fmt, ...)  int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...)
1916  {  {
1917          va_list args;          va_list args;
1918          int error = -EPERM;          int error;
         int pos;  
1919          int len;          int len;
1920          static unsigned int ccs_serial;          static unsigned int ccs_serial;
1921          struct ccs_query_entry *ccs_query_entry = NULL;          struct ccs_query entry = { };
1922          bool quota_exceeded = false;          bool quota_exceeded = false;
1923          char *header;          va_start(args, fmt);
1924          if (!r->domain)          len = vsnprintf((char *) &len, 1, fmt, args) + 1;
1925                  r->domain = ccs_current_domain();          va_end(args);
1926          if (!atomic_read(&ccs_query_observers)) {          /* Write /proc/ccs/grant_log or /proc/ccs/reject_log . */
1927            va_start(args, fmt);
1928            ccs_write_log2(r, len, fmt, args);
1929            va_end(args);
1930            /* Nothing more to do if granted. */
1931            if (r->granted)
1932                    return 0;
1933            if (r->mode)
1934                    ccs_update_stat(r->mode);
1935            switch (r->mode) {
1936                  int i;                  int i;
1937                  if (current->ccs_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR)                  struct ccs_profile *p;
1938                          return -EPERM;          case CCS_CONFIG_ENFORCING:
1939                  for (i = 0; i < ccs_check_flags(r->domain, CCS_SLEEP_PERIOD);                  error = -EPERM;
1940                       i++) {                  if (atomic_read(&ccs_query_observers))
1941                            break;
1942                    if (ccs_current_flags() & CCS_DONT_SLEEP_ON_ENFORCE_ERROR)
1943                            goto out;
1944                    p = ccs_profile(r->profile);
1945                    /* Check enforcing_penalty parameter. */
1946                    for (i = 0; i < p->pref[CCS_PREF_ENFORCING_PENALTY]; i++) {
1947                          set_current_state(TASK_INTERRUPTIBLE);                          set_current_state(TASK_INTERRUPTIBLE);
1948                          schedule_timeout(HZ / 10);                          schedule_timeout(HZ / 10);
1949                  }                  }
1950                  return -EPERM;                  goto out;
1951            case CCS_CONFIG_LEARNING:
1952                    error = 0;
1953                    /* Check mac_learning_entry parameter. */
1954                    if (ccs_domain_quota_ok(r))
1955                            break;
1956                    /* fall through */
1957            default:
1958                    return 0;
1959          }          }
1960            /* Get message. */
1961          va_start(args, fmt);          va_start(args, fmt);
1962          len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;          entry.query = ccs_init_log(r, len, fmt, args);
1963          va_end(args);          va_end(args);
1964          header = ccs_init_audit_log(&len, r);          if (!entry.query)
         if (!header)  
1965                  goto out;                  goto out;
1966          ccs_query_entry = kzalloc(sizeof(*ccs_query_entry), GFP_KERNEL);          entry.query_len = strlen(entry.query) + 1;
1967          if (!ccs_query_entry)          if (!error) {
1968                    ccs_add_entry(entry.query);
1969                  goto out;                  goto out;
1970          ccs_query_entry->query = kzalloc(len, GFP_KERNEL);          }
1971          if (!ccs_query_entry->query)          len = ccs_round2(entry.query_len);
                 goto out;  
         INIT_LIST_HEAD(&ccs_query_entry->list);  
         /***** CRITICAL SECTION START *****/  
1972          spin_lock(&ccs_query_list_lock);          spin_lock(&ccs_query_list_lock);
1973          if (ccs_quota_for_query && ccs_query_memory_size + len +          if (ccs_memory_quota[CCS_MEMORY_QUERY] &&
1974              sizeof(*ccs_query_entry) >= ccs_quota_for_query) {              ccs_memory_used[CCS_MEMORY_QUERY] + len
1975                >= ccs_memory_quota[CCS_MEMORY_QUERY]) {
1976                  quota_exceeded = true;                  quota_exceeded = true;
1977          } else {          } else {
1978                  ccs_query_memory_size += len + sizeof(*ccs_query_entry);                  entry.serial = ccs_serial++;
1979                  ccs_query_entry->serial = ccs_serial++;                  entry.retry = r->retry;
1980                    ccs_memory_used[CCS_MEMORY_QUERY] += len;
1981                    list_add_tail(&entry.list, &ccs_query_list);
1982          }          }
1983          spin_unlock(&ccs_query_list_lock);          spin_unlock(&ccs_query_list_lock);
         /***** CRITICAL SECTION END *****/  
1984          if (quota_exceeded)          if (quota_exceeded)
1985                  goto out;                  goto out;
         pos = snprintf(ccs_query_entry->query, len - 1, "Q%u-%hu\n%s",  
                        ccs_query_entry->serial, r->retry, header);  
         kfree(header);  
         header = NULL;  
         va_start(args, fmt);  
         vsnprintf(ccs_query_entry->query + pos, len - 1 - pos, fmt, args);  
         ccs_query_entry->query_len = strlen(ccs_query_entry->query) + 1;  
         va_end(args);  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&ccs_query_list_lock);  
         list_add_tail(&ccs_query_entry->list, &ccs_query_list);  
         spin_unlock(&ccs_query_list_lock);  
         /***** CRITICAL SECTION END *****/  
1986          /* Give 10 seconds for supervisor's opinion. */          /* Give 10 seconds for supervisor's opinion. */
1987          for (ccs_query_entry->timer = 0;          while (entry.timer < 10) {
1988               atomic_read(&ccs_query_observers) && ccs_query_entry->timer < 100;                  wake_up_all(&ccs_query_wait);
1989               ccs_query_entry->timer++) {                  if (wait_event_interruptible_timeout
1990                  wake_up(&ccs_query_wait);                      (ccs_answer_wait, entry.answer ||
1991                  set_current_state(TASK_INTERRUPTIBLE);                       !atomic_read(&ccs_query_observers), HZ))
                 schedule_timeout(HZ / 10);  
                 if (ccs_query_entry->answer)  
1992                          break;                          break;
1993                    else
1994                            entry.timer++;
1995          }          }
         /***** CRITICAL SECTION START *****/  
1996          spin_lock(&ccs_query_list_lock);          spin_lock(&ccs_query_list_lock);
1997          list_del(&ccs_query_entry->list);          list_del(&entry.list);
1998          ccs_query_memory_size -= len + sizeof(*ccs_query_entry);          ccs_memory_used[CCS_MEMORY_QUERY] -= len;
1999          spin_unlock(&ccs_query_list_lock);          spin_unlock(&ccs_query_list_lock);
2000          /***** CRITICAL SECTION END *****/          switch (entry.answer) {
         switch (ccs_query_entry->answer) {  
2001          case 3: /* Asked to retry by administrator. */          case 3: /* Asked to retry by administrator. */
2002                  error = 1;                  error = CCS_RETRY_REQUEST;
2003                  r->retry++;                  r->retry++;
2004                  break;                  break;
2005          case 1:          case 1:
2006                  /* Granted by administrator. */                  /* Granted by administrator. */
2007                  error = 0;                  error = 0;
2008                  break;                  break;
         case 0:  
                 /* Timed out. */  
                 break;  
2009          default:          default:
2010                  /* Rejected by administrator. */                  /* Timed out or rejected by administrator. */
2011                  break;                  break;
2012          }          }
2013   out:  out:
2014          if (ccs_query_entry)          kfree(entry.query);
                 kfree(ccs_query_entry->query);  
         kfree(ccs_query_entry);  
         kfree(header);  
2015          return error;          return error;
2016  }  }
2017    
# Line 1709  static int ccs_poll_query(struct file *f Line 2031  static int ccs_poll_query(struct file *f
2031          bool found = false;          bool found = false;
2032          u8 i;          u8 i;
2033          for (i = 0; i < 2; i++) {          for (i = 0; i < 2; i++) {
                 /***** CRITICAL SECTION START *****/  
2034                  spin_lock(&ccs_query_list_lock);                  spin_lock(&ccs_query_list_lock);
2035                  list_for_each(tmp, &ccs_query_list) {                  list_for_each(tmp, &ccs_query_list) {
2036                          struct ccs_query_entry *ptr                          struct ccs_query *ptr =
2037                                  = list_entry(tmp, struct ccs_query_entry, list);                                  list_entry(tmp, typeof(*ptr), list);
2038                          if (ptr->answer)                          if (ptr->answer)
2039                                  continue;                                  continue;
2040                          found = true;                          found = true;
2041                          break;                          break;
2042                  }                  }
2043                  spin_unlock(&ccs_query_list_lock);                  spin_unlock(&ccs_query_list_lock);
                 /***** CRITICAL SECTION END *****/  
2044                  if (found)                  if (found)
2045                          return POLLIN | POLLRDNORM;                          return POLLIN | POLLRDNORM;
2046                  if (i)                  if (i)
# Line 1734  static int ccs_poll_query(struct file *f Line 2054  static int ccs_poll_query(struct file *f
2054   * ccs_read_query - Read access requests which violated policy in enforcing mode.   * ccs_read_query - Read access requests which violated policy in enforcing mode.
2055   *   *
2056   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
  *  
  * Returns 0.  
2057   */   */
2058  static int ccs_read_query(struct ccs_io_buffer *head)  static void ccs_read_query(struct ccs_io_buffer *head)
2059  {  {
2060          struct list_head *tmp;          struct list_head *tmp;
2061          int pos = 0;          int pos = 0;
2062          int len = 0;          int len = 0;
2063          char *buf;          char *buf;
2064          if (head->read_avail)          if (head->r.w_pos)
2065                  return 0;                  return;
2066          if (head->read_buf) {          if (head->read_buf) {
2067                  kfree(head->read_buf);                  kfree(head->read_buf);
2068                  head->read_buf = NULL;                  head->read_buf = NULL;
                 head->readbuf_size = 0;  
2069          }          }
         /***** CRITICAL SECTION START *****/  
2070          spin_lock(&ccs_query_list_lock);          spin_lock(&ccs_query_list_lock);
2071          list_for_each(tmp, &ccs_query_list) {          list_for_each(tmp, &ccs_query_list) {
2072                  struct ccs_query_entry *ptr                  struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
                         = list_entry(tmp, struct ccs_query_entry, list);  
2073                  if (ptr->answer)                  if (ptr->answer)
2074                          continue;                          continue;
2075                  if (pos++ != head->read_step)                  if (pos++ != head->r.query_index)
2076                          continue;                          continue;
2077                  len = ptr->query_len;                  len = ptr->query_len;
2078                  break;                  break;
2079          }          }
2080          spin_unlock(&ccs_query_list_lock);          spin_unlock(&ccs_query_list_lock);
         /***** CRITICAL SECTION END *****/  
2081          if (!len) {          if (!len) {
2082                  head->read_step = 0;                  head->r.query_index = 0;
2083                  return 0;                  return;
2084          }          }
2085          buf = kzalloc(len, GFP_KERNEL);          buf = kzalloc(len + 32, CCS_GFP_FLAGS);
2086          if (!buf)          if (!buf)
2087                  return 0;                  return;
2088          pos = 0;          pos = 0;
         /***** CRITICAL SECTION START *****/  
2089          spin_lock(&ccs_query_list_lock);          spin_lock(&ccs_query_list_lock);
2090          list_for_each(tmp, &ccs_query_list) {          list_for_each(tmp, &ccs_query_list) {
2091                  struct ccs_query_entry *ptr                  struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
                         = list_entry(tmp, struct ccs_query_entry, list);  
2092                  if (ptr->answer)                  if (ptr->answer)
2093                          continue;                          continue;
2094                  if (pos++ != head->read_step)                  if (pos++ != head->r.query_index)
2095                          continue;                          continue;
2096                  /*                  /*
2097                   * Some query can be skipped because ccs_query_list                   * Some query can be skipped because ccs_query_list
2098                   * can change, but I don't care.                   * can change, but I don't care.
2099                   */                   */
2100                  if (len == ptr->query_len)                  if (len == ptr->query_len)
2101                          memmove(buf, ptr->query, len);                          snprintf(buf, len + 32, "Q%u-%hu\n%s", ptr->serial,
2102                                     ptr->retry, ptr->query);
2103                  break;                  break;
2104          }          }
2105          spin_unlock(&ccs_query_list_lock);          spin_unlock(&ccs_query_list_lock);
         /***** CRITICAL SECTION END *****/  
2106          if (buf[0]) {          if (buf[0]) {
                 head->read_avail = len;  
                 head->readbuf_size = head->read_avail;  
2107                  head->read_buf = buf;                  head->read_buf = buf;
2108                  head->read_step++;                  head->r.w[head->r.w_pos++] = buf;
2109                    head->r.query_index++;
2110          } else {          } else {
2111                  kfree(buf);                  kfree(buf);
2112          }          }
         return 0;  
2113  }  }
2114    
2115  /**  /**
# Line 1815  static int ccs_write_answer(struct ccs_i Line 2125  static int ccs_write_answer(struct ccs_i
2125          struct list_head *tmp;          struct list_head *tmp;
2126          unsigned int serial;          unsigned int serial;
2127          unsigned int answer;          unsigned int answer;
         /***** CRITICAL SECTION START *****/  
2128          spin_lock(&ccs_query_list_lock);          spin_lock(&ccs_query_list_lock);
2129          list_for_each(tmp, &ccs_query_list) {          list_for_each(tmp, &ccs_query_list) {
2130                  struct ccs_query_entry *ptr                  struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
                         = list_entry(tmp, struct ccs_query_entry, list);  
2131                  ptr->timer = 0;                  ptr->timer = 0;
2132          }          }
2133          spin_unlock(&ccs_query_list_lock);          spin_unlock(&ccs_query_list_lock);
         /***** CRITICAL SECTION END *****/  
2134          if (sscanf(data, "A%u=%u", &serial, &answer) != 2)          if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
2135                  return -EINVAL;                  return -EINVAL;
         /***** CRITICAL SECTION START *****/  
2136          spin_lock(&ccs_query_list_lock);          spin_lock(&ccs_query_list_lock);
2137          list_for_each(tmp, &ccs_query_list) {          list_for_each(tmp, &ccs_query_list) {
2138                  struct ccs_query_entry *ptr                  struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
                         = list_entry(tmp, struct ccs_query_entry, list);  
2139                  if (ptr->serial != serial)                  if (ptr->serial != serial)
2140                          continue;                          continue;
2141                  if (!ptr->answer)                  if (!ptr->answer)
# Line 1838  static int ccs_write_answer(struct ccs_i Line 2143  static int ccs_write_answer(struct ccs_i
2143                  break;                  break;
2144          }          }
2145          spin_unlock(&ccs_query_list_lock);          spin_unlock(&ccs_query_list_lock);
2146          /***** CRITICAL SECTION END *****/          wake_up_all(&ccs_answer_wait);
2147          return 0;          return 0;
2148  }  }
2149    
# Line 1846  static int ccs_write_answer(struct ccs_i Line 2151  static int ccs_write_answer(struct ccs_i
2151   * ccs_read_version: Get version.   * ccs_read_version: Get version.
2152   *   *
2153   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
  *  
  * Returns version information.  
2154   */   */
2155  static int ccs_read_version(struct ccs_io_buffer *head)  static void ccs_read_version(struct ccs_io_buffer *head)
2156  {  {
2157          if (!head->read_eof) {          if (head->r.eof)
2158                  ccs_io_printf(head, "1.7.0-pre");                  return;
2159                  head->read_eof = true;          ccs_set_string(head, "1.8.0-pre");
2160          }          head->r.eof = true;
         return 0;  
 }  
   
 /**  
  * ccs_read_self_domain - Get the current process's domainname.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  *  
  * Returns the current process's domainname.  
  */  
 static int ccs_read_self_domain(struct ccs_io_buffer *head)  
 {  
         if (!head->read_eof) {  
                 /*  
                  * ccs_current_domain()->domainname != NULL  
                  * because every process belongs to a domain and  
                  * the domain's name cannot be NULL.  
                  */  
                 ccs_io_printf(head, "%s",  
                               ccs_current_domain()->domainname->name);  
                 head->read_eof = true;  
         }  
         return 0;  
2161  }  }
2162    
2163  /**  /**
# Line 1890  static int ccs_read_self_domain(struct c Line 2170  static int ccs_read_self_domain(struct c
2170   */   */
2171  int ccs_open_control(const u8 type, struct file *file)  int ccs_open_control(const u8 type, struct file *file)
2172  {  {
2173          struct ccs_io_buffer *head = kzalloc(sizeof(*head), GFP_KERNEL);          struct ccs_io_buffer *head = kzalloc(sizeof(*head), CCS_GFP_FLAGS);
2174          if (!head)          if (!head)
2175                  return -ENOMEM;                  return -ENOMEM;
2176          mutex_init(&head->io_sem);          mutex_init(&head->io_sem);
2177          head->type = type;          head->type = type;
2178          switch (type) {          switch (type) {
2179          case CCS_DOMAINPOLICY: /* /proc/ccs/domain_policy */          case CCS_DOMAINPOLICY: /* /proc/ccs/domain_policy */
2180                  head->write = ccs_write_domain_policy;                  head->write = ccs_write_domain;
2181                  head->read = ccs_read_domain_policy;                  head->read = ccs_read_domain;
2182                  break;                  break;
2183          case CCS_EXCEPTIONPOLICY: /* /proc/ccs/exception_policy */          case CCS_EXCEPTIONPOLICY: /* /proc/ccs/exception_policy */
2184                  head->write = ccs_write_exception_policy;                  head->write = ccs_write_exception;
2185                  head->read = ccs_read_exception_policy;                  head->read = ccs_read_exception;
2186                  break;                  break;
 #ifdef CONFIG_CCSECURITY_AUDIT  
2187          case CCS_GRANTLOG: /* /proc/ccs/grant_log */          case CCS_GRANTLOG: /* /proc/ccs/grant_log */
                 head->poll = ccs_poll_grant_log;  
                 head->read = ccs_read_grant_log;  
                 break;  
2188          case CCS_REJECTLOG: /* /proc/ccs/reject_log */          case CCS_REJECTLOG: /* /proc/ccs/reject_log */
2189                  head->poll = ccs_poll_reject_log;                  head->poll = ccs_poll_log;
2190                  head->read = ccs_read_reject_log;                  head->read = ccs_read_log;
                 break;  
 #endif  
         case CCS_SELFDOMAIN: /* /proc/ccs/self_domain */  
                 head->read = ccs_read_self_domain;  
2191                  break;                  break;
2192          case CCS_DOMAIN_STATUS: /* /proc/ccs/.domain_status */          case CCS_DOMAIN_STATUS: /* /proc/ccs/.domain_status */
2193                  head->write = ccs_write_domain_profile;                  head->write = ccs_write_domain_profile;
# Line 1923  int ccs_open_control(const u8 type, stru Line 2195  int ccs_open_control(const u8 type, stru
2195                  break;                  break;
2196          case CCS_EXECUTE_HANDLER: /* /proc/ccs/.execute_handler */          case CCS_EXECUTE_HANDLER: /* /proc/ccs/.execute_handler */
2197                  /* Allow execute_handler to read process's status. */                  /* Allow execute_handler to read process's status. */
2198                  if (!(current->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)) {                  if (!(ccs_current_flags() & CCS_TASK_IS_EXECUTE_HANDLER)) {
2199                          kfree(head);                          kfree(head);
2200                          return -EPERM;                          return -EPERM;
2201                  }                  }
# Line 1951  int ccs_open_control(const u8 type, stru Line 2223  int ccs_open_control(const u8 type, stru
2223                  head->read = ccs_read_query;                  head->read = ccs_read_query;
2224                  break;                  break;
2225          case CCS_MANAGER: /* /proc/ccs/manager */          case CCS_MANAGER: /* /proc/ccs/manager */
2226                  head->write = ccs_write_manager_policy;                  head->write = ccs_write_manager;
2227                  head->read = ccs_read_manager_policy;                  head->read = ccs_read_manager;
2228                  break;                  break;
2229          }          }
2230          if (!(file->f_mode & FMODE_READ)) {          if (!(file->f_mode & FMODE_READ)) {
# Line 1962  int ccs_open_control(const u8 type, stru Line 2234  int ccs_open_control(const u8 type, stru
2234                   */                   */
2235                  head->read = NULL;                  head->read = NULL;
2236                  head->poll = NULL;                  head->poll = NULL;
2237          } else if (type != CCS_QUERY &&          } else if (!head->poll) {
2238                     type != CCS_GRANTLOG && type != CCS_REJECTLOG) {                  /* Don't allocate read_buf for poll() access. */
                 /*  
                  * Don't allocate buffer for reading if the file is one of  
                  * /proc/ccs/grant_log , /proc/ccs/reject_log , /proc/ccs/query.  
                  */  
2239                  if (!head->readbuf_size)                  if (!head->readbuf_size)
2240                          head->readbuf_size = 4096 * 2;                          head->readbuf_size = 4096;
2241                  head->read_buf = kzalloc(head->readbuf_size, GFP_KERNEL);                  head->read_buf = kzalloc(head->readbuf_size, CCS_GFP_FLAGS);
2242                  if (!head->read_buf) {                  if (!head->read_buf) {
2243                          kfree(head);                          kfree(head);
2244                          return -ENOMEM;                          return -ENOMEM;
# Line 1983  int ccs_open_control(const u8 type, stru Line 2251  int ccs_open_control(const u8 type, stru
2251                   */                   */
2252                  head->write = NULL;                  head->write = NULL;
2253          } else if (head->write) {          } else if (head->write) {
2254                  head->writebuf_size = 4096 * 2;                  head->writebuf_size = 4096;
2255                  head->write_buf = kzalloc(head->writebuf_size, GFP_KERNEL);                  head->write_buf = kzalloc(head->writebuf_size, CCS_GFP_FLAGS);
2256                  if (!head->write_buf) {                  if (!head->write_buf) {
2257                          kfree(head->read_buf);                          kfree(head->read_buf);
2258                          kfree(head);                          kfree(head);
2259                          return -ENOMEM;                          return -ENOMEM;
2260                  }                  }
2261          }          }
         if (type != CCS_QUERY &&  
             type != CCS_GRANTLOG && type != CCS_REJECTLOG)  
                 head->reader_idx = ccs_read_lock();  
         file->private_data = head;  
         /*  
          * Call the handler now if the file is /proc/ccs/self_domain  
          * so that the user can use "cat < /proc/ccs/self_domain" to  
          * know the current process's domainname.  
          */  
         if (type == CCS_SELFDOMAIN)  
                 ccs_read_control(file, NULL, 0);  
2262          /*          /*
2263           * If the file is /proc/ccs/query , increment the observer counter.           * If the file is /proc/ccs/query , increment the observer counter.
2264           * The obserber counter is used by ccs_check_supervisor() to see if           * The obserber counter is used by ccs_supervisor() to see if
2265           * there is some process monitoring /proc/ccs/query.           * there is some process monitoring /proc/ccs/query.
2266           */           */
2267          else if (type == CCS_QUERY)          if (type == CCS_QUERY)
2268                  atomic_inc(&ccs_query_observers);                  atomic_inc(&ccs_query_observers);
2269            else if (type != CCS_GRANTLOG && type != CCS_REJECTLOG)
2270                    head->reader_idx = ccs_lock();
2271            file->private_data = head;
2272          return 0;          return 0;
2273  }  }
2274    
# Line 2019  int ccs_open_control(const u8 type, stru Line 2279  int ccs_open_control(const u8 type, stru
2279   * @wait: Pointer to "poll_table".   * @wait: Pointer to "poll_table".
2280   *   *
2281   * Waits for read readiness.   * Waits for read readiness.
2282   * /proc/ccs/query is handled by /usr/lib/ccs/ccs-queryd and   * /proc/ccs/query is handled by /usr/sbin/ccs-queryd and
2283   * /proc/ccs/grant_log and /proc/ccs/reject_log are handled by   * /proc/ccs/grant_log and /proc/ccs/reject_log are handled by
2284   * /usr/lib/ccs/ccs-auditd.   * /usr/sbin/ccs-auditd .
2285   */   */
2286  int ccs_poll_control(struct file *file, poll_table *wait)  int ccs_poll_control(struct file *file, poll_table *wait)
2287  {  {
# Line 2043  int ccs_poll_control(struct file *file, Line 2303  int ccs_poll_control(struct file *file,
2303  int ccs_read_control(struct file *file, char __user *buffer,  int ccs_read_control(struct file *file, char __user *buffer,
2304                       const int buffer_len)                       const int buffer_len)
2305  {  {
2306          int len = 0;          int len;
2307          struct ccs_io_buffer *head = file->private_data;          struct ccs_io_buffer *head = file->private_data;
2308          char *cp;          int idx;
2309          if (!head->read)          if (!head->read)
2310                  return -ENOSYS;                  return -ENOSYS;
2311          if (!access_ok(VERIFY_WRITE, buffer, buffer_len))          if (!access_ok(VERIFY_WRITE, buffer, buffer_len))
2312                  return -EFAULT;                  return -EFAULT;
2313          if (mutex_lock_interruptible(&head->io_sem))          if (mutex_lock_interruptible(&head->io_sem))
2314                  return -EINTR;                  return -EINTR;
2315          /* Call the policy handler. */          head->read_user_buf = buffer;
2316          len = head->read(head);          head->read_user_buf_avail = buffer_len;
2317          if (len < 0)          idx = ccs_read_lock();
2318                  goto out;          if (ccs_flush(head))
2319          /* Write to buffer. */                  /* Call the policy handler. */
2320          len = head->read_avail;                  head->read(head);
2321          if (len > buffer_len)          ccs_flush(head);
2322         &