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

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 3872 by kumaneko, Sun Aug 1 02:11:31 2010 UTC trunk/1.8.x/ccs-patch/security/ccsecurity/policy_io.c revision 5526 by kumaneko, Mon Oct 3 07:12:14 2011 UTC
# Line 1  Line 1 
1  /*  /*
2   * security/ccsecurity/policy_io.c   * security/ccsecurity/policy_io.c
3   *   *
4   * Copyright (C) 2005-2010  NTT DATA CORPORATION   * Copyright (C) 2005-2011  NTT DATA CORPORATION
  *  
  * Version: 1.8.0-pre   2010/08/01  
  *  
  * This file is applicable to both 2.4.30 and 2.6.11 and later.  
  * See README.ccs for ChangeLog.  
5   *   *
6     * Version: 1.8.3   2011/09/29
7   */   */
8    
9  #include "internal.h"  #include "internal.h"
10    
11  static struct ccs_profile ccs_default_profile = {  #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
12  #ifdef CONFIG_CCSECURITY_AUDIT  
13          .preference.audit_max_grant_log = CONFIG_CCSECURITY_MAX_GRANT_LOG,  /**
14          .preference.audit_max_reject_log = CONFIG_CCSECURITY_MAX_REJECT_LOG,   * __wait_event_interruptible_timeout - Sleep until a condition gets true or a timeout elapses.
15     *
16     * @wq:        The waitqueue to wait on.
17     * @condition: A C expression for the event to wait for.
18     * @ret:       Timeout, in jiffies.
19     *
20     * Returns 0 if the @timeout elapsed, -ERESTARTSYS if it was interrupted by a
21     * signal, and the remaining jiffies otherwise if the condition evaluated to
22     * true before the timeout elapsed.
23     *
24     * This is for compatibility with older kernels.
25     */
26    #define __wait_event_interruptible_timeout(wq, condition, ret)          \
27    do {                                                                    \
28            wait_queue_t __wait;                                            \
29            init_waitqueue_entry(&__wait, current);                         \
30                                                                            \
31            add_wait_queue(&wq, &__wait);                                   \
32            for (;;) {                                                      \
33                    set_current_state(TASK_INTERRUPTIBLE);                  \
34                    if (condition)                                          \
35                            break;                                          \
36                    if (!signal_pending(current)) {                         \
37                            ret = schedule_timeout(ret);                    \
38                            if (!ret)                                       \
39                                    break;                                  \
40                            continue;                                       \
41                    }                                                       \
42                    ret = -ERESTARTSYS;                                     \
43                    break;                                                  \
44            }                                                               \
45            current->state = TASK_RUNNING;                                  \
46            remove_wait_queue(&wq, &__wait);                                \
47    } while (0)
48    
49    /**
50     * wait_event_interruptible_timeout - Sleep until a condition gets true or a timeout elapses.
51     *
52     * @wq:        The waitqueue to wait on.
53     * @condition: A C expression for the event to wait for.
54     * @timeout:   Timeout, in jiffies.
55     *
56     * Returns 0 if the @timeout elapsed, -ERESTARTSYS if it was interrupted by a
57     * signal, and the remaining jiffies otherwise if the condition evaluated to
58     * true before the timeout elapsed.
59     *
60     * This is for compatibility with older kernels.
61     */
62    #define wait_event_interruptible_timeout(wq, condition, timeout)        \
63    ({                                                                      \
64            long __ret = timeout;                                           \
65            if (!(condition))                                               \
66                    __wait_event_interruptible_timeout(wq, condition, __ret); \
67            __ret;                                                          \
68    })
69    
70  #endif  #endif
71          .preference.audit_task_info = true,  
72          .preference.audit_path_info = true,  /**
73          .preference.enforcing_penalty = 0,   * list_for_each_cookie - iterate over a list with cookie.
74          .preference.learning_max_entry = CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY,   *
75          .preference.learning_exec_realpath = true,   * @pos:  Pointer to "struct list_head".
76          .preference.learning_exec_argv0 = true,   * @head: Pointer to "struct list_head".
77          .preference.learning_symlink_target = true,   */
78    #define list_for_each_cookie(pos, head)                                 \
79            for (pos = pos ? pos : srcu_dereference((head)->next, &ccs_ss); \
80                 pos != (head); pos = srcu_dereference(pos->next, &ccs_ss))
81    
82    /* String table for operation mode. */
83    const char * const ccs_mode[CCS_CONFIG_MAX_MODE] = {
84            [CCS_CONFIG_DISABLED]   = "disabled",
85            [CCS_CONFIG_LEARNING]   = "learning",
86            [CCS_CONFIG_PERMISSIVE] = "permissive",
87            [CCS_CONFIG_ENFORCING]  = "enforcing"
88  };  };
89    
90  /* Profile version. Currently only 20090903 is defined. */  /* String table for /proc/ccs/profile interface. */
91  static unsigned int ccs_profile_version;  const char * const ccs_mac_keywords[CCS_MAX_MAC_INDEX
92                                        + CCS_MAX_MAC_CATEGORY_INDEX] = {
93            /* CONFIG::file group */
94            [CCS_MAC_FILE_EXECUTE]    = "execute",
95            [CCS_MAC_FILE_OPEN]       = "open",
96            [CCS_MAC_FILE_CREATE]     = "create",
97            [CCS_MAC_FILE_UNLINK]     = "unlink",
98            [CCS_MAC_FILE_GETATTR]    = "getattr",
99            [CCS_MAC_FILE_MKDIR]      = "mkdir",
100            [CCS_MAC_FILE_RMDIR]      = "rmdir",
101            [CCS_MAC_FILE_MKFIFO]     = "mkfifo",
102            [CCS_MAC_FILE_MKSOCK]     = "mksock",
103            [CCS_MAC_FILE_TRUNCATE]   = "truncate",
104            [CCS_MAC_FILE_SYMLINK]    = "symlink",
105            [CCS_MAC_FILE_MKBLOCK]    = "mkblock",
106            [CCS_MAC_FILE_MKCHAR]     = "mkchar",
107            [CCS_MAC_FILE_LINK]       = "link",
108            [CCS_MAC_FILE_RENAME]     = "rename",
109            [CCS_MAC_FILE_CHMOD]      = "chmod",
110            [CCS_MAC_FILE_CHOWN]      = "chown",
111            [CCS_MAC_FILE_CHGRP]      = "chgrp",
112            [CCS_MAC_FILE_IOCTL]      = "ioctl",
113            [CCS_MAC_FILE_CHROOT]     = "chroot",
114            [CCS_MAC_FILE_MOUNT]      = "mount",
115            [CCS_MAC_FILE_UMOUNT]     = "unmount",
116            [CCS_MAC_FILE_PIVOT_ROOT] = "pivot_root",
117            /* CONFIG::misc group */
118            [CCS_MAC_ENVIRON] = "env",
119            /* CONFIG::network group */
120            [CCS_MAC_NETWORK_INET_STREAM_BIND]       = "inet_stream_bind",
121            [CCS_MAC_NETWORK_INET_STREAM_LISTEN]     = "inet_stream_listen",
122            [CCS_MAC_NETWORK_INET_STREAM_CONNECT]    = "inet_stream_connect",
123            [CCS_MAC_NETWORK_INET_STREAM_ACCEPT]     = "inet_stream_accept",
124            [CCS_MAC_NETWORK_INET_DGRAM_BIND]        = "inet_dgram_bind",
125            [CCS_MAC_NETWORK_INET_DGRAM_SEND]        = "inet_dgram_send",
126            [CCS_MAC_NETWORK_INET_DGRAM_RECV]        = "inet_dgram_recv",
127            [CCS_MAC_NETWORK_INET_RAW_BIND]          = "inet_raw_bind",
128            [CCS_MAC_NETWORK_INET_RAW_SEND]          = "inet_raw_send",
129            [CCS_MAC_NETWORK_INET_RAW_RECV]          = "inet_raw_recv",
130            [CCS_MAC_NETWORK_UNIX_STREAM_BIND]       = "unix_stream_bind",
131            [CCS_MAC_NETWORK_UNIX_STREAM_LISTEN]     = "unix_stream_listen",
132            [CCS_MAC_NETWORK_UNIX_STREAM_CONNECT]    = "unix_stream_connect",
133            [CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT]     = "unix_stream_accept",
134            [CCS_MAC_NETWORK_UNIX_DGRAM_BIND]        = "unix_dgram_bind",
135            [CCS_MAC_NETWORK_UNIX_DGRAM_SEND]        = "unix_dgram_send",
136            [CCS_MAC_NETWORK_UNIX_DGRAM_RECV]        = "unix_dgram_recv",
137            [CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND]    = "unix_seqpacket_bind",
138            [CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN]  = "unix_seqpacket_listen",
139            [CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
140            [CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT]  = "unix_seqpacket_accept",
141            /* CONFIG::ipc group */
142            [CCS_MAC_SIGNAL] = "signal",
143            /* CONFIG::capability group */
144            [CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET]  = "use_route",
145            [CCS_MAC_CAPABILITY_USE_PACKET_SOCKET] = "use_packet",
146            [CCS_MAC_CAPABILITY_SYS_REBOOT]        = "SYS_REBOOT",
147            [CCS_MAC_CAPABILITY_SYS_VHANGUP]       = "SYS_VHANGUP",
148            [CCS_MAC_CAPABILITY_SYS_SETTIME]       = "SYS_TIME",
149            [CCS_MAC_CAPABILITY_SYS_NICE]          = "SYS_NICE",
150            [CCS_MAC_CAPABILITY_SYS_SETHOSTNAME]   = "SYS_SETHOSTNAME",
151            [CCS_MAC_CAPABILITY_USE_KERNEL_MODULE] = "use_kernel_module",
152            [CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD]    = "SYS_KEXEC_LOAD",
153            [CCS_MAC_CAPABILITY_SYS_PTRACE]        = "SYS_PTRACE",
154            /* CONFIG group */
155            [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_FILE]       = "file",
156            [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_NETWORK]    = "network",
157            [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_MISC]       = "misc",
158            [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_IPC]        = "ipc",
159            [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_CAPABILITY] = "capability",
160    };
161    
162  /* Profile table. Memory is allocated as needed. */  /* String table for path operation. */
163  static struct ccs_profile *ccs_profile_ptr[CCS_MAX_PROFILES];  const char * const ccs_path_keyword[CCS_MAX_PATH_OPERATION] = {
164            [CCS_TYPE_EXECUTE]    = "execute",
165            [CCS_TYPE_READ]       = "read",
166            [CCS_TYPE_WRITE]      = "write",
167            [CCS_TYPE_APPEND]     = "append",
168            [CCS_TYPE_UNLINK]     = "unlink",
169            [CCS_TYPE_GETATTR]    = "getattr",
170            [CCS_TYPE_RMDIR]      = "rmdir",
171            [CCS_TYPE_TRUNCATE]   = "truncate",
172            [CCS_TYPE_SYMLINK]    = "symlink",
173            [CCS_TYPE_CHROOT]     = "chroot",
174            [CCS_TYPE_UMOUNT]     = "unmount",
175    };
176    
177  /* String table for functionality that takes 4 modes. */  /* String table for socket's operation. */
178  const char *ccs_mode[CCS_CONFIG_MAX_MODE] = {  const char * const ccs_socket_keyword[CCS_MAX_NETWORK_OPERATION] = {
179          [CCS_CONFIG_DISABLED] = "disabled",          [CCS_NETWORK_BIND]    = "bind",
180          [CCS_CONFIG_LEARNING] = "learning",          [CCS_NETWORK_LISTEN]  = "listen",
181          [CCS_CONFIG_PERMISSIVE] = "permissive",          [CCS_NETWORK_CONNECT] = "connect",
182          [CCS_CONFIG_ENFORCING] = "enforcing"          [CCS_NETWORK_ACCEPT]  = "accept",
183            [CCS_NETWORK_SEND]    = "send",
184            [CCS_NETWORK_RECV]    = "recv",
185  };  };
186    
187  /* String table for /proc/ccs/profile */  /* String table for categories. */
188  static const char *ccs_mac_keywords[CCS_MAX_MAC_INDEX +  static const char * const ccs_category_keywords[CCS_MAX_MAC_CATEGORY_INDEX] = {
189                                      CCS_MAX_CAPABILITY_INDEX +          [CCS_MAC_CATEGORY_FILE]       = "file",
190                                      CCS_MAX_MAC_CATEGORY_INDEX] = {          [CCS_MAC_CATEGORY_NETWORK]    = "network",
191          [CCS_MAC_FILE_EXECUTE]          [CCS_MAC_CATEGORY_MISC]       = "misc",
192          = "file::execute",          [CCS_MAC_CATEGORY_IPC]        = "ipc",
193          [CCS_MAC_FILE_OPEN]          [CCS_MAC_CATEGORY_CAPABILITY] = "capability",
194          = "file::open",  };
195          [CCS_MAC_FILE_CREATE]  
196          = "file::create",  /* String table for conditions. */
197          [CCS_MAC_FILE_UNLINK]  const char * const ccs_condition_keyword[CCS_MAX_CONDITION_KEYWORD] = {
198          = "file::unlink",          [CCS_TASK_UID]             = "task.uid",
199          [CCS_MAC_FILE_MKDIR]          [CCS_TASK_EUID]            = "task.euid",
200          = "file::mkdir",          [CCS_TASK_SUID]            = "task.suid",
201          [CCS_MAC_FILE_RMDIR]          [CCS_TASK_FSUID]           = "task.fsuid",
202          = "file::rmdir",          [CCS_TASK_GID]             = "task.gid",
203          [CCS_MAC_FILE_MKFIFO]          [CCS_TASK_EGID]            = "task.egid",
204          = "file::mkfifo",          [CCS_TASK_SGID]            = "task.sgid",
205          [CCS_MAC_FILE_MKSOCK]          [CCS_TASK_FSGID]           = "task.fsgid",
206          = "file::mksock",          [CCS_TASK_PID]             = "task.pid",
207          [CCS_MAC_FILE_TRUNCATE]          [CCS_TASK_PPID]            = "task.ppid",
208          = "file::truncate",          [CCS_EXEC_ARGC]            = "exec.argc",
209          [CCS_MAC_FILE_SYMLINK]          [CCS_EXEC_ENVC]            = "exec.envc",
210          = "file::symlink",          [CCS_TYPE_IS_SOCKET]       = "socket",
211          [CCS_MAC_FILE_MKBLOCK]          [CCS_TYPE_IS_SYMLINK]      = "symlink",
212          = "file::mkblock",          [CCS_TYPE_IS_FILE]         = "file",
213          [CCS_MAC_FILE_MKCHAR]          [CCS_TYPE_IS_BLOCK_DEV]    = "block",
214          = "file::mkchar",          [CCS_TYPE_IS_DIRECTORY]    = "directory",
215          [CCS_MAC_FILE_LINK]          [CCS_TYPE_IS_CHAR_DEV]     = "char",
216          = "file::link",          [CCS_TYPE_IS_FIFO]         = "fifo",
217          [CCS_MAC_FILE_RENAME]          [CCS_MODE_SETUID]          = "setuid",
218          = "file::rename",          [CCS_MODE_SETGID]          = "setgid",
219          [CCS_MAC_FILE_CHMOD]          [CCS_MODE_STICKY]          = "sticky",
220          = "file::chmod",          [CCS_MODE_OWNER_READ]      = "owner_read",
221          [CCS_MAC_FILE_CHOWN]          [CCS_MODE_OWNER_WRITE]     = "owner_write",
222          = "file::chown",          [CCS_MODE_OWNER_EXECUTE]   = "owner_execute",
223          [CCS_MAC_FILE_CHGRP]          [CCS_MODE_GROUP_READ]      = "group_read",
224          = "file::chgrp",          [CCS_MODE_GROUP_WRITE]     = "group_write",
225          [CCS_MAC_FILE_IOCTL]          [CCS_MODE_GROUP_EXECUTE]   = "group_execute",
226          = "file::ioctl",          [CCS_MODE_OTHERS_READ]     = "others_read",
227          [CCS_MAC_FILE_CHROOT]          [CCS_MODE_OTHERS_WRITE]    = "others_write",
228          = "file::chroot",          [CCS_MODE_OTHERS_EXECUTE]  = "others_execute",
229          [CCS_MAC_FILE_MOUNT]          [CCS_TASK_TYPE]            = "task.type",
230          = "file::mount",          [CCS_TASK_EXECUTE_HANDLER] = "execute_handler",
231          [CCS_MAC_FILE_UMOUNT]          [CCS_EXEC_REALPATH]        = "exec.realpath",
232          = "file::umount",          [CCS_SYMLINK_TARGET]       = "symlink.target",
233          [CCS_MAC_FILE_PIVOT_ROOT]          [CCS_PATH1_UID]            = "path1.uid",
234          = "file::pivot_root",          [CCS_PATH1_GID]            = "path1.gid",
235          [CCS_MAC_FILE_TRANSIT]          [CCS_PATH1_INO]            = "path1.ino",
236          = "file::transit",          [CCS_PATH1_MAJOR]          = "path1.major",
237          [CCS_MAC_ENVIRON]          [CCS_PATH1_MINOR]          = "path1.minor",
238          = "misc::env",          [CCS_PATH1_PERM]           = "path1.perm",
239          [CCS_MAC_NETWORK_TCP_BIND]          [CCS_PATH1_TYPE]           = "path1.type",
240          = "network::inet_tcp_bind",          [CCS_PATH1_DEV_MAJOR]      = "path1.dev_major",
241          [CCS_MAC_NETWORK_TCP_LISTEN]          [CCS_PATH1_DEV_MINOR]      = "path1.dev_minor",
242          = "network::inet_tcp_listen",          [CCS_PATH2_UID]            = "path2.uid",
243          [CCS_MAC_NETWORK_TCP_CONNECT]          [CCS_PATH2_GID]            = "path2.gid",
244          = "network::inet_tcp_connect",          [CCS_PATH2_INO]            = "path2.ino",
245          [CCS_MAC_NETWORK_TCP_ACCEPT]          [CCS_PATH2_MAJOR]          = "path2.major",
246          = "network::inet_tcp_accept",          [CCS_PATH2_MINOR]          = "path2.minor",
247          [CCS_MAC_NETWORK_UDP_BIND]          [CCS_PATH2_PERM]           = "path2.perm",
248          = "network::inet_udp_bind",          [CCS_PATH2_TYPE]           = "path2.type",
249          [CCS_MAC_NETWORK_UDP_SEND]          [CCS_PATH2_DEV_MAJOR]      = "path2.dev_major",
250          = "network::inet_udp_send",          [CCS_PATH2_DEV_MINOR]      = "path2.dev_minor",
251          [CCS_MAC_NETWORK_UDP_RECV]          [CCS_PATH1_PARENT_UID]     = "path1.parent.uid",
252          = "network::inet_udp_recv",          [CCS_PATH1_PARENT_GID]     = "path1.parent.gid",
253          [CCS_MAC_NETWORK_RAW_BIND]          [CCS_PATH1_PARENT_INO]     = "path1.parent.ino",
254          = "network::inet_raw_bind",          [CCS_PATH1_PARENT_PERM]    = "path1.parent.perm",
255          [CCS_MAC_NETWORK_RAW_SEND]          [CCS_PATH2_PARENT_UID]     = "path2.parent.uid",
256          = "network::inet_raw_send",          [CCS_PATH2_PARENT_GID]     = "path2.parent.gid",
257          [CCS_MAC_NETWORK_RAW_RECV]          [CCS_PATH2_PARENT_INO]     = "path2.parent.ino",
258          = "network::inet_raw_recv",          [CCS_PATH2_PARENT_PERM]    = "path2.parent.perm",
259          [CCS_MAC_SIGNAL]  };
260          = "ipc::signal",  
261          [CCS_MAX_MAC_INDEX + CCS_USE_ROUTE_SOCKET]  /* String table for PREFERENCE keyword. */
262          = "capability::use_route",  static const char * const ccs_pref_keywords[CCS_MAX_PREF] = {
263          [CCS_MAX_MAC_INDEX + CCS_USE_PACKET_SOCKET]          [CCS_PREF_MAX_AUDIT_LOG]      = "max_audit_log",
264          = "capability::use_packet",          [CCS_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry",
265          [CCS_MAX_MAC_INDEX + CCS_SYS_REBOOT]          [CCS_PREF_ENFORCING_PENALTY]  = "enforcing_penalty",
         = "capability::SYS_REBOOT",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_VHANGUP]  
         = "capability::SYS_VHANGUP",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_SETTIME]  
         = "capability::SYS_TIME",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_NICE]  
         = "capability::SYS_NICE",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_SETHOSTNAME]  
         = "capability::SYS_SETHOSTNAME",  
         [CCS_MAX_MAC_INDEX + CCS_USE_KERNEL_MODULE]  
         = "capability::use_kernel_module",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_KEXEC_LOAD]  
         = "capability::SYS_KEXEC_LOAD",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_PTRACE]  
         = "capability::SYS_PTRACE",  
         [CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX  
          + CCS_MAC_CATEGORY_FILE] = "file",  
         [CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX  
          + CCS_MAC_CATEGORY_NETWORK] = "network",  
         [CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX  
          + CCS_MAC_CATEGORY_MISC] = "misc",  
         [CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX  
          + CCS_MAC_CATEGORY_IPC] = "ipc",  
         [CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX  
          + CCS_MAC_CATEGORY_CAPABILITY] = "capability",  
266  };  };
267    
268  /* Permit policy management by non-root user? */  /* Permit policy management by non-root user? */
269  static bool ccs_manage_by_non_root;  static bool ccs_manage_by_non_root;
270    
271  /**  /**
272   * ccs_cap2keyword - Convert capability operation to capability name.   * ccs_yesno - Return "yes" or "no".
273   *   *
274   * @operation: The capability index.   * @value: Bool value.
275   *   *
276   * Returns the name of the specified capability's name.   * Returns "yes" if @value is not 0, "no" otherwise.
277   */   */
278  const char *ccs_cap2keyword(const u8 operation)  const char *ccs_yesno(const unsigned int value)
279  {  {
280          return operation < CCS_MAX_CAPABILITY_INDEX          return value ? "yes" : "no";
                 ? ccs_mac_keywords[CCS_MAX_MAC_INDEX + operation] + 12 : NULL;  
281  }  }
282    
283    /* Prototype for ccs_addprintf(). */
284    static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)
285            __attribute__ ((format(printf, 3, 4)));
286    
287  /**  /**
288   * ccs_yesno - Return "yes" or "no".   * ccs_addprintf - strncat()-like-snprintf().
289   *   *
290   * @value: Bool value.   * @buffer: Buffer to write to. Must be '\0'-terminated.
291     * @len:    Size of @buffer.
292     * @fmt:    The printf()'s format string, followed by parameters.
293     *
294     * Returns nothing.
295   */   */
 static const char *ccs_yesno(const unsigned int value)  
 {  
         return value ? "yes" : "no";  
 }  
   
296  static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)  static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)
297  {  {
298          va_list args;          va_list args;
# Line 184  static void ccs_addprintf(char *buffer, Line 305  static void ccs_addprintf(char *buffer,
305  /**  /**
306   * ccs_flush - Flush queued string to userspace's buffer.   * ccs_flush - Flush queued string to userspace's buffer.
307   *   *
308   * @head:   Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
309   *   *
310   * Returns true if all data was flushed, false otherwise.   * Returns true if all data was flushed, false otherwise.
311   */   */
# Line 192  static bool ccs_flush(struct ccs_io_buff Line 313  static bool ccs_flush(struct ccs_io_buff
313  {  {
314          while (head->r.w_pos) {          while (head->r.w_pos) {
315                  const char *w = head->r.w[0];                  const char *w = head->r.w[0];
316                  int len = strlen(w);                  size_t len = strlen(w);
317                  if (len) {                  if (len) {
318                          if (len > head->read_user_buf_avail)                          if (len > head->read_user_buf_avail)
319                                  len = head->read_user_buf_avail;                                  len = head->read_user_buf_avail;
# Line 204  static bool ccs_flush(struct ccs_io_buff Line 325  static bool ccs_flush(struct ccs_io_buff
325                          head->read_user_buf += len;                          head->read_user_buf += len;
326                          w += len;                          w += len;
327                  }                  }
328                  if (*w) {                  head->r.w[0] = w;
329                          head->r.w[0] = w;                  if (*w)
330                          return false;                          return false;
                 }  
331                  /* Add '\0' for audit logs and query. */                  /* Add '\0' for audit logs and query. */
332                  if (head->poll) {                  if (head->type == CCS_AUDIT || head->type == CCS_QUERY) {
333                          if (!head->read_user_buf_avail ||                          if (!head->read_user_buf_avail ||
334                              copy_to_user(head->read_user_buf, "", 1))                              copy_to_user(head->read_user_buf, "", 1))
335                                  return false;                                  return false;
# Line 230  static bool ccs_flush(struct ccs_io_buff Line 350  static bool ccs_flush(struct ccs_io_buff
350   * @head:   Pointer to "struct ccs_io_buffer".   * @head:   Pointer to "struct ccs_io_buffer".
351   * @string: String to print.   * @string: String to print.
352   *   *
353     * Returns nothing.
354     *
355   * Note that @string has to be kept valid until @head is kfree()d.   * Note that @string has to be kept valid until @head is kfree()d.
356   * This means that char[] allocated on stack memory cannot be passed to   * This means that char[] allocated on stack memory cannot be passed to
357   * this function. Use ccs_io_printf() for char[] allocated on stack memory.   * this function. Use ccs_io_printf() for char[] allocated on stack memory.
# Line 243  static void ccs_set_string(struct ccs_io Line 365  static void ccs_set_string(struct ccs_io
365                  printk(KERN_WARNING "Too many words in a line.\n");                  printk(KERN_WARNING "Too many words in a line.\n");
366  }  }
367    
368    /* Prototype for ccs_io_printf(). */
369    static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
370            __attribute__ ((format(printf, 2, 3)));
371    
372  /**  /**
373   * ccs_io_printf - printf() to "struct ccs_io_buffer" structure.   * ccs_io_printf - printf() to "struct ccs_io_buffer" structure.
374   *   *
375   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
376   * @fmt:  The printf()'s format string, followed by parameters.   * @fmt:  The printf()'s format string, followed by parameters.
377     *
378     * Returns nothing.
379   */   */
380  void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)  static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
381  {  {
382          va_list args;          va_list args;
383          int len;          size_t len;
384          int pos = head->r.avail;          size_t pos = head->r.avail;
385          int size = head->readbuf_size - pos;          int size = head->readbuf_size - pos;
386          if (size <= 0)          if (size <= 0)
387                  return;                  return;
# Line 268  void ccs_io_printf(struct ccs_io_buffer Line 396  void ccs_io_printf(struct ccs_io_buffer
396          ccs_set_string(head, head->read_buf + pos);          ccs_set_string(head, head->read_buf + pos);
397  }  }
398    
399    /**
400     * ccs_set_space - Put a space to "struct ccs_io_buffer" structure.
401     *
402     * @head: Pointer to "struct ccs_io_buffer".
403     *
404     * Returns nothing.
405     */
406  static void ccs_set_space(struct ccs_io_buffer *head)  static void ccs_set_space(struct ccs_io_buffer *head)
407  {  {
408          ccs_set_string(head, " ");          ccs_set_string(head, " ");
409  }  }
410    
411    /**
412     * ccs_set_lf - Put a line feed to "struct ccs_io_buffer" structure.
413     *
414     * @head: Pointer to "struct ccs_io_buffer".
415     *
416     * Returns nothing.
417     */
418  static bool ccs_set_lf(struct ccs_io_buffer *head)  static bool ccs_set_lf(struct ccs_io_buffer *head)
419  {  {
420          ccs_set_string(head, "\n");          ccs_set_string(head, "\n");
# Line 280  static bool ccs_set_lf(struct ccs_io_buf Line 422  static bool ccs_set_lf(struct ccs_io_buf
422  }  }
423    
424  /**  /**
425     * ccs_set_slash - Put a shash to "struct ccs_io_buffer" structure.
426     *
427     * @head: Pointer to "struct ccs_io_buffer".
428     *
429     * Returns nothing.
430     */
431    static void ccs_set_slash(struct ccs_io_buffer *head)
432    {
433            ccs_set_string(head, "/");
434    }
435    
436    /* List of namespaces. */
437    LIST_HEAD(ccs_namespace_list);
438    /* True if namespace other than ccs_kernel_namespace is defined. */
439    static bool ccs_namespace_enabled;
440    
441    /**
442     * ccs_init_policy_namespace - Initialize namespace.
443     *
444     * @ns: Pointer to "struct ccs_policy_namespace".
445     *
446     * Returns nothing.
447     */
448    void ccs_init_policy_namespace(struct ccs_policy_namespace *ns)
449    {
450            unsigned int idx;
451            for (idx = 0; idx < CCS_MAX_ACL_GROUPS; idx++)
452                    INIT_LIST_HEAD(&ns->acl_group[idx]);
453            for (idx = 0; idx < CCS_MAX_GROUP; idx++)
454                    INIT_LIST_HEAD(&ns->group_list[idx]);
455            for (idx = 0; idx < CCS_MAX_POLICY; idx++)
456                    INIT_LIST_HEAD(&ns->policy_list[idx]);
457            ns->profile_version = 20100903;
458            ccs_namespace_enabled = !list_empty(&ccs_namespace_list);
459            list_add_tail_rcu(&ns->namespace_list, &ccs_namespace_list);
460    }
461    
462    /**
463     * ccs_print_namespace - Print namespace header.
464     *
465     * @head: Pointer to "struct ccs_io_buffer".
466     *
467     * Returns nothing.
468     */
469    static void ccs_print_namespace(struct ccs_io_buffer *head)
470    {
471            if (!ccs_namespace_enabled)
472                    return;
473            ccs_set_string(head,
474                           container_of(head->r.ns, struct ccs_policy_namespace,
475                                        namespace_list)->name);
476            ccs_set_space(head);
477    }
478    
479    /**
480   * ccs_assign_profile - Create a new profile.   * ccs_assign_profile - Create a new profile.
481   *   *
482     * @ns:      Pointer to "struct ccs_policy_namespace".
483   * @profile: Profile number to create.   * @profile: Profile number to create.
484   *   *
485   * Returns pointer to "struct ccs_profile" on success, NULL otherwise.   * Returns pointer to "struct ccs_profile" on success, NULL otherwise.
486   */   */
487  static struct ccs_profile *ccs_assign_profile(const unsigned int profile)  static struct ccs_profile *ccs_assign_profile(struct ccs_policy_namespace *ns,
488                                                  const unsigned int profile)
489  {  {
490          struct ccs_profile *ptr;          struct ccs_profile *ptr;
491          struct ccs_profile *entry;          struct ccs_profile *entry;
492          if (profile >= CCS_MAX_PROFILES)          if (profile >= CCS_MAX_PROFILES)
493                  return NULL;                  return NULL;
494          ptr = ccs_profile_ptr[profile];          ptr = ns->profile_ptr[profile];
495          if (ptr)          if (ptr)
496                  return ptr;                  return ptr;
497          entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);          entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
498          if (mutex_lock_interruptible(&ccs_policy_lock))          if (mutex_lock_interruptible(&ccs_policy_lock))
499                  goto out;                  goto out;
500          ptr = ccs_profile_ptr[profile];          ptr = ns->profile_ptr[profile];
501          if (!ptr && ccs_memory_ok(entry, sizeof(*entry))) {          if (!ptr && ccs_memory_ok(entry, sizeof(*entry))) {
502                  ptr = entry;                  ptr = entry;
503                  ptr->default_config = CCS_CONFIG_DISABLED |                  ptr->default_config = CCS_CONFIG_DISABLED |
                         CCS_CONFIG_VERBOSE |  
504                          CCS_CONFIG_WANT_GRANT_LOG | CCS_CONFIG_WANT_REJECT_LOG;                          CCS_CONFIG_WANT_GRANT_LOG | CCS_CONFIG_WANT_REJECT_LOG;
505                  memset(ptr->config, CCS_CONFIG_USE_DEFAULT,                  memset(ptr->config, CCS_CONFIG_USE_DEFAULT,
506                         sizeof(ptr->config));                         sizeof(ptr->config));
507                    ptr->pref[CCS_PREF_MAX_AUDIT_LOG] =
508                            CONFIG_CCSECURITY_MAX_AUDIT_LOG;
509                    ptr->pref[CCS_PREF_MAX_LEARNING_ENTRY] =
510                            CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY;
511                  mb(); /* Avoid out-of-order execution. */                  mb(); /* Avoid out-of-order execution. */
512                  ccs_profile_ptr[profile] = ptr;                  ns->profile_ptr[profile] = ptr;
513                  entry = NULL;                  entry = NULL;
514          }          }
515          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
516   out:  out:
517          kfree(entry);          kfree(entry);
518          return ptr;          return ptr;
519  }  }
520    
521  /**  /**
522   * ccs_check_profile - Check all profiles currently assigned to domains are defined.   * ccs_check_profile - Check all profiles currently assigned to domains are defined.
523     *
524     * Returns nothing.
525   */   */
526  static void ccs_check_profile(void)  static void ccs_check_profile(void)
527  {  {
528          struct ccs_domain_info *domain;          struct ccs_domain_info *domain;
529          const int idx = ccs_read_lock();          const int idx = ccs_read_lock();
530          ccs_policy_loaded = true;          ccs_policy_loaded = true;
531          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {          printk(KERN_INFO "CCSecurity: 1.8.3   2011/09/29\n");
532            list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
533                  const u8 profile = domain->profile;                  const u8 profile = domain->profile;
534                  if (ccs_profile_ptr[profile])                  const struct ccs_policy_namespace *ns = domain->ns;
535                    if (ns->profile_version != 20100903)
536                            printk(KERN_ERR
537                                   "Profile version %u is not supported.\n",
538                                   ns->profile_version);
539                    else if (!ns->profile_ptr[profile])
540                            printk(KERN_ERR
541                                   "Profile %u (used by '%s') is not defined.\n",
542                                   profile, domain->domainname->name);
543                    else
544                          continue;                          continue;
545                  panic("Profile %u (used by '%s') not defined.\n",                  printk(KERN_ERR
546                        profile, domain->domainname->name);                         "Userland tools for TOMOYO 1.8 must be installed and "
547                           "policy must be initialized.\n");
548                    printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/1.8/ "
549                           "for more information.\n");
550                    panic("STOP!");
551          }          }
552          ccs_read_unlock(idx);          ccs_read_unlock(idx);
         if (ccs_profile_version != 20090903)  
                 panic("Profile version %u is not supported.\n",  
                       ccs_profile_version);  
         printk(KERN_INFO "CCSecurity: 1.8.0-pre   2010/08/01\n");  
553          printk(KERN_INFO "Mandatory Access Control activated.\n");          printk(KERN_INFO "Mandatory Access Control activated.\n");
554  }  }
555    
# Line 348  static void ccs_check_profile(void) Line 562  static void ccs_check_profile(void)
562   */   */
563  struct ccs_profile *ccs_profile(const u8 profile)  struct ccs_profile *ccs_profile(const u8 profile)
564  {  {
565          struct ccs_profile *ptr = ccs_profile_ptr[profile];          static struct ccs_profile ccs_null_profile;
566          if (!ccs_policy_loaded)          struct ccs_profile *ptr = ccs_current_namespace()->
567                  return &ccs_default_profile;                  profile_ptr[profile];
568          BUG_ON(!ptr);          if (!ptr)
569                    ptr = &ccs_null_profile;
570          return ptr;          return ptr;
571  }  }
572    
573    /**
574     * ccs_find_yesno - Find values for specified keyword.
575     *
576     * @string: String to check.
577     * @find:   Name of keyword.
578     *
579     * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise.
580     */
581  static s8 ccs_find_yesno(const char *string, const char *find)  static s8 ccs_find_yesno(const char *string, const char *find)
582  {  {
583          const char *cp = strstr(string, find);          const char *cp = strstr(string, find);
# Line 368  static s8 ccs_find_yesno(const char *str Line 591  static s8 ccs_find_yesno(const char *str
591          return -1;          return -1;
592  }  }
593    
594  static void ccs_set_bool(bool *b, const char *string, const char *find)  /**
595  {   * ccs_set_uint - Set value for specified preference.
596          switch (ccs_find_yesno(string, find)) {   *
597          case 1:   * @i:      Pointer to "unsigned int".
598                  *b = true;   * @string: String to check.
599                  break;   * @find:   Name of keyword.
600          case 0:   *
601                  *b = false;   * Returns nothing.
602                  break;   */
         }  
 }  
   
603  static void ccs_set_uint(unsigned int *i, const char *string, const char *find)  static void ccs_set_uint(unsigned int *i, const char *string, const char *find)
604  {  {
605          const char *cp = strstr(string, find);          const char *cp = strstr(string, find);
# Line 387  static void ccs_set_uint(unsigned int *i Line 607  static void ccs_set_uint(unsigned int *i
607                  sscanf(cp + strlen(find), "=%u", i);                  sscanf(cp + strlen(find), "=%u", i);
608  }  }
609    
610  static void ccs_set_pref(const char *name, const char *value,  /**
611                           struct ccs_profile *profile)   * ccs_set_mode - Set mode for specified profile.
612  {   *
613          if (!strcmp(name, "audit")) {   * @name:    Name of functionality.
614  #ifdef CONFIG_CCSECURITY_AUDIT   * @value:   Mode for @name.
615                  ccs_set_uint(&profile->preference.audit_max_grant_log, value,   * @profile: Pointer to "struct ccs_profile".
616                               "max_grant_log");   *
617                  ccs_set_uint(&profile->preference.audit_max_reject_log, value,   * Returns 0 on success, negative value otherwise.
618                               "max_reject_log");   */
 #endif  
                 ccs_set_bool(&profile->preference.audit_task_info, value,  
                              "task_info");  
                 ccs_set_bool(&profile->preference.audit_path_info, value,  
                              "path_info");  
                 return;  
         }  
         if (!strcmp(name, "enforcing")) {  
                 ccs_set_uint(&profile->preference.enforcing_penalty, value,  
                              "penalty");  
                 return;  
         }  
         if (!strcmp(name, "learning")) {  
                 ccs_set_uint(&profile->preference.learning_max_entry, value,  
                              "max_entry");  
                 ccs_set_bool(&profile->preference.learning_exec_realpath,  
                              value, "exec.realpath");  
                 ccs_set_bool(&profile->preference.learning_exec_argv0, value,  
                              "exec.argv0");  
                 ccs_set_bool(&profile->preference.learning_symlink_target,  
                              value, "symlink.target");  
                 return;  
         }  
 }  
   
619  static int ccs_set_mode(char *name, const char *value,  static int ccs_set_mode(char *name, const char *value,
620                          struct ccs_profile *profile)                          struct ccs_profile *profile)
621  {  {
622          u8 i;          u8 i;
623          u8 config;          u8 config;
624          if (!strcmp(name, "CONFIG")) {          if (!strcmp(name, "CONFIG")) {
625                  i = CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX                  i = CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
                         + CCS_MAX_MAC_CATEGORY_INDEX;  
626                  config = profile->default_config;                  config = profile->default_config;
627          } else if (ccs_str_starts(&name, "CONFIG::")) {          } else if (ccs_str_starts(&name, "CONFIG::")) {
628                  config = 0;                  config = 0;
629                  for (i = 0; i < CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX                  for (i = 0; i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
630                               + CCS_MAX_MAC_CATEGORY_INDEX; i++) {                       i++) {
631                          if (strcmp(name, ccs_mac_keywords[i]))                          int len = 0;
632                            if (i < CCS_MAX_MAC_INDEX) {
633                                    const u8 c = ccs_index2category[i];
634                                    const char *category =
635                                            ccs_category_keywords[c];
636                                    len = strlen(category);
637                                    if (strncmp(name, category, len) ||
638                                        name[len++] != ':' || name[len++] != ':')
639                                            continue;
640                            }
641                            if (strcmp(name + len, ccs_mac_keywords[i]))
642                                  continue;                                  continue;
643                          config = profile->config[i];                          config = profile->config[i];
644                          break;                          break;
645                  }                  }
646                  if (i == CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX                  if (i == CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
                     + CCS_MAX_MAC_CATEGORY_INDEX)  
647                          return -EINVAL;                          return -EINVAL;
648          } else {          } else {
649                  return -EINVAL;                  return -EINVAL;
# Line 457  static int ccs_set_mode(char *name, cons Line 660  static int ccs_set_mode(char *name, cons
660                                   */                                   */
661                                  config = (config & ~7) | mode;                                  config = (config & ~7) | mode;
662                  if (config != CCS_CONFIG_USE_DEFAULT) {                  if (config != CCS_CONFIG_USE_DEFAULT) {
                         switch (ccs_find_yesno(value, "verbose")) {  
                         case 1:  
                                 config |= CCS_CONFIG_VERBOSE;  
                                 break;  
                         case 0:  
                                 config &= ~CCS_CONFIG_VERBOSE;  
                                 break;  
                         }  
 #ifdef CONFIG_CCSECURITY_AUDIT  
663                          switch (ccs_find_yesno(value, "grant_log")) {                          switch (ccs_find_yesno(value, "grant_log")) {
664                          case 1:                          case 1:
665                                  config |= CCS_CONFIG_WANT_GRANT_LOG;                                  config |= CCS_CONFIG_WANT_GRANT_LOG;
# Line 482  static int ccs_set_mode(char *name, cons Line 676  static int ccs_set_mode(char *name, cons
676                                  config &= ~CCS_CONFIG_WANT_REJECT_LOG;                                  config &= ~CCS_CONFIG_WANT_REJECT_LOG;
677                                  break;                                  break;
678                          }                          }
 #endif  
679                  }                  }
680          }          }
681          if (i < CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX          if (i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
             + CCS_MAX_MAC_CATEGORY_INDEX)  
682                  profile->config[i] = config;                  profile->config[i] = config;
683          else if (config != CCS_CONFIG_USE_DEFAULT)          else if (config != CCS_CONFIG_USE_DEFAULT)
684                  profile->default_config = config;                  profile->default_config = config;
# Line 506  static int ccs_write_profile(struct ccs_ Line 698  static int ccs_write_profile(struct ccs_
698          unsigned int i;          unsigned int i;
699          char *cp;          char *cp;
700          struct ccs_profile *profile;          struct ccs_profile *profile;
701          if (sscanf(data, "PROFILE_VERSION=%u", &ccs_profile_version) == 1)          if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version)
702                == 1)
703                  return 0;                  return 0;
704          i = simple_strtoul(data, &cp, 10);          i = simple_strtoul(data, &cp, 10);
705          if (*cp != '-')          if (*cp != '-')
706                  return -EINVAL;                  return -EINVAL;
707          data = cp + 1;          data = cp + 1;
708          profile = ccs_assign_profile(i);          profile = ccs_assign_profile(head->w.ns, i);
709          if (!profile)          if (!profile)
710                  return -EINVAL;                  return -EINVAL;
711          cp = strchr(data, '=');          cp = strchr(data, '=');
712          if (!cp)          if (!cp)
713                  return -EINVAL;                  return -EINVAL;
714          *cp++ = '\0';          *cp++ = '\0';
         if (ccs_str_starts(&data, "PREFERENCE::")) {  
                 ccs_set_pref(data, cp, profile);  
                 return 0;  
         }  
715          if (!strcmp(data, "COMMENT")) {          if (!strcmp(data, "COMMENT")) {
716                  const struct ccs_path_info *old_comment = profile->comment;                  static DEFINE_SPINLOCK(lock);
717                  profile->comment = ccs_get_name(cp);                  const struct ccs_path_info *new_comment = ccs_get_name(cp);
718                    const struct ccs_path_info *old_comment;
719                    if (!new_comment)
720                            return -ENOMEM;
721                    spin_lock(&lock);
722                    old_comment = profile->comment;
723                    profile->comment = new_comment;
724                    spin_unlock(&lock);
725                  ccs_put_name(old_comment);                  ccs_put_name(old_comment);
726                  return 0;                  return 0;
727          }          }
728            if (!strcmp(data, "PREFERENCE")) {
729                    for (i = 0; i < CCS_MAX_PREF; i++)
730                            ccs_set_uint(&profile->pref[i], cp,
731                                         ccs_pref_keywords[i]);
732                    return 0;
733            }
734          return ccs_set_mode(data, cp, profile);          return ccs_set_mode(data, cp, profile);
735  }  }
736    
737  static void ccs_print_preference(struct ccs_io_buffer *head, const int index)  /**
738  {   * ccs_print_config - Print mode for specified functionality.
739          struct ccs_profile *profile = ccs_profile_ptr[index];   *
740          struct ccs_preference *pref = &profile->preference;   * @head:   Pointer to "struct ccs_io_buffer".
741          ccs_io_printf(head, "%u-PREFERENCE::%s={ "   * @config: Mode for that functionality.
742  #ifdef CONFIG_CCSECURITY_AUDIT   *
743                        "max_grant_log=%u max_reject_log=%u "   * Returns nothing.
744  #endif   *
745                        "task_info=%s path_info=%s }\n", index,   * Caller prints functionality's name.
746                        "audit",   */
 #ifdef CONFIG_CCSECURITY_AUDIT  
                       pref->audit_max_grant_log,  
                       pref->audit_max_reject_log,  
 #endif  
                       ccs_yesno(pref->audit_task_info),  
                       ccs_yesno(pref->audit_path_info));  
         ccs_io_printf(head, "%u-PREFERENCE::%s={ "  
                       "max_entry=%u exec.realpath=%s "  
                       "exec.argv0=%s symlink.target=%s }\n",  
                       index, "learning",  
                       pref->learning_max_entry,  
                       ccs_yesno(pref->learning_exec_realpath),  
                       ccs_yesno(pref->learning_exec_argv0),  
                       ccs_yesno(pref->learning_symlink_target));  
         ccs_io_printf(head, "%u-PREFERENCE::%s={ penalty=%u }\n", index,  
                       "enforcing", pref->enforcing_penalty);  
 }  
   
747  static void ccs_print_config(struct ccs_io_buffer *head, const u8 config)  static void ccs_print_config(struct ccs_io_buffer *head, const u8 config)
748  {  {
749          ccs_io_printf(head, "={ mode=%s verbose=%s", ccs_mode[config & 3],          ccs_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n",
750                        ccs_yesno(config & CCS_CONFIG_VERBOSE));                        ccs_mode[config & 3],
 #ifdef CONFIG_CCSECURITY_AUDIT  
         ccs_io_printf(head, " grant_log=%s reject_log=%s",  
751                        ccs_yesno(config & CCS_CONFIG_WANT_GRANT_LOG),                        ccs_yesno(config & CCS_CONFIG_WANT_GRANT_LOG),
752                        ccs_yesno(config & CCS_CONFIG_WANT_REJECT_LOG));                        ccs_yesno(config & CCS_CONFIG_WANT_REJECT_LOG));
 #endif  
         ccs_set_string(head, " }\n");  
753  }  }
754    
755  /**  /**
756   * ccs_read_profile - Read profile table.   * ccs_read_profile - Read profile table.
757   *   *
758   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
759     *
760     * Returns nothing.
761   */   */
762  static void ccs_read_profile(struct ccs_io_buffer *head)  static void ccs_read_profile(struct ccs_io_buffer *head)
763  {  {
764          u8 index;          u8 index;
765            struct ccs_policy_namespace *ns = container_of(head->r.ns, typeof(*ns),
766                                                           namespace_list);
767          const struct ccs_profile *profile;          const struct ccs_profile *profile;
768   next:          if (head->r.eof)
769                    return;
770    next:
771          index = head->r.index;          index = head->r.index;
772          profile = ccs_profile_ptr[index];          profile = ns->profile_ptr[index];
773          switch (head->r.step) {          switch (head->r.step) {
774          case 0:          case 0:
775                  ccs_io_printf(head, "PROFILE_VERSION=%s\n", "20090903");                  ccs_print_namespace(head);
776                    ccs_io_printf(head, "PROFILE_VERSION=%u\n",
777                                  ns->profile_version);
778                  head->r.step++;                  head->r.step++;
779                  break;                  break;
780          case 1:          case 1:
781                  for ( ; head->r.index < CCS_MAX_PROFILES;                  for ( ; head->r.index < CCS_MAX_PROFILES; head->r.index++)
782                        head->r.index++)                          if (ns->profile_ptr[head->r.index])
                         if (ccs_profile_ptr[head->r.index])  
783                                  break;                                  break;
784                  if (head->r.index == CCS_MAX_PROFILES)                  if (head->r.index == CCS_MAX_PROFILES) {
785                            head->r.eof = true;
786                          return;                          return;
787                    }
788                  head->r.step++;                  head->r.step++;
789                  break;                  break;
790          case 2:          case 2:
791                  {                  {
792                            u8 i;
793                          const struct ccs_path_info *comment = profile->comment;                          const struct ccs_path_info *comment = profile->comment;
794                            ccs_print_namespace(head);
795                          ccs_io_printf(head, "%u-COMMENT=", index);                          ccs_io_printf(head, "%u-COMMENT=", index);
796                          ccs_set_string(head, comment ? comment->name : "");                          ccs_set_string(head, comment ? comment->name : "");
797                          ccs_set_lf(head);                          ccs_set_lf(head);
798                            ccs_print_namespace(head);
799                            ccs_io_printf(head, "%u-PREFERENCE={ ", index);
800                            for (i = 0; i < CCS_MAX_PREF; i++)
801                                    ccs_io_printf(head, "%s=%u ",
802                                                  ccs_pref_keywords[i],
803                                                  profile->pref[i]);
804                            ccs_set_string(head, "}\n");
805                          head->r.step++;                          head->r.step++;
806                  }                  }
807                  break;                  break;
808          case 3:          case 3:
809                  {                  {
810                            ccs_print_namespace(head);
811                          ccs_io_printf(head, "%u-%s", index, "CONFIG");                          ccs_io_printf(head, "%u-%s", index, "CONFIG");
812                          ccs_print_config(head, profile->default_config);                          ccs_print_config(head, profile->default_config);
813                          head->r.bit = 0;                          head->r.bit = 0;
# Line 617  static void ccs_read_profile(struct ccs_ Line 816  static void ccs_read_profile(struct ccs_
816                  break;                  break;
817          case 4:          case 4:
818                  for ( ; head->r.bit < CCS_MAX_MAC_INDEX                  for ( ; head->r.bit < CCS_MAX_MAC_INDEX
                               + CCS_MAX_CAPABILITY_INDEX  
819                                + CCS_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {                                + CCS_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
820                          const u8 i = head->r.bit;                          const u8 i = head->r.bit;
821                          const u8 config = profile->config[i];                          const u8 config = profile->config[i];
822                          if (config == CCS_CONFIG_USE_DEFAULT)                          if (config == CCS_CONFIG_USE_DEFAULT)
823                                  continue;                                  continue;
824                          ccs_io_printf(head, "%u-%s%s", index, "CONFIG::",                          ccs_print_namespace(head);
825                                        ccs_mac_keywords[i]);                          if (i < CCS_MAX_MAC_INDEX)
826                                    ccs_io_printf(head, "%u-CONFIG::%s::%s", index,
827                                                  ccs_category_keywords
828                                                  [ccs_index2category[i]],
829                                                  ccs_mac_keywords[i]);
830                            else
831                                    ccs_io_printf(head, "%u-CONFIG::%s", index,
832                                                  ccs_mac_keywords[i]);
833                          ccs_print_config(head, config);                          ccs_print_config(head, config);
834                          head->r.bit++;                          head->r.bit++;
835                          break;                          break;
836                  }                  }
837                  if (head->r.bit == CCS_MAX_MAC_INDEX                  if (head->r.bit == CCS_MAX_MAC_INDEX
                     + CCS_MAX_CAPABILITY_INDEX  
838                      + CCS_MAX_MAC_CATEGORY_INDEX) {                      + CCS_MAX_MAC_CATEGORY_INDEX) {
                         ccs_print_preference(head, index);  
839                          head->r.index++;                          head->r.index++;
840                          head->r.step = 1;                          head->r.step = 1;
841                  }                  }
# Line 642  static void ccs_read_profile(struct ccs_ Line 845  static void ccs_read_profile(struct ccs_
845                  goto next;                  goto next;
846  }  }
847    
848    /**
849     * ccs_same_manager - Check for duplicated "struct ccs_manager" entry.
850     *
851     * @a: Pointer to "struct ccs_acl_head".
852     * @b: Pointer to "struct ccs_acl_head".
853     *
854     * Returns true if @a == @b, false otherwise.
855     */
856  static bool ccs_same_manager(const struct ccs_acl_head *a,  static bool ccs_same_manager(const struct ccs_acl_head *a,
857                               const struct ccs_acl_head *b)                               const struct ccs_acl_head *b)
858  {  {
# Line 657  static bool ccs_same_manager(const struc Line 868  static bool ccs_same_manager(const struc
868   *   *
869   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
870   */   */
871  static int ccs_update_manager_entry(const char *manager, const bool is_delete)  static inline int ccs_update_manager_entry(const char *manager,
872                                               const bool is_delete)
873  {  {
874          struct ccs_manager e = { };          struct ccs_manager e = { };
875            struct ccs_acl_param param = {
876                    /* .ns = &ccs_kernel_namespace, */
877                    .is_delete = is_delete,
878                    .list = &ccs_kernel_namespace.policy_list[CCS_ID_MANAGER],
879            };
880          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
881          if (ccs_domain_def(manager)) {          if (ccs_domain_def(manager)) {
882                  if (!ccs_correct_domain(manager))                  if (!ccs_correct_domain(manager))
# Line 670  static int ccs_update_manager_entry(cons Line 887  static int ccs_update_manager_entry(cons
887                          return -EINVAL;                          return -EINVAL;
888          }          }
889          e.manager = ccs_get_name(manager);          e.manager = ccs_get_name(manager);
890          if (!e.manager)          if (e.manager) {
891                  return error;                  error = ccs_update_policy(&e.head, sizeof(e), &param,
892          error = ccs_update_policy(&e.head, sizeof(e), is_delete,                                            ccs_same_manager);
893                                    &ccs_policy_list[CCS_ID_MANAGER],                  ccs_put_name(e.manager);
894                                    ccs_same_manager);          }
         ccs_put_name(e.manager);  
895          return error;          return error;
896  }  }
897    
# Line 688  static int ccs_update_manager_entry(cons Line 904  static int ccs_update_manager_entry(cons
904   */   */
905  static int ccs_write_manager(struct ccs_io_buffer *head)  static int ccs_write_manager(struct ccs_io_buffer *head)
906  {  {
907          char *data = head->write_buf;          const char *data = head->write_buf;
         bool is_delete = ccs_str_starts(&data, CCS_KEYWORD_DELETE);  
908          if (!strcmp(data, "manage_by_non_root")) {          if (!strcmp(data, "manage_by_non_root")) {
909                  ccs_manage_by_non_root = !is_delete;                  ccs_manage_by_non_root = !head->w.is_delete;
910                  return 0;                  return 0;
911          }          }
912          return ccs_update_manager_entry(data, is_delete);          return ccs_update_manager_entry(data, head->w.is_delete);
913  }  }
914    
915  /**  /**
# Line 702  static int ccs_write_manager(struct ccs_ Line 917  static int ccs_write_manager(struct ccs_
917   *   *
918   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
919   *   *
920     * Returns nothing.
921     *
922   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
923   */   */
924  static void ccs_read_manager(struct ccs_io_buffer *head)  static void ccs_read_manager(struct ccs_io_buffer *head)
925  {  {
926          if (head->r.eof)          if (head->r.eof)
927                  return;                  return;
928          list_for_each_cookie(head->r.acl, &ccs_policy_list[CCS_ID_MANAGER]) {          list_for_each_cookie(head->r.acl, &ccs_kernel_namespace.
929                                 policy_list[CCS_ID_MANAGER]) {
930                  struct ccs_manager *ptr =                  struct ccs_manager *ptr =
931                          list_entry(head->r.acl, typeof(*ptr), head.list);                          list_entry(head->r.acl, typeof(*ptr), head.list);
932                  if (ptr->head.is_deleted)                  if (ptr->head.is_deleted)
# Line 733  static bool ccs_manager(void) Line 951  static bool ccs_manager(void)
951  {  {
952          struct ccs_manager *ptr;          struct ccs_manager *ptr;
953          const char *exe;          const char *exe;
954          struct task_struct *task = current;          struct ccs_security *task = ccs_current_security();
955          const struct ccs_path_info *domainname          const struct ccs_path_info *domainname
956                  = ccs_current_domain()->domainname;                  = ccs_current_domain()->domainname;
957          bool found = false;          bool found = false;
# Line 744  static bool ccs_manager(void) Line 962  static bool ccs_manager(void)
962          if (!ccs_manage_by_non_root && (current_uid() || current_euid()))          if (!ccs_manage_by_non_root && (current_uid() || current_euid()))
963                  return false;                  return false;
964          exe = ccs_get_exe();          exe = ccs_get_exe();
965          list_for_each_entry_rcu(ptr, &ccs_policy_list[CCS_ID_MANAGER],          list_for_each_entry_srcu(ptr, &ccs_kernel_namespace.
966                                  head.list) {                                   policy_list[CCS_ID_MANAGER], head.list,
967                                     &ccs_ss) {
968                  if (ptr->head.is_deleted)                  if (ptr->head.is_deleted)
969                          continue;                          continue;
970                  if (ptr->is_domain) {                  if (ptr->is_domain) {
# Line 774  static bool ccs_manager(void) Line 993  static bool ccs_manager(void)
993  }  }
994    
995  /**  /**
996   * ccs_find_condition_part - Find condition part from the statement.   * ccs_select_domain - 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)  
                 cp = strstr(data, " ; set ");  
         if (cp)  
                 *cp++ = '\0';  
         return cp;  
 }  
   
 /**  
  * ccs_select_one - Parse select command.  
997   *   *
998   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
999   * @data: String to parse.   * @data: String to parse.
# Line 801  static char *ccs_find_condition_part(cha Line 1002  static char *ccs_find_condition_part(cha
1002   *   *
1003   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
1004   */   */
1005  static bool ccs_select_one(struct ccs_io_buffer *head, const char *data)  static bool ccs_select_domain(struct ccs_io_buffer *head, const char *data)
1006  {  {
1007          unsigned int pid;          unsigned int pid;
1008          struct ccs_domain_info *domain = NULL;          struct ccs_domain_info *domain = NULL;
1009          bool global_pid = false;          bool global_pid = false;
1010          if (!strcmp(data, "execute")) {          if (strncmp(data, "select ", 7))
1011                  head->r.print_execute_only = true;                  return false;
1012                  return true;          data += 7;
         }  
1013          if (sscanf(data, "pid=%u", &pid) == 1 ||          if (sscanf(data, "pid=%u", &pid) == 1 ||
1014              (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {              (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
1015                  struct task_struct *p;                  struct task_struct *p;
# Line 827  static bool ccs_select_one(struct ccs_io Line 1027  static bool ccs_select_one(struct ccs_io
1027                          domain = ccs_task_domain(p);                          domain = ccs_task_domain(p);
1028                  ccs_tasklist_unlock();                  ccs_tasklist_unlock();
1029          } else if (!strncmp(data, "domain=", 7)) {          } else if (!strncmp(data, "domain=", 7)) {
1030                  if (ccs_domain_def(data + 7))                  if (*(data + 7) == '<')
1031                          domain = ccs_find_domain(data + 7);                          domain = ccs_find_domain(data + 7);
1032          } else          } else
1033                  return false;                  return false;
# Line 837  static bool ccs_select_one(struct ccs_io Line 1037  static bool ccs_select_one(struct ccs_io
1037                  return true; /* Do nothing if open(O_WRONLY). */                  return true; /* Do nothing if open(O_WRONLY). */
1038          memset(&head->r, 0, sizeof(head->r));          memset(&head->r, 0, sizeof(head->r));
1039          head->r.print_this_domain_only = true;          head->r.print_this_domain_only = true;
1040          head->r.eof = !domain;          if (domain)
1041          head->r.domain = &domain->list;                  head->r.domain = &domain->list;
1042            else
1043                    head->r.eof = true;
1044          ccs_io_printf(head, "# select %s\n", data);          ccs_io_printf(head, "# select %s\n", data);
1045          if (domain && domain->is_deleted)          if (domain && domain->is_deleted)
1046                  ccs_set_string(head, "# This is a deleted domain.\n");                  ccs_set_string(head, "# This is a deleted domain.\n");
1047          return true;          return true;
1048  }  }
1049    
1050  static int ccs_write_domain2(char *data, struct ccs_domain_info *domain,  /**
1051     * ccs_same_handler_acl - Check for duplicated "struct ccs_handler_acl" entry.
1052     *
1053     * @a: Pointer to "struct ccs_acl_info".
1054     * @b: Pointer to "struct ccs_acl_info".
1055     *
1056     * Returns true if @a == @b, false otherwise.
1057     */
1058    static bool ccs_same_handler_acl(const struct ccs_acl_info *a,
1059                                     const struct ccs_acl_info *b)
1060    {
1061            const struct ccs_handler_acl *p1 = container_of(a, typeof(*p1), head);
1062            const struct ccs_handler_acl *p2 = container_of(b, typeof(*p2), head);
1063            return p1->handler == p2->handler;
1064    }
1065    
1066    /**
1067     * ccs_same_task_acl - Check for duplicated "struct ccs_task_acl" entry.
1068     *
1069     * @a: Pointer to "struct ccs_acl_info".
1070     * @b: Pointer to "struct ccs_acl_info".
1071     *
1072     * Returns true if @a == @b, false otherwise.
1073     */
1074    static bool ccs_same_task_acl(const struct ccs_acl_info *a,
1075                                  const struct ccs_acl_info *b)
1076    {
1077            const struct ccs_task_acl *p1 = container_of(a, typeof(*p1), head);
1078            const struct ccs_task_acl *p2 = container_of(b, typeof(*p2), head);
1079            return p1->domainname == p2->domainname;
1080    }
1081    
1082    /**
1083     * ccs_write_task - Update task related list.
1084     *
1085     * @param: Pointer to "struct ccs_acl_param".
1086     *
1087     * Returns 0 on success, negative value otherwise.
1088     *
1089     * Caller holds ccs_read_lock().
1090     */
1091    static int ccs_write_task(struct ccs_acl_param *param)
1092    {
1093            int error;
1094            const bool is_auto = ccs_str_starts(&param->data,
1095                                                "auto_domain_transition ");
1096            if (!is_auto && !ccs_str_starts(&param->data,
1097                                            "manual_domain_transition ")) {
1098                    struct ccs_handler_acl e = { };
1099                    char *handler;
1100                    if (ccs_str_starts(&param->data, "auto_execute_handler "))
1101                            e.head.type = CCS_TYPE_AUTO_EXECUTE_HANDLER;
1102                    else if (ccs_str_starts(&param->data,
1103                                            "denied_execute_handler "))
1104                            e.head.type = CCS_TYPE_DENIED_EXECUTE_HANDLER;
1105                    else
1106                            return -EINVAL;
1107                    handler = ccs_read_token(param);
1108                    if (!ccs_correct_path(handler))
1109                            return -EINVAL;
1110                    e.handler = ccs_get_name(handler);
1111                    if (!e.handler)
1112                            return -ENOMEM;
1113                    if (e.handler->is_patterned)
1114                            error = -EINVAL; /* No patterns allowed. */
1115                    else
1116                            error = ccs_update_domain(&e.head, sizeof(e), param,
1117                                                      ccs_same_handler_acl, NULL);
1118                    ccs_put_name(e.handler);
1119            } else {
1120                    struct ccs_task_acl e = {
1121                            .head.type = is_auto ?
1122                            CCS_TYPE_AUTO_TASK_ACL : CCS_TYPE_MANUAL_TASK_ACL,
1123                            .domainname = ccs_get_domainname(param),
1124                    };
1125                    if (!e.domainname)
1126                            error = -EINVAL;
1127                    else
1128                            error = ccs_update_domain(&e.head, sizeof(e), param,
1129                                                      ccs_same_task_acl, NULL);
1130                    ccs_put_name(e.domainname);
1131            }
1132            return error;
1133    }
1134    
1135    /**
1136     * ccs_write_domain2 - Write domain policy.
1137     *
1138     * @ns:        Pointer to "struct ccs_policy_namespace".
1139     * @list:      Pointer to "struct list_head".
1140     * @data:      Policy to be interpreted.
1141     * @is_delete: True if it is a delete request.
1142     *
1143     * Returns 0 on success, negative value otherwise.
1144     *
1145     * Caller holds ccs_read_lock().
1146     */
1147    static int ccs_write_domain2(struct ccs_policy_namespace *ns,
1148                                 struct list_head *list, char *data,
1149                               const bool is_delete)                               const bool is_delete)
1150  {  {
1151            struct ccs_acl_param param = {
1152                    .ns = ns,
1153                    .list = list,
1154                    .data = data,
1155                    .is_delete = is_delete,
1156            };
1157          static const struct {          static const struct {
1158                  const char *keyword;                  const char *keyword;
1159                  int (*write) (char *, struct ccs_domain_info *,                  int (*write) (struct ccs_acl_param *);
1160                                struct ccs_condition *, const bool);          } ccs_callback[7] = {
1161          } ccs_callback[4] = {                  { "file ", ccs_write_file },
1162                  { "network ", ccs_write_network },                  { "network inet ", ccs_write_inet_network },
1163                    { "network unix ", ccs_write_unix_network },
1164                  { "misc ", ccs_write_misc },                  { "misc ", ccs_write_misc },
1165                  { "capability ", ccs_write_capability },                  { "capability ", ccs_write_capability },
1166                  { "ipc ", ccs_write_ipc },                  { "ipc signal ", ccs_write_ipc },
1167                    { "task ", ccs_write_task },
1168          };          };
         int (*write) (char *, struct ccs_domain_info *, struct ccs_condition *,  
                       const bool) = ccs_write_file;  
         int error;  
1169          u8 i;          u8 i;
1170          struct ccs_condition *cond = NULL;          for (i = 0; i < ARRAY_SIZE(ccs_callback); i++) {
1171          char *cp = ccs_find_condition_part(data);                  if (!ccs_str_starts(&param.data, ccs_callback[i].keyword))
1172          if (cp) {                          continue;
1173                  cond = ccs_get_condition(cp);                  return ccs_callback[i].write(&param);
                 if (!cond)  
                         return -EINVAL;  
1174          }          }
1175          for (i = 0; i < 4; i++) {          return -EINVAL;
1176                  if (!ccs_str_starts(&data, ccs_callback[i].keyword))  }
1177    
1178    /**
1179     * ccs_delete_domain - Delete a domain.
1180     *
1181     * @domainname: The name of domain.
1182     *
1183     * Returns 0.
1184     */
1185    static int ccs_delete_domain(char *domainname)
1186    {
1187            struct ccs_domain_info *domain;
1188            struct ccs_path_info name;
1189            name.name = domainname;
1190            ccs_fill_path_info(&name);
1191            if (mutex_lock_interruptible(&ccs_policy_lock))
1192                    return 0;
1193            /* Is there an active domain? */
1194            list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
1195                    /* Never delete ccs_kernel_domain. */
1196                    if (domain == &ccs_kernel_domain)
1197                            continue;
1198                    if (domain->is_deleted ||
1199                        ccs_pathcmp(domain->domainname, &name))
1200                          continue;                          continue;
1201                  write = ccs_callback[i].write;                  domain->is_deleted = true;
1202                  break;                  break;
1203          }          }
1204          error = write(data, domain, cond, is_delete);          mutex_unlock(&ccs_policy_lock);
1205          if (cond)          return 0;
                 ccs_put_condition(cond);  
         return error;  
1206  }  }
1207    
1208  static const char *ccs_dif[CCS_MAX_DOMAIN_INFO_FLAGS] = {  /* String table for domain flags. */
1209          [CCS_DIF_QUOTA_WARNED] = CCS_KEYWORD_QUOTA_EXCEEDED "\n",  const char * const ccs_dif[CCS_MAX_DOMAIN_INFO_FLAGS] = {
1210          [CCS_DIF_TRANSITION_FAILED] = CCS_KEYWORD_TRANSITION_FAILED "\n"          [CCS_DIF_QUOTA_WARNED]      = "quota_exceeded\n",
1211            [CCS_DIF_TRANSITION_FAILED] = "transition_failed\n",
1212  };  };
1213            
1214  /**  /**
1215   * ccs_write_domain - Write domain policy.   * ccs_write_domain - Write domain policy.
1216   *   *
1217   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
1218   *   *
1219   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
1220     *
1221     * Caller holds ccs_read_lock().
1222   */   */
1223  static int ccs_write_domain(struct ccs_io_buffer *head)  static int ccs_write_domain(struct ccs_io_buffer *head)
1224  {  {
1225          char *data = head->write_buf;          char *data = head->write_buf;
1226            struct ccs_policy_namespace *ns;
1227          struct ccs_domain_info *domain = head->w.domain;          struct ccs_domain_info *domain = head->w.domain;
1228          bool is_delete = false;          const bool is_delete = head->w.is_delete;
1229          bool is_select = false;          const bool is_select = !is_delete && ccs_str_starts(&data, "select ");
1230          unsigned int profile;          unsigned int profile;
1231          if (ccs_str_starts(&data, CCS_KEYWORD_DELETE))          if (*data == '<') {
                 is_delete = true;  
         else if (ccs_str_starts(&data, CCS_KEYWORD_SELECT))  
                 is_select = true;  
         if (is_select && ccs_select_one(head, data))  
                 return 0;  
         /* Don't allow updating policies by non manager programs. */  
         if (!ccs_manager())  
                 return -EPERM;  
         if (ccs_domain_def(data)) {  
1232                  domain = NULL;                  domain = NULL;
1233                  if (is_delete)                  if (is_delete)
1234                          ccs_delete_domain(data);                          ccs_delete_domain(data);
1235                  else if (is_select)                  else if (is_select)
1236                          domain = ccs_find_domain(data);                          domain = ccs_find_domain(data);
1237                  else                  else
1238                          domain = ccs_assign_domain(data, 0, 0);                          domain = ccs_assign_domain(data, false);
1239                  head->w.domain = domain;                  head->w.domain = domain;
1240                  return 0;                  return 0;
1241          }          }
1242          if (!domain)          if (!domain)
1243                  return -EINVAL;                  return -EINVAL;
1244            ns = domain->ns;
1245          if (sscanf(data, CCS_KEYWORD_USE_PROFILE "%u", &profile) == 1          if (sscanf(data, "use_profile %u\n", &profile) == 1
1246              && profile < CCS_MAX_PROFILES) {              && profile < CCS_MAX_PROFILES) {
1247                  if (!ccs_policy_loaded || ccs_profile_ptr[(u8) profile])                  if (!ccs_policy_loaded || ns->profile_ptr[(u8) profile])
1248                          domain->profile = (u8) profile;                          if (!is_delete)
1249                                    domain->profile = (u8) profile;
1250                  return 0;                  return 0;
1251          }          }
1252          if (sscanf(data, CCS_KEYWORD_USE_GROUP "%u", &profile) == 1          if (sscanf(data, "use_group %u\n", &profile) == 1
1253              && profile < CCS_MAX_ACL_GROUPS) {              && profile < CCS_MAX_ACL_GROUPS) {
1254                  domain->group = (u8) profile;                  if (!is_delete)
1255                            domain->group = (u8) profile;
1256                  return 0;                  return 0;
1257          }          }
1258          for (profile = 0; profile < CCS_MAX_DOMAIN_INFO_FLAGS; profile++) {          for (profile = 0; profile < CCS_MAX_DOMAIN_INFO_FLAGS; profile++) {
# Line 941  static int ccs_write_domain(struct ccs_i Line 1262  static int ccs_write_domain(struct ccs_i
1262                  domain->flags[profile] = !is_delete;                  domain->flags[profile] = !is_delete;
1263                  return 0;                  return 0;
1264          }          }
1265          return ccs_write_domain2(data, domain, is_delete);          return ccs_write_domain2(ns, &domain->acl_info_list, data, is_delete);
1266  }  }
1267    
1268  /**  /**
# Line 949  static int ccs_write_domain(struct ccs_i Line 1270  static int ccs_write_domain(struct ccs_i
1270   *   *
1271   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
1272   * @ptr:  Pointer to "struct ccs_name_union".   * @ptr:  Pointer to "struct ccs_name_union".
1273     *
1274     * Returns nothing.
1275   */   */
1276  static void ccs_print_name_union(struct ccs_io_buffer *head,  static void ccs_print_name_union(struct ccs_io_buffer *head,
1277                                   const struct ccs_name_union *ptr)                                   const struct ccs_name_union *ptr)
1278  {  {
1279          const bool cond = head->r.print_cond_part;          ccs_set_space(head);
1280          if (!cond)          if (ptr->group) {
                 ccs_set_space(head);  
         if (ptr->is_group) {  
1281                  ccs_set_string(head, "@");                  ccs_set_string(head, "@");
1282                  ccs_set_string(head, ptr->group->group_name->name);                  ccs_set_string(head, ptr->group->group_name->name);
1283          } else {          } else {
                 if (cond)  
                         ccs_set_string(head, "\"");  
1284                  ccs_set_string(head, ptr->filename->name);                  ccs_set_string(head, ptr->filename->name);
                 if (cond)  
                         ccs_set_string(head, "\"");  
1285          }          }
1286  }  }
1287    
1288  /**  /**
1289   * ccs_print_number_union - Print a ccs_number_union.   * ccs_print_name_union_quoted - Print a ccs_name_union with a quote.
1290     *
1291     * @head: Pointer to "struct ccs_io_buffer".
1292     * @ptr:  Pointer to "struct ccs_name_union".
1293     *
1294     * Returns nothing.
1295     */
1296    static void ccs_print_name_union_quoted(struct ccs_io_buffer *head,
1297                                            const struct ccs_name_union *ptr)
1298    {
1299            if (ptr->group) {
1300                    ccs_set_string(head, "@");
1301                    ccs_set_string(head, ptr->group->group_name->name);
1302            } else {
1303                    ccs_set_string(head, "\"");
1304                    ccs_set_string(head, ptr->filename->name);
1305                    ccs_set_string(head, "\"");
1306            }
1307    }
1308    
1309    /**
1310     * ccs_print_number_union_nospace - Print a ccs_number_union without a space.
1311   *   *
1312   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
1313   * @ptr:  Pointer to "struct ccs_number_union".   * @ptr:  Pointer to "struct ccs_number_union".
1314     *
1315     * Returns nothing.
1316   */   */
1317  static void ccs_print_number_union(struct ccs_io_buffer *head,  static void ccs_print_number_union_nospace(struct ccs_io_buffer *head,
1318                                     const struct ccs_number_union *ptr)                                             const struct ccs_number_union *ptr)
1319  {  {
1320          if (!head->r.print_cond_part)          if (ptr->group) {
                 ccs_set_space(head);  
         if (ptr->is_group) {  
1321                  ccs_set_string(head, "@");                  ccs_set_string(head, "@");
1322                  ccs_set_string(head, ptr->group->group_name->name);                  ccs_set_string(head, ptr->group->group_name->name);
1323          } else {          } else {
# Line 1016  static void ccs_print_number_union(struc Line 1354  static void ccs_print_number_union(struc
1354  }  }
1355    
1356  /**  /**
1357     * ccs_print_number_union - Print a ccs_number_union.
1358     *
1359     * @head: Pointer to "struct ccs_io_buffer".
1360     * @ptr:  Pointer to "struct ccs_number_union".
1361     *
1362     * Returns nothing.
1363     */
1364    static void ccs_print_number_union(struct ccs_io_buffer *head,
1365                                       const struct ccs_number_union *ptr)
1366    {
1367            ccs_set_space(head);
1368            ccs_print_number_union_nospace(head, ptr);
1369    }
1370    
1371    /**
1372   * ccs_print_condition - Print condition part.   * ccs_print_condition - Print condition part.
1373   *   *
1374   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
# Line 1028  static bool ccs_print_condition(struct c Line 1381  static bool ccs_print_condition(struct c
1381  {  {
1382          switch (head->r.cond_step) {          switch (head->r.cond_step) {
1383          case 0:          case 0:
1384                  {                  head->r.cond_index = 0;
1385                          if (cond->condc)                  head->r.cond_step++;
1386                                  ccs_set_string(head, " if");                  if (cond->transit && cond->exec_transit) {
1387                          head->r.cond_index = 0;                          ccs_set_space(head);
1388                          head->r.cond_step++;                          ccs_set_string(head, cond->transit->name);
1389                  }                  }
1390                  /* fall through */                  /* fall through */
1391          case 1:          case 1:
# Line 1086  static bool ccs_print_condition(struct c Line 1439  static bool ccs_print_condition(struct c
1439                                  switch (left) {                                  switch (left) {
1440                                  case CCS_ARGV_ENTRY:                                  case CCS_ARGV_ENTRY:
1441                                          ccs_io_printf(head,                                          ccs_io_printf(head,
1442                                                        "exec.argv[%u]%s\"%s\"",                                                        "exec.argv[%lu]%s=\"",
1443                                                        argv->index,                                                        argv->index,
1444                                                        argv->is_not ?                                                        argv->is_not ? "!" : "");
1445                                                        "!=" : "=",                                          ccs_set_string(head,
1446                                                        argv->value->name);                                                         argv->value->name);
1447                                            ccs_set_string(head, "\"");
1448                                          argv++;                                          argv++;
1449                                          continue;                                          continue;
1450                                  case CCS_ENVP_ENTRY:                                  case CCS_ENVP_ENTRY:
1451                                          ccs_io_printf(head,                                          ccs_set_string(head, "exec.envp[\"");
1452                                                        "exec.envp[\"%s\"]%s",                                          ccs_set_string(head, envp->name->name);
1453                                                        envp->name->name,                                          ccs_io_printf(head, "\"]%s=",
1454                                                        envp->is_not ?                                                        envp->is_not ? "!" : "");
                                                       "!=" : "=");  
1455                                          if (envp->value) {                                          if (envp->value) {
1456                                                  ccs_set_string(head, "\"");                                                  ccs_set_string(head, "\"");
1457                                                  ccs_set_string(head, envp->                                                  ccs_set_string(head, envp->
# Line 1110  static bool ccs_print_condition(struct c Line 1463  static bool ccs_print_condition(struct c
1463                                          envp++;                                          envp++;
1464                                          continue;                                          continue;
1465                                  case CCS_NUMBER_UNION:                                  case CCS_NUMBER_UNION:
1466                                          ccs_print_number_union(head,                                          ccs_print_number_union_nospace
1467                                                                 numbers_p++);                                                  (head, numbers_p++);
1468                                          break;                                          break;
1469                                  default:                                  default:
1470                                          ccs_set_string(head,                                          ccs_set_string(head,
# Line 1121  static bool ccs_print_condition(struct c Line 1474  static bool ccs_print_condition(struct c
1474                                  ccs_set_string(head, match ? "=" : "!=");                                  ccs_set_string(head, match ? "=" : "!=");
1475                                  switch (right) {                                  switch (right) {
1476                                  case CCS_NAME_UNION:                                  case CCS_NAME_UNION:
1477                                          ccs_print_name_union(head, names_p++);                                          ccs_print_name_union_quoted
1478                                                    (head, names_p++);
1479                                          break;                                          break;
1480                                  case CCS_NUMBER_UNION:                                  case CCS_NUMBER_UNION:
1481                                          ccs_print_number_union(head,                                          ccs_print_number_union_nospace
1482                                                                 numbers_p++);                                                  (head, numbers_p++);
1483                                          break;                                          break;
1484                                  default:                                  default:
1485                                          ccs_set_string(head,                                          ccs_set_string(head,
# Line 1142  static bool ccs_print_condition(struct c Line 1496  static bool ccs_print_condition(struct c
1496                  head->r.cond_step++;                  head->r.cond_step++;
1497                  /* fall through */                  /* fall through */
1498          case 3:          case 3:
1499                  {                  if (cond->grant_log != CCS_GRANTLOG_AUTO)
1500                          u8 j;                          ccs_io_printf(head, " grant_log=%s",
1501                          const u8 i = cond->post_state[3];                                        ccs_yesno(cond->grant_log ==
1502                          if (i)                                                  CCS_GRANTLOG_YES));
1503                                  ccs_set_string(head, " ; set");                  if (cond->transit && !cond->exec_transit) {
1504                          for (j = 0; j < 3; j++)                          const char *name = cond->transit->name;
1505                                  if ((i & (1 << j)))                          ccs_set_string(head, " auto_domain_transition=\"");
1506                                          ccs_io_printf(head,                          ccs_set_string(head, name);
1507                                                        " task.state[%u]=%u", j,                          ccs_set_string(head, "\"");
                                                       cond->post_state[j]);  
                         if (i & (1 << 4))  
                                 ccs_io_printf(head, " audit=%s",  
                                               ccs_yesno(cond->post_state[4]));  
1508                  }                  }
1509                  ccs_set_lf(head);                  ccs_set_lf(head);
1510                  return true;                  return true;
# Line 1163  static bool ccs_print_condition(struct c Line 1513  static bool ccs_print_condition(struct c
1513  }  }
1514    
1515  /**  /**
1516   * ccs_fns - Find next set bit.   * ccs_set_group - Print "acl_group " header keyword and category name.
1517   *   *
1518   * @perm: 8 bits value.   * @head:     Pointer to "struct ccs_io_buffer".
1519   * @bit:  First bit to find.   * @category: Category name.
1520   *   *
1521   * Returns next set bit on success, 8 otherwise.   * Returns nothing.
1522   */   */
1523  static u8 ccs_fns(const u8 perm, u8 bit)  static void ccs_set_group(struct ccs_io_buffer *head, const char *category)
 {  
         for ( ; bit < 8; bit++)  
                 if (perm & (1 << bit))  
                         break;  
         return bit;  
 }  
   
 static void ccs_set_group(struct ccs_io_buffer *head)  
1524  {  {
1525          if (head->type == CCS_EXCEPTIONPOLICY)          if (head->type == CCS_EXCEPTIONPOLICY) {
1526                  ccs_io_printf(head, "acl_group %u ", head->r.group_index);                  ccs_print_namespace(head);
1527                    ccs_io_printf(head, "acl_group %u ", head->r.acl_group_index);
1528            }
1529            ccs_set_string(head, category);
1530  }  }
1531    
1532  /**  /**
# Line 1196  static bool ccs_print_entry(struct ccs_i Line 1541  static bool ccs_print_entry(struct ccs_i
1541                              const struct ccs_acl_info *acl)                              const struct ccs_acl_info *acl)
1542  {  {
1543          const u8 acl_type = acl->type;          const u8 acl_type = acl->type;
1544            const bool may_trigger_transition = acl->cond && acl->cond->transit;
1545            bool first = true;
1546          u8 bit;          u8 bit;
1547          if (head->r.print_cond_part)          if (head->r.print_cond_part)
1548                  goto print_cond_part;                  goto print_cond_part;
1549          if (acl->is_deleted)          if (acl->is_deleted)
1550                  return true;                  return true;
  next:  
         bit = head->r.bit;  
1551          if (!ccs_flush(head))          if (!ccs_flush(head))
1552                  return false;                  return false;
1553          else if (acl_type == CCS_TYPE_PATH_ACL) {          else if (acl_type == CCS_TYPE_PATH_ACL) {
1554                  struct ccs_path_acl *ptr                  struct ccs_path_acl *ptr
1555                          = container_of(acl, typeof(*ptr), head);                          = container_of(acl, typeof(*ptr), head);
1556                  const u16 perm = ptr->perm;                  const u16 perm = ptr->perm;
1557                  for ( ; bit < CCS_MAX_PATH_OPERATION; bit++) {                  for (bit = 0; bit < CCS_MAX_PATH_OPERATION; bit++) {
1558                          if (!(perm & (1 << bit)))                          if (!(perm & (1 << bit)))
1559                                  continue;                                  continue;
1560                          if (head->r.print_execute_only &&                          if (head->r.print_transition_related_only &&
1561                              bit != CCS_TYPE_EXECUTE && bit != CCS_TYPE_TRANSIT)                              bit != CCS_TYPE_EXECUTE && !may_trigger_transition)
1562                                  continue;                                  continue;
1563                          break;                          if (first) {
1564                                    ccs_set_group(head, "file ");
1565                                    first = false;
1566                            } else {
1567                                    ccs_set_slash(head);
1568                            }
1569                            ccs_set_string(head, ccs_path_keyword[bit]);
1570                  }                  }
1571                  if (bit >= CCS_MAX_PATH_OPERATION)                  if (first)
1572                          goto done;                          return true;
                 ccs_set_group(head);  
                 ccs_set_string(head, "file ");  
                 ccs_set_string(head, ccs_path_keyword[bit]);  
1573                  ccs_print_name_union(head, &ptr->name);                  ccs_print_name_union(head, &ptr->name);
1574          } else if (acl_type == CCS_TYPE_EXECUTE_HANDLER ||          } else if (acl_type == CCS_TYPE_AUTO_EXECUTE_HANDLER ||
1575                     acl_type == CCS_TYPE_DENIED_EXECUTE_HANDLER) {                     acl_type == CCS_TYPE_DENIED_EXECUTE_HANDLER) {
1576                  struct ccs_execute_handler *ptr                  struct ccs_handler_acl *ptr
1577                          = container_of(acl, typeof(*ptr), head);                          = container_of(acl, typeof(*ptr), head);
1578                  ccs_set_group(head);                  ccs_set_group(head, "task ");
1579                  ccs_io_printf(head, "%s ",                  ccs_set_string(head, acl_type == CCS_TYPE_AUTO_EXECUTE_HANDLER
1580                                acl_type == CCS_TYPE_EXECUTE_HANDLER ?                                 ? "auto_execute_handler " :
1581                                CCS_KEYWORD_EXECUTE_HANDLER :                                 "denied_execute_handler ");
                               CCS_KEYWORD_DENIED_EXECUTE_HANDLER);  
1582                  ccs_set_string(head, ptr->handler->name);                  ccs_set_string(head, ptr->handler->name);
1583          } else if (head->r.print_execute_only) {          } else if (acl_type == CCS_TYPE_AUTO_TASK_ACL ||
1584                       acl_type == CCS_TYPE_MANUAL_TASK_ACL) {
1585                    struct ccs_task_acl *ptr =
1586                            container_of(acl, typeof(*ptr), head);
1587                    ccs_set_group(head, "task ");
1588                    ccs_set_string(head, acl_type == CCS_TYPE_AUTO_TASK_ACL ?
1589                                   "auto_domain_transition " :
1590                                   "manual_domain_transition ");
1591                    ccs_set_string(head, ptr->domainname->name);
1592            } else if (head->r.print_transition_related_only &&
1593                       !may_trigger_transition) {
1594                  return true;                  return true;
1595          } else if (acl_type == CCS_TYPE_MKDEV_ACL) {          } else if (acl_type == CCS_TYPE_MKDEV_ACL) {
1596                  struct ccs_mkdev_acl *ptr =                  struct ccs_mkdev_acl *ptr =
1597                          container_of(acl, typeof(*ptr), head);                          container_of(acl, typeof(*ptr), head);
1598                  bit = ccs_fns(ptr->perm, bit);                  const u8 perm = ptr->perm;
1599                  if (bit >= CCS_MAX_MKDEV_OPERATION)                  for (bit = 0; bit < CCS_MAX_MKDEV_OPERATION; bit++) {
1600                          goto done;                          if (!(perm & (1 << bit)))
1601                  ccs_set_group(head);                                  continue;
1602                  ccs_set_string(head, "file ");                          if (first) {
1603                  ccs_set_string(head, ccs_mkdev_keyword[bit]);                                  ccs_set_group(head, "file ");
1604                                    first = false;
1605                            } else {
1606                                    ccs_set_slash(head);
1607                            }
1608                            ccs_set_string(head, ccs_mac_keywords
1609                                           [ccs_pnnn2mac[bit]]);
1610                    }
1611                    if (first)
1612                            return true;
1613                  ccs_print_name_union(head, &ptr->name);                  ccs_print_name_union(head, &ptr->name);
1614                  ccs_print_number_union(head, &ptr->mode);                  ccs_print_number_union(head, &ptr->mode);
1615                  ccs_print_number_union(head, &ptr->major);                  ccs_print_number_union(head, &ptr->major);
# Line 1251  static bool ccs_print_entry(struct ccs_i Line 1617  static bool ccs_print_entry(struct ccs_i
1617          } else if (acl_type == CCS_TYPE_PATH2_ACL) {          } else if (acl_type == CCS_TYPE_PATH2_ACL) {
1618                  struct ccs_path2_acl *ptr =                  struct ccs_path2_acl *ptr =
1619                          container_of(acl, typeof(*ptr), head);                          container_of(acl, typeof(*ptr), head);
1620                  bit = ccs_fns(ptr->perm, bit);                  const u8 perm = ptr->perm;
1621                  if (bit >= CCS_MAX_PATH2_OPERATION)                  for (bit = 0; bit < CCS_MAX_PATH2_OPERATION; bit++) {
1622                          goto done;                          if (!(perm & (1 << bit)))
1623                  ccs_set_group(head);                                  continue;
1624                  ccs_set_string(head, "file ");                          if (first) {
1625                  ccs_set_string(head, ccs_path2_keyword[bit]);                                  ccs_set_group(head, "file ");
1626                                    first = false;
1627                            } else {
1628                                    ccs_set_slash(head);
1629                            }
1630                            ccs_set_string(head, ccs_mac_keywords
1631                                           [ccs_pp2mac[bit]]);
1632                    }
1633                    if (first)
1634                            return true;
1635                  ccs_print_name_union(head, &ptr->name1);                  ccs_print_name_union(head, &ptr->name1);
1636                  ccs_print_name_union(head, &ptr->name2);                  ccs_print_name_union(head, &ptr->name2);
1637          } else if (acl_type == CCS_TYPE_PATH_NUMBER_ACL) {          } else if (acl_type == CCS_TYPE_PATH_NUMBER_ACL) {
1638                  struct ccs_path_number_acl *ptr =                  struct ccs_path_number_acl *ptr =
1639                          container_of(acl, typeof(*ptr), head);                          container_of(acl, typeof(*ptr), head);
1640                  bit = ccs_fns(ptr->perm, bit);                  const u8 perm = ptr->perm;
1641                  if (bit >= CCS_MAX_PATH_NUMBER_OPERATION)                  for (bit = 0; bit < CCS_MAX_PATH_NUMBER_OPERATION; bit++) {
1642                          goto done;                          if (!(perm & (1 << bit)))
1643                  ccs_set_group(head);                                  continue;
1644                  ccs_set_string(head, "file ");                          if (first) {
1645                  ccs_set_string(head, ccs_path_number_keyword[bit]);                                  ccs_set_group(head, "file ");
1646                                    first = false;
1647                            } else {
1648                                    ccs_set_slash(head);
1649                            }
1650                            ccs_set_string(head, ccs_mac_keywords
1651                                           [ccs_pn2mac[bit]]);
1652                    }
1653                    if (first)
1654                            return true;
1655                  ccs_print_name_union(head, &ptr->name);                  ccs_print_name_union(head, &ptr->name);
1656                  ccs_print_number_union(head, &ptr->number);                  ccs_print_number_union(head, &ptr->number);
1657          } else if (acl_type == CCS_TYPE_ENV_ACL) {          } else if (acl_type == CCS_TYPE_ENV_ACL) {
1658                  struct ccs_env_acl *ptr =                  struct ccs_env_acl *ptr =
1659                          container_of(acl, typeof(*ptr), head);                          container_of(acl, typeof(*ptr), head);
1660                  ccs_set_group(head);                  ccs_set_group(head, "misc env ");
                 ccs_set_string(head, "misc env ");  
1661                  ccs_set_string(head, ptr->env->name);                  ccs_set_string(head, ptr->env->name);
1662          } else if (acl_type == CCS_TYPE_CAPABILITY_ACL) {          } else if (acl_type == CCS_TYPE_CAPABILITY_ACL) {
1663                  struct ccs_capability_acl *ptr =                  struct ccs_capability_acl *ptr =
1664                          container_of(acl, typeof(*ptr), head);                          container_of(acl, typeof(*ptr), head);
1665                  ccs_set_group(head);                  ccs_set_group(head, "capability ");
1666                  ccs_set_string(head, "capability ");                  ccs_set_string(head, ccs_mac_keywords
1667                  ccs_set_string(head, ccs_cap2keyword(ptr->operation));                                 [ccs_c2mac[ptr->operation]]);
1668          } else if (acl_type == CCS_TYPE_IP_NETWORK_ACL) {          } else if (acl_type == CCS_TYPE_INET_ACL) {
1669                  struct ccs_ip_network_acl *ptr =                  struct ccs_inet_acl *ptr =
1670                          container_of(acl, typeof(*ptr), head);                          container_of(acl, typeof(*ptr), head);
1671                  bit = ccs_fns(ptr->perm, bit);                  const u8 perm = ptr->perm;
1672                  if (bit >= CCS_MAX_NETWORK_OPERATION)                  for (bit = 0; bit < CCS_MAX_NETWORK_OPERATION; bit++) {
1673                          goto done;                          if (!(perm & (1 << bit)))
1674                  ccs_set_group(head);                                  continue;
1675                  ccs_set_string(head, "network ");                          if (first) {
1676                  ccs_set_string(head, ccs_net_protocol_keyword[ptr->protocol]);                                  ccs_set_group(head, "network inet ");
1677                  ccs_set_space(head);                                  ccs_set_string(head, ccs_proto_keyword
1678                  ccs_set_string(head, ccs_net_keyword[bit]);                                                 [ptr->protocol]);
1679                                    ccs_set_space(head);
1680                                    first = false;
1681                            } else {
1682                                    ccs_set_slash(head);
1683                            }
1684                            ccs_set_string(head, ccs_socket_keyword[bit]);
1685                    }
1686                    if (first)
1687                            return true;
1688                  ccs_set_space(head);                  ccs_set_space(head);
1689                  switch (ptr->address_type) {                  if (ptr->address.group) {
                         char buf[128];  
                 case CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP:  
1690                          ccs_set_string(head, "@");                          ccs_set_string(head, "@");
1691                          ccs_set_string(head,                          ccs_set_string(head,
1692                                         ptr->address.group->group_name->name);                                         ptr->address.group->group_name->name);
1693                          break;                  } else {
1694                  case CCS_IP_ADDRESS_TYPE_IPv4:                          char buf[128];
1695                          ccs_print_ipv4(buf, sizeof(buf), ptr->address.ipv4.min,                          ccs_print_ip(buf, sizeof(buf), &ptr->address);
                                        ptr->address.ipv4.max);  
                         ccs_io_printf(head, "%s", buf);  
                         break;  
                 case CCS_IP_ADDRESS_TYPE_IPv6:  
                         ccs_print_ipv6(buf, sizeof(buf), ptr->address.ipv6.min,  
                                        ptr->address.ipv6.max);  
1696                          ccs_io_printf(head, "%s", buf);                          ccs_io_printf(head, "%s", buf);
                         break;  
1697                  }                  }
1698                  ccs_print_number_union(head, &ptr->port);                  ccs_print_number_union(head, &ptr->port);
1699            } else if (acl_type == CCS_TYPE_UNIX_ACL) {
1700                    struct ccs_unix_acl *ptr =
1701                            container_of(acl, typeof(*ptr), head);
1702                    const u8 perm = ptr->perm;
1703                    for (bit = 0; bit < CCS_MAX_NETWORK_OPERATION; bit++) {
1704                            if (!(perm & (1 << bit)))
1705                                    continue;
1706                            if (first) {
1707                                    ccs_set_group(head, "network unix ");
1708                                    ccs_set_string(head, ccs_proto_keyword
1709                                                   [ptr->protocol]);
1710                                    ccs_set_space(head);
1711                                    first = false;
1712                            } else {
1713                                    ccs_set_slash(head);
1714                            }
1715                            ccs_set_string(head, ccs_socket_keyword[bit]);
1716                    }
1717                    if (first)
1718                            return true;
1719                    ccs_print_name_union(head, &ptr->name);
1720          } else if (acl_type == CCS_TYPE_SIGNAL_ACL) {          } else if (acl_type == CCS_TYPE_SIGNAL_ACL) {
1721                  struct ccs_signal_acl *ptr =                  struct ccs_signal_acl *ptr =
1722                          container_of(acl, typeof(*ptr), head);                          container_of(acl, typeof(*ptr), head);
1723                  ccs_set_group(head);                  ccs_set_group(head, "ipc signal ");
1724                  ccs_set_string(head, "ipc signal ");                  ccs_print_number_union_nospace(head, &ptr->sig);
1725                  ccs_io_printf(head, "%u ", ptr->sig);                  ccs_set_space(head);
1726                  ccs_set_string(head, ptr->domainname->name);                  ccs_set_string(head, ptr->domainname->name);
1727          } else if (acl_type == CCS_TYPE_MOUNT_ACL) {          } else if (acl_type == CCS_TYPE_MOUNT_ACL) {
1728                  struct ccs_mount_acl *ptr =                  struct ccs_mount_acl *ptr =
1729                          container_of(acl, typeof(*ptr), head);                          container_of(acl, typeof(*ptr), head);
1730                  ccs_set_group(head);                  ccs_set_group(head, "file mount");
                 ccs_io_printf(head, "file mount");  
1731                  ccs_print_name_union(head, &ptr->dev_name);                  ccs_print_name_union(head, &ptr->dev_name);
1732                  ccs_print_name_union(head, &ptr->dir_name);                  ccs_print_name_union(head, &ptr->dir_name);
1733                  ccs_print_name_union(head, &ptr->fs_type);                  ccs_print_name_union(head, &ptr->fs_type);
1734                  ccs_print_number_union(head, &ptr->flags);                  ccs_print_number_union(head, &ptr->flags);
1735          }          }
         head->r.bit = bit + 1;  
1736          if (acl->cond) {          if (acl->cond) {
1737                  head->r.print_cond_part = true;                  head->r.print_cond_part = true;
1738                  head->r.cond_step = 0;                  head->r.cond_step = 0;
1739                  if (!ccs_flush(head))                  if (!ccs_flush(head))
1740                          return false;                          return false;
1741   print_cond_part:  print_cond_part:
1742                  if (!ccs_print_condition(head, acl->cond))                  if (!ccs_print_condition(head, acl->cond))
1743                          return false;                          return false;
1744                  head->r.print_cond_part = false;                  head->r.print_cond_part = false;
1745          } else {          } else {
1746                  ccs_set_lf(head);                  ccs_set_lf(head);
1747          }          }
         switch (acl_type) {  
         case CCS_TYPE_PATH_ACL:  
         case CCS_TYPE_MKDEV_ACL:  
         case CCS_TYPE_PATH2_ACL:  
         case CCS_TYPE_PATH_NUMBER_ACL:  
         case CCS_TYPE_IP_NETWORK_ACL:  
                 goto next;  
         }  
  done:  
         head->r.bit = 0;  
1748          return true;          return true;
1749  }  }
1750    
1751  /**  /**
1752   * ccs_read_domain2 - Read domain policy.   * ccs_read_domain2 - Read domain policy.
1753   *   *
1754   * @head:   Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
1755   * @domain: Pointer to "struct ccs_domain_info".   * @list: Pointer to "struct list_head".
  *  
  * Caller holds ccs_read_lock().  
1756   *   *
1757   * Returns true on success, false otherwise.   * Returns true on success, false otherwise.
1758     *
1759     * Caller holds ccs_read_lock().
1760   */   */
1761  static bool ccs_read_domain2(struct ccs_io_buffer *head,  static bool ccs_read_domain2(struct ccs_io_buffer *head,
1762                               struct ccs_domain_info *domain)                               struct list_head *list)
1763  {  {
1764          list_for_each_cookie(head->r.acl, &domain->acl_info_list) {          list_for_each_cookie(head->r.acl, list) {
1765                  struct ccs_acl_info *ptr =                  struct ccs_acl_info *ptr =
1766                          list_entry(head->r.acl, typeof(*ptr), list);                          list_entry(head->r.acl, typeof(*ptr), list);
1767                  if (!ccs_print_entry(head, ptr))                  if (!ccs_print_entry(head, ptr))
# Line 1384  static bool ccs_read_domain2(struct ccs_ Line 1776  static bool ccs_read_domain2(struct ccs_
1776   *   *
1777   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
1778   *   *
1779     * Returns nothing.
1780     *
1781   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
1782   */   */
1783  static void ccs_read_domain(struct ccs_io_buffer *head)  static void ccs_read_domain(struct ccs_io_buffer *head)
# Line 1402  static void ccs_read_domain(struct ccs_i Line 1796  static void ccs_read_domain(struct ccs_i
1796                          /* Print domainname and flags. */                          /* Print domainname and flags. */
1797                          ccs_set_string(head, domain->domainname->name);                          ccs_set_string(head, domain->domainname->name);
1798                          ccs_set_lf(head);                          ccs_set_lf(head);
1799                          ccs_io_printf(head, CCS_KEYWORD_USE_PROFILE "%u\n",                          ccs_io_printf(head, "use_profile %u\n",
1800                                        domain->profile);                                        domain->profile);
1801                          ccs_io_printf(head, CCS_KEYWORD_USE_GROUP "%u\n",                          ccs_io_printf(head, "use_group %u\n", domain->group);
                                       domain->group);  
1802                          for (i = 0; i < CCS_MAX_DOMAIN_INFO_FLAGS; i++)                          for (i = 0; i < CCS_MAX_DOMAIN_INFO_FLAGS; i++)
1803                                  if (domain->flags[i])                                  if (domain->flags[i])
1804                                          ccs_set_string(head, ccs_dif[i]);                                          ccs_set_string(head, ccs_dif[i]);
# Line 1413  static void ccs_read_domain(struct ccs_i Line 1806  static void ccs_read_domain(struct ccs_i
1806                          ccs_set_lf(head);                          ccs_set_lf(head);
1807                          /* fall through */                          /* fall through */
1808                  case 1:                  case 1:
1809                          if (!ccs_read_domain2(head, domain))                          if (!ccs_read_domain2(head, &domain->acl_info_list))
1810                                  return;                                  return;
1811                          head->r.step++;                          head->r.step++;
1812                          if (!ccs_set_lf(head))                          if (!ccs_set_lf(head))
# Line 1425  static void ccs_read_domain(struct ccs_i Line 1818  static void ccs_read_domain(struct ccs_i
1818                                  goto done;                                  goto done;
1819                  }                  }
1820          }          }
1821   done:  done:
1822          head->r.eof = true;          head->r.eof = true;
1823  }  }
1824    
1825  /**  /**
1826   * ccs_write_domain_profile - Assign profile for specified domain.   * ccs_write_pid - Specify PID to obtain domainname.
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  *  
  * Returns 0 on success, -EINVAL otherwise.  
  *  
  * This is equivalent to doing  
  *  
  *     ( echo "select " $domainname; echo "use_profile " $profile ) |  
  *     /usr/sbin/ccs-loadpolicy -d  
  *  
  * Caller holds ccs_read_lock().  
  */  
 static int ccs_write_domain_profile(struct ccs_io_buffer *head)  
 {  
         char *data = head->write_buf;  
         char *cp = strchr(data, ' ');  
         struct ccs_domain_info *domain;  
         unsigned int profile;  
         if (!cp)  
                 return -EINVAL;  
         *cp = '\0';  
         profile = simple_strtoul(data, NULL, 10);  
         if (profile >= CCS_MAX_PROFILES)  
                 return -EINVAL;  
         domain = ccs_find_domain(cp + 1);  
         if (domain && (!ccs_policy_loaded || ccs_profile_ptr[(u8) profile]))  
                 domain->profile = (u8) profile;  
         return 0;  
 }  
   
 /**  
  * ccs_read_domain_profile - Read only domainname and profile.  
  *  
  * @head: Pointer to "struct ccs_io_buffer".  
  *  
  * This is equivalent to doing  
  *  
  *     grep -A 1 '^<kernel>' /proc/ccs/domain_policy |  
  *     awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )  
  *     domainname = $0; } else if ( $1 == "use_profile" ) {  
  *     print $2 " " domainname; domainname = ""; } } ; '  
  *  
  * Caller holds ccs_read_lock().  
  */  
 static void ccs_read_domain_profile(struct ccs_io_buffer *head)  
 {  
         if (head->r.eof)  
                 return;  
         list_for_each_cookie(head->r.domain, &ccs_domain_list) {  
                 struct ccs_domain_info *domain =  
                         list_entry(head->r.domain, typeof(*domain), list);  
                 if (domain->is_deleted)  
                         continue;  
                 if (!ccs_flush(head))  
                         return;  
                 ccs_io_printf(head, "%u ", domain->profile);  
                 ccs_set_string(head, domain->domainname->name);  
                 ccs_set_lf(head);  
         }  
         head->r.eof = true;  
 }  
   
 /**  
  * ccs_write_pid: Specify PID to obtain domainname.  
1827   *   *
1828   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
1829   *   *
# Line 1550  static void ccs_read_pid(struct ccs_io_b Line 1879  static void ccs_read_pid(struct ccs_io_b
1879  #endif  #endif
1880          if (p) {          if (p) {
1881                  domain = ccs_task_domain(p);                  domain = ccs_task_domain(p);
1882                  ccs_flags = p->ccs_flags;                  ccs_flags = ccs_task_flags(p);
1883          }          }
1884          ccs_tasklist_unlock();          ccs_tasklist_unlock();
1885          if (!domain)          if (!domain)
# Line 1559  static void ccs_read_pid(struct ccs_io_b Line 1888  static void ccs_read_pid(struct ccs_io_b
1888                  ccs_io_printf(head, "%u %u ", pid, domain->profile);                  ccs_io_printf(head, "%u %u ", pid, domain->profile);
1889                  ccs_set_string(head, domain->domainname->name);                  ccs_set_string(head, domain->domainname->name);
1890          } else {          } else {
1891                  ccs_io_printf(head, "%u manager=%s execute_handler=%s "                  ccs_io_printf(head, "%u manager=%s execute_handler=%s ", pid,
                               "state[0]=%u state[1]=%u state[2]=%u", pid,  
1892                                ccs_yesno(ccs_flags &                                ccs_yesno(ccs_flags &
1893                                          CCS_TASK_IS_MANAGER),                                          CCS_TASK_IS_MANAGER),
1894                                ccs_yesno(ccs_flags &                                ccs_yesno(ccs_flags &
1895                                          CCS_TASK_IS_EXECUTE_HANDLER),                                          CCS_TASK_IS_EXECUTE_HANDLER));
                               (u8) (ccs_flags >> 24),  
                               (u8) (ccs_flags >> 16),  
                               (u8) (ccs_flags >> 8));  
1896          }          }
1897  }  }
1898    
1899  static const char *ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = {  /* String table for domain transition control keywords. */
1900          [CCS_TRANSITION_CONTROL_NO_INITIALIZE]  static const char * const ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = {
1901          = CCS_KEYWORD_NO_INITIALIZE_DOMAIN,          [CCS_TRANSITION_CONTROL_NO_RESET]      = "no_reset_domain ",
1902          [CCS_TRANSITION_CONTROL_INITIALIZE] = CCS_KEYWORD_INITIALIZE_DOMAIN,          [CCS_TRANSITION_CONTROL_RESET]         = "reset_domain ",
1903          [CCS_TRANSITION_CONTROL_NO_KEEP] = CCS_KEYWORD_NO_KEEP_DOMAIN,          [CCS_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
1904          [CCS_TRANSITION_CONTROL_KEEP] = CCS_KEYWORD_KEEP_DOMAIN          [CCS_TRANSITION_CONTROL_INITIALIZE]    = "initialize_domain ",
1905            [CCS_TRANSITION_CONTROL_NO_KEEP]       = "no_keep_domain ",
1906            [CCS_TRANSITION_CONTROL_KEEP]          = "keep_domain ",
1907  };  };
1908    
1909  static const char *ccs_group_name[CCS_MAX_GROUP] = {  /* String table for grouping keywords. */
1910          [CCS_PATH_GROUP] = CCS_KEYWORD_PATH_GROUP,  static const char * const ccs_group_name[CCS_MAX_GROUP] = {
1911          [CCS_NUMBER_GROUP] = CCS_KEYWORD_NUMBER_GROUP,          [CCS_PATH_GROUP]    = "path_group ",
1912          [CCS_ADDRESS_GROUP] = CCS_KEYWORD_ADDRESS_GROUP          [CCS_NUMBER_GROUP]  = "number_group ",
1913            [CCS_ADDRESS_GROUP] = "address_group ",
1914  };  };
1915    
1916  /**  /**
# Line 1594  static const char *ccs_group_name[CCS_MA Line 1922  static const char *ccs_group_name[CCS_MA
1922   */   */
1923  static int ccs_write_exception(struct ccs_io_buffer *head)  static int ccs_write_exception(struct ccs_io_buffer *head)
1924  {  {
1925          char *data = head->write_buf;          const bool is_delete = head->w.is_delete;
1926          const bool is_delete = ccs_str_starts(&data, CCS_KEYWORD_DELETE);          struct ccs_acl_param param = {
1927          u8 i;                  .ns = head->w.ns,
1928          static const struct {                  .is_delete = is_delete,
1929                  const char *keyword;                  .data = head->write_buf,
                 int (*write) (char *, const bool);  
         } ccs_callback[3] = {  
                 { CCS_KEYWORD_AGGREGATOR, ccs_write_aggregator },  
                 { CCS_KEYWORD_FILE_PATTERN, ccs_write_pattern },  
                 { CCS_KEYWORD_DENY_AUTOBIND, ccs_write_reserved_port }  
1930          };          };
1931          for (i = 0; i < 3; i++)          u8 i;
1932                  if (ccs_str_starts(&data, ccs_callback[i].keyword))          if (ccs_str_starts(&param.data, "aggregator "))
1933                          return ccs_callback[i].write(data, is_delete);                  return ccs_write_aggregator(&param);
1934            if (ccs_str_starts(&param.data, "deny_autobind "))
1935                    return ccs_write_reserved_port(&param);
1936          for (i = 0; i < CCS_MAX_TRANSITION_TYPE; i++)          for (i = 0; i < CCS_MAX_TRANSITION_TYPE; i++)
1937                  if (ccs_str_starts(&data, ccs_transition_type[i]))                  if (ccs_str_starts(&param.data, ccs_transition_type[i]))
1938                          return ccs_write_transition_control(data, is_delete,                          return ccs_write_transition_control(&param, i);
                                                             i);  
1939          for (i = 0; i < CCS_MAX_GROUP; i++)          for (i = 0; i < CCS_MAX_GROUP; i++)
1940                  if (ccs_str_starts(&data, ccs_group_name[i]))                  if (ccs_str_starts(&param.data, ccs_group_name[i]))
1941                          return ccs_write_group(data, is_delete, i);                          return ccs_write_group(&param, i);
1942          if (ccs_str_starts(&data, "acl_group ")) {          if (ccs_str_starts(&param.data, "acl_group ")) {
1943                  unsigned int group;                  unsigned int group;
1944                  if (sscanf(data, "%u", &group) == 1 &&                  char *data;
1945                      group < CCS_MAX_ACL_GROUPS) {                  group = simple_strtoul(param.data, &data, 10);
1946                          data = strchr(data, ' ');                  if (group < CCS_MAX_ACL_GROUPS && *data++ == ' ')
1947                          if (data)                          return ccs_write_domain2(head->w.ns,
1948                                  return ccs_write_domain2(data + 1,                                                   &head->w.ns->acl_group[group],
1949                                                           &ccs_acl_group[group],                                                   data, is_delete);
                                                          is_delete);  
                 }  
1950          }          }
1951          return -EINVAL;          return -EINVAL;
1952  }  }
# Line 1641  static int ccs_write_exception(struct cc Line 1963  static int ccs_write_exception(struct cc
1963   */   */
1964  static bool ccs_read_group(struct ccs_io_buffer *head, const int idx)  static bool ccs_read_group(struct ccs_io_buffer *head, const int idx)
1965  {  {
1966          list_for_each_cookie(head->r.group, &ccs_group_list[idx]) {          struct ccs_policy_namespace *ns = container_of(head->r.ns, typeof(*ns),
1967                                                           namespace_list);
1968            struct list_head *list = &ns->group_list[idx];
1969            list_for_each_cookie(head->r.group, list) {
1970                  struct ccs_group *group =                  struct ccs_group *group =
1971                          list_entry(head->r.group, typeof(*group), head.list);                          list_entry(head->r.group, typeof(*group), head.list);
1972                  list_for_each_cookie(head->r.acl, &group->member_list) {                  list_for_each_cookie(head->r.acl, &group->member_list) {
# Line 1651  static bool ccs_read_group(struct ccs_io Line 1976  static bool ccs_read_group(struct ccs_io
1976                                  continue;                                  continue;
1977                          if (!ccs_flush(head))                          if (!ccs_flush(head))
1978                                  return false;                                  return false;
1979                            ccs_print_namespace(head);
1980                          ccs_set_string(head, ccs_group_name[idx]);                          ccs_set_string(head, ccs_group_name[idx]);
1981                          ccs_set_string(head, group->group_name->name);                          ccs_set_string(head, group->group_name->name);
1982                          if (idx == CCS_PATH_GROUP) {                          if (idx == CCS_PATH_GROUP) {
# Line 1660  static bool ccs_read_group(struct ccs_io Line 1986  static bool ccs_read_group(struct ccs_io
1986                                                  head)->member_name->name);                                                  head)->member_name->name);
1987                          } else if (idx == CCS_NUMBER_GROUP) {                          } else if (idx == CCS_NUMBER_GROUP) {
1988                                  ccs_print_number_union(head, &container_of                                  ccs_print_number_union(head, &container_of
1989                                                         (ptr, struct ccs_number_group,                                                 (ptr, struct ccs_number_group,
1990                                                          head)->number);                                                  head)->number);
1991                          } else if (idx == CCS_ADDRESS_GROUP) {                          } else if (idx == CCS_ADDRESS_GROUP) {
1992                                  char buffer[128];                                  char buffer[128];
1993                                  struct ccs_address_group *member =                                  struct ccs_address_group *member =
1994                                          container_of(ptr, typeof(*member),                                          container_of(ptr, typeof(*member),
1995                                                       head);                                                       head);
1996                                  if (member->is_ipv6)                                  ccs_print_ip(buffer, sizeof(buffer),
1997                                          ccs_print_ipv6(buffer, sizeof(buffer),                                               &member->address);
                                                        member->min.ipv6,  
                                                        member->max.ipv6);  
                                 else  
                                         ccs_print_ipv4(buffer, sizeof(buffer),  
                                                        member->min.ipv4,  
                                                        member->max.ipv4);  
1998                                  ccs_io_printf(head, " %s", buffer);                                  ccs_io_printf(head, " %s", buffer);
1999                          }                          }
2000                          ccs_set_lf(head);                          ccs_set_lf(head);
# Line 1697  static bool ccs_read_group(struct ccs_io Line 2017  static bool ccs_read_group(struct ccs_io
2017   */   */
2018  static bool ccs_read_policy(struct ccs_io_buffer *head, const int idx)  static bool ccs_read_policy(struct ccs_io_buffer *head, const int idx)
2019  {  {
2020          list_for_each_cookie(head->r.acl, &ccs_policy_list[idx]) {          struct ccs_policy_namespace *ns = container_of(head->r.ns, typeof(*ns),
2021                                                           namespace_list);
2022            struct list_head *list = &ns->policy_list[idx];
2023            list_for_each_cookie(head->r.acl, list) {
2024                  struct ccs_acl_head *acl =                  struct ccs_acl_head *acl =
2025                          container_of(head->r.acl, typeof(*acl), list);                          container_of(head->r.acl, typeof(*acl), list);
2026                  if (acl->is_deleted)                  if (acl->is_deleted)
2027                          continue;                          continue;
2028                    if (head->r.print_transition_related_only &&
2029                        idx != CCS_ID_TRANSITION_CONTROL)
2030                            continue;
2031                  if (!ccs_flush(head))                  if (!ccs_flush(head))
2032                          return false;                          return false;
2033                  switch (idx) {                  switch (idx) {
# Line 1709  static bool ccs_read_policy(struct ccs_i Line 2035  static bool ccs_read_policy(struct ccs_i
2035                          {                          {
2036                                  struct ccs_transition_control *ptr =                                  struct ccs_transition_control *ptr =
2037                                          container_of(acl, typeof(*ptr), head);                                          container_of(acl, typeof(*ptr), head);
2038                                    ccs_print_namespace(head);
2039                                  ccs_set_string(head,                                  ccs_set_string(head,
2040                                                 ccs_transition_type[ptr->type]);                                                 ccs_transition_type[ptr->type]);
2041                                  ccs_set_string(head, ptr->program ?                                  ccs_set_string(head, ptr->program ?
# Line 1722  static bool ccs_read_policy(struct ccs_i Line 2049  static bool ccs_read_policy(struct ccs_i
2049                          {                          {
2050                                  struct ccs_aggregator *ptr =                                  struct ccs_aggregator *ptr =
2051                                          container_of(acl, typeof(*ptr), head);                                          container_of(acl, typeof(*ptr), head);
2052                                  ccs_set_string(head, CCS_KEYWORD_AGGREGATOR);                                  ccs_print_namespace(head);
2053                                    ccs_set_string(head, "aggregator ");
2054                                  ccs_set_string(head, ptr->original_name->name);                                  ccs_set_string(head, ptr->original_name->name);
2055                                  ccs_set_space(head);                                  ccs_set_space(head);
2056                                  ccs_set_string(head,                                  ccs_set_string(head,
2057                                                 ptr->aggregated_name->name);                                                 ptr->aggregated_name->name);
2058                          }                          }
2059                          break;                          break;
                 case CCS_ID_PATTERN:  
                         {  
                                 struct ccs_pattern *ptr =  
                                         container_of(acl, typeof(*ptr), head);  
                                 ccs_set_string(head, CCS_KEYWORD_FILE_PATTERN);  
                                 ccs_set_string(head, ptr->pattern->name);  
                         }  
                         break;  
2060                  case CCS_ID_RESERVEDPORT:                  case CCS_ID_RESERVEDPORT:
2061                          {                          {
2062                                  struct ccs_reserved *ptr =                                  struct ccs_reserved *ptr =
2063                                          container_of(acl, typeof(*ptr), head);                                          container_of(acl, typeof(*ptr), head);
2064                                  const u16 min_port = ptr->min_port;                                  ccs_print_namespace(head);
2065                                  const u16 max_port = ptr->max_port;                                  ccs_set_string(head, "deny_autobind ");
2066                                  ccs_set_string(head,                                  ccs_print_number_union_nospace(head,
2067                                                 CCS_KEYWORD_DENY_AUTOBIND);                                                                 &ptr->port);
                                 ccs_io_printf(head, "%u", min_port);  
                                 if (min_port != max_port)  
                                         ccs_io_printf(head, "-%u", max_port);  
2068                          }                          }
2069                          break;                          break;
2070                  default:                  default:
# Line 1764  static bool ccs_read_policy(struct ccs_i Line 2081  static bool ccs_read_policy(struct ccs_i
2081   *   *
2082   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
2083   *   *
2084     * Returns nothing.
2085     *
2086   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
2087   */   */
2088  static void ccs_read_exception(struct ccs_io_buffer *head)  static void ccs_read_exception(struct ccs_io_buffer *head)
2089  {  {
2090            struct ccs_policy_namespace *ns = container_of(head->r.ns, typeof(*ns),
2091                                                           namespace_list);
2092          if (head->r.eof)          if (head->r.eof)
2093                  return;                  return;
2094          while (head->r.step < CCS_MAX_POLICY &&          while (head->r.step < CCS_MAX_POLICY &&
# Line 1782  static void ccs_read_exception(struct cc Line 2103  static void ccs_read_exception(struct cc
2103                  return;                  return;
2104          while (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP          while (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP
2105                 + CCS_MAX_ACL_GROUPS) {                 + CCS_MAX_ACL_GROUPS) {
2106                  head->r.group_index = head->r.step - CCS_MAX_POLICY                  head->r.acl_group_index =
2107                          - CCS_MAX_GROUP;                          head->r.step - CCS_MAX_POLICY - CCS_MAX_GROUP;
2108                  if (!ccs_read_domain2(head,                  if (!ccs_read_domain2(head, &ns->acl_group
2109                                        &ccs_acl_group[head->r.group_index]))                                        [head->r.acl_group_index]))
2110                          return;                          return;
2111                  head->r.step++;                  head->r.step++;
2112          }          }
2113          head->r.eof = true;          head->r.eof = true;
2114  }  }
2115    
2116  /* Wait queue for ccs_query_list. */  /* Wait queue for kernel -> userspace notification. */
2117  static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait);  static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait);
2118    /* Wait queue for userspace -> kernel notification. */
2119  /* Lock for manipulating ccs_query_list. */  static DECLARE_WAIT_QUEUE_HEAD(ccs_answer_wait);
 static DEFINE_SPINLOCK(ccs_query_list_lock);  
2120    
2121  /* Structure for query. */  /* Structure for query. */
2122  struct ccs_query {  struct ccs_query {
2123          struct list_head list;          struct list_head list;
2124          char *query;          char *query;
2125          int query_len;          size_t query_len;
2126          unsigned int serial;          unsigned int serial;
2127          int timer;          u8 timer;
2128          int answer;          u8 answer;
2129            u8 retry;
2130  };  };
2131    
2132  /* The list for "struct ccs_query". */  /* The list for "struct ccs_query". */
2133  static LIST_HEAD(ccs_query_list);  static LIST_HEAD(ccs_query_list);
2134    
2135    /* Lock for manipulating ccs_query_list. */
2136    static DEFINE_SPINLOCK(ccs_query_list_lock);
2137    
2138  /* Number of "struct file" referring /proc/ccs/query interface. */  /* Number of "struct file" referring /proc/ccs/query interface. */
2139  static atomic_t ccs_query_observers = ATOMIC_INIT(0);  static atomic_t ccs_query_observers = ATOMIC_INIT(0);
2140    
2141  static void ccs_truncate(char *str)  /**
2142     * ccs_truncate - Truncate a line.
2143     *
2144     * @str: String to truncate.
2145     *
2146     * Returns length of truncated @str.
2147     */
2148    static int ccs_truncate(char *str)
2149  {  {
2150          while (* (unsigned char *) str > (unsigned char) ' ')          char *start = str;
2151            while (*(unsigned char *) str > (unsigned char) ' ')
2152                  str++;                  str++;
2153          *str = '\0';          *str = '\0';
2154            return strlen(start) + 1;
2155    }
2156    
2157    /**
2158     * ccs_add_entry - Add an ACL to current thread's domain. Used by learning mode.
2159     *
2160     * @header: Lines containing ACL.
2161     *
2162     * Returns nothing.
2163     */
2164    static void ccs_add_entry(char *header)
2165    {
2166            char *buffer;
2167            char *realpath = NULL;
2168            char *argv0 = NULL;
2169            char *symlink = NULL;
2170            char *handler;
2171            char *cp = strchr(header, '\n');
2172            int len;
2173            if (!cp)
2174                    return;
2175            cp = strchr(cp + 1, '\n');
2176            if (!cp)
2177                    return;
2178            *cp++ = '\0';
2179            len = strlen(cp) + 1;
2180            /* strstr() will return NULL if ordering is wrong. */
2181            if (*cp == 'f') {
2182                    argv0 = strstr(header, " argv[]={ \"");
2183                    if (argv0) {
2184                            argv0 += 10;
2185                            len += ccs_truncate(argv0) + 14;
2186                    }
2187                    realpath = strstr(header, " exec={ realpath=\"");
2188                    if (realpath) {
2189                            realpath += 8;
2190                            len += ccs_truncate(realpath) + 6;
2191                    }
2192                    symlink = strstr(header, " symlink.target=\"");
2193                    if (symlink)
2194                            len += ccs_truncate(symlink + 1) + 1;
2195            }
2196            handler = strstr(header, "type=execute_handler");
2197            if (handler)
2198                    len += ccs_truncate(handler) + 6;
2199            buffer = kmalloc(len, CCS_GFP_FLAGS);
2200            if (!buffer)
2201                    return;
2202            snprintf(buffer, len - 1, "%s", cp);
2203            if (handler)
2204                    ccs_addprintf(buffer, len, " task.%s", handler);
2205            if (realpath)
2206                    ccs_addprintf(buffer, len, " exec.%s", realpath);
2207            if (argv0)
2208                    ccs_addprintf(buffer, len, " exec.argv[0]=%s", argv0);
2209            if (symlink)
2210                    ccs_addprintf(buffer, len, "%s", symlink);
2211            ccs_normalize_line(buffer);
2212            {
2213                    struct ccs_domain_info *domain = ccs_current_domain();
2214                    if (!ccs_write_domain2(domain->ns, &domain->acl_info_list,
2215                                           buffer, false))
2216                            ccs_update_stat(CCS_STAT_POLICY_UPDATES);
2217            }
2218            kfree(buffer);
2219  }  }
2220    
2221  /**  /**
# Line 1835  static void ccs_truncate(char *str) Line 2232  static void ccs_truncate(char *str)
2232  int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...)  int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...)
2233  {  {
2234          va_list args;          va_list args;
2235          int error = -EPERM;          int error;
         int pos;  
2236          int len;          int len;
2237          static unsigned int ccs_serial;          static unsigned int ccs_serial;
2238          struct ccs_query *entry = NULL;          struct ccs_query entry = { };
2239          bool quota_exceeded = false;          bool quota_exceeded = false;
         char *header;  
         struct ccs_domain_info * const domain = ccs_current_domain();  
2240          va_start(args, fmt);          va_start(args, fmt);
2241          len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 80;          len = vsnprintf((char *) &len, 1, fmt, args) + 1;
2242          va_end(args);          va_end(args);
2243          if (r->mode == CCS_CONFIG_LEARNING) {          /* Write /proc/ccs/audit. */
2244                  char *buffer;          va_start(args, fmt);
2245                  char *realpath = NULL;          ccs_write_log2(r, len, fmt, args);
2246                  char *argv0 = NULL;          va_end(args);
2247                  char *symlink = NULL;          /* Nothing more to do if granted. */
2248                  char *handler = NULL;          if (r->granted)
                 const struct ccs_preference *pref;  
                 if (!ccs_domain_quota_ok(r))  
                         return 0;  
                 header = ccs_init_log(&len, r);  
                 if (!header)  
                         return 0;  
                 pref = &ccs_profile(r->profile)->preference;  
                 /* strstr() will return NULL if ordering is wrong. */  
                 if (r->param_type == CCS_TYPE_PATH_ACL &&  
                     r->param.path.operation == CCS_TYPE_EXECUTE) {  
                         if (pref->learning_exec_argv0) {  
                                 argv0 = strstr(header, " argv[]={ \"");  
                                 if (argv0) {  
                                         argv0 += 10;  
                                         ccs_truncate(argv0);  
                                 }  
                         }  
                         if (pref->learning_exec_realpath) {  
                                 realpath = strstr(header,  
                                                   " exec={ realpath=\"");  
                                 if (realpath) {  
                                         realpath += 8;  
                                         ccs_truncate(realpath);  
                                 }  
                         }  
                 } else if (r->param_type == CCS_TYPE_PATH_ACL &&  
                            r->param.path.operation == CCS_TYPE_SYMLINK &&  
                            pref->learning_symlink_target) {  
                         symlink = strstr(header, " symlink.target=\"");  
                         if (symlink)  
                                 ccs_truncate(symlink + 1);  
                 }  
                 handler = strstr(header, "type=execute_handler");  
                 if (handler)  
                         ccs_truncate(handler);  
                 buffer = kmalloc(len, CCS_GFP_FLAGS);  
                 if (buffer) {  
                         va_start(args, fmt);  
                         vsnprintf(buffer, len - 1, fmt, args);  
                         va_end(args);  
                         if (handler || realpath || argv0 || symlink) {  
                                 ccs_addprintf(buffer, len, " if");  
                                 if (handler)  
                                         ccs_addprintf(buffer, len, " task.%s",  
                                                       handler);  
                                 if (realpath)  
                                         ccs_addprintf(buffer, len, " exec.%s",  
                                                       realpath);  
                                 if (argv0)  
                                         ccs_addprintf(buffer, len,  
                                                       " exec.argv[0]=%s",  
                                                       argv0);  
                                 if (symlink)  
                                         ccs_addprintf(buffer, len, "%s",  
                                                       symlink);  
                         }  
                         ccs_normalize_line(buffer);  
                         ccs_write_domain2(buffer, domain, false);  
                         kfree(buffer);  
                 }  
                 kfree(header);  
                 return 0;  
         }  
         if (r->mode != CCS_CONFIG_ENFORCING)  
2249                  return 0;                  return 0;
2250          if (!atomic_read(&ccs_query_observers)) {          if (r->mode)
2251                    ccs_update_stat(r->mode);
2252            switch (r->mode) {
2253                  int i;                  int i;
2254                  if (current->ccs_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR)                  struct ccs_profile *p;
2255                          return -EPERM;          case CCS_CONFIG_ENFORCING:
2256                  for (i = 0; i < ccs_profile(domain->profile)->preference.                  error = -EPERM;
2257                               enforcing_penalty; i++) {                  if (atomic_read(&ccs_query_observers))
2258                            break;
2259                    if (r->dont_sleep_on_enforce_error)
2260                            goto out;
2261                    p = ccs_profile(r->profile);
2262                    /* Check enforcing_penalty parameter. */
2263                    for (i = 0; i < p->pref[CCS_PREF_ENFORCING_PENALTY]; i++) {
2264                          set_current_state(TASK_INTERRUPTIBLE);                          set_current_state(TASK_INTERRUPTIBLE);
2265                          schedule_timeout(HZ / 10);                          schedule_timeout(HZ / 10);
2266                  }                  }
                 return -EPERM;  
         }  
         header = ccs_init_log(&len, r);  
         if (!header)  
2267                  goto out;                  goto out;
2268          entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);          case CCS_CONFIG_LEARNING:
2269          if (!entry)                  error = 0;
2270                    /* Check max_learning_entry parameter. */
2271                    if (ccs_domain_quota_ok(r))
2272                            break;
2273                    /* fall through */
2274            default:
2275                    return 0;
2276            }
2277            /* Get message. */
2278            va_start(args, fmt);
2279            entry.query = ccs_init_log(r, len, fmt, args);
2280            va_end(args);
2281            if (!entry.query)
2282                  goto out;                  goto out;
2283          len = ccs_round2(len);          entry.query_len = strlen(entry.query) + 1;
2284          entry->query = kzalloc(len, CCS_GFP_FLAGS);          if (!error) {
2285          if (!entry->query)                  ccs_add_entry(entry.query);
2286                  goto out;                  goto out;
2287            }
2288            len = ccs_round2(entry.query_len);
2289          spin_lock(&ccs_query_list_lock);          spin_lock(&ccs_query_list_lock);
2290          if (ccs_quota_for_query && ccs_query_memory_size + len +          if (ccs_memory_quota[CCS_MEMORY_QUERY] &&
2291              sizeof(*entry) >= ccs_quota_for_query) {              ccs_memory_used[CCS_MEMORY_QUERY] + len
2292                >= ccs_memory_quota[CCS_MEMORY_QUERY]) {
2293                  quota_exceeded = true;                  quota_exceeded = true;
2294          } else {          } else {
2295                  ccs_query_memory_size += len + sizeof(*entry);                  entry.serial = ccs_serial++;
2296                  entry->serial = ccs_serial++;                  entry.retry = r->retry;
2297                    ccs_memory_used[CCS_MEMORY_QUERY] += len;
2298                    list_add_tail(&entry.list, &ccs_query_list);
2299          }          }
2300          spin_unlock(&ccs_query_list_lock);          spin_unlock(&ccs_query_list_lock);
2301          if (quota_exceeded)          if (quota_exceeded)
2302                  goto out;                  goto out;
         pos = snprintf(entry->query, len - 1, "Q%u-%hu\n%s",  
                        entry->serial, r->retry, header);  
         kfree(header);  
         header = NULL;  
         va_start(args, fmt);  
         vsnprintf(entry->query + pos, len - 1 - pos, fmt, args);  
         entry->query_len = strlen(entry->query) + 1;  
         va_end(args);  
         spin_lock(&ccs_query_list_lock);  
         list_add_tail(&entry->list, &ccs_query_list);  
         spin_unlock(&ccs_query_list_lock);  
2303          /* Give 10 seconds for supervisor's opinion. */          /* Give 10 seconds for supervisor's opinion. */
2304          for (entry->timer = 0;          while (entry.timer < 10) {
2305               atomic_read(&ccs_query_observers) && entry->timer < 100;                  wake_up_all(&ccs_query_wait);
2306               entry->timer++) {                  if (wait_event_interruptible_timeout
2307                  wake_up(&ccs_query_wait);                      (ccs_answer_wait, entry.answer ||
2308                  set_current_state(TASK_INTERRUPTIBLE);                       !atomic_read(&ccs_query_observers), HZ))
                 schedule_timeout(HZ / 10);  
                 if (entry->answer)  
2309                          break;                          break;
2310                    else
2311                            entry.timer++;
2312          }          }
2313          spin_lock(&ccs_query_list_lock);          spin_lock(&ccs_query_list_lock);
2314          list_del(&entry->list);          list_del(&entry.list);
2315          ccs_query_memory_size -= len + sizeof(*entry);          ccs_memory_used[CCS_MEMORY_QUERY] -= len;
2316          spin_unlock(&ccs_query_list_lock);          spin_unlock(&ccs_query_list_lock);
2317          switch (entry->answer) {          switch (entry.answer) {
2318          case 3: /* Asked to retry by administrator. */          case 3: /* Asked to retry by administrator. */
2319                  error = CCS_RETRY_REQUEST;                  error = CCS_RETRY_REQUEST;
2320                  r->retry++;                  r->retry++;
# Line 1983  int ccs_supervisor(struct ccs_request_in Line 2323  int ccs_supervisor(struct ccs_request_in
2323                  /* Granted by administrator. */                  /* Granted by administrator. */
2324                  error = 0;                  error = 0;
2325                  break;                  break;
         case 0:  
                 /* Timed out. */  
                 break;  
2326          default:          default:
2327                  /* Rejected by administrator. */                  /* Timed out or rejected by administrator. */
2328                  break;                  break;
2329          }          }
2330   out:  out:
2331          if (entry)          kfree(entry.query);
                 kfree(entry->query);  
         kfree(entry);  
         kfree(header);  
2332          return error;          return error;
2333  }  }
2334    
# Line 2037  static int ccs_poll_query(struct file *f Line 2371  static int ccs_poll_query(struct file *f
2371   * ccs_read_query - Read access requests which violated policy in enforcing mode.   * ccs_read_query - Read access requests which violated policy in enforcing mode.
2372   *   *
2373   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
2374     *
2375     * Returns nothing.
2376   */   */
2377  static void ccs_read_query(struct ccs_io_buffer *head)  static void ccs_read_query(struct ccs_io_buffer *head)
2378  {  {
2379          struct list_head *tmp;          struct list_head *tmp;
2380          int pos = 0;          unsigned int pos = 0;
2381          int len = 0;          size_t len = 0;
2382          char *buf;          char *buf;
2383          if (head->r.w_pos)          if (head->r.w_pos)
2384                  return;                  return;
2385          if (head->read_buf) {          kfree(head->read_buf);
2386                  kfree(head->read_buf);          head->read_buf = NULL;
                 head->read_buf = NULL;  
         }  
2387          spin_lock(&ccs_query_list_lock);          spin_lock(&ccs_query_list_lock);
2388          list_for_each(tmp, &ccs_query_list) {          list_for_each(tmp, &ccs_query_list) {
2389                  struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);                  struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
# Line 2065  static void ccs_read_query(struct ccs_io Line 2399  static void ccs_read_query(struct ccs_io
2399                  head->r.query_index = 0;                  head->r.query_index = 0;
2400                  return;                  return;
2401          }          }
2402          buf = kzalloc(len, CCS_GFP_FLAGS);          buf = kzalloc(len + 32, CCS_GFP_FLAGS);
2403          if (!buf)          if (!buf)
2404                  return;                  return;
2405          pos = 0;          pos = 0;
# Line 2081  static void ccs_read_query(struct ccs_io Line 2415  static void ccs_read_query(struct ccs_io
2415                   * can change, but I don't care.                   * can change, but I don't care.
2416                   */                   */
2417                  if (len == ptr->query_len)                  if (len == ptr->query_len)
2418                          memmove(buf, ptr->query, len);                          snprintf(buf, len + 31, "Q%u-%hu\n%s", ptr->serial,
2419                                     ptr->retry, ptr->query);
2420                  break;                  break;
2421          }          }
2422          spin_unlock(&ccs_query_list_lock);          spin_unlock(&ccs_query_list_lock);
# Line 2121  static int ccs_write_answer(struct ccs_i Line 2456  static int ccs_write_answer(struct ccs_i
2456                  if (ptr->serial != serial)                  if (ptr->serial != serial)
2457                          continue;                          continue;
2458                  if (!ptr->answer)                  if (!ptr->answer)
2459                          ptr->answer = answer;                          ptr->answer = (u8) answer;
2460                  break;                  break;
2461          }          }
2462          spin_unlock(&ccs_query_list_lock);          spin_unlock(&ccs_query_list_lock);
2463            wake_up_all(&ccs_answer_wait);
2464          return 0;          return 0;
2465  }  }
2466    
2467  /**  /**
2468   * ccs_read_version: Get version.   * ccs_read_version - Get version.
2469   *   *
2470   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
2471     *
2472     * Returns nothing.
2473   */   */
2474  static void ccs_read_version(struct ccs_io_buffer *head)  static void ccs_read_version(struct ccs_io_buffer *head)
2475  {  {
2476          if (head->r.eof)          if (head->r.eof)
2477                  return;                  return;
2478          ccs_set_string(head, "1.8.0-pre");          ccs_set_string(head, "1.8.3");
2479          head->r.eof = true;          head->r.eof = true;
2480  }  }
2481    
2482    /* String table for /proc/ccs/stat interface. */
2483    static const char * const ccs_policy_headers[CCS_MAX_POLICY_STAT] = {
2484            [CCS_STAT_POLICY_UPDATES]    = "update:",
2485            [CCS_STAT_POLICY_LEARNING]   = "violation in learning mode:",
2486            [CCS_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:",
2487            [CCS_STAT_POLICY_ENFORCING]  = "violation in enforcing mode:",
2488    };
2489    
2490    /* String table for /proc/ccs/stat interface. */
2491    static const char * const ccs_memory_headers[CCS_MAX_MEMORY_STAT] = {
2492            [CCS_MEMORY_POLICY]     = "policy:",
2493            [CCS_MEMORY_AUDIT]      = "audit log:",
2494            [CCS_MEMORY_QUERY]      = "query message:",
2495    };
2496    
2497    /* Timestamp counter for last updated. */
2498    static unsigned int ccs_stat_updated[CCS_MAX_POLICY_STAT];
2499    /* Counter for number of updates. */
2500    static unsigned int ccs_stat_modified[CCS_MAX_POLICY_STAT];
2501    
2502    /**
2503     * ccs_update_stat - Update statistic counters.
2504     *
2505     * @index: Index for policy type.
2506     *
2507     * Returns nothing.
2508     */
2509    void ccs_update_stat(const u8 index)
2510    {
2511            struct timeval tv;
2512            do_gettimeofday(&tv);
2513            /*
2514             * I don't use atomic operations because race condition is not fatal.
2515             */
2516            ccs_stat_updated[index]++;
2517            ccs_stat_modified[index] = tv.tv_sec;
2518    }
2519    
2520  /**  /**
2521   * ccs_read_self_domain - Get the current process's domainname.   * ccs_read_stat - Read statistic data.
2522   *   *
2523   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
2524     *
2525     * Returns nothing.
2526   */   */
2527  static void ccs_read_self_domain(struct ccs_io_buffer *head)  static void ccs_read_stat(struct ccs_io_buffer *head)
2528  {  {
2529            u8 i;
2530            unsigned int total = 0;
2531          if (head->r.eof)          if (head->r.eof)
2532                  return;                  return;
2533          /*          for (i = 0; i < CCS_MAX_POLICY_STAT; i++) {
2534           * ccs_current_domain()->domainname != NULL because every process                  ccs_io_printf(head, "Policy %-30s %10u", ccs_policy_headers[i],
2535           * belongs to a domain and the domain's name cannot be NULL.                                ccs_stat_updated[i]);
2536           */                  if (ccs_stat_modified[i]) {
2537          ccs_io_printf(head, "%s", ccs_current_domain()->domainname->name);                          struct ccs_time stamp;
2538                            ccs_convert_time(ccs_stat_modified[i], &stamp);
2539                            ccs_io_printf(head, " (Last: %04u/%02u/%02u "
2540                                          "%02u:%02u:%02u)",
2541                                          stamp.year, stamp.month, stamp.day,
2542                                          stamp.hour, stamp.min, stamp.sec);
2543                    }
2544                    ccs_set_lf(head);
2545            }
2546            for (i = 0; i < CCS_MAX_MEMORY_STAT; i++) {
2547                    unsigned int used = ccs_memory_used[i];
2548                    total += used;
2549                    ccs_io_printf(head, "Memory used by %-22s %10u",
2550                                  ccs_memory_headers[i], used);
2551                    used = ccs_memory_quota[i];
2552                    if (used)
2553                            ccs_io_printf(head, " (Quota: %10u)", used);
2554                    ccs_set_lf(head);
2555            }
2556            ccs_io_printf(head, "Total memory used:                    %10u\n",
2557                          total);
2558          head->r.eof = true;          head->r.eof = true;
2559  }  }
2560    
2561  /**  /**
2562     * ccs_write_stat - Set memory quota.
2563     *
2564     * @head: Pointer to "struct ccs_io_buffer".
2565     *
2566     * Returns 0.
2567     */
2568    static int ccs_write_stat(struct ccs_io_buffer *head)
2569    {
2570            char *data = head->write_buf;
2571            u8 i;
2572            if (ccs_str_starts(&data, "Memory used by "))
2573                    for (i = 0; i < CCS_MAX_MEMORY_STAT; i++)
2574                            if (ccs_str_starts(&data, ccs_memory_headers[i])) {
2575                                    if (*data == ' ')
2576                                            data++;
2577                                    ccs_memory_quota[i] =
2578                                            simple_strtoul(data, NULL, 10);
2579                            }
2580            return 0;
2581    }
2582    
2583    /**
2584   * ccs_open_control - open() for /proc/ccs/ interface.   * ccs_open_control - open() for /proc/ccs/ interface.
2585   *   *
2586   * @type: Type of interface.   * @type: Type of interface.
2587   * @file: Pointer to "struct file".   * @file: Pointer to "struct file".
2588   *   *
2589   * Associates policy handler and returns 0 on success, -ENOMEM otherwise.   * Returns 0 on success, negative value otherwise.
2590   */   */
2591  int ccs_open_control(const u8 type, struct file *file)  int ccs_open_control(const u8 type, struct file *file)
2592  {  {
# Line 2173  int ccs_open_control(const u8 type, stru Line 2595  int ccs_open_control(const u8 type, stru
2595                  return -ENOMEM;                  return -ENOMEM;
2596          mutex_init(&head->io_sem);          mutex_init(&head->io_sem);
2597          head->type = type;          head->type = type;
2598          switch (type) {          if (type == CCS_EXECUTE_HANDLER) {
         case CCS_DOMAINPOLICY: /* /proc/ccs/domain_policy */  
                 head->write = ccs_write_domain;  
                 head->read = ccs_read_domain;  
                 break;  
         case CCS_EXCEPTIONPOLICY: /* /proc/ccs/exception_policy */  
                 head->write = ccs_write_exception;  
                 head->read = ccs_read_exception;  
                 break;  
 #ifdef CONFIG_CCSECURITY_AUDIT  
         case CCS_GRANTLOG: /* /proc/ccs/grant_log */  
         case CCS_REJECTLOG: /* /proc/ccs/reject_log */  
                 head->poll = ccs_poll_log;  
                 head->read = ccs_read_log;  
                 break;  
 #endif  
         case CCS_SELFDOMAIN: /* /proc/ccs/self_domain */  
                 head->read = ccs_read_self_domain;  
                 break;  
         case CCS_DOMAIN_STATUS: /* /proc/ccs/.domain_status */  
                 head->write = ccs_write_domain_profile;  
                 head->read = ccs_read_domain_profile;  
                 break;  
         case CCS_EXECUTE_HANDLER: /* /proc/ccs/.execute_handler */  
2599                  /* Allow execute_handler to read process's status. */                  /* Allow execute_handler to read process's status. */
2600                  if (!(current->ccs_flags & CCS_TASK_IS_EXECUTE_HANDLER)) {                  if (!(ccs_current_flags() & CCS_TASK_IS_EXECUTE_HANDLER)) {
2601                          kfree(head);                          kfree(head);
2602                          return -EPERM;                          return -EPERM;
2603                  }                  }
                 /* fall through */  
         case CCS_PROCESS_STATUS: /* /proc/ccs/.process_status */  
                 head->write = ccs_write_pid;  
                 head->read = ccs_read_pid;  
                 break;  
         case CCS_VERSION: /* /proc/ccs/version */  
                 head->read = ccs_read_version;  
                 head->readbuf_size = 128;  
                 break;  
         case CCS_MEMINFO: /* /proc/ccs/meminfo */  
                 head->write = ccs_write_memory_quota;  
                 head->read = ccs_read_memory_counter;  
                 head->readbuf_size = 512;  
                 break;  
         case CCS_PROFILE: /* /proc/ccs/profile */  
                 head->write = ccs_write_profile;  
                 head->read = ccs_read_profile;  
                 break;  
         case CCS_QUERY: /* /proc/ccs/query */  
                 head->poll = ccs_poll_query;  
                 head->write = ccs_write_answer;  
                 head->read = ccs_read_query;  
                 break;  
         case CCS_MANAGER: /* /proc/ccs/manager */  
                 head->write = ccs_write_manager;  
                 head->read = ccs_read_manager;  
                 break;  
2604          }          }
2605          if (!(file->f_mode & FMODE_READ)) {          if ((file->f_mode & FMODE_READ) && type != CCS_AUDIT &&
2606                  /*              type != CCS_QUERY) {
                  * No need to allocate read_buf since it is not opened  
                  * for reading.  
                  */  
                 head->read = NULL;  
                 head->poll = NULL;  
         } else if (!head->poll) {  
2607                  /* Don't allocate read_buf for poll() access. */                  /* Don't allocate read_buf for poll() access. */
2608                  if (!head->readbuf_size)                  head->readbuf_size = 4096;
                         head->readbuf_size = 4096;  
2609                  head->read_buf = kzalloc(head->readbuf_size, CCS_GFP_FLAGS);                  head->read_buf = kzalloc(head->readbuf_size, CCS_GFP_FLAGS);
2610                  if (!head->read_buf) {                  if (!head->read_buf) {
2611                          kfree(head);                          kfree(head);
2612                          return -ENOMEM;                          return -ENOMEM;
2613                  }                  }
2614          }          }
2615          if (!(file->f_mode & FMODE_WRITE)) {          if (file->f_mode & FMODE_WRITE) {
                 /*  
                  * No need to allocate write_buf since it is not opened  
                  * for writing.  
                  */  
                 head->write = NULL;  
         } else if (head->write) {  
2616                  head->writebuf_size = 4096;                  head->writebuf_size = 4096;
2617                  head->write_buf = kzalloc(head->writebuf_size, CCS_GFP_FLAGS);                  head->write_buf = kzalloc(head->writebuf_size, CCS_GFP_FLAGS);
2618                  if (!head->write_buf) {                  if (!head->write_buf) {
# Line 2262  int ccs_open_control(const u8 type, stru Line 2621  int ccs_open_control(const u8 type, stru
2621                          return -ENOMEM;                          return -ENOMEM;
2622                  }                  }
2623          }          }
         if (type != CCS_QUERY &&  
             type != CCS_GRANTLOG && type != CCS_REJECTLOG)  
                 head->reader_idx = ccs_lock();  
         file->private_data = head;  
2624          /*          /*
2625           * Call the handler now if the file is /proc/ccs/self_domain           * If the file is /proc/ccs/query, increment the observer counter.
          * 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);  
         /*  
          * If the file is /proc/ccs/query , increment the observer counter.  
2626           * The obserber counter is used by ccs_supervisor() to see if           * The obserber counter is used by ccs_supervisor() to see if
2627           * there is some process monitoring /proc/ccs/query.           * there is some process monitoring /proc/ccs/query.
2628           */           */
2629          else if (type == CCS_QUERY)          if (type == CCS_QUERY)
2630                  atomic_inc(&ccs_query_observers);                  atomic_inc(&ccs_query_observers);
2631            file->private_data = head;
2632            ccs_notify_gc(head, true);
2633          return 0;          return 0;
2634  }  }
2635    
# Line 2289  int ccs_open_control(const u8 type, stru Line 2639  int ccs_open_control(const u8 type, stru
2639   * @file: Pointer to "struct file".   * @file: Pointer to "struct file".
2640   * @wait: Pointer to "poll_table".   * @wait: Pointer to "poll_table".
2641   *   *
2642     * Returns return value of poll().
2643     *
2644   * Waits for read readiness.   * Waits for read readiness.
2645   * /proc/ccs/query is handled by /usr/sbin/ccs-queryd and   * /proc/ccs/query is handled by /usr/sbin/ccs-queryd and
2646   * /proc/ccs/grant_log and /proc/ccs/reject_log are handled by   * /proc/ccs/audit is handled by /usr/sbin/ccs-auditd.
  * /usr/sbin/ccs-auditd .  
2647   */   */
2648  int ccs_poll_control(struct file *file, poll_table *wait)  int ccs_poll_control(struct file *file, poll_table *wait)
2649  {  {
2650          struct ccs_io_buffer *head = file->private_data;          struct ccs_io_buffer *head = file->private_data;
2651          if (!head->poll)          switch (head->type) {
2652            case CCS_AUDIT:
2653                    return ccs_poll_log(file, wait);
2654            case CCS_QUERY:
2655                    return ccs_poll_query(file, wait);
2656            default:
2657                  return -ENOSYS;                  return -ENOSYS;
2658          return head->poll(file, wait);          }
2659    }
2660    
2661    /**
2662     * ccs_set_namespace_cursor - Set namespace to read.
2663     *
2664     * @head: Pointer to "struct ccs_io_buffer".
2665     *
2666     * Returns nothing.
2667     */
2668    static inline void ccs_set_namespace_cursor(struct ccs_io_buffer *head)
2669    {
2670            struct list_head *ns;
2671            if (head->type != CCS_EXCEPTIONPOLICY && head->type != CCS_PROFILE)
2672                    return;
2673            /*
2674             * If this is the first read, or reading previous namespace finished
2675             * and has more namespaces to read, update the namespace cursor.
2676             */
2677            ns = head->r.ns;
2678            if (!ns || (head->r.eof && ns->next != &ccs_namespace_list)) {
2679                    /* Clearing is OK because ccs_flush() returned true. */
2680                    memset(&head->r, 0, sizeof(head->r));
2681                    head->r.ns = ns ? ns->next : ccs_namespace_list.next;
2682            }
2683    }
2684    
2685    /**
2686     * ccs_has_more_namespace - Check for unread namespaces.
2687     *
2688     * @head: Pointer to "struct ccs_io_buffer".
2689     *
2690     * Returns true if we have more entries to print, false otherwise.
2691     */
2692    static inline bool ccs_has_more_namespace(struct ccs_io_buffer *head)
2693    {
2694            return (head->type == CCS_EXCEPTIONPOLICY ||
2695                    head->type == CCS_PROFILE) && head->r.eof &&
2696