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

Subversion リポジトリの参照

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

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

revision 4963 by kumaneko, Thu May 5 10:37:30 2011 UTC revision 5966 by kumaneko, Wed Mar 28 07:30:14 2012 UTC
# Line 1  Line 1 
1  /*  /*
2   * security/ccsecurity/policy_io.c   * security/ccsecurity/policy_io.c
3   *   *
4   * Copyright (C) 2005-2011  NTT DATA CORPORATION   * Copyright (C) 2005-2012  NTT DATA CORPORATION
5   *   *
6   * Version: 1.8.1+   2011/05/05   * Version: 1.8.3+   2012/04/01
7   */   */
8    
9  #include "internal.h"  #include "internal.h"
10    
11  #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)  /***** SECTION1: Constants definition *****/
12    
13  /**  /* Define this to enable debug mode. */
14   * __wait_event_interruptible_timeout - Sleep until a condition gets true or a timeout elapses.  /* #define DEBUG_CONDITION */
  *  
  * @wq:        The waitqueue to wait on.  
  * @condition: A C expression for the event to wait for.  
  * @ret:       Timeout, in jiffies.  
  *  
  * Returns 0 if the @timeout elapsed, -ERESTARTSYS if it was interrupted by a  
  * signal, and the remaining jiffies otherwise if the condition evaluated to  
  * true before the timeout elapsed.  
  *  
  * This is for compatibility with older kernels.  
  */  
 #define __wait_event_interruptible_timeout(wq, condition, ret)          \  
 do {                                                                    \  
         wait_queue_t __wait;                                            \  
         init_waitqueue_entry(&__wait, current);                         \  
                                                                         \  
         add_wait_queue(&wq, &__wait);                                   \  
         for (;;) {                                                      \  
                 set_current_state(TASK_INTERRUPTIBLE);                  \  
                 if (condition)                                          \  
                         break;                                          \  
                 if (!signal_pending(current)) {                         \  
                         ret = schedule_timeout(ret);                    \  
                         if (!ret)                                       \  
                                 break;                                  \  
                         continue;                                       \  
                 }                                                       \  
                 ret = -ERESTARTSYS;                                     \  
                 break;                                                  \  
         }                                                               \  
         current->state = TASK_RUNNING;                                  \  
         remove_wait_queue(&wq, &__wait);                                \  
 } while (0)  
   
 /**  
  * wait_event_interruptible_timeout - Sleep until a condition gets true or a timeout elapses.  
  *  
  * @wq:        The waitqueue to wait on.  
  * @condition: A C expression for the event to wait for.  
  * @timeout:   Timeout, in jiffies.  
  *  
  * Returns 0 if the @timeout elapsed, -ERESTARTSYS if it was interrupted by a  
  * signal, and the remaining jiffies otherwise if the condition evaluated to  
  * true before the timeout elapsed.  
  *  
  * This is for compatibility with older kernels.  
  */  
 #define wait_event_interruptible_timeout(wq, condition, timeout)        \  
 ({                                                                      \  
         long __ret = timeout;                                           \  
         if (!(condition))                                               \  
                 __wait_event_interruptible_timeout(wq, condition, __ret); \  
         __ret;                                                          \  
 })  
15    
16    #ifdef DEBUG_CONDITION
17    #define dprintk printk
18    #else
19    #define dprintk(...) do { } while (0)
20  #endif  #endif
21    
22  /**  /* Mapping table from "enum ccs_mac_index" to "enum ccs_mac_category_index". */
23   * list_for_each_cookie - iterate over a list with cookie.  static const u8 ccs_index2category[CCS_MAX_MAC_INDEX] = {
24   *          /* CONFIG::file group */
25   * @pos:  Pointer to "struct list_head".          [CCS_MAC_FILE_EXECUTE]    = CCS_MAC_CATEGORY_FILE,
26   * @head: Pointer to "struct list_head".          [CCS_MAC_FILE_OPEN]       = CCS_MAC_CATEGORY_FILE,
27   */          [CCS_MAC_FILE_CREATE]     = CCS_MAC_CATEGORY_FILE,
28  #define list_for_each_cookie(pos, head)                                 \          [CCS_MAC_FILE_UNLINK]     = CCS_MAC_CATEGORY_FILE,
29          for (pos = pos ? pos : srcu_dereference((head)->next, &ccs_ss); \  #ifdef CONFIG_CCSECURITY_FILE_GETATTR
30               pos != (head); pos = srcu_dereference(pos->next, &ccs_ss))          [CCS_MAC_FILE_GETATTR]    = CCS_MAC_CATEGORY_FILE,
31    #endif
32            [CCS_MAC_FILE_MKDIR]      = CCS_MAC_CATEGORY_FILE,
33  /* Profile version. Currently only 20100903 is defined. */          [CCS_MAC_FILE_RMDIR]      = CCS_MAC_CATEGORY_FILE,
34  static unsigned int ccs_profile_version;          [CCS_MAC_FILE_MKFIFO]     = CCS_MAC_CATEGORY_FILE,
35            [CCS_MAC_FILE_MKSOCK]     = CCS_MAC_CATEGORY_FILE,
36  /* Profile table. Memory is allocated as needed. */          [CCS_MAC_FILE_TRUNCATE]   = CCS_MAC_CATEGORY_FILE,
37  static struct ccs_profile *ccs_profile_ptr[CCS_MAX_PROFILES];          [CCS_MAC_FILE_SYMLINK]    = CCS_MAC_CATEGORY_FILE,
38            [CCS_MAC_FILE_MKBLOCK]    = CCS_MAC_CATEGORY_FILE,
39            [CCS_MAC_FILE_MKCHAR]     = CCS_MAC_CATEGORY_FILE,
40            [CCS_MAC_FILE_LINK]       = CCS_MAC_CATEGORY_FILE,
41            [CCS_MAC_FILE_RENAME]     = CCS_MAC_CATEGORY_FILE,
42            [CCS_MAC_FILE_CHMOD]      = CCS_MAC_CATEGORY_FILE,
43            [CCS_MAC_FILE_CHOWN]      = CCS_MAC_CATEGORY_FILE,
44            [CCS_MAC_FILE_CHGRP]      = CCS_MAC_CATEGORY_FILE,
45            [CCS_MAC_FILE_IOCTL]      = CCS_MAC_CATEGORY_FILE,
46            [CCS_MAC_FILE_CHROOT]     = CCS_MAC_CATEGORY_FILE,
47            [CCS_MAC_FILE_MOUNT]      = CCS_MAC_CATEGORY_FILE,
48            [CCS_MAC_FILE_UMOUNT]     = CCS_MAC_CATEGORY_FILE,
49            [CCS_MAC_FILE_PIVOT_ROOT] = CCS_MAC_CATEGORY_FILE,
50    #ifdef CONFIG_CCSECURITY_MISC
51            /* CONFIG::misc group */
52            [CCS_MAC_ENVIRON]         = CCS_MAC_CATEGORY_MISC,
53    #endif
54    #ifdef CONFIG_CCSECURITY_NETWORK
55            /* CONFIG::network group */
56            [CCS_MAC_NETWORK_INET_STREAM_BIND]       = CCS_MAC_CATEGORY_NETWORK,
57            [CCS_MAC_NETWORK_INET_STREAM_LISTEN]     = CCS_MAC_CATEGORY_NETWORK,
58            [CCS_MAC_NETWORK_INET_STREAM_CONNECT]    = CCS_MAC_CATEGORY_NETWORK,
59            [CCS_MAC_NETWORK_INET_STREAM_ACCEPT]     = CCS_MAC_CATEGORY_NETWORK,
60            [CCS_MAC_NETWORK_INET_DGRAM_BIND]        = CCS_MAC_CATEGORY_NETWORK,
61            [CCS_MAC_NETWORK_INET_DGRAM_SEND]        = CCS_MAC_CATEGORY_NETWORK,
62    #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
63            [CCS_MAC_NETWORK_INET_DGRAM_RECV]        = CCS_MAC_CATEGORY_NETWORK,
64    #endif
65            [CCS_MAC_NETWORK_INET_RAW_BIND]          = CCS_MAC_CATEGORY_NETWORK,
66            [CCS_MAC_NETWORK_INET_RAW_SEND]          = CCS_MAC_CATEGORY_NETWORK,
67    #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
68            [CCS_MAC_NETWORK_INET_RAW_RECV]          = CCS_MAC_CATEGORY_NETWORK,
69    #endif
70            [CCS_MAC_NETWORK_UNIX_STREAM_BIND]       = CCS_MAC_CATEGORY_NETWORK,
71            [CCS_MAC_NETWORK_UNIX_STREAM_LISTEN]     = CCS_MAC_CATEGORY_NETWORK,
72            [CCS_MAC_NETWORK_UNIX_STREAM_CONNECT]    = CCS_MAC_CATEGORY_NETWORK,
73            [CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT]     = CCS_MAC_CATEGORY_NETWORK,
74            [CCS_MAC_NETWORK_UNIX_DGRAM_BIND]        = CCS_MAC_CATEGORY_NETWORK,
75            [CCS_MAC_NETWORK_UNIX_DGRAM_SEND]        = CCS_MAC_CATEGORY_NETWORK,
76    #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
77            [CCS_MAC_NETWORK_UNIX_DGRAM_RECV]        = CCS_MAC_CATEGORY_NETWORK,
78    #endif
79            [CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND]    = CCS_MAC_CATEGORY_NETWORK,
80            [CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN]  = CCS_MAC_CATEGORY_NETWORK,
81            [CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
82            [CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT]  = CCS_MAC_CATEGORY_NETWORK,
83    #endif
84    #ifdef CONFIG_CCSECURITY_IPC
85            /* CONFIG::ipc group */
86            [CCS_MAC_SIGNAL]          = CCS_MAC_CATEGORY_IPC,
87    #endif
88    #ifdef CONFIG_CCSECURITY_CAPABILITY
89            /* CONFIG::capability group */
90            [CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET]  = CCS_MAC_CATEGORY_CAPABILITY,
91            [CCS_MAC_CAPABILITY_USE_PACKET_SOCKET] = CCS_MAC_CATEGORY_CAPABILITY,
92            [CCS_MAC_CAPABILITY_SYS_REBOOT]        = CCS_MAC_CATEGORY_CAPABILITY,
93            [CCS_MAC_CAPABILITY_SYS_VHANGUP]       = CCS_MAC_CATEGORY_CAPABILITY,
94            [CCS_MAC_CAPABILITY_SYS_SETTIME]       = CCS_MAC_CATEGORY_CAPABILITY,
95            [CCS_MAC_CAPABILITY_SYS_NICE]          = CCS_MAC_CATEGORY_CAPABILITY,
96            [CCS_MAC_CAPABILITY_SYS_SETHOSTNAME]   = CCS_MAC_CATEGORY_CAPABILITY,
97            [CCS_MAC_CAPABILITY_USE_KERNEL_MODULE] = CCS_MAC_CATEGORY_CAPABILITY,
98            [CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD]    = CCS_MAC_CATEGORY_CAPABILITY,
99            [CCS_MAC_CAPABILITY_SYS_PTRACE]        = CCS_MAC_CATEGORY_CAPABILITY,
100    #endif
101    };
102    
103  /* String table for operation mode. */  /* String table for operation mode. */
104  const char * const ccs_mode[CCS_CONFIG_MAX_MODE] = {  static const char * const ccs_mode[CCS_CONFIG_MAX_MODE] = {
105          [CCS_CONFIG_DISABLED]   = "disabled",          [CCS_CONFIG_DISABLED]   = "disabled",
106          [CCS_CONFIG_LEARNING]   = "learning",          [CCS_CONFIG_LEARNING]   = "learning",
107          [CCS_CONFIG_PERMISSIVE] = "permissive",          [CCS_CONFIG_PERMISSIVE] = "permissive",
# Line 95  const char * const ccs_mode[CCS_CONFIG_M Line 109  const char * const ccs_mode[CCS_CONFIG_M
109  };  };
110    
111  /* String table for /proc/ccs/profile interface. */  /* String table for /proc/ccs/profile interface. */
112  const char * const ccs_mac_keywords[CCS_MAX_MAC_INDEX  static const char * const ccs_mac_keywords[CCS_MAX_MAC_INDEX
113                                      + CCS_MAX_MAC_CATEGORY_INDEX] = {                                             + CCS_MAX_MAC_CATEGORY_INDEX] = {
114          /* CONFIG::file group */          /* CONFIG::file group */
115          [CCS_MAC_FILE_EXECUTE]    = "execute",          [CCS_MAC_FILE_EXECUTE]    = "execute",
116          [CCS_MAC_FILE_OPEN]       = "open",          [CCS_MAC_FILE_OPEN]       = "open",
117          [CCS_MAC_FILE_CREATE]     = "create",          [CCS_MAC_FILE_CREATE]     = "create",
118          [CCS_MAC_FILE_UNLINK]     = "unlink",          [CCS_MAC_FILE_UNLINK]     = "unlink",
119    #ifdef CONFIG_CCSECURITY_FILE_GETATTR
120          [CCS_MAC_FILE_GETATTR]    = "getattr",          [CCS_MAC_FILE_GETATTR]    = "getattr",
121    #endif
122          [CCS_MAC_FILE_MKDIR]      = "mkdir",          [CCS_MAC_FILE_MKDIR]      = "mkdir",
123          [CCS_MAC_FILE_RMDIR]      = "rmdir",          [CCS_MAC_FILE_RMDIR]      = "rmdir",
124          [CCS_MAC_FILE_MKFIFO]     = "mkfifo",          [CCS_MAC_FILE_MKFIFO]     = "mkfifo",
# Line 121  const char * const ccs_mac_keywords[CCS_ Line 137  const char * const ccs_mac_keywords[CCS_
137          [CCS_MAC_FILE_MOUNT]      = "mount",          [CCS_MAC_FILE_MOUNT]      = "mount",
138          [CCS_MAC_FILE_UMOUNT]     = "unmount",          [CCS_MAC_FILE_UMOUNT]     = "unmount",
139          [CCS_MAC_FILE_PIVOT_ROOT] = "pivot_root",          [CCS_MAC_FILE_PIVOT_ROOT] = "pivot_root",
140    #ifdef CONFIG_CCSECURITY_MISC
141          /* CONFIG::misc group */          /* CONFIG::misc group */
142          [CCS_MAC_ENVIRON] = "env",          [CCS_MAC_ENVIRON] = "env",
143    #endif
144    #ifdef CONFIG_CCSECURITY_NETWORK
145          /* CONFIG::network group */          /* CONFIG::network group */
146          [CCS_MAC_NETWORK_INET_STREAM_BIND]       = "inet_stream_bind",          [CCS_MAC_NETWORK_INET_STREAM_BIND]       = "inet_stream_bind",
147          [CCS_MAC_NETWORK_INET_STREAM_LISTEN]     = "inet_stream_listen",          [CCS_MAC_NETWORK_INET_STREAM_LISTEN]     = "inet_stream_listen",
# Line 130  const char * const ccs_mac_keywords[CCS_ Line 149  const char * const ccs_mac_keywords[CCS_
149          [CCS_MAC_NETWORK_INET_STREAM_ACCEPT]     = "inet_stream_accept",          [CCS_MAC_NETWORK_INET_STREAM_ACCEPT]     = "inet_stream_accept",
150          [CCS_MAC_NETWORK_INET_DGRAM_BIND]        = "inet_dgram_bind",          [CCS_MAC_NETWORK_INET_DGRAM_BIND]        = "inet_dgram_bind",
151          [CCS_MAC_NETWORK_INET_DGRAM_SEND]        = "inet_dgram_send",          [CCS_MAC_NETWORK_INET_DGRAM_SEND]        = "inet_dgram_send",
152    #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
153          [CCS_MAC_NETWORK_INET_DGRAM_RECV]        = "inet_dgram_recv",          [CCS_MAC_NETWORK_INET_DGRAM_RECV]        = "inet_dgram_recv",
154    #endif
155          [CCS_MAC_NETWORK_INET_RAW_BIND]          = "inet_raw_bind",          [CCS_MAC_NETWORK_INET_RAW_BIND]          = "inet_raw_bind",
156          [CCS_MAC_NETWORK_INET_RAW_SEND]          = "inet_raw_send",          [CCS_MAC_NETWORK_INET_RAW_SEND]          = "inet_raw_send",
157    #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
158          [CCS_MAC_NETWORK_INET_RAW_RECV]          = "inet_raw_recv",          [CCS_MAC_NETWORK_INET_RAW_RECV]          = "inet_raw_recv",
159    #endif
160          [CCS_MAC_NETWORK_UNIX_STREAM_BIND]       = "unix_stream_bind",          [CCS_MAC_NETWORK_UNIX_STREAM_BIND]       = "unix_stream_bind",
161          [CCS_MAC_NETWORK_UNIX_STREAM_LISTEN]     = "unix_stream_listen",          [CCS_MAC_NETWORK_UNIX_STREAM_LISTEN]     = "unix_stream_listen",
162          [CCS_MAC_NETWORK_UNIX_STREAM_CONNECT]    = "unix_stream_connect",          [CCS_MAC_NETWORK_UNIX_STREAM_CONNECT]    = "unix_stream_connect",
163          [CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT]     = "unix_stream_accept",          [CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT]     = "unix_stream_accept",
164          [CCS_MAC_NETWORK_UNIX_DGRAM_BIND]        = "unix_dgram_bind",          [CCS_MAC_NETWORK_UNIX_DGRAM_BIND]        = "unix_dgram_bind",
165          [CCS_MAC_NETWORK_UNIX_DGRAM_SEND]        = "unix_dgram_send",          [CCS_MAC_NETWORK_UNIX_DGRAM_SEND]        = "unix_dgram_send",
166    #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
167          [CCS_MAC_NETWORK_UNIX_DGRAM_RECV]        = "unix_dgram_recv",          [CCS_MAC_NETWORK_UNIX_DGRAM_RECV]        = "unix_dgram_recv",
168    #endif
169          [CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND]    = "unix_seqpacket_bind",          [CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND]    = "unix_seqpacket_bind",
170          [CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN]  = "unix_seqpacket_listen",          [CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN]  = "unix_seqpacket_listen",
171          [CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",          [CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
172          [CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT]  = "unix_seqpacket_accept",          [CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT]  = "unix_seqpacket_accept",
173    #endif
174    #ifdef CONFIG_CCSECURITY_IPC
175          /* CONFIG::ipc group */          /* CONFIG::ipc group */
176          [CCS_MAC_SIGNAL] = "signal",          [CCS_MAC_SIGNAL] = "signal",
177    #endif
178    #ifdef CONFIG_CCSECURITY_CAPABILITY
179          /* CONFIG::capability group */          /* CONFIG::capability group */
180          [CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET]  = "use_route",          [CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET]  = "use_route",
181          [CCS_MAC_CAPABILITY_USE_PACKET_SOCKET] = "use_packet",          [CCS_MAC_CAPABILITY_USE_PACKET_SOCKET] = "use_packet",
# Line 158  const char * const ccs_mac_keywords[CCS_ Line 187  const char * const ccs_mac_keywords[CCS_
187          [CCS_MAC_CAPABILITY_USE_KERNEL_MODULE] = "use_kernel_module",          [CCS_MAC_CAPABILITY_USE_KERNEL_MODULE] = "use_kernel_module",
188          [CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD]    = "SYS_KEXEC_LOAD",          [CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD]    = "SYS_KEXEC_LOAD",
189          [CCS_MAC_CAPABILITY_SYS_PTRACE]        = "SYS_PTRACE",          [CCS_MAC_CAPABILITY_SYS_PTRACE]        = "SYS_PTRACE",
190    #endif
191          /* CONFIG group */          /* CONFIG group */
192          [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_FILE]       = "file",          [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_FILE]       = "file",
193    #ifdef CONFIG_CCSECURITY_NETWORK
194          [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_NETWORK]    = "network",          [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_NETWORK]    = "network",
195    #endif
196    #ifdef CONFIG_CCSECURITY_MISC
197          [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_MISC]       = "misc",          [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_MISC]       = "misc",
198    #endif
199    #ifdef CONFIG_CCSECURITY_IPC
200          [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_IPC]        = "ipc",          [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_IPC]        = "ipc",
201    #endif
202    #ifdef CONFIG_CCSECURITY_CAPABILITY
203          [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_CAPABILITY] = "capability",          [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_CAPABILITY] = "capability",
204    #endif
205  };  };
206    
207  /* String table for path operation. */  /* String table for path operation. */
208  const char * const ccs_path_keyword[CCS_MAX_PATH_OPERATION] = {  static const char * const ccs_path_keyword[CCS_MAX_PATH_OPERATION] = {
209          [CCS_TYPE_EXECUTE]    = "execute",          [CCS_TYPE_EXECUTE]    = "execute",
210          [CCS_TYPE_READ]       = "read",          [CCS_TYPE_READ]       = "read",
211          [CCS_TYPE_WRITE]      = "write",          [CCS_TYPE_WRITE]      = "write",
212          [CCS_TYPE_APPEND]     = "append",          [CCS_TYPE_APPEND]     = "append",
213          [CCS_TYPE_UNLINK]     = "unlink",          [CCS_TYPE_UNLINK]     = "unlink",
214    #ifdef CONFIG_CCSECURITY_FILE_GETATTR
215          [CCS_TYPE_GETATTR]    = "getattr",          [CCS_TYPE_GETATTR]    = "getattr",
216    #endif
217          [CCS_TYPE_RMDIR]      = "rmdir",          [CCS_TYPE_RMDIR]      = "rmdir",
218          [CCS_TYPE_TRUNCATE]   = "truncate",          [CCS_TYPE_TRUNCATE]   = "truncate",
219          [CCS_TYPE_SYMLINK]    = "symlink",          [CCS_TYPE_SYMLINK]    = "symlink",
# Line 181  const char * const ccs_path_keyword[CCS_ Line 221  const char * const ccs_path_keyword[CCS_
221          [CCS_TYPE_UMOUNT]     = "unmount",          [CCS_TYPE_UMOUNT]     = "unmount",
222  };  };
223    
224    #ifdef CONFIG_CCSECURITY_NETWORK
225    
226    /* String table for socket's operation. */
227    static const char * const ccs_socket_keyword[CCS_MAX_NETWORK_OPERATION] = {
228            [CCS_NETWORK_BIND]    = "bind",
229            [CCS_NETWORK_LISTEN]  = "listen",
230            [CCS_NETWORK_CONNECT] = "connect",
231            [CCS_NETWORK_ACCEPT]  = "accept",
232            [CCS_NETWORK_SEND]    = "send",
233    #ifdef CONFIG_CCSECURITY_NETWORK_RECVMSG
234            [CCS_NETWORK_RECV]    = "recv",
235    #endif
236    };
237    
238    /* String table for socket's protocols. */
239    static const char * const ccs_proto_keyword[CCS_SOCK_MAX] = {
240            [SOCK_STREAM]    = "stream",
241            [SOCK_DGRAM]     = "dgram",
242            [SOCK_RAW]       = "raw",
243            [SOCK_SEQPACKET] = "seqpacket",
244            [0] = " ", /* Dummy for avoiding NULL pointer dereference. */
245            [4] = " ", /* Dummy for avoiding NULL pointer dereference. */
246    };
247    
248    #endif
249    
250  /* String table for categories. */  /* String table for categories. */
251  static const char * const ccs_category_keywords[CCS_MAX_MAC_CATEGORY_INDEX] = {  static const char * const ccs_category_keywords[CCS_MAX_MAC_CATEGORY_INDEX] = {
252          [CCS_MAC_CATEGORY_FILE]       = "file",          [CCS_MAC_CATEGORY_FILE]       = "file",
253    #ifdef CONFIG_CCSECURITY_NETWORK
254          [CCS_MAC_CATEGORY_NETWORK]    = "network",          [CCS_MAC_CATEGORY_NETWORK]    = "network",
255    #endif
256    #ifdef CONFIG_CCSECURITY_MISC
257          [CCS_MAC_CATEGORY_MISC]       = "misc",          [CCS_MAC_CATEGORY_MISC]       = "misc",
258    #endif
259    #ifdef CONFIG_CCSECURITY_IPC
260          [CCS_MAC_CATEGORY_IPC]        = "ipc",          [CCS_MAC_CATEGORY_IPC]        = "ipc",
261    #endif
262    #ifdef CONFIG_CCSECURITY_CAPABILITY
263          [CCS_MAC_CATEGORY_CAPABILITY] = "capability",          [CCS_MAC_CATEGORY_CAPABILITY] = "capability",
264    #endif
265  };  };
266    
267  /* String table for conditions. */  /* String table for conditions. */
268  const char * const ccs_condition_keyword[CCS_MAX_CONDITION_KEYWORD] = {  static const char * const ccs_condition_keyword[CCS_MAX_CONDITION_KEYWORD] = {
269          [CCS_TASK_UID]             = "task.uid",          [CCS_TASK_UID]             = "task.uid",
270          [CCS_TASK_EUID]            = "task.euid",          [CCS_TASK_EUID]            = "task.euid",
271          [CCS_TASK_SUID]            = "task.suid",          [CCS_TASK_SUID]            = "task.suid",
# Line 262  static const char * const ccs_pref_keywo Line 336  static const char * const ccs_pref_keywo
336          [CCS_PREF_ENFORCING_PENALTY]  = "enforcing_penalty",          [CCS_PREF_ENFORCING_PENALTY]  = "enforcing_penalty",
337  };  };
338    
339    /* String table for domain flags. */
340    const char * const ccs_dif[CCS_MAX_DOMAIN_INFO_FLAGS] = {
341            [CCS_DIF_QUOTA_WARNED]      = "quota_exceeded\n",
342            [CCS_DIF_TRANSITION_FAILED] = "transition_failed\n",
343    };
344    
345    /* String table for domain transition control keywords. */
346    static const char * const ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = {
347            [CCS_TRANSITION_CONTROL_NO_RESET]      = "no_reset_domain ",
348            [CCS_TRANSITION_CONTROL_RESET]         = "reset_domain ",
349            [CCS_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
350            [CCS_TRANSITION_CONTROL_INITIALIZE]    = "initialize_domain ",
351            [CCS_TRANSITION_CONTROL_NO_KEEP]       = "no_keep_domain ",
352            [CCS_TRANSITION_CONTROL_KEEP]          = "keep_domain ",
353    };
354    
355    /* String table for grouping keywords. */
356    static const char * const ccs_group_name[CCS_MAX_GROUP] = {
357            [CCS_PATH_GROUP]    = "path_group ",
358            [CCS_NUMBER_GROUP]  = "number_group ",
359    #ifdef CONFIG_CCSECURITY_NETWORK
360            [CCS_ADDRESS_GROUP] = "address_group ",
361    #endif
362    };
363    
364    /* String table for /proc/ccs/stat interface. */
365    static const char * const ccs_policy_headers[CCS_MAX_POLICY_STAT] = {
366            [CCS_STAT_POLICY_UPDATES]    = "update:",
367            [CCS_STAT_POLICY_LEARNING]   = "violation in learning mode:",
368            [CCS_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:",
369            [CCS_STAT_POLICY_ENFORCING]  = "violation in enforcing mode:",
370    };
371    
372    /* String table for /proc/ccs/stat interface. */
373    static const char * const ccs_memory_headers[CCS_MAX_MEMORY_STAT] = {
374            [CCS_MEMORY_POLICY]     = "policy:",
375            [CCS_MEMORY_AUDIT]      = "audit log:",
376            [CCS_MEMORY_QUERY]      = "query message:",
377    };
378    
379    /***** SECTION2: Structure definition *****/
380    
381    struct iattr;
382    
383    /* Structure for query. */
384    struct ccs_query {
385            struct list_head list;
386            struct ccs_domain_info *domain;
387            char *query;
388            size_t query_len;
389            unsigned int serial;
390            u8 timer;
391            u8 answer;
392            u8 retry;
393    };
394    
395    /* Structure for audit log. */
396    struct ccs_log {
397            struct list_head list;
398            char *log;
399            int size;
400    };
401    
402    /***** SECTION3: Prototype definition section *****/
403    
404    int ccs_audit_log(struct ccs_request_info *r);
405    struct ccs_domain_info *ccs_assign_domain(const char *domainname,
406                                              const bool transit);
407    u8 ccs_get_config(const u8 profile, const u8 index);
408    void ccs_transition_failed(const char *domainname);
409    void ccs_write_log(struct ccs_request_info *r, const char *fmt, ...);
410    
411    static bool ccs_correct_domain(const unsigned char *domainname);
412    static bool ccs_correct_path(const char *filename);
413    static bool ccs_correct_word(const char *string);
414    static bool ccs_correct_word2(const char *string, size_t len);
415    static bool ccs_domain_def(const unsigned char *buffer);
416    static bool ccs_domain_quota_ok(struct ccs_request_info *r);
417    static bool ccs_flush(struct ccs_io_buffer *head);
418    static bool ccs_get_audit(const struct ccs_request_info *r);
419    static bool ccs_has_more_namespace(struct ccs_io_buffer *head);
420    static bool ccs_manager(void);
421    static bool ccs_namespace_jump(const char *domainname);
422    static bool ccs_parse_argv(char *left, char *right, struct ccs_argv *argv);
423    static bool ccs_parse_envp(char *left, char *right, struct ccs_envp *envp);
424    static bool ccs_parse_name_union(struct ccs_acl_param *param,
425                                     struct ccs_name_union *ptr);
426    static bool ccs_parse_name_union_quoted(struct ccs_acl_param *param,
427                                            struct ccs_name_union *ptr);
428    static bool ccs_parse_number_union(struct ccs_acl_param *param,
429                                       struct ccs_number_union *ptr);
430    static bool ccs_permstr(const char *string, const char *keyword);
431    static bool ccs_print_condition(struct ccs_io_buffer *head,
432                                    const struct ccs_condition *cond);
433    static bool ccs_print_entry(struct ccs_io_buffer *head,
434                                const struct ccs_acl_info *acl);
435    static bool ccs_print_group(struct ccs_io_buffer *head,
436                                const struct ccs_group *group);
437    static bool ccs_read_acl(struct ccs_io_buffer *head, struct list_head *list);
438    static bool ccs_read_group(struct ccs_io_buffer *head, const int idx);
439    static bool ccs_read_policy(struct ccs_io_buffer *head, const int idx);
440    static bool ccs_same_condition(const struct ccs_condition *a,
441                                   const struct ccs_condition *b);
442    static bool ccs_select_domain(struct ccs_io_buffer *head, const char *data);
443    static bool ccs_set_lf(struct ccs_io_buffer *head);
444    static bool ccs_str_starts(char **src, const char *find);
445    static char *ccs_get_transit_preference(struct ccs_acl_param *param,
446                                            struct ccs_condition *e);
447    static char *ccs_init_log(struct ccs_request_info *r, int len, const char *fmt,
448                              va_list args);
449    static char *ccs_print_bprm(struct linux_binprm *bprm,
450                                struct ccs_page_dump *dump);
451    static char *ccs_print_header(struct ccs_request_info *r);
452    static char *ccs_read_token(struct ccs_acl_param *param);
453    static const char *ccs_yesno(const unsigned int value);
454    static const struct ccs_path_info *ccs_get_domainname
455    (struct ccs_acl_param *param);
456    static const struct ccs_path_info *ccs_get_dqword(char *start);
457    static int __init ccs_init_module(void);
458    static int ccs_delete_domain(char *domainname);
459    static int ccs_open(struct inode *inode, struct file *file);
460    static int ccs_parse_policy(struct ccs_io_buffer *head, char *line);
461    static int ccs_release(struct inode *inode, struct file *file);
462    static int ccs_set_mode(char *name, const char *value,
463                            struct ccs_profile *profile);
464    static int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...)
465            __printf(2, 3);
466    static int ccs_truncate(char *str);
467    static int ccs_update_acl(const int size, struct ccs_acl_param *param);
468    static int ccs_update_manager_entry(const char *manager, const bool is_delete);
469    static int ccs_update_policy(const int size, struct ccs_acl_param *param);
470    static int ccs_write_acl(struct ccs_policy_namespace *ns,
471                             struct list_head *list, char *data,
472                             const bool is_delete);
473    static int ccs_write_aggregator(struct ccs_acl_param *param);
474    static int ccs_write_answer(struct ccs_io_buffer *head);
475    static int ccs_write_domain(struct ccs_io_buffer *head);
476    static int ccs_write_exception(struct ccs_io_buffer *head);
477    static int ccs_write_file(struct ccs_acl_param *param);
478    static int ccs_write_group(struct ccs_acl_param *param, const u8 type);
479    static int ccs_write_manager(struct ccs_io_buffer *head);
480    static int ccs_write_pid(struct ccs_io_buffer *head);
481    static int ccs_write_profile(struct ccs_io_buffer *head);
482    static int ccs_write_stat(struct ccs_io_buffer *head);
483    static int ccs_write_task(struct ccs_acl_param *param);
484    static int ccs_write_transition_control(struct ccs_acl_param *param,
485                                            const u8 type);
486    static s8 ccs_find_yesno(const char *string, const char *find);
487    static ssize_t ccs_read(struct file *file, char __user *buf, size_t count,
488                            loff_t *ppos);
489    static ssize_t ccs_read_self(struct file *file, char __user *buf, size_t count,
490                                 loff_t *ppos);
491    static ssize_t ccs_write(struct file *file, const char __user *buf,
492                             size_t count, loff_t *ppos);
493    static struct ccs_condition *ccs_commit_condition(struct ccs_condition *entry);
494    static struct ccs_condition *ccs_get_condition(struct ccs_acl_param *param);
495    static struct ccs_domain_info *ccs_find_domain(const char *domainname);
496    static struct ccs_domain_info *ccs_find_domain_by_qid(unsigned int serial);
497    static struct ccs_group *ccs_get_group(struct ccs_acl_param *param,
498                                           const u8 idx);
499    static struct ccs_policy_namespace *ccs_assign_namespace
500    (const char *domainname);
501    static struct ccs_policy_namespace *ccs_find_namespace(const char *name,
502                                                           const unsigned int len);
503    static struct ccs_profile *ccs_assign_profile(struct ccs_policy_namespace *ns,
504                                                  const unsigned int profile);
505    static struct ccs_profile *ccs_profile(const u8 profile);
506    static u8 ccs_condition_type(const char *word);
507    static u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3);
508    static u8 ccs_parse_ulong(unsigned long *result, char **str);
509    static unsigned int ccs_poll(struct file *file, poll_table *wait);
510    static void __init ccs_create_entry(const char *name, const umode_t mode,
511                                        struct proc_dir_entry *parent,
512                                        const u8 key);
513    static void __init ccs_load_builtin_policy(void);
514    static void __init ccs_policy_io_init(void);
515    static void __init ccs_proc_init(void);
516    static void ccs_add_entry(char *header);
517    static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)
518            __printf(3, 4);
519    static void ccs_addprintf(char *buffer, int len, const char *fmt, ...);
520    static void ccs_check_profile(void);
521    static void ccs_convert_time(time_t time, struct ccs_time *stamp);
522    static void ccs_init_policy_namespace(struct ccs_policy_namespace *ns);
523    static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
524            __printf(2, 3);
525    static void ccs_normalize_line(unsigned char *buffer);
526    static void ccs_print_config(struct ccs_io_buffer *head, const u8 config);
527    static void ccs_print_name_union(struct ccs_io_buffer *head,
528                                     const struct ccs_name_union *ptr);
529    static void ccs_print_name_union_quoted(struct ccs_io_buffer *head,
530                                            const struct ccs_name_union *ptr);
531    static void ccs_print_namespace(struct ccs_io_buffer *head);
532    static void ccs_print_number_union(struct ccs_io_buffer *head,
533                                       const struct ccs_number_union *ptr);
534    static void ccs_print_number_union_nospace(struct ccs_io_buffer *head,
535                                               const struct ccs_number_union *ptr);
536    static void ccs_read_domain(struct ccs_io_buffer *head);
537    static void ccs_read_exception(struct ccs_io_buffer *head);
538    static void ccs_read_log(struct ccs_io_buffer *head);
539    static void ccs_read_manager(struct ccs_io_buffer *head);
540    static void ccs_read_pid(struct ccs_io_buffer *head);
541    static void ccs_read_profile(struct ccs_io_buffer *head);
542    static void ccs_read_query(struct ccs_io_buffer *head);
543    static void ccs_read_stat(struct ccs_io_buffer *head);
544    static void ccs_read_version(struct ccs_io_buffer *head);
545    static void ccs_set_group(struct ccs_io_buffer *head, const char *category);
546    static void ccs_set_namespace_cursor(struct ccs_io_buffer *head);
547    static void ccs_set_slash(struct ccs_io_buffer *head);
548    static void ccs_set_space(struct ccs_io_buffer *head);
549    static void ccs_set_string(struct ccs_io_buffer *head, const char *string);
550    static void ccs_set_uint(unsigned int *i, const char *string,
551                             const char *find);
552    static void ccs_update_stat(const u8 index);
553    static void ccs_update_task_domain(struct ccs_request_info *r);
554    static void ccs_write_log2(struct ccs_request_info *r, int len,
555                               const char *fmt, va_list args);
556    
557    #ifdef CONFIG_CCSECURITY_PORTRESERVE
558    static bool __ccs_lport_reserved(const u16 port);
559    static int ccs_write_reserved_port(struct ccs_acl_param *param);
560    #endif
561    
562    #ifdef CONFIG_CCSECURITY_NETWORK
563    static bool ccs_parse_ipaddr_union(struct ccs_acl_param *param,
564                                       struct ccs_ipaddr_union *ptr);
565    static int ccs_print_ipv4(char *buffer, const unsigned int buffer_len,
566                              const u32 *ip);
567    static int ccs_print_ipv6(char *buffer, const unsigned int buffer_len,
568                              const struct in6_addr *ip);
569    static int ccs_write_inet_network(struct ccs_acl_param *param);
570    static int ccs_write_unix_network(struct ccs_acl_param *param);
571    static void ccs_print_ip(char *buf, const unsigned int size,
572                             const struct ccs_ipaddr_union *ptr);
573    #endif
574    
575    #ifdef CONFIG_CCSECURITY_CAPABILITY
576    static int ccs_write_capability(struct ccs_acl_param *param);
577    #endif
578    
579    #ifdef CONFIG_CCSECURITY_MISC
580    static int ccs_write_misc(struct ccs_acl_param *param);
581    #endif
582    
583    #ifdef CONFIG_CCSECURITY_IPC
584    static int ccs_write_ipc(struct ccs_acl_param *param);
585    #endif
586    
587    #ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
588    static ssize_t ccs_write_self(struct file *file, const char __user *buf,
589                                  size_t count, loff_t *ppos);
590    #endif
591    
592    /***** SECTION4: Standalone functions section *****/
593    
594    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
595    
596    /**
597     * fatal_signal_pending - Check whether SIGKILL is pending or not.
598     *
599     * @p: Pointer to "struct task_struct".
600     *
601     * Returns true if SIGKILL is pending on @p, false otherwise.
602     *
603     * This is for compatibility with older kernels.
604     */
605    #define fatal_signal_pending(p) (signal_pending(p) &&                   \
606                                     sigismember(&p->pending.signal, SIGKILL))
607    
608    #endif
609    
610    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
611    
612    /**
613     * __wait_event_interruptible_timeout - Sleep until a condition gets true or a timeout elapses.
614     *
615     * @wq:        The waitqueue to wait on.
616     * @condition: A C expression for the event to wait for.
617     * @ret:       Timeout, in jiffies.
618     *
619     * Returns 0 if the @timeout elapsed, -ERESTARTSYS if it was interrupted by a
620     * signal, and the remaining jiffies otherwise if the condition evaluated to
621     * true before the timeout elapsed.
622     *
623     * This is for compatibility with older kernels.
624     */
625    #define __wait_event_interruptible_timeout(wq, condition, ret)          \
626    do {                                                                    \
627            wait_queue_t __wait;                                            \
628            init_waitqueue_entry(&__wait, current);                         \
629                                                                            \
630            add_wait_queue(&wq, &__wait);                                   \
631            for (;;) {                                                      \
632                    set_current_state(TASK_INTERRUPTIBLE);                  \
633                    if (condition)                                          \
634                            break;                                          \
635                    if (!signal_pending(current)) {                         \
636                            ret = schedule_timeout(ret);                    \
637                            if (!ret)                                       \
638                                    break;                                  \
639                            continue;                                       \
640                    }                                                       \
641                    ret = -ERESTARTSYS;                                     \
642                    break;                                                  \
643            }                                                               \
644            current->state = TASK_RUNNING;                                  \
645            remove_wait_queue(&wq, &__wait);                                \
646    } while (0)
647    
648    /**
649     * wait_event_interruptible_timeout - Sleep until a condition gets true or a timeout elapses.
650     *
651     * @wq:        The waitqueue to wait on.
652     * @condition: A C expression for the event to wait for.
653     * @timeout:   Timeout, in jiffies.
654     *
655     * Returns 0 if the @timeout elapsed, -ERESTARTSYS if it was interrupted by a
656     * signal, and the remaining jiffies otherwise if the condition evaluated to
657     * true before the timeout elapsed.
658     *
659     * This is for compatibility with older kernels.
660     */
661    #define wait_event_interruptible_timeout(wq, condition, timeout)        \
662    ({                                                                      \
663            long __ret = timeout;                                           \
664            if (!(condition))                                               \
665                    __wait_event_interruptible_timeout(wq, condition, __ret); \
666            __ret;                                                          \
667    })
668    
669    #endif
670    
671    /**
672     * ccs_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss.
673     *
674     * @time:  Seconds since 1970/01/01 00:00:00.
675     * @stamp: Pointer to "struct ccs_time".
676     *
677     * Returns nothing.
678     *
679     * This function does not handle Y2038 problem.
680     */
681    static void ccs_convert_time(time_t time, struct ccs_time *stamp)
682    {
683            static const u16 ccs_eom[2][12] = {
684                    { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
685                    { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
686            };
687            u16 y;
688            u8 m;
689            bool r;
690            stamp->sec = time % 60;
691            time /= 60;
692            stamp->min = time % 60;
693            time /= 60;
694            stamp->hour = time % 24;
695            time /= 24;
696            for (y = 1970; ; y++) {
697                    const unsigned short days = (y & 3) ? 365 : 366;
698                    if (time < days)
699                            break;
700                    time -= days;
701            }
702            r = (y & 3) == 0;
703            for (m = 0; m < 11 && time >= ccs_eom[r][m]; m++);
704            if (m)
705                    time -= ccs_eom[r][m - 1];
706            stamp->year = y;
707            stamp->month = ++m;
708            stamp->day = ++time;
709    }
710    
711    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 23)
712    #if !defined(RHEL_VERSION) || RHEL_VERSION != 3
713    
714    /**
715     * PDE - Get "struct proc_dir_entry".
716     *
717     * @inode: Pointer to "struct inode".
718     *
719     * Returns pointer to "struct proc_dir_entry".
720     *
721     * This is for compatibility with older kernels.
722     */
723    static inline struct proc_dir_entry *PDE(const struct inode *inode)
724    {
725            return (struct proc_dir_entry *) inode->u.generic_ip;
726    }
727    
728    #endif
729    #endif
730    
731    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
732    
733    /**
734     * proc_notify_change - Update inode's attributes and reflect to the dentry.
735     *
736     * @dentry: Pointer to "struct dentry".
737     * @iattr:  Pointer to "struct iattr".
738     *
739     * Returns 0 on success, negative value otherwise.
740     *
741     * The 2.4 kernels don't allow chmod()/chown() for files in /proc,
742     * while the 2.6 kernels allow.
743     * To permit management of /proc/ccs/ interface by non-root user,
744     * I modified to allow chmod()/chown() of /proc/ccs/ interface like 2.6 kernels
745     * by adding "struct inode_operations"->setattr hook.
746     */
747    static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
748    {
749            struct inode *inode = dentry->d_inode;
750            struct proc_dir_entry *de = PDE(inode);
751            int error;
752    
753            error = inode_change_ok(inode, iattr);
754            if (error)
755                    goto out;
756    
757            error = inode_setattr(inode, iattr);
758            if (error)
759                    goto out;
760    
761            de->uid = inode->i_uid;
762            de->gid = inode->i_gid;
763            de->mode = inode->i_mode;
764    out:
765            return error;
766    }
767    
768    #endif
769    
770    #ifdef CONFIG_CCSECURITY_NETWORK
771    
772    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) && defined(CONFIG_NET)
773    #define ccs_in4_pton in4_pton
774    #define ccs_in6_pton in6_pton
775    #else
776    /*
777     * Routines for parsing IPv4 or IPv6 address.
778     * These are copied from lib/hexdump.c net/core/utils.c .
779     */
780    #include <linux/ctype.h>
781    
782    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
783    static int hex_to_bin(char ch)
784    {
785            if ((ch >= '0') && (ch <= '9'))
786                    return ch - '0';
787            ch = tolower(ch);
788            if ((ch >= 'a') && (ch <= 'f'))
789                    return ch - 'a' + 10;
790            return -1;
791    }
792    #endif
793    
794    #define IN6PTON_XDIGIT          0x00010000
795    #define IN6PTON_DIGIT           0x00020000
796    #define IN6PTON_COLON_MASK      0x00700000
797    #define IN6PTON_COLON_1         0x00100000      /* single : requested */
798    #define IN6PTON_COLON_2         0x00200000      /* second : requested */
799    #define IN6PTON_COLON_1_2       0x00400000      /* :: requested */
800    #define IN6PTON_DOT             0x00800000      /* . */
801    #define IN6PTON_DELIM           0x10000000
802    #define IN6PTON_NULL            0x20000000      /* first/tail */
803    #define IN6PTON_UNKNOWN         0x40000000
804    
805    static inline int xdigit2bin(char c, int delim)
806    {
807            int val;
808    
809            if (c == delim || c == '\0')
810                    return IN6PTON_DELIM;
811            if (c == ':')
812                    return IN6PTON_COLON_MASK;
813            if (c == '.')
814                    return IN6PTON_DOT;
815    
816            val = hex_to_bin(c);
817            if (val >= 0)
818                    return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0);
819    
820            if (delim == -1)
821                    return IN6PTON_DELIM;
822            return IN6PTON_UNKNOWN;
823    }
824    
825    static int ccs_in4_pton(const char *src, int srclen, u8 *dst, int delim,
826                            const char **end)
827    {
828            const char *s;
829            u8 *d;
830            u8 dbuf[4];
831            int ret = 0;
832            int i;
833            int w = 0;
834    
835            if (srclen < 0)
836                    srclen = strlen(src);
837            s = src;
838            d = dbuf;
839            i = 0;
840            while (1) {
841                    int c;
842                    c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
843                    if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM |
844                               IN6PTON_COLON_MASK)))
845                            goto out;
846                    if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
847                            if (w == 0)
848                                    goto out;
849                            *d++ = w & 0xff;
850                            w = 0;
851                            i++;
852                            if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
853                                    if (i != 4)
854                                            goto out;
855                                    break;
856                            }
857                            goto cont;
858                    }
859                    w = (w * 10) + c;
860                    if ((w & 0xffff) > 255)
861                            goto out;
862    cont:
863                    if (i >= 4)
864                            goto out;
865                    s++;
866                    srclen--;
867            }
868            ret = 1;
869            memcpy(dst, dbuf, sizeof(dbuf));
870    out:
871            if (end)
872                    *end = s;
873            return ret;
874    }
875    
876    static int ccs_in6_pton(const char *src, int srclen, u8 *dst, int delim,
877                            const char **end)
878    {
879            const char *s, *tok = NULL;
880            u8 *d, *dc = NULL;
881            u8 dbuf[16];
882            int ret = 0;
883            int i;
884            int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
885            int w = 0;
886    
887            memset(dbuf, 0, sizeof(dbuf));
888    
889            s = src;
890            d = dbuf;
891            if (srclen < 0)
892                    srclen = strlen(src);
893    
894            while (1) {
895                    int c;
896    
897                    c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
898                    if (!(c & state))
899                            goto out;
900                    if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
901                            /* process one 16-bit word */
902                            if (!(state & IN6PTON_NULL)) {
903                                    *d++ = (w >> 8) & 0xff;
904                                    *d++ = w & 0xff;
905                            }
906                            w = 0;
907                            if (c & IN6PTON_DELIM) {
908                                    /* We've processed last word */
909                                    break;
910                            }
911                            /*
912                             * COLON_1 => XDIGIT
913                             * COLON_2 => XDIGIT|DELIM
914                             * COLON_1_2 => COLON_2
915                             */
916                            switch (state & IN6PTON_COLON_MASK) {
917                            case IN6PTON_COLON_2:
918                                    dc = d;
919                                    state = IN6PTON_XDIGIT | IN6PTON_DELIM;
920                                    if (dc - dbuf >= sizeof(dbuf))
921                                            state |= IN6PTON_NULL;
922                                    break;
923                            case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
924                                    state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
925                                    break;
926                            case IN6PTON_COLON_1:
927                                    state = IN6PTON_XDIGIT;
928                                    break;
929                            case IN6PTON_COLON_1_2:
930                                    state = IN6PTON_COLON_2;
931                                    break;
932                            default:
933                                    state = 0;
934                            }
935                            tok = s + 1;
936                            goto cont;
937                    }
938    
939                    if (c & IN6PTON_DOT) {
940                            ret = ccs_in4_pton(tok ? tok : s, srclen +
941                                               (int)(s - tok), d, delim, &s);
942                            if (ret > 0) {
943                                    d += 4;
944                                    break;
945                            }
946                            goto out;
947                    }
948    
949                    w = (w << 4) | (0xff & c);
950                    state = IN6PTON_COLON_1 | IN6PTON_DELIM;
951                    if (!(w & 0xf000))
952                            state |= IN6PTON_XDIGIT;
953                    if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
954                            state |= IN6PTON_COLON_1_2;
955                            state &= ~IN6PTON_DELIM;
956                    }
957                    if (d + 2 >= dbuf + sizeof(dbuf))
958                            state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
959    cont:
960                    if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
961                        d + 4 == dbuf + sizeof(dbuf))
962                            state |= IN6PTON_DOT;
963                    if (d >= dbuf + sizeof(dbuf))
964                            state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
965                    s++;
966                    srclen--;
967            }
968    
969            i = 15; d--;
970    
971            if (dc) {
972                    while (d >= dc)
973                            dst[i--] = *d--;
974                    while (i >= dc - dbuf)
975                            dst[i--] = 0;
976                    while (i >= 0)
977                            dst[i--] = *d--;
978            } else
979                    memcpy(dst, dbuf, sizeof(dbuf));
980    
981            ret = 1;
982    out:
983            if (end)
984                    *end = s;
985            return ret;
986    }
987    #endif
988    
989    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
990    
991    /*
992     * Routines for printing IPv4 or IPv6 address.
993     * These are copied from include/linux/kernel.h include/net/ipv6.h
994     * include/net/addrconf.h lib/hexdump.c lib/vsprintf.c and simplified.
995     */
996    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
997    static const char hex_asc[] = "0123456789abcdef";
998    #define hex_asc_lo(x)   hex_asc[((x) & 0x0f)]
999    #define hex_asc_hi(x)   hex_asc[((x) & 0xf0) >> 4]
1000    
1001    static inline char *pack_hex_byte(char *buf, u8 byte)
1002    {
1003            *buf++ = hex_asc_hi(byte);
1004            *buf++ = hex_asc_lo(byte);
1005            return buf;
1006    }
1007    #endif
1008    
1009    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
1010    static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
1011    {
1012            return (a->s6_addr32[0] | a->s6_addr32[1] |
1013                    (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0;
1014    }
1015    #endif
1016    
1017    static inline int ipv6_addr_is_isatap(const struct in6_addr *addr)
1018    {
1019            return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE);
1020    }
1021    
1022    static char *ip4_string(char *p, const u8 *addr)
1023    {
1024            /*
1025             * Since this function is called outside vsnprintf(), I can use
1026             * sprintf() here.
1027             */
1028            return p +
1029                    sprintf(p, "%u.%u.%u.%u", addr[0], addr[1], addr[2], addr[3]);
1030    }
1031    
1032    static char *ip6_compressed_string(char *p, const char *addr)
1033    {
1034            int i, j, range;
1035            unsigned char zerolength[8];
1036            int longest = 1;
1037            int colonpos = -1;
1038            u16 word;
1039            u8 hi, lo;
1040            bool needcolon = false;
1041            bool useIPv4;
1042            struct in6_addr in6;
1043    
1044            memcpy(&in6, addr, sizeof(struct in6_addr));
1045    
1046            useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6);
1047    
1048            memset(zerolength, 0, sizeof(zerolength));
1049    
1050            if (useIPv4)
1051                    range = 6;
1052            else
1053                    range = 8;
1054    
1055            /* find position of longest 0 run */
1056            for (i = 0; i < range; i++) {
1057                    for (j = i; j < range; j++) {
1058                            if (in6.s6_addr16[j] != 0)
1059                                    break;
1060                            zerolength[i]++;
1061                    }
1062            }
1063            for (i = 0; i < range; i++) {
1064                    if (zerolength[i] > longest) {
1065                            longest = zerolength[i];
1066                            colonpos = i;
1067                    }
1068            }
1069            if (longest == 1)               /* don't compress a single 0 */
1070                    colonpos = -1;
1071    
1072            /* emit address */
1073            for (i = 0; i < range; i++) {
1074                    if (i == colonpos) {
1075                            if (needcolon || i == 0)
1076                                    *p++ = ':';
1077                            *p++ = ':';
1078                            needcolon = false;
1079                            i += longest - 1;
1080                            continue;
1081                    }
1082                    if (needcolon) {
1083                            *p++ = ':';
1084                            needcolon = false;
1085                    }
1086                    /* hex u16 without leading 0s */
1087                    word = ntohs(in6.s6_addr16[i]);
1088                    hi = word >> 8;
1089                    lo = word & 0xff;
1090                    if (hi) {
1091                            if (hi > 0x0f)
1092                                    p = pack_hex_byte(p, hi);
1093                            else
1094                                    *p++ = hex_asc_lo(hi);
1095                            p = pack_hex_byte(p, lo);
1096                    } else if (lo > 0x0f)
1097                            p = pack_hex_byte(p, lo);
1098                    else
1099                            *p++ = hex_asc_lo(lo);
1100                    needcolon = true;
1101            }
1102    
1103            if (useIPv4) {
1104                    if (needcolon)
1105                            *p++ = ':';
1106                    p = ip4_string(p, &in6.s6_addr[12]);
1107            }
1108            *p = '\0';
1109    
1110            return p;
1111    }
1112    #endif
1113    
1114    /**
1115     * ccs_print_ipv4 - Print an IPv4 address.
1116     *
1117     * @buffer:     Buffer to write to.
1118     * @buffer_len: Size of @buffer.
1119     * @ip:         Pointer to "u32 in network byte order".
1120     *
1121     * Returns written length.
1122     */
1123    static int ccs_print_ipv4(char *buffer, const unsigned int buffer_len,
1124                              const u32 *ip)
1125    {
1126    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
1127            return snprintf(buffer, buffer_len, "%pI4", ip);
1128    #else
1129            char addr[sizeof("255.255.255.255")];
1130            ip4_string(addr, (const u8 *) ip);
1131            return snprintf(buffer, buffer_len, "%s", addr);
1132    #endif
1133    }
1134    
1135    /**
1136     * ccs_print_ipv6 - Print an IPv6 address.
1137     *
1138     * @buffer:     Buffer to write to.
1139     * @buffer_len: Size of @buffer.
1140     * @ip:         Pointer to "struct in6_addr".
1141     *
1142     * Returns written length.
1143     */
1144    static int ccs_print_ipv6(char *buffer, const unsigned int buffer_len,
1145                              const struct in6_addr *ip)
1146    {
1147    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
1148            return snprintf(buffer, buffer_len, "%pI6c", ip);
1149    #else
1150            char addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
1151            ip6_compressed_string(addr, (const u8 *) ip);
1152            return snprintf(buffer, buffer_len, "%s", addr);
1153    #endif
1154    }
1155    
1156    /**
1157     * ccs_print_ip - Print an IP address.
1158     *
1159     * @buf:  Buffer to write to.
1160     * @size: Size of @buf.
1161     * @ptr:  Pointer to "struct ipaddr_union".
1162     *
1163     * Returns nothing.
1164     */
1165    static void ccs_print_ip(char *buf, const unsigned int size,
1166                             const struct ccs_ipaddr_union *ptr)
1167    {
1168            int len;
1169            if (ptr->is_ipv6)
1170                    len = ccs_print_ipv6(buf, size, &ptr->ip[0]);
1171            else
1172                    len = ccs_print_ipv4(buf, size, &ptr->ip[0].s6_addr32[0]);
1173            if (!memcmp(&ptr->ip[0], &ptr->ip[1], 16) || len >= size / 2)
1174                    return;
1175            buf[len++] = '-';
1176            if (ptr->is_ipv6)
1177                    ccs_print_ipv6(buf + len, size - len, &ptr->ip[1]);
1178            else
1179                    ccs_print_ipv4(buf + len, size - len,
1180                                   &ptr->ip[1].s6_addr32[0]);
1181    }
1182    
1183    #endif
1184    
1185    /***** SECTION5: Variables definition section *****/
1186    
1187  /* Permit policy management by non-root user? */  /* Permit policy management by non-root user? */
1188  static bool ccs_manage_by_non_root;  static bool ccs_manage_by_non_root;
1189    
1190    /* Lock for protecting policy. */
1191    DEFINE_MUTEX(ccs_policy_lock);
1192    
1193    /* Has /sbin/init started? */
1194    bool ccs_policy_loaded;
1195    
1196    /* List of namespaces. */
1197    LIST_HEAD(ccs_namespace_list);
1198    /* True if namespace other than ccs_kernel_namespace is defined. */
1199    static bool ccs_namespace_enabled;
1200    
1201    /* Initial namespace.*/
1202    static struct ccs_policy_namespace ccs_kernel_namespace;
1203    
1204    /* List of "struct ccs_condition". */
1205    LIST_HEAD(ccs_condition_list);
1206    
1207    #ifdef CONFIG_CCSECURITY_PORTRESERVE
1208    /* Bitmap for reserved local port numbers.*/
1209    static u8 ccs_reserved_port_map[8192];
1210    #endif
1211    
1212    /* Wait queue for kernel -> userspace notification. */
1213    static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait);
1214    /* Wait queue for userspace -> kernel notification. */
1215    static DECLARE_WAIT_QUEUE_HEAD(ccs_answer_wait);
1216    
1217    /* The list for "struct ccs_query". */
1218    static LIST_HEAD(ccs_query_list);
1219    
1220    /* Lock for manipulating ccs_query_list. */
1221    static DEFINE_SPINLOCK(ccs_query_list_lock);
1222    
1223    /* Number of "struct file" referring /proc/ccs/query interface. */
1224    static atomic_t ccs_query_observers = ATOMIC_INIT(0);
1225    
1226    /* Wait queue for /proc/ccs/audit. */
1227    static DECLARE_WAIT_QUEUE_HEAD(ccs_log_wait);
1228    
1229    /* The list for "struct ccs_log". */
1230    static LIST_HEAD(ccs_log);
1231    
1232    /* Lock for "struct list_head ccs_log". */
1233    static DEFINE_SPINLOCK(ccs_log_lock);
1234    
1235    /* Length of "stuct list_head ccs_log". */
1236    static unsigned int ccs_log_count;
1237    
1238    /* Timestamp counter for last updated. */
1239    static unsigned int ccs_stat_updated[CCS_MAX_POLICY_STAT];
1240    
1241    /* Counter for number of updates. */
1242    static unsigned int ccs_stat_modified[CCS_MAX_POLICY_STAT];
1243    
1244    /* Operations for /proc/ccs/self_domain interface. */
1245    static
1246    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
1247    const
1248    #endif
1249    struct file_operations ccs_self_operations = {
1250    #ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
1251            .write = ccs_write_self,
1252    #endif
1253            .read  = ccs_read_self,
1254    };
1255    
1256    /* Operations for /proc/ccs/ interface. */
1257    static
1258    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
1259    const
1260    #endif
1261    struct file_operations ccs_operations = {
1262            .open    = ccs_open,
1263            .release = ccs_release,
1264            .poll    = ccs_poll,
1265            .read    = ccs_read,
1266            .write   = ccs_write,
1267    };
1268    
1269    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
1270    
1271    /* The inode operations for /proc/ccs/ directory. */
1272    static struct inode_operations ccs_dir_inode_operations;
1273    
1274    /* The inode operations for files under /proc/ccs/ directory. */
1275    static struct inode_operations ccs_file_inode_operations;
1276    
1277    #endif
1278    
1279    /***** SECTION6: Dependent functions section *****/
1280    
1281    /**
1282     * list_for_each_cookie - iterate over a list with cookie.
1283     *
1284     * @pos:  Pointer to "struct list_head".
1285     * @head: Pointer to "struct list_head".
1286     */
1287    #define list_for_each_cookie(pos, head)                                 \
1288            for (pos = pos ? pos : srcu_dereference((head)->next, &ccs_ss); \
1289                 pos != (head); pos = srcu_dereference(pos->next, &ccs_ss))
1290    
1291    /**
1292     * ccs_read_token - Read a word from a line.
1293     *
1294     * @param: Pointer to "struct ccs_acl_param".
1295     *
1296     * Returns a word on success, "" otherwise.
1297     *
1298     * To allow the caller to skip NULL check, this function returns "" rather than
1299     * NULL if there is no more words to read.
1300     */
1301    static char *ccs_read_token(struct ccs_acl_param *param)
1302    {
1303            char *pos = param->data;
1304            char *del = strchr(pos, ' ');
1305            if (del)
1306                    *del++ = '\0';
1307            else
1308                    del = pos + strlen(pos);
1309            param->data = del;
1310            return pos;
1311    }
1312    
1313    /**
1314     * ccs_make_byte - Make byte value from three octal characters.
1315     *
1316     * @c1: The first character.
1317     * @c2: The second character.
1318     * @c3: The third character.
1319     *
1320     * Returns byte value.
1321     */
1322    static u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3)
1323    {
1324            return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
1325    }
1326    
1327    /**
1328     * ccs_correct_word2 - Check whether the given string follows the naming rules.
1329     *
1330     * @string: The byte sequence to check. Not '\0'-terminated.
1331     * @len:    Length of @string.
1332     *
1333     * Returns true if @string follows the naming rules, false otherwise.
1334     */
1335    static bool ccs_correct_word2(const char *string, size_t len)
1336    {
1337            const char *const start = string;
1338            bool in_repetition = false;
1339            unsigned char c;
1340            unsigned char d;
1341            unsigned char e;
1342            if (!len)
1343                    goto out;
1344            while (len--) {
1345                    c = *string++;
1346                    if (c == '\\') {
1347                            if (!len--)
1348                                    goto out;
1349                            c = *string++;
1350                            switch (c) {
1351                            case '\\':  /* "\\" */
1352                                    continue;
1353                            case '$':   /* "\$" */
1354                            case '+':   /* "\+" */
1355                            case '?':   /* "\?" */
1356                            case '*':   /* "\*" */
1357                            case '@':   /* "\@" */
1358                            case 'x':   /* "\x" */
1359                            case 'X':   /* "\X" */
1360                            case 'a':   /* "\a" */
1361                            case 'A':   /* "\A" */
1362                            case '-':   /* "\-" */
1363                                    continue;
1364                            case '{':   /* "/\{" */
1365                                    if (string - 3 < start || *(string - 3) != '/')
1366                                            break;
1367                                    in_repetition = true;
1368                                    continue;
1369                            case '}':   /* "\}/" */
1370                                    if (*string != '/')
1371                                            break;
1372                                    if (!in_repetition)
1373                                            break;
1374                                    in_repetition = false;
1375                                    continue;
1376                            case '0':   /* "\ooo" */
1377                            case '1':
1378                            case '2':
1379                            case '3':
1380                                    if (!len-- || !len--)
1381                                            break;
1382                                    d = *string++;
1383                                    e = *string++;
1384                                    if (d < '0' || d > '7' || e < '0' || e > '7')
1385                                            break;
1386                                    c = ccs_make_byte(c, d, e);
1387                                    if (c <= ' ' || c >= 127)
1388                                            continue;
1389                            }
1390                            goto out;
1391                    } else if (in_repetition && c == '/') {
1392                            goto out;
1393                    } else if (c <= ' ' || c >= 127) {
1394                            goto out;
1395                    }
1396            }
1397            if (in_repetition)
1398                    goto out;
1399            return true;
1400    out:
1401            return false;
1402    }
1403    
1404    /**
1405     * ccs_correct_word - Check whether the given string follows the naming rules.
1406     *
1407     * @string: The string to check.
1408     *
1409     * Returns true if @string follows the naming rules, false otherwise.
1410     */
1411    static bool ccs_correct_word(const char *string)
1412    {
1413            return ccs_correct_word2(string, strlen(string));
1414    }
1415    
1416    /**
1417     * ccs_get_group - Allocate memory for "struct ccs_path_group"/"struct ccs_number_group"/"struct ccs_address_group".
1418     *
1419     * @param: Pointer to "struct ccs_acl_param".
1420     * @idx:   Index number.
1421     *
1422     * Returns pointer to "struct ccs_group" on success, NULL otherwise.
1423     */
1424    static struct ccs_group *ccs_get_group(struct ccs_acl_param *param,
1425                                           const u8 idx)
1426    {
1427            struct ccs_group e = { };
1428            struct ccs_group *group = NULL;
1429            struct list_head *list;
1430            const char *group_name = ccs_read_token(param);
1431            bool found = false;
1432            if (!ccs_correct_word(group_name) || idx >= CCS_MAX_GROUP)
1433                    return NULL;
1434            e.group_name = ccs_get_name(group_name);
1435            if (!e.group_name)
1436                    return NULL;
1437            if (mutex_lock_interruptible(&ccs_policy_lock))
1438                    goto out;
1439            list = &param->ns->group_list[idx];
1440            list_for_each_entry(group, list, head.list) {
1441                    if (e.group_name != group->group_name ||
1442                        atomic_read(&group->head.users) == CCS_GC_IN_PROGRESS)
1443                            continue;
1444                    atomic_inc(&group->head.users);
1445                    found = true;
1446                    break;
1447            }
1448            if (!found) {
1449                    struct ccs_group *entry = ccs_commit_ok(&e, sizeof(e));
1450                    if (entry) {
1451                            INIT_LIST_HEAD(&entry->member_list);
1452                            atomic_set(&entry->head.users, 1);
1453                            list_add_tail_rcu(&entry->head.list, list);
1454                            group = entry;
1455                            found = true;
1456                    }
1457            }
1458            mutex_unlock(&ccs_policy_lock);
1459    out:
1460            ccs_put_name(e.group_name);
1461            return found ? group : NULL;
1462    }
1463    
1464    /**
1465     * ccs_parse_name_union - Parse a ccs_name_union.
1466     *
1467     * @param: Pointer to "struct ccs_acl_param".
1468     * @ptr:   Pointer to "struct ccs_name_union".
1469     *
1470     * Returns true on success, false otherwise.
1471     */
1472    static bool ccs_parse_name_union(struct ccs_acl_param *param,
1473                                     struct ccs_name_union *ptr)
1474    {
1475            char *filename;
1476            if (param->data[0] == '@') {
1477                    param->data++;
1478                    ptr->group = ccs_get_group(param, CCS_PATH_GROUP);
1479                    return ptr->group != NULL;
1480            }
1481            filename = ccs_read_token(param);
1482            if (!ccs_correct_word(filename))
1483                    return false;
1484            ptr->filename = ccs_get_name(filename);
1485            return ptr->filename != NULL;
1486    }
1487    
1488    /**
1489     * ccs_parse_ulong - Parse an "unsigned long" value.
1490     *
1491     * @result: Pointer to "unsigned long".
1492     * @str:    Pointer to string to parse.
1493     *
1494     * Returns one of values in "enum ccs_value_type".
1495     *
1496     * The @src is updated to point the first character after the value
1497     * on success.
1498     */
1499    static u8 ccs_parse_ulong(unsigned long *result, char **str)
1500    {
1501            const char *cp = *str;
1502            char *ep;
1503            int base = 10;
1504            if (*cp == '0') {
1505                    char c = *(cp + 1);
1506                    if (c == 'x' || c == 'X') {
1507                            base = 16;
1508                            cp += 2;
1509                    } else if (c >= '0' && c <= '7') {
1510                            base = 8;
1511                            cp++;
1512                    }
1513            }
1514            *result = simple_strtoul(cp, &ep, base);
1515            if (cp == ep)
1516                    return CCS_VALUE_TYPE_INVALID;
1517            *str = ep;
1518            switch (base) {
1519            case 16:
1520                    return CCS_VALUE_TYPE_HEXADECIMAL;
1521            case 8:
1522                    return CCS_VALUE_TYPE_OCTAL;
1523            default:
1524                    return CCS_VALUE_TYPE_DECIMAL;
1525            }
1526    }
1527    
1528    /**
1529     * ccs_parse_number_union - Parse a ccs_number_union.
1530     *
1531     * @param: Pointer to "struct ccs_acl_param".
1532     * @ptr:   Pointer to "struct ccs_number_union".
1533     *
1534     * Returns true on success, false otherwise.
1535     */
1536    static bool ccs_parse_number_union(struct ccs_acl_param *param,
1537                                       struct ccs_number_union *ptr)
1538    {
1539            char *data;
1540            u8 type;
1541            unsigned long v;
1542            memset(ptr, 0, sizeof(*ptr));
1543            if (param->data[0] == '@') {
1544                    param->data++;
1545                    ptr->group = ccs_get_group(param, CCS_NUMBER_GROUP);
1546                    return ptr->group != NULL;
1547            }
1548            data = ccs_read_token(param);
1549            type = ccs_parse_ulong(&v, &data);
1550            if (type == CCS_VALUE_TYPE_INVALID)
1551                    return false;
1552            ptr->values[0] = v;
1553            ptr->value_type[0] = type;
1554            if (!*data) {
1555                    ptr->values[1] = v;
1556                    ptr->value_type[1] = type;
1557                    return true;
1558            }
1559            if (*data++ != '-')
1560                    return false;
1561            type = ccs_parse_ulong(&v, &data);
1562            if (type == CCS_VALUE_TYPE_INVALID || *data || ptr->values[0] > v)
1563                    return false;
1564            ptr->values[1] = v;
1565            ptr->value_type[1] = type;
1566            return true;
1567    }
1568    
1569    #ifdef CONFIG_CCSECURITY_NETWORK
1570    
1571    /**
1572     * ccs_parse_ipaddr_union - Parse an IP address.
1573     *
1574     * @param: Pointer to "struct ccs_acl_param".
1575     * @ptr:   Pointer to "struct ccs_ipaddr_union".
1576     *
1577     * Returns true on success, false otherwise.
1578     */
1579    static bool ccs_parse_ipaddr_union(struct ccs_acl_param *param,
1580                                       struct ccs_ipaddr_union *ptr)
1581    {
1582            u8 * const min = ptr->ip[0].in6_u.u6_addr8;
1583            u8 * const max = ptr->ip[1].in6_u.u6_addr8;
1584            char *address = ccs_read_token(param);
1585            const char *end;
1586            if (!strchr(address, ':') &&
1587                ccs_in4_pton(address, -1, min, '-', &end) > 0) {
1588                    ptr->is_ipv6 = false;
1589                    if (!*end)
1590                            ptr->ip[1].s6_addr32[0] = ptr->ip[0].s6_addr32[0];
1591                    else if (*end++ != '-' ||
1592                             ccs_in4_pton(end, -1, max, '\0', &end) <= 0 || *end)
1593                            return false;
1594                    return true;
1595            }
1596            if (ccs_in6_pton(address, -1, min, '-', &end) > 0) {
1597                    ptr->is_ipv6 = true;
1598                    if (!*end)
1599                            memmove(max, min, sizeof(u16) * 8);
1600                    else if (*end++ != '-' ||
1601                             ccs_in6_pton(end, -1, max, '\0', &end) <= 0 || *end)
1602                            return false;
1603                    return true;
1604            }
1605            return false;
1606    }
1607    
1608    #endif
1609    
1610    /**
1611     * ccs_get_dqword - ccs_get_name() for a quoted string.
1612     *
1613     * @start: String to save.
1614     *
1615     * Returns pointer to "struct ccs_path_info" on success, NULL otherwise.
1616     */
1617    static const struct ccs_path_info *ccs_get_dqword(char *start)
1618    {
1619            char *cp = start + strlen(start) - 1;
1620            if (cp == start || *start++ != '"' || *cp != '"')
1621                    return NULL;
1622            *cp = '\0';
1623            if (*start && !ccs_correct_word(start))
1624                    return NULL;
1625            return ccs_get_name(start);
1626    }
1627    
1628    /**
1629     * ccs_parse_name_union_quoted - Parse a quoted word.
1630     *
1631     * @param: Pointer to "struct ccs_acl_param".
1632     * @ptr:   Pointer to "struct ccs_name_union".
1633     *
1634     * Returns true on success, false otherwise.
1635     */
1636    static bool ccs_parse_name_union_quoted(struct ccs_acl_param *param,
1637                                            struct ccs_name_union *ptr)
1638    {
1639            char *filename = param->data;
1640            if (*filename == '@')
1641                    return ccs_parse_name_union(param, ptr);
1642            ptr->filename = ccs_get_dqword(filename);
1643            return ptr->filename != NULL;
1644    }
1645    
1646    /**
1647     * ccs_parse_argv - Parse an argv[] condition part.
1648     *
1649     * @left:  Lefthand value.
1650     * @right: Righthand value.
1651     * @argv:  Pointer to "struct ccs_argv".
1652     *
1653     * Returns true on success, false otherwise.
1654     */
1655    static bool ccs_parse_argv(char *left, char *right, struct ccs_argv *argv)
1656    {
1657            if (ccs_parse_ulong(&argv->index, &left) != CCS_VALUE_TYPE_DECIMAL ||
1658                *left++ != ']' || *left)
1659                    return false;
1660            argv->value = ccs_get_dqword(right);
1661            return argv->value != NULL;
1662    }
1663    
1664    /**
1665     * ccs_parse_envp - Parse an envp[] condition part.
1666     *
1667     * @left:  Lefthand value.
1668     * @right: Righthand value.
1669     * @envp:  Pointer to "struct ccs_envp".
1670     *
1671     * Returns true on success, false otherwise.
1672     */
1673    static bool ccs_parse_envp(char *left, char *right, struct ccs_envp *envp)
1674    {
1675            const struct ccs_path_info *name;
1676            const struct ccs_path_info *value;
1677            char *cp = left + strlen(left) - 1;
1678            if (*cp-- != ']' || *cp != '"')
1679                    goto out;
1680            *cp = '\0';
1681            if (!ccs_correct_word(left))
1682                    goto out;
1683            name = ccs_get_name(left);
1684            if (!name)
1685                    goto out;
1686            if (!strcmp(right, "NULL")) {
1687                    value = NULL;
1688            } else {
1689                    value = ccs_get_dqword(right);
1690                    if (!value) {
1691                            ccs_put_name(name);
1692                            goto out;
1693                    }
1694            }
1695            envp->name = name;
1696            envp->value = value;
1697            return true;
1698    out:
1699            return false;
1700    }
1701    
1702    /**
1703     * ccs_same_condition - Check for duplicated "struct ccs_condition" entry.
1704     *
1705     * @a: Pointer to "struct ccs_condition".
1706     * @b: Pointer to "struct ccs_condition".
1707     *
1708     * Returns true if @a == @b, false otherwise.
1709     */
1710    static bool ccs_same_condition(const struct ccs_condition *a,
1711                                   const struct ccs_condition *b)
1712    {
1713            return a->size == b->size && a->condc == b->condc &&
1714                    a->numbers_count == b->numbers_count &&
1715                    a->names_count == b->names_count &&
1716                    a->argc == b->argc && a->envc == b->envc &&
1717                    a->grant_log == b->grant_log &&
1718                    a->exec_transit == b->exec_transit && a->transit == b->transit
1719                    && !memcmp(a + 1, b + 1, a->size - sizeof(*a));
1720    }
1721    
1722    /**
1723     * ccs_condition_type - Get condition type.
1724     *
1725     * @word: Keyword string.
1726     *
1727     * Returns one of values in "enum ccs_conditions_index" on success,
1728     * CCS_MAX_CONDITION_KEYWORD otherwise.
1729     */
1730    static u8 ccs_condition_type(const char *word)
1731    {
1732            u8 i;
1733            for (i = 0; i < CCS_MAX_CONDITION_KEYWORD; i++) {
1734                    if (!strcmp(word, ccs_condition_keyword[i]))
1735                            break;
1736            }
1737            return i;
1738    }
1739    
1740    /**
1741     * ccs_commit_condition - Commit "struct ccs_condition".
1742     *
1743     * @entry: Pointer to "struct ccs_condition".
1744     *
1745     * Returns pointer to "struct ccs_condition" on success, NULL otherwise.
1746     *
1747     * This function merges duplicated entries. This function returns NULL if
1748     * @entry is not duplicated but memory quota for policy has exceeded.
1749     */
1750    static struct ccs_condition *ccs_commit_condition(struct ccs_condition *entry)
1751    {
1752            struct ccs_condition *ptr;
1753            bool found = false;
1754            if (mutex_lock_interruptible(&ccs_policy_lock)) {
1755                    dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
1756                    ptr = NULL;
1757                    found = true;
1758                    goto out;
1759            }
1760            list_for_each_entry(ptr, &ccs_condition_list, head.list) {
1761                    if (!ccs_same_condition(ptr, entry) ||
1762                        atomic_read(&ptr->head.users) == CCS_GC_IN_PROGRESS)
1763                            continue;
1764                    /* Same entry found. Share this entry. */
1765                    atomic_inc(&ptr->head.users);
1766                    found = true;
1767                    break;
1768            }
1769            if (!found) {
1770                    if (ccs_memory_ok(entry, entry->size)) {
1771                            atomic_set(&entry->head.users, 1);
1772                            list_add(&entry->head.list, &ccs_condition_list);
1773                    } else {
1774                            found = true;
1775                            ptr = NULL;
1776                    }
1777            }
1778            mutex_unlock(&ccs_policy_lock);
1779    out:
1780            if (found) {
1781                    ccs_del_condition(&entry->head.list);
1782                    kfree(entry);
1783                    entry = ptr;
1784            }
1785            return entry;
1786    }
1787    
1788    /**
1789     * ccs_correct_path - Check whether the given pathname follows the naming rules.
1790     *
1791     * @filename: The pathname to check.
1792     *
1793     * Returns true if @filename follows the naming rules, false otherwise.
1794     */
1795    static bool ccs_correct_path(const char *filename)
1796    {
1797            return *filename == '/' && ccs_correct_word(filename);
1798    }
1799    
1800    /**
1801     * ccs_domain_def - Check whether the given token can be a domainname.
1802     *
1803     * @buffer: The token to check.
1804     *
1805     * Returns true if @buffer possibly be a domainname, false otherwise.
1806     */
1807    static bool ccs_domain_def(const unsigned char *buffer)
1808    {
1809            const unsigned char *cp;
1810            int len;
1811            if (*buffer != '<')
1812                    return false;
1813            cp = strchr(buffer, ' ');
1814            if (!cp)
1815                    len = strlen(buffer);
1816            else
1817                    len = cp - buffer;
1818            if (buffer[len - 1] != '>' || !ccs_correct_word2(buffer + 1, len - 2))
1819                    return false;
1820            return true;
1821    }
1822    
1823    /**
1824     * ccs_correct_domain - Check whether the given domainname follows the naming rules.
1825     *
1826     * @domainname: The domainname to check.
1827     *
1828     * Returns true if @domainname follows the naming rules, false otherwise.
1829     */
1830    static bool ccs_correct_domain(const unsigned char *domainname)
1831    {
1832            if (!domainname || !ccs_domain_def(domainname))
1833                    return false;
1834            domainname = strchr(domainname, ' ');
1835            if (!domainname++)
1836                    return true;
1837            while (1) {
1838                    const unsigned char *cp = strchr(domainname, ' ');
1839                    if (!cp)
1840                            break;
1841                    if (*domainname != '/' ||
1842                        !ccs_correct_word2(domainname, cp - domainname))
1843                            return false;
1844                    domainname = cp + 1;
1845            }
1846            return ccs_correct_path(domainname);
1847    }
1848    
1849    /**
1850     * ccs_normalize_line - Format string.
1851     *
1852     * @buffer: The line to normalize.
1853     *
1854     * Returns nothing.
1855     *
1856     * Leading and trailing whitespaces are removed.
1857     * Multiple whitespaces are packed into single space.
1858     */
1859    static void ccs_normalize_line(unsigned char *buffer)
1860    {
1861            unsigned char *sp = buffer;
1862            unsigned char *dp = buffer;
1863            bool first = true;
1864            while (*sp && (*sp <= ' ' || *sp >= 127))
1865                    sp++;
1866            while (*sp) {
1867                    if (!first)
1868                            *dp++ = ' ';
1869                    first = false;
1870                    while (*sp > ' ' && *sp < 127)
1871                            *dp++ = *sp++;
1872                    while (*sp && (*sp <= ' ' || *sp >= 127))
1873                            sp++;
1874            }
1875            *dp = '\0';
1876    }
1877    
1878    /**
1879     * ccs_get_domainname - Read a domainname from a line.
1880     *
1881     * @param: Pointer to "struct ccs_acl_param".
1882     *
1883     * Returns a domainname on success, NULL otherwise.
1884     */
1885    static const struct ccs_path_info *ccs_get_domainname
1886    (struct ccs_acl_param *param)
1887    {
1888            char *start = param->data;
1889            char *pos = start;
1890            while (*pos) {
1891                    if (*pos++ != ' ' || *pos++ == '/')
1892                            continue;
1893                    pos -= 2;
1894                    *pos++ = '\0';
1895                    break;
1896            }
1897            param->data = pos;
1898            if (ccs_correct_domain(start))
1899                    return ccs_get_name(start);
1900            return NULL;
1901    }
1902    
1903    /**
1904     * ccs_get_transit_preference - Parse domain transition preference for execve().
1905     *
1906     * @param: Pointer to "struct ccs_acl_param".
1907     * @e:     Pointer to "struct ccs_condition".
1908     *
1909     * Returns the condition string part.
1910     */
1911    static char *ccs_get_transit_preference(struct ccs_acl_param *param,
1912                                            struct ccs_condition *e)
1913    {
1914            char * const pos = param->data;
1915            bool flag;
1916            if (*pos == '<') {
1917                    e->transit = ccs_get_domainname(param);
1918                    goto done;
1919            }
1920            {
1921                    char *cp = strchr(pos, ' ');
1922                    if (cp)
1923                            *cp = '\0';
1924                    flag = ccs_correct_path(pos) || !strcmp(pos, "keep") ||
1925                            !strcmp(pos, "initialize") || !strcmp(pos, "reset") ||
1926                            !strcmp(pos, "child") || !strcmp(pos, "parent");
1927                    if (cp)
1928                            *cp = ' ';
1929            }
1930            if (!flag)
1931                    return pos;
1932            e->transit = ccs_get_name(ccs_read_token(param));
1933    done:
1934            if (e->transit) {
1935                    e->exec_transit = true;
1936                    return param->data;
1937            }
1938            /*
1939             * Return a bad read-only condition string that will let
1940             * ccs_get_condition() return NULL.
1941             */
1942            return "/";
1943    }
1944    
1945    /**
1946     * ccs_get_condition - Parse condition part.
1947     *
1948     * @param: Pointer to "struct ccs_acl_param".
1949     *
1950     * Returns pointer to "struct ccs_condition" on success, NULL otherwise.
1951     */
1952    struct ccs_condition *ccs_get_condition(struct ccs_acl_param *param)
1953    {
1954            struct ccs_condition *entry = NULL;
1955            struct ccs_condition_element *condp = NULL;
1956            struct ccs_number_union *numbers_p = NULL;
1957            struct ccs_name_union *names_p = NULL;
1958            struct ccs_argv *argv = NULL;
1959            struct ccs_envp *envp = NULL;
1960            struct ccs_condition e = { };
1961            char * const start_of_string = ccs_get_transit_preference(param, &e);
1962            char * const end_of_string = start_of_string + strlen(start_of_string);
1963            char *pos;
1964    rerun:
1965            pos = start_of_string;
1966            while (1) {
1967                    u8 left = -1;
1968                    u8 right = -1;
1969                    char *left_word = pos;
1970                    char *cp;
1971                    char *right_word;
1972                    bool is_not;
1973                    if (!*left_word)
1974                            break;
1975                    /*
1976                     * Since left-hand condition does not allow use of "path_group"
1977                     * or "number_group" and environment variable's names do not
1978                     * accept '=', it is guaranteed that the original line consists
1979                     * of one or more repetition of $left$operator$right blocks
1980                     * where "$left is free from '=' and ' '" and "$operator is
1981                     * either '=' or '!='" and "$right is free from ' '".
1982                     * Therefore, we can reconstruct the original line at the end
1983                     * of dry run even if we overwrite $operator with '\0'.
1984                     */
1985                    cp = strchr(pos, ' ');
1986                    if (cp) {
1987                            *cp = '\0'; /* Will restore later. */
1988                            pos = cp + 1;
1989                    } else {
1990                            pos = "";
1991                    }
1992                    right_word = strchr(left_word, '=');
1993                    if (!right_word || right_word == left_word)
1994                            goto out;
1995                    is_not = *(right_word - 1) == '!';
1996                    if (is_not)
1997                            *(right_word++ - 1) = '\0'; /* Will restore later. */
1998                    else if (*(right_word + 1) != '=')
1999                            *right_word++ = '\0'; /* Will restore later. */
2000                    else
2001                            goto out;
2002                    dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
2003                            is_not ? "!" : "", right_word);
2004                    if (!strcmp(left_word, "grant_log")) {
2005                            if (entry) {
2006                                    if (is_not ||
2007                                        entry->grant_log != CCS_GRANTLOG_AUTO)
2008                                            goto out;
2009                                    else if (!strcmp(right_word, "yes"))
2010                                            entry->grant_log = CCS_GRANTLOG_YES;
2011                                    else if (!strcmp(right_word, "no"))
2012                                            entry->grant_log = CCS_GRANTLOG_NO;
2013                                    else
2014                                            goto out;
2015                            }
2016                            continue;
2017                    }
2018                    if (!strcmp(left_word, "auto_domain_transition")) {
2019                            if (entry) {
2020                                    if (is_not || entry->transit)
2021                                            goto out;
2022                                    entry->transit = ccs_get_dqword(right_word);
2023                                    if (!entry->transit ||
2024                                        (entry->transit->name[0] != '/' &&
2025                                         !ccs_domain_def(entry->transit->name)))
2026                                            goto out;
2027                            }
2028                            continue;
2029                    }
2030                    if (!strncmp(left_word, "exec.argv[", 10)) {
2031                            if (!argv) {
2032                                    e.argc++;
2033                                    e.condc++;
2034                            } else {
2035                                    e.argc--;
2036                                    e.condc--;
2037                                    left = CCS_ARGV_ENTRY;
2038                                    argv->is_not = is_not;
2039                                    if (!ccs_parse_argv(left_word + 10,
2040                                                        right_word, argv++))
2041                                            goto out;
2042                            }
2043                            goto store_value;
2044                    }
2045                    if (!strncmp(left_word, "exec.envp[\"", 11)) {
2046                            if (!envp) {
2047                                    e.envc++;
2048                                    e.condc++;
2049                            } else {
2050                                    e.envc--;
2051                                    e.condc--;
2052                                    left = CCS_ENVP_ENTRY;
2053                                    envp->is_not = is_not;
2054                                    if (!ccs_parse_envp(left_word + 11,
2055                                                        right_word, envp++))
2056                                            goto out;
2057                            }
2058                            goto store_value;
2059                    }
2060                    left = ccs_condition_type(left_word);
2061                    dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
2062                            left);
2063                    if (left == CCS_MAX_CONDITION_KEYWORD) {
2064                            if (!numbers_p) {
2065                                    e.numbers_count++;
2066                            } else {
2067                                    e.numbers_count--;
2068                                    left = CCS_NUMBER_UNION;
2069                                    param->data = left_word;
2070                                    if (*left_word == '@' ||
2071                                        !ccs_parse_number_union(param,
2072                                                                numbers_p++))
2073                                            goto out;
2074                            }
2075                    }
2076                    if (!condp)
2077                            e.condc++;
2078                    else
2079                            e.condc--;
2080                    if (left == CCS_EXEC_REALPATH || left == CCS_SYMLINK_TARGET) {
2081                            if (!names_p) {
2082                                    e.names_count++;
2083                            } else {
2084                                    e.names_count--;
2085                                    right = CCS_NAME_UNION;
2086                                    param->data = right_word;
2087                                    if (!ccs_parse_name_union_quoted(param,
2088                                                                     names_p++))
2089                                            goto out;
2090                            }
2091                            goto store_value;
2092                    }
2093                    right = ccs_condition_type(right_word);
2094                    if (right == CCS_MAX_CONDITION_KEYWORD) {
2095                            if (!numbers_p) {
2096                                    e.numbers_count++;
2097                            } else {
2098                                    e.numbers_count--;
2099                                    right = CCS_NUMBER_UNION;
2100                                    param->data = right_word;
2101                                    if (!ccs_parse_number_union(param,
2102                                                                numbers_p++))
2103                                            goto out;
2104                            }
2105                    }
2106    store_value:
2107                    if (!condp) {
2108                            dprintk(KERN_WARNING "%u: dry_run left=%u right=%u "
2109                                    "match=%u\n", __LINE__, left, right, !is_not);
2110                            continue;
2111                    }
2112                    condp->left = left;
2113                    condp->right = right;
2114                    condp->equals = !is_not;
2115                    dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
2116                            __LINE__, condp->left, condp->right,
2117                            condp->equals);
2118                    condp++;
2119            }
2120            dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n",
2121                    __LINE__, e.condc, e.numbers_count, e.names_count, e.argc,
2122                    e.envc);
2123            if (entry) {
2124                    BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc |
2125                           e.condc);
2126                    return ccs_commit_condition(entry);
2127            }
2128            e.size = sizeof(*entry)
2129                    + e.condc * sizeof(struct ccs_condition_element)
2130                    + e.numbers_count * sizeof(struct ccs_number_union)
2131                    + e.names_count * sizeof(struct ccs_name_union)
2132                    + e.argc * sizeof(struct ccs_argv)
2133                    + e.envc * sizeof(struct ccs_envp);
2134            entry = kzalloc(e.size, CCS_GFP_FLAGS);
2135            if (!entry)
2136                    goto out2;
2137            *entry = e;
2138            e.transit = NULL;
2139            condp = (struct ccs_condition_element *) (entry + 1);
2140            numbers_p = (struct ccs_number_union *) (condp + e.condc);
2141            names_p = (struct ccs_name_union *) (numbers_p + e.numbers_count);
2142            argv = (struct ccs_argv *) (names_p + e.names_count);
2143            envp = (struct ccs_envp *) (argv + e.argc);
2144            {
2145                    bool flag = false;
2146                    for (pos = start_of_string; pos < end_of_string; pos++) {
2147                            if (*pos)
2148                                    continue;
2149                            if (flag) /* Restore " ". */
2150                                    *pos = ' ';
2151                            else if (*(pos + 1) == '=') /* Restore "!=". */
2152                                    *pos = '!';
2153                            else /* Restore "=". */
2154                                    *pos = '=';
2155                            flag = !flag;
2156                    }
2157            }
2158            goto rerun;
2159    out:
2160            dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
2161            if (entry) {
2162                    ccs_del_condition(&entry->head.list);
2163                    kfree(entry);
2164            }
2165    out2:
2166            ccs_put_name(e.transit);
2167            return NULL;
2168    }
2169    
2170  /**  /**
2171   * ccs_yesno - Return "yes" or "no".   * ccs_yesno - Return "yes" or "no".
2172   *   *
# Line 272  static bool ccs_manage_by_non_root; Line 2174  static bool ccs_manage_by_non_root;
2174   *   *
2175   * Returns "yes" if @value is not 0, "no" otherwise.   * Returns "yes" if @value is not 0, "no" otherwise.
2176   */   */
2177  const char *ccs_yesno(const unsigned int value)  static const char *ccs_yesno(const unsigned int value)
2178  {  {
2179          return value ? "yes" : "no";          return value ? "yes" : "no";
2180  }  }
2181    
 /* Prototype for ccs_addprintf(). */  
 static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)  
         __attribute__ ((format(printf, 3, 4)));  
   
2182  /**  /**
2183   * ccs_addprintf - strncat()-like-snprintf().   * ccs_addprintf - strncat()-like-snprintf().
2184   *   *
# Line 326  static bool ccs_flush(struct ccs_io_buff Line 2224  static bool ccs_flush(struct ccs_io_buff
2224                  if (*w)                  if (*w)
2225                          return false;                          return false;
2226                  /* Add '\0' for audit logs and query. */                  /* Add '\0' for audit logs and query. */
2227                  if (head->poll) {                  if (head->type == CCS_AUDIT || head->type == CCS_QUERY) {
2228                          if (!head->read_user_buf_avail ||                          if (!head->read_user_buf_avail ||
2229                              copy_to_user(head->read_user_buf, "", 1))                              copy_to_user(head->read_user_buf, "", 1))
2230                                  return false;                                  return false;
# Line 362  static void ccs_set_string(struct ccs_io Line 2260  static void ccs_set_string(struct ccs_io
2260                  printk(KERN_WARNING "Too many words in a line.\n");                  printk(KERN_WARNING "Too many words in a line.\n");
2261  }  }
2262    
 /* Prototype for ccs_io_printf(). */  
 static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)  
         __attribute__ ((format(printf, 2, 3)));  
   
2263  /**  /**
2264   * ccs_io_printf - printf() to "struct ccs_io_buffer" structure.   * ccs_io_printf - printf() to "struct ccs_io_buffer" structure.
2265   *   *
# Line 410  static void ccs_set_space(struct ccs_io_ Line 2304  static void ccs_set_space(struct ccs_io_
2304   *   *
2305   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
2306   *   *
2307   * Returns nothing.   * Returns true if all data was flushed, false otherwise.
2308   */   */
2309  static bool ccs_set_lf(struct ccs_io_buffer *head)  static bool ccs_set_lf(struct ccs_io_buffer *head)
2310  {  {
# Line 431  static void ccs_set_slash(struct ccs_io_ Line 2325  static void ccs_set_slash(struct ccs_io_
2325  }  }
2326    
2327  /**  /**
2328     * ccs_init_policy_namespace - Initialize namespace.
2329     *
2330     * @ns: Pointer to "struct ccs_policy_namespace".
2331     *
2332     * Returns nothing.
2333     */
2334    static void ccs_init_policy_namespace(struct ccs_policy_namespace *ns)
2335    {
2336            unsigned int idx;
2337            for (idx = 0; idx < CCS_MAX_ACL_GROUPS; idx++)
2338                    INIT_LIST_HEAD(&ns->acl_group[idx]);
2339            for (idx = 0; idx < CCS_MAX_GROUP; idx++)
2340                    INIT_LIST_HEAD(&ns->group_list[idx]);
2341            for (idx = 0; idx < CCS_MAX_POLICY; idx++)
2342                    INIT_LIST_HEAD(&ns->policy_list[idx]);
2343            ns->profile_version = 20100903;
2344            ccs_namespace_enabled = !list_empty(&ccs_namespace_list);
2345            list_add_tail_rcu(&ns->namespace_list, &ccs_namespace_list);
2346    }
2347    
2348    /**
2349     * ccs_print_namespace - Print namespace header.
2350     *
2351     * @head: Pointer to "struct ccs_io_buffer".
2352     *
2353     * Returns nothing.
2354     */
2355    static void ccs_print_namespace(struct ccs_io_buffer *head)
2356    {
2357            if (!ccs_namespace_enabled)
2358                    return;
2359            ccs_set_string(head,
2360                           container_of(head->r.ns, struct ccs_policy_namespace,
2361                                        namespace_list)->name);
2362            ccs_set_space(head);
2363    }
2364    
2365    /**
2366   * ccs_assign_profile - Create a new profile.   * ccs_assign_profile - Create a new profile.
2367   *   *
2368     * @ns:      Pointer to "struct ccs_policy_namespace".
2369   * @profile: Profile number to create.   * @profile: Profile number to create.
2370   *   *
2371   * Returns pointer to "struct ccs_profile" on success, NULL otherwise.   * Returns pointer to "struct ccs_profile" on success, NULL otherwise.
2372   */   */
2373  static struct ccs_profile *ccs_assign_profile(const unsigned int profile)  static struct ccs_profile *ccs_assign_profile(struct ccs_policy_namespace *ns,
2374                                                  const unsigned int profile)
2375  {  {
2376          struct ccs_profile *ptr;          struct ccs_profile *ptr;
2377          struct ccs_profile *entry;          struct ccs_profile *entry;
2378          if (profile >= CCS_MAX_PROFILES)          if (profile >= CCS_MAX_PROFILES)
2379                  return NULL;                  return NULL;
2380          ptr = ccs_profile_ptr[profile];          ptr = ns->profile_ptr[profile];
2381          if (ptr)          if (ptr)
2382                  return ptr;                  return ptr;
2383          entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);          entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
2384          if (mutex_lock_interruptible(&ccs_policy_lock))          if (mutex_lock_interruptible(&ccs_policy_lock))
2385                  goto out;                  goto out;
2386          ptr = ccs_profile_ptr[profile];          ptr = ns->profile_ptr[profile];
2387          if (!ptr && ccs_memory_ok(entry, sizeof(*entry))) {          if (!ptr && ccs_memory_ok(entry, sizeof(*entry))) {
2388                  ptr = entry;                  ptr = entry;
2389                  ptr->default_config = CCS_CONFIG_DISABLED |                  ptr->default_config = CCS_CONFIG_DISABLED |
# Line 461  static struct ccs_profile *ccs_assign_pr Line 2395  static struct ccs_profile *ccs_assign_pr
2395                  ptr->pref[CCS_PREF_MAX_LEARNING_ENTRY] =                  ptr->pref[CCS_PREF_MAX_LEARNING_ENTRY] =
2396                          CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY;                          CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY;
2397                  mb(); /* Avoid out-of-order execution. */                  mb(); /* Avoid out-of-order execution. */
2398                  ccs_profile_ptr[profile] = ptr;                  ns->profile_ptr[profile] = ptr;
2399                  entry = NULL;                  entry = NULL;
2400          }          }
2401          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
# Line 480  static void ccs_check_profile(void) Line 2414  static void ccs_check_profile(void)
2414          struct ccs_domain_info *domain;          struct ccs_domain_info *domain;
2415          const int idx = ccs_read_lock();          const int idx = ccs_read_lock();
2416          ccs_policy_loaded = true;          ccs_policy_loaded = true;
2417            printk(KERN_INFO "CCSecurity: 1.8.3+   2012/04/01\n");
2418          list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {          list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
2419                  const u8 profile = domain->profile;                  const u8 profile = domain->profile;
2420                  if (ccs_profile_ptr[profile])                  const struct ccs_policy_namespace *ns = domain->ns;
2421                    if (ns->profile_version != 20100903)
2422                            printk(KERN_ERR
2423                                   "Profile version %u is not supported.\n",
2424                                   ns->profile_version);
2425                    else if (!ns->profile_ptr[profile])
2426                            printk(KERN_ERR
2427                                   "Profile %u (used by '%s') is not defined.\n",
2428                                   profile, domain->domainname->name);
2429                    else
2430                          continue;                          continue;
2431                  printk(KERN_ERR "Profile %u must be defined before using it.\n",                  printk(KERN_ERR
2432                         profile);                         "Userland tools for TOMOYO 1.8 must be installed and "
2433                           "policy must be initialized.\n");
2434                  printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/1.8/ "                  printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/1.8/ "
2435                         "for more information.\n");                         "for more information.\n");
2436                  panic("Profile %u (used by '%s') not defined.\n",                  panic("STOP!");
                       profile, domain->domainname->name);  
2437          }          }
2438          ccs_read_unlock(idx);          ccs_read_unlock(idx);
         if (ccs_profile_version != 20100903) {  
                 printk(KERN_ERR "Userland tools must be installed for "  
                        "TOMOYO 1.8, and policy must be initialized.\n");  
                 printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/1.8/ "  
                        "for more information.\n");  
                 panic("Profile version %u is not supported.\n",  
                       ccs_profile_version);  
         }  
         printk(KERN_INFO "CCSecurity: 1.8.1+   2011/05/05\n");  
2439          printk(KERN_INFO "Mandatory Access Control activated.\n");          printk(KERN_INFO "Mandatory Access Control activated.\n");
2440  }  }
2441    
# Line 511  static void ccs_check_profile(void) Line 2446  static void ccs_check_profile(void)
2446   *   *
2447   * Returns pointer to "struct ccs_profile".   * Returns pointer to "struct ccs_profile".
2448   */   */
2449  struct ccs_profile *ccs_profile(const u8 profile)  static struct ccs_profile *ccs_profile(const u8 profile)
2450  {  {
2451          static struct ccs_profile ccs_null_profile;          static struct ccs_profile ccs_null_profile;
2452          struct ccs_profile *ptr = ccs_profile_ptr[profile];          struct ccs_profile *ptr = ccs_current_namespace()->
2453                    profile_ptr[profile];
2454          if (!ptr)          if (!ptr)
2455                  ptr = &ccs_null_profile;                  ptr = &ccs_null_profile;
2456          return ptr;          return ptr;
2457  }  }
2458    
2459  /**  /**
2460     * ccs_get_config - Get config for specified profile's specified functionality.
2461     *
2462     * @profile: Profile number.
2463     * @index:   Index number of functionality.
2464     *
2465     * Returns config.
2466     *
2467     * First, check for CONFIG::category::functionality.
2468     * If CONFIG::category::functionality is set to use default, then check
2469     * CONFIG::category. If CONFIG::category is set to use default, then use
2470     * CONFIG. CONFIG cannot be set to use default.
2471     */
2472    u8 ccs_get_config(const u8 profile, const u8 index)
2473    {
2474            u8 config;
2475            const struct ccs_profile *p;
2476            if (!ccs_policy_loaded)
2477                    return CCS_CONFIG_DISABLED;
2478            p = ccs_profile(profile);
2479            config = p->config[index];
2480            if (config == CCS_CONFIG_USE_DEFAULT)
2481                    config = p->config[ccs_index2category[index]
2482                                       + CCS_MAX_MAC_INDEX];
2483            if (config == CCS_CONFIG_USE_DEFAULT)
2484                    config = p->default_config;
2485            return config;
2486    }
2487    
2488    /**
2489   * ccs_find_yesno - Find values for specified keyword.   * ccs_find_yesno - Find values for specified keyword.
2490   *   *
2491   * @string: String to check.   * @string: String to check.
# Line 558  static void ccs_set_uint(unsigned int *i Line 2523  static void ccs_set_uint(unsigned int *i
2523  }  }
2524    
2525  /**  /**
2526     * ccs_str_starts - Check whether the given string starts with the given keyword.
2527     *
2528     * @src:  Pointer to pointer to the string.
2529     * @find: Pointer to the keyword.
2530     *
2531     * Returns true if @src starts with @find, false otherwise.
2532     *
2533     * The @src is updated to point the first character after the @find
2534     * if @src starts with @find.
2535     */
2536    static bool ccs_str_starts(char **src, const char *find)
2537    {
2538            const int len = strlen(find);
2539            char *tmp = *src;
2540            if (strncmp(tmp, find, len))
2541                    return false;
2542            tmp += len;
2543            *src = tmp;
2544            return true;
2545    }
2546    
2547    /**
2548     * ccs_print_group - Print group's name.
2549     *
2550     * @head:  Pointer to "struct ccs_io_buffer".
2551     * @group: Pointer to "struct ccsgroup". Maybe NULL.
2552     *
2553     * Returns true if @group is not NULL. false otherwise.
2554     */
2555    static bool ccs_print_group(struct ccs_io_buffer *head,
2556                                const struct ccs_group *group)
2557    {
2558            if (group) {
2559                    ccs_set_string(head, "@");
2560                    ccs_set_string(head, group->group_name->name);
2561                    return true;
2562            }
2563            return false;
2564    }
2565    
2566    /**
2567   * ccs_set_mode - Set mode for specified profile.   * ccs_set_mode - Set mode for specified profile.
2568   *   *
2569   * @name:    Name of functionality.   * @name:    Name of functionality.
# Line 648  static int ccs_write_profile(struct ccs_ Line 2654  static int ccs_write_profile(struct ccs_
2654          unsigned int i;          unsigned int i;
2655          char *cp;          char *cp;
2656          struct ccs_profile *profile;          struct ccs_profile *profile;
2657          if (sscanf(data, "PROFILE_VERSION=%u", &ccs_profile_version) == 1)          if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version)
2658                == 1)
2659                  return 0;                  return 0;
2660          i = simple_strtoul(data, &cp, 10);          i = simple_strtoul(data, &cp, 10);
2661          if (*cp != '-')          if (*cp != '-')
2662                  return -EINVAL;                  return -EINVAL;
2663          data = cp + 1;          data = cp + 1;
2664          profile = ccs_assign_profile(i);          profile = ccs_assign_profile(head->w.ns, i);
2665          if (!profile)          if (!profile)
2666                  return -EINVAL;                  return -EINVAL;
2667          cp = strchr(data, '=');          cp = strchr(data, '=');
# Line 711  static void ccs_print_config(struct ccs_ Line 2718  static void ccs_print_config(struct ccs_
2718  static void ccs_read_profile(struct ccs_io_buffer *head)  static void ccs_read_profile(struct ccs_io_buffer *head)
2719  {  {
2720          u8 index;          u8 index;
2721            struct ccs_policy_namespace *ns = container_of(head->r.ns, typeof(*ns),
2722                                                           namespace_list);
2723          const struct ccs_profile *profile;          const struct ccs_profile *profile;
2724            if (head->r.eof)
2725                    return;
2726  next:  next:
2727          index = head->r.index;          index = head->r.index;
2728          profile = ccs_profile_ptr[index];          profile = ns->profile_ptr[index];
2729          switch (head->r.step) {          switch (head->r.step) {
2730          case 0:          case 0:
2731                  ccs_io_printf(head, "PROFILE_VERSION=%u\n", 20100903);                  ccs_print_namespace(head);
2732                    ccs_io_printf(head, "PROFILE_VERSION=%u\n",
2733                                  ns->profile_version);
2734                  head->r.step++;                  head->r.step++;
2735                  break;                  break;
2736          case 1:          case 1:
2737                  for ( ; head->r.index < CCS_MAX_PROFILES;                  for ( ; head->r.index < CCS_MAX_PROFILES; head->r.index++)
2738                        head->r.index++)                          if (ns->profile_ptr[head->r.index])
                         if (ccs_profile_ptr[head->r.index])  
2739                                  break;                                  break;
2740                  if (head->r.index == CCS_MAX_PROFILES)                  if (head->r.index == CCS_MAX_PROFILES) {
2741                            head->r.eof = true;
2742                          return;                          return;
2743                    }
2744                  head->r.step++;                  head->r.step++;
2745                  break;                  break;
2746          case 2:          case 2:
2747                  {                  {
2748                          u8 i;                          u8 i;
2749                          const struct ccs_path_info *comment = profile->comment;                          const struct ccs_path_info *comment = profile->comment;
2750                            ccs_print_namespace(head);
2751                          ccs_io_printf(head, "%u-COMMENT=", index);                          ccs_io_printf(head, "%u-COMMENT=", index);
2752                          ccs_set_string(head, comment ? comment->name : "");                          ccs_set_string(head, comment ? comment->name : "");
2753                          ccs_set_lf(head);                          ccs_set_lf(head);
2754                            ccs_print_namespace(head);
2755                          ccs_io_printf(head, "%u-PREFERENCE={ ", index);                          ccs_io_printf(head, "%u-PREFERENCE={ ", index);
2756                          for (i = 0; i < CCS_MAX_PREF; i++)                          for (i = 0; i < CCS_MAX_PREF; i++)
2757                                  ccs_io_printf(head, "%s=%u ",                                  ccs_io_printf(head, "%s=%u ",
# Line 747  next: Line 2763  next:
2763                  break;                  break;
2764          case 3:          case 3:
2765                  {                  {
2766                            ccs_print_namespace(head);
2767                          ccs_io_printf(head, "%u-%s", index, "CONFIG");                          ccs_io_printf(head, "%u-%s", index, "CONFIG");
2768                          ccs_print_config(head, profile->default_config);                          ccs_print_config(head, profile->default_config);
2769                          head->r.bit = 0;                          head->r.bit = 0;
# Line 760  next: Line 2777  next:
2777                          const u8 config = profile->config[i];                          const u8 config = profile->config[i];
2778                          if (config == CCS_CONFIG_USE_DEFAULT)                          if (config == CCS_CONFIG_USE_DEFAULT)
2779                                  continue;                                  continue;
2780                            ccs_print_namespace(head);
2781                          if (i < CCS_MAX_MAC_INDEX)                          if (i < CCS_MAX_MAC_INDEX)
2782                                  ccs_io_printf(head, "%u-CONFIG::%s::%s", index,                                  ccs_io_printf(head, "%u-CONFIG::%s::%s", index,
2783                                                ccs_category_keywords                                                ccs_category_keywords
# Line 784  next: Line 2802  next:
2802  }  }
2803    
2804  /**  /**
2805   * ccs_same_manager - Check for duplicated "struct ccs_manager" entry.   * ccs_update_policy - Update an entry for exception policy.
2806   *   *
2807   * @a: Pointer to "struct ccs_acl_head".   * @size:  Size of new entry in bytes.
2808   * @b: Pointer to "struct ccs_acl_head".   * @param: Pointer to "struct ccs_acl_param".
2809   *   *
2810   * Returns true if @a == @b, false otherwise.   * Returns 0 on success, negative value otherwise.
2811     *
2812     * Caller holds ccs_read_lock().
2813   */   */
2814  static bool ccs_same_manager(const struct ccs_acl_head *a,  static int ccs_update_policy(const int size, struct ccs_acl_param *param)
                              const struct ccs_acl_head *b)  
2815  {  {
2816          return container_of(a, struct ccs_manager, head)->manager          struct ccs_acl_head *new_entry = &param->e.acl_head;
2817                  == container_of(b, struct ccs_manager, head)->manager;          int error = param->is_delete ? -ENOENT : -ENOMEM;
2818            struct ccs_acl_head *entry;
2819            struct list_head *list = param->list;
2820            BUG_ON(size < sizeof(*entry));
2821            if (mutex_lock_interruptible(&ccs_policy_lock))
2822                    return -ENOMEM;
2823            list_for_each_entry_srcu(entry, list, list, &ccs_ss) {
2824                    if (entry->is_deleted == CCS_GC_IN_PROGRESS)
2825                            continue;
2826                    if (memcmp(entry + 1, new_entry + 1, size - sizeof(*entry)))
2827                            continue;
2828                    entry->is_deleted = param->is_delete;
2829                    error = 0;
2830                    break;
2831            }
2832            if (error && !param->is_delete) {
2833                    entry = ccs_commit_ok(new_entry, size);
2834                    if (entry) {
2835                            list_add_tail_rcu(&entry->list, list);
2836                            error = 0;
2837                    }
2838            }
2839            mutex_unlock(&ccs_policy_lock);
2840            return error;
2841  }  }
2842    
2843  /**  /**
# Line 806  static bool ccs_same_manager(const struc Line 2848  static bool ccs_same_manager(const struc
2848   *   *
2849   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
2850   */   */
2851  static int ccs_update_manager_entry(const char *manager, const bool is_delete)  static int ccs_update_manager_entry(const char *manager,
2852                                        const bool is_delete)
2853  {  {
2854          struct ccs_manager e = { };          struct ccs_acl_param param = {
2855                    /* .ns = &ccs_kernel_namespace, */
2856                    .is_delete = is_delete,
2857                    .list = &ccs_kernel_namespace.policy_list[CCS_ID_MANAGER],
2858            };
2859            struct ccs_manager *e = &param.e.manager;
2860          int error = is_delete ? -ENOENT : -ENOMEM;          int error = is_delete ? -ENOENT : -ENOMEM;
2861            /* Forced zero clear for using memcmp() at ccs_update_policy(). */
2862            memset(&param.e, 0, sizeof(param.e));
2863          if (ccs_domain_def(manager)) {          if (ccs_domain_def(manager)) {
2864                  if (!ccs_correct_domain(manager))                  if (!ccs_correct_domain(manager))
2865                          return -EINVAL;                          return -EINVAL;
2866                  e.is_domain = true;                  e->is_domain = true;
2867          } else {          } else {
2868                  if (!ccs_correct_path(manager))                  if (!ccs_correct_path(manager))
2869                          return -EINVAL;                          return -EINVAL;
2870          }          }
2871          e.manager = ccs_get_name(manager);          e->manager = ccs_get_name(manager);
2872          if (!e.manager)          if (e->manager) {
2873                  return error;                  error = ccs_update_policy(sizeof(*e), &param);
2874          error = ccs_update_policy(&e.head, sizeof(e), is_delete,                  ccs_put_name(e->manager);
2875                                    &ccs_policy_list[CCS_ID_MANAGER],          }
                                   ccs_same_manager);  
         ccs_put_name(e.manager);  
2876          return error;          return error;
2877  }  }
2878    
# Line 837  static int ccs_update_manager_entry(cons Line 2885  static int ccs_update_manager_entry(cons
2885   */   */
2886  static int ccs_write_manager(struct ccs_io_buffer *head)  static int ccs_write_manager(struct ccs_io_buffer *head)
2887  {  {
2888          char *data = head->write_buf;          const char *data = head->write_buf;
         bool is_delete = ccs_str_starts(&data, "delete ");  
2889          if (!strcmp(data, "manage_by_non_root")) {          if (!strcmp(data, "manage_by_non_root")) {
2890                  ccs_manage_by_non_root = !is_delete;                  ccs_manage_by_non_root = !head->w.is_delete;
2891                  return 0;                  return 0;
2892          }          }
2893          return ccs_update_manager_entry(data, is_delete);          return ccs_update_manager_entry(data, head->w.is_delete);
2894  }  }
2895    
2896  /**  /**
# Line 859  static void ccs_read_manager(struct ccs_ Line 2906  static void ccs_read_manager(struct ccs_
2906  {  {
2907          if (head->r.eof)          if (head->r.eof)
2908                  return;                  return;
2909          list_for_each_cookie(head->r.acl, &ccs_policy_list[CCS_ID_MANAGER]) {          list_for_each_cookie(head->r.acl, &ccs_kernel_namespace.
2910                                 policy_list[CCS_ID_MANAGER]) {
2911                  struct ccs_manager *ptr =                  struct ccs_manager *ptr =
2912                          list_entry(head->r.acl, typeof(*ptr), head.list);                          list_entry(head->r.acl, typeof(*ptr), head.list);
2913                  if (ptr->head.is_deleted)                  if (ptr->head.is_deleted)
# Line 895  static bool ccs_manager(void) Line 2943  static bool ccs_manager(void)
2943          if (!ccs_manage_by_non_root && (current_uid() || current_euid()))          if (!ccs_manage_by_non_root && (current_uid() || current_euid()))
2944                  return false;                  return false;
2945          exe = ccs_get_exe();          exe = ccs_get_exe();
2946          list_for_each_entry_srcu(ptr, &ccs_policy_list[CCS_ID_MANAGER],          list_for_each_entry_srcu(ptr, &ccs_kernel_namespace.
2947                                   head.list, &ccs_ss) {                                   policy_list[CCS_ID_MANAGER], head.list,
2948                                     &ccs_ss) {
2949                  if (ptr->head.is_deleted)                  if (ptr->head.is_deleted)
2950                          continue;                          continue;
2951                  if (ptr->is_domain) {                  if (ptr->is_domain) {
# Line 925  static bool ccs_manager(void) Line 2974  static bool ccs_manager(void)
2974  }  }
2975    
2976  /**  /**
2977   * ccs_select_one - Parse select command.   * ccs_find_domain - Find a domain by the given name.
2978     *
2979     * @domainname: The domainname to find.
2980     *
2981     * Returns pointer to "struct ccs_domain_info" if found, NULL otherwise.
2982     *
2983     * Caller holds ccs_read_lock().
2984     */
2985    static struct ccs_domain_info *ccs_find_domain(const char *domainname)
2986    {
2987            struct ccs_domain_info *domain;
2988            struct ccs_path_info name;
2989            name.name = domainname;
2990            ccs_fill_path_info(&name);
2991            list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
2992                    if (!domain->is_deleted &&
2993                        !ccs_pathcmp(&name, domain->domainname))
2994                            return domain;
2995            }
2996            return NULL;
2997    }
2998    
2999    /**
3000     * ccs_select_domain - Parse select command.
3001   *   *
3002   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
3003   * @data: String to parse.   * @data: String to parse.
# Line 934  static bool ccs_manager(void) Line 3006  static bool ccs_manager(void)
3006   *   *
3007   * Caller holds ccs_read_lock().   * Caller holds ccs_read_lock().
3008   */   */
3009  static bool ccs_select_one(struct ccs_io_buffer *head, const char *data)  static bool ccs_select_domain(struct ccs_io_buffer *head, const char *data)
3010  {  {
3011          unsigned int pid;          unsigned int pid;
3012          struct ccs_domain_info *domain = NULL;          struct ccs_domain_info *domain = NULL;
3013          bool global_pid = false;          bool global_pid = false;
3014          if (!strcmp(data, "transition_only")) {          if (strncmp(data, "select ", 7))
3015                  head->r.print_transition_related_only = true;                  return false;
3016                  return true;          data += 7;
         }  
3017          if (sscanf(data, "pid=%u", &pid) == 1 ||          if (sscanf(data, "pid=%u", &pid) == 1 ||
3018              (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {              (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
3019                  struct task_struct *p;                  struct task_struct *p;
# Line 960  static bool ccs_select_one(struct ccs_io Line 3031  static bool ccs_select_one(struct ccs_io
3031                          domain = ccs_task_domain(p);                          domain = ccs_task_domain(p);
3032                  ccs_tasklist_unlock();                  ccs_tasklist_unlock();
3033          } else if (!strncmp(data, "domain=", 7)) {          } else if (!strncmp(data, "domain=", 7)) {
3034                  if (ccs_domain_def(data + 7))                  if (*(data + 7) == '<')
3035                          domain = ccs_find_domain(data + 7);                          domain = ccs_find_domain(data + 7);
3036            } else if (sscanf(data, "Q=%u", &pid) == 1) {
3037                    domain = ccs_find_domain_by_qid(pid);
3038          } else          } else
3039                  return false;                  return false;
3040          head->w.domain = domain;          head->w.domain = domain;
# Line 981  static bool ccs_select_one(struct ccs_io Line 3054  static bool ccs_select_one(struct ccs_io
3054  }  }
3055    
3056  /**  /**
3057   * ccs_same_handler_acl - Check for duplicated "struct ccs_handler_acl" entry.   * ccs_update_acl - Update "struct ccs_acl_info" entry.
3058   *   *
3059   * @a: Pointer to "struct ccs_acl_info".   * @size:  Size of new entry in bytes.
3060   * @b: Pointer to "struct ccs_acl_info".   * @param: Pointer to "struct ccs_acl_param".
3061   *   *
3062   * Returns true if @a == @b, false otherwise.   * Returns 0 on success, negative value otherwise.
3063     *
3064     * Caller holds ccs_read_lock().
3065   */   */
3066  static bool ccs_same_handler_acl(const struct ccs_acl_info *a,  static int ccs_update_acl(const int size, struct ccs_acl_param *param)
                                  const struct ccs_acl_info *b)  
3067  {  {
3068          const struct ccs_handler_acl *p1 = container_of(a, typeof(*p1), head);          struct ccs_acl_info *new_entry = &param->e.acl_info;
3069          const struct ccs_handler_acl *p2 = container_of(b, typeof(*p2), head);          const bool is_delete = param->is_delete;
3070          return p1->handler == p2->handler;          int error = is_delete ? -ENOENT : -ENOMEM;
3071            struct ccs_acl_info *entry;
3072            struct list_head * const list = param->list;
3073            BUG_ON(size < sizeof(*entry));
3074            if (param->data[0]) {
3075                    new_entry->cond = ccs_get_condition(param);
3076                    if (!new_entry->cond)
3077                            return -EINVAL;
3078                    /*
3079                     * Domain transition preference is allowed for only
3080                     * "file execute"/"task auto_execute_handler"/
3081                     * "task denied_auto_execute_handler" entries.
3082                     */
3083                    if (new_entry->cond->exec_transit &&
3084                        !(new_entry->type == CCS_TYPE_PATH_ACL &&
3085                          new_entry->perm == 1 << CCS_TYPE_EXECUTE)
3086    #ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
3087                        && new_entry->type != CCS_TYPE_AUTO_EXECUTE_HANDLER &&
3088                        new_entry->type != CCS_TYPE_DENIED_EXECUTE_HANDLER
3089    #endif
3090                        )
3091                            return -EINVAL;
3092            }
3093            if (mutex_lock_interruptible(&ccs_policy_lock))
3094                    return -ENOMEM;
3095            list_for_each_entry_srcu(entry, list, list, &ccs_ss) {
3096                    if (entry->is_deleted == CCS_GC_IN_PROGRESS)
3097                            continue;
3098                    if (entry->type != new_entry->type ||
3099                        entry->cond != new_entry->cond ||
3100                        memcmp(entry + 1, new_entry + 1, size - sizeof(*entry)))
3101                            continue;
3102                    if (is_delete)
3103                            entry->perm &= ~new_entry->perm;
3104                    else
3105                            entry->perm |= new_entry->perm;
3106                    entry->is_deleted = !entry->perm;
3107                    error = 0;
3108                    break;
3109            }
3110            if (error && !is_delete) {
3111                    entry = ccs_commit_ok(new_entry, size);
3112                    if (entry) {
3113                            list_add_tail_rcu(&entry->list, list);
3114                            error = 0;
3115                    }
3116            }
3117            mutex_unlock(&ccs_policy_lock);
3118            return error;
3119  }  }
3120    
3121  /**  /**
3122   * ccs_same_task_acl - Check for duplicated "struct ccs_task_acl" entry.   * ccs_permstr - Find permission keywords.
3123   *   *
3124   * @a: Pointer to "struct ccs_acl_info".   * @string: String representation for permissions in foo/bar/buz format.
3125   * @b: Pointer to "struct ccs_acl_info".   * @keyword: Keyword to find from @string/
3126   *   *
3127   * Returns true if @a == @b, false otherwise.   * Returns ture if @keyword was found in @string, false otherwise.
3128     *
3129     * This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2.
3130   */   */
3131  static bool ccs_same_task_acl(const struct ccs_acl_info *a,  static bool ccs_permstr(const char *string, const char *keyword)
                               const struct ccs_acl_info *b)  
3132  {  {
3133          const struct ccs_task_acl *p1 = container_of(a, typeof(*p1), head);          const char *cp = strstr(string, keyword);
3134          const struct ccs_task_acl *p2 = container_of(b, typeof(*p2), head);          if (cp)
3135          return p1->domainname == p2->domainname;                  return cp == string || *(cp - 1) == '/';
3136            return false;
3137  }  }
3138    
3139  /**  /**
# Line 1028  static int ccs_write_task(struct ccs_acl Line 3152  static int ccs_write_task(struct ccs_acl
3152                                              "auto_domain_transition ");                                              "auto_domain_transition ");
3153          if (!is_auto && !ccs_str_starts(&param->data,          if (!is_auto && !ccs_str_starts(&param->data,
3154                                          "manual_domain_transition ")) {                                          "manual_domain_transition ")) {
3155                  struct ccs_handler_acl e = { };  #ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER
3156                    struct ccs_handler_acl *e = &param->e.handler_acl;
3157                  char *handler;                  char *handler;
3158                  if (ccs_str_starts(&param->data, "auto_execute_handler "))                  if (ccs_str_starts(&param->data, "auto_execute_handler "))
3159                          e.head.type = CCS_TYPE_AUTO_EXECUTE_HANDLER;                          e->head.type = CCS_TYPE_AUTO_EXECUTE_HANDLER;
3160                  else if (ccs_str_starts(&param->data,                  else if (ccs_str_starts(&param->data,
3161                                          "denied_execute_handler "))                                          "denied_execute_handler "))
3162                          e.head.type = CCS_TYPE_DENIED_EXECUTE_HANDLER;                          e->head.type = CCS_TYPE_DENIED_EXECUTE_HANDLER;
3163                  else                  else
3164                          return -EINVAL;                          return -EINVAL;
3165                  handler = ccs_read_token(param);                  handler = ccs_read_token(param);
3166                  if (!ccs_correct_path(handler))                  if (!ccs_correct_path(handler))
3167                          return -EINVAL;                          return -EINVAL;
3168                  e.handler = ccs_get_name(handler);                  e->handler = ccs_get_name(handler);
3169                  if (!e.handler)                  if (!e->handler)
3170                          return -ENOMEM;                          return -ENOMEM;
3171                  if (e.handler->is_patterned)                  if (e->handler->is_patterned)
3172                          error = -EINVAL; /* No patterns allowed. */                          return -EINVAL; /* No patterns allowed. */
3173                  else                  return ccs_update_acl(sizeof(*e), param);
3174                          error = ccs_update_domain(&e.head, sizeof(e), param,  #else
3175                                                    ccs_same_handler_acl, NULL);                  error = -EINVAL;
3176                  ccs_put_name(e.handler);  #endif
3177          } else {          } else {
3178                  struct ccs_task_acl e = {  #ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
3179                          .head.type = is_auto ?                  struct ccs_task_acl *e = &param->e.task_acl;
3180                          CCS_TYPE_AUTO_TASK_ACL : CCS_TYPE_MANUAL_TASK_ACL,                  e->head.type = is_auto ?
3181                          .domainname = ccs_get_domainname(param),                          CCS_TYPE_AUTO_TASK_ACL : CCS_TYPE_MANUAL_TASK_ACL;
3182                  };                  e->domainname = ccs_get_domainname(param);
3183                  if (!e.domainname)                  if (!e->domainname)
3184                          error = -EINVAL;                          return -EINVAL;
3185                  else                  return ccs_update_acl(sizeof(*e), param);
3186                          error = ccs_update_domain(&e.head, sizeof(e), param,  #else
3187                                                    ccs_same_task_acl, NULL);                  error = -EINVAL;
3188                  ccs_put_name(e.domainname);  #endif
3189          }          }
3190          return error;          return error;
3191  }  }
3192    
3193    #ifdef CONFIG_CCSECURITY_NETWORK
3194    
3195    /**
3196     * ccs_write_inet_network - Write "struct ccs_inet_acl" list.
3197