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

Subversion リポジトリの参照

Diff of /branches/ccs-patch/security/ccsecurity/policy_io.c

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

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