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

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

trunk/1.7.x/ccs-patch/security/ccsecurity/policy_io.c revision 3512 by kumaneko, Fri Mar 19 08:37:22 2010 UTC trunk/1.8.x/ccs-patch/security/ccsecurity/policy_io.c revision 5889 by kumaneko, Wed Feb 29 06:41:55 2012 UTC
# Line 1  Line 1 
1  /*  /*
2   * security/ccsecurity/policy_io.c   * security/ccsecurity/policy_io.c
3   *   *
4   * Copyright (C) 2005-2010  NTT DATA CORPORATION   * Copyright (C) 2005-2012  NTT DATA CORPORATION
  *  
  * Version: 1.7.2-pre   2010/03/08  
  *  
  * This file is applicable to both 2.4.30 and 2.6.11 and later.  
  * See README.ccs for ChangeLog.  
5   *   *
6     * Version: 1.8.3+   2012/02/29
7   */   */
8    
9  #include "internal.h"  #include "internal.h"
10    
11  static struct ccs_profile ccs_default_profile = {  /***** SECTION1: Constants definition *****/
12          .learning = &ccs_default_profile.preference,  
13          .permissive = &ccs_default_profile.preference,  /* Define this to enable debug mode. */
14          .enforcing = &ccs_default_profile.preference,  /* #define DEBUG_CONDITION */
15          .audit = &ccs_default_profile.preference,  
16  #ifdef CONFIG_CCSECURITY_AUDIT  #ifdef DEBUG_CONDITION
17          .preference.audit_max_grant_log = CONFIG_CCSECURITY_MAX_GRANT_LOG,  #define dprintk printk
18          .preference.audit_max_reject_log = CONFIG_CCSECURITY_MAX_REJECT_LOG,  #else
19  #endif  #define dprintk(...) do { } while (0)
20          .preference.audit_task_info = true,  #endif
21          .preference.audit_path_info = true,  
22          .preference.enforcing_penalty = 0,  /* Mapping table from "enum ccs_mac_index" to "enum ccs_mac_category_index". */
23          .preference.enforcing_verbose = true,  static const u8 ccs_index2category[CCS_MAX_MAC_INDEX] = {
24          .preference.learning_max_entry = CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY,          /* CONFIG::file group */
25          .preference.learning_verbose = false,          [CCS_MAC_FILE_EXECUTE]    = CCS_MAC_CATEGORY_FILE,
26          .preference.learning_exec_realpath = true,          [CCS_MAC_FILE_OPEN]       = CCS_MAC_CATEGORY_FILE,
27          .preference.learning_exec_argv0 = true,          [CCS_MAC_FILE_CREATE]     = CCS_MAC_CATEGORY_FILE,
28          .preference.learning_symlink_target = true,          [CCS_MAC_FILE_UNLINK]     = CCS_MAC_CATEGORY_FILE,
29          .preference.permissive_verbose = true  #ifdef CONFIG_CCSECURITY_FILE_GETATTR
30            [CCS_MAC_FILE_GETATTR]    = CCS_MAC_CATEGORY_FILE,
31    #endif
32            [CCS_MAC_FILE_MKDIR]      = CCS_MAC_CATEGORY_FILE,
33            [CCS_MAC_FILE_RMDIR]      = CCS_MAC_CATEGORY_FILE,
34            [CCS_MAC_FILE_MKFIFO]     = CCS_MAC_CATEGORY_FILE,
35            [CCS_MAC_FILE_MKSOCK]     = CCS_MAC_CATEGORY_FILE,
36            [CCS_MAC_FILE_TRUNCATE]   = CCS_MAC_CATEGORY_FILE,
37            [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. */
104    static const char * const ccs_mode[CCS_CONFIG_MAX_MODE] = {
105            [CCS_CONFIG_DISABLED]   = "disabled",
106            [CCS_CONFIG_LEARNING]   = "learning",
107            [CCS_CONFIG_PERMISSIVE] = "permissive",
108            [CCS_CONFIG_ENFORCING]  = "enforcing"
109    };
110    
111    /* String table for /proc/ccs/profile interface. */
112    static const char * const ccs_mac_keywords[CCS_MAX_MAC_INDEX
113                                               + CCS_MAX_MAC_CATEGORY_INDEX] = {
114            /* CONFIG::file group */
115            [CCS_MAC_FILE_EXECUTE]    = "execute",
116            [CCS_MAC_FILE_OPEN]       = "open",
117            [CCS_MAC_FILE_CREATE]     = "create",
118            [CCS_MAC_FILE_UNLINK]     = "unlink",
119    #ifdef CONFIG_CCSECURITY_FILE_GETATTR
120            [CCS_MAC_FILE_GETATTR]    = "getattr",
121    #endif
122            [CCS_MAC_FILE_MKDIR]      = "mkdir",
123            [CCS_MAC_FILE_RMDIR]      = "rmdir",
124            [CCS_MAC_FILE_MKFIFO]     = "mkfifo",
125            [CCS_MAC_FILE_MKSOCK]     = "mksock",
126            [CCS_MAC_FILE_TRUNCATE]   = "truncate",
127            [CCS_MAC_FILE_SYMLINK]    = "symlink",
128            [CCS_MAC_FILE_MKBLOCK]    = "mkblock",
129            [CCS_MAC_FILE_MKCHAR]     = "mkchar",
130            [CCS_MAC_FILE_LINK]       = "link",
131            [CCS_MAC_FILE_RENAME]     = "rename",
132            [CCS_MAC_FILE_CHMOD]      = "chmod",
133            [CCS_MAC_FILE_CHOWN]      = "chown",
134            [CCS_MAC_FILE_CHGRP]      = "chgrp",
135            [CCS_MAC_FILE_IOCTL]      = "ioctl",
136            [CCS_MAC_FILE_CHROOT]     = "chroot",
137            [CCS_MAC_FILE_MOUNT]      = "mount",
138            [CCS_MAC_FILE_UMOUNT]     = "unmount",
139            [CCS_MAC_FILE_PIVOT_ROOT] = "pivot_root",
140    #ifdef CONFIG_CCSECURITY_MISC
141            /* CONFIG::misc group */
142            [CCS_MAC_ENVIRON] = "env",
143    #endif
144    #ifdef CONFIG_CCSECURITY_NETWORK
145            /* CONFIG::network group */
146            [CCS_MAC_NETWORK_INET_STREAM_BIND]       = "inet_stream_bind",
147            [CCS_MAC_NETWORK_INET_STREAM_LISTEN]     = "inet_stream_listen",
148            [CCS_MAC_NETWORK_INET_STREAM_CONNECT]    = "inet_stream_connect",
149            [CCS_MAC_NETWORK_INET_STREAM_ACCEPT]     = "inet_stream_accept",
150            [CCS_MAC_NETWORK_INET_DGRAM_BIND]        = "inet_dgram_bind",
151            [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",
154    #endif
155            [CCS_MAC_NETWORK_INET_RAW_BIND]          = "inet_raw_bind",
156            [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",
159    #endif
160            [CCS_MAC_NETWORK_UNIX_STREAM_BIND]       = "unix_stream_bind",
161            [CCS_MAC_NETWORK_UNIX_STREAM_LISTEN]     = "unix_stream_listen",
162            [CCS_MAC_NETWORK_UNIX_STREAM_CONNECT]    = "unix_stream_connect",
163            [CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT]     = "unix_stream_accept",
164            [CCS_MAC_NETWORK_UNIX_DGRAM_BIND]        = "unix_dgram_bind",
165            [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",
168    #endif
169            [CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND]    = "unix_seqpacket_bind",
170            [CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN]  = "unix_seqpacket_listen",
171            [CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
172            [CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT]  = "unix_seqpacket_accept",
173    #endif
174    #ifdef CONFIG_CCSECURITY_IPC
175            /* CONFIG::ipc group */
176            [CCS_MAC_SIGNAL] = "signal",
177    #endif
178    #ifdef CONFIG_CCSECURITY_CAPABILITY
179            /* CONFIG::capability group */
180            [CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET]  = "use_route",
181            [CCS_MAC_CAPABILITY_USE_PACKET_SOCKET] = "use_packet",
182            [CCS_MAC_CAPABILITY_SYS_REBOOT]        = "SYS_REBOOT",
183            [CCS_MAC_CAPABILITY_SYS_VHANGUP]       = "SYS_VHANGUP",
184            [CCS_MAC_CAPABILITY_SYS_SETTIME]       = "SYS_TIME",
185            [CCS_MAC_CAPABILITY_SYS_NICE]          = "SYS_NICE",
186            [CCS_MAC_CAPABILITY_SYS_SETHOSTNAME]   = "SYS_SETHOSTNAME",
187            [CCS_MAC_CAPABILITY_USE_KERNEL_MODULE] = "use_kernel_module",
188            [CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD]    = "SYS_KEXEC_LOAD",
189            [CCS_MAC_CAPABILITY_SYS_PTRACE]        = "SYS_PTRACE",
190    #endif
191            /* CONFIG group */
192            [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_FILE]       = "file",
193    #ifdef CONFIG_CCSECURITY_NETWORK
194            [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",
198    #endif
199    #ifdef CONFIG_CCSECURITY_IPC
200            [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",
204    #endif
205    };
206    
207    /* String table for path operation. */
208    static const char * const ccs_path_keyword[CCS_MAX_PATH_OPERATION] = {
209            [CCS_TYPE_EXECUTE]    = "execute",
210            [CCS_TYPE_READ]       = "read",
211            [CCS_TYPE_WRITE]      = "write",
212            [CCS_TYPE_APPEND]     = "append",
213            [CCS_TYPE_UNLINK]     = "unlink",
214    #ifdef CONFIG_CCSECURITY_FILE_GETATTR
215            [CCS_TYPE_GETATTR]    = "getattr",
216    #endif
217            [CCS_TYPE_RMDIR]      = "rmdir",
218            [CCS_TYPE_TRUNCATE]   = "truncate",
219            [CCS_TYPE_SYMLINK]    = "symlink",
220            [CCS_TYPE_CHROOT]     = "chroot",
221            [CCS_TYPE_UMOUNT]     = "unmount",
222  };  };
223    
224  /* Profile version. Currently only 20090903 is defined. */  #ifdef CONFIG_CCSECURITY_NETWORK
 static unsigned int ccs_profile_version;  
225    
226  /* Profile table. Memory is allocated as needed. */  /* String table for socket's operation. */
227  static struct ccs_profile *ccs_profile_ptr[CCS_MAX_PROFILES];  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. */
251    static const char * const ccs_category_keywords[CCS_MAX_MAC_CATEGORY_INDEX] = {
252            [CCS_MAC_CATEGORY_FILE]       = "file",
253    #ifdef CONFIG_CCSECURITY_NETWORK
254            [CCS_MAC_CATEGORY_NETWORK]    = "network",
255    #endif
256    #ifdef CONFIG_CCSECURITY_MISC
257            [CCS_MAC_CATEGORY_MISC]       = "misc",
258    #endif
259    #ifdef CONFIG_CCSECURITY_IPC
260            [CCS_MAC_CATEGORY_IPC]        = "ipc",
261    #endif
262    #ifdef CONFIG_CCSECURITY_CAPABILITY
263            [CCS_MAC_CATEGORY_CAPABILITY] = "capability",
264    #endif
265    };
266    
267    /* String table for conditions. */
268    static const char * const ccs_condition_keyword[CCS_MAX_CONDITION_KEYWORD] = {
269            [CCS_TASK_UID]             = "task.uid",
270            [CCS_TASK_EUID]            = "task.euid",
271            [CCS_TASK_SUID]            = "task.suid",
272            [CCS_TASK_FSUID]           = "task.fsuid",
273            [CCS_TASK_GID]             = "task.gid",
274            [CCS_TASK_EGID]            = "task.egid",
275            [CCS_TASK_SGID]            = "task.sgid",
276            [CCS_TASK_FSGID]           = "task.fsgid",
277            [CCS_TASK_PID]             = "task.pid",
278            [CCS_TASK_PPID]            = "task.ppid",
279            [CCS_EXEC_ARGC]            = "exec.argc",
280            [CCS_EXEC_ENVC]            = "exec.envc",
281            [CCS_TYPE_IS_SOCKET]       = "socket",
282            [CCS_TYPE_IS_SYMLINK]      = "symlink",
283            [CCS_TYPE_IS_FILE]         = "file",
284            [CCS_TYPE_IS_BLOCK_DEV]    = "block",
285            [CCS_TYPE_IS_DIRECTORY]    = "directory",
286            [CCS_TYPE_IS_CHAR_DEV]     = "char",
287            [CCS_TYPE_IS_FIFO]         = "fifo",
288            [CCS_MODE_SETUID]          = "setuid",
289            [CCS_MODE_SETGID]          = "setgid",
290            [CCS_MODE_STICKY]          = "sticky",
291            [CCS_MODE_OWNER_READ]      = "owner_read",
292            [CCS_MODE_OWNER_WRITE]     = "owner_write",
293            [CCS_MODE_OWNER_EXECUTE]   = "owner_execute",
294            [CCS_MODE_GROUP_READ]      = "group_read",
295            [CCS_MODE_GROUP_WRITE]     = "group_write",
296            [CCS_MODE_GROUP_EXECUTE]   = "group_execute",
297            [CCS_MODE_OTHERS_READ]     = "others_read",
298            [CCS_MODE_OTHERS_WRITE]    = "others_write",
299            [CCS_MODE_OTHERS_EXECUTE]  = "others_execute",
300            [CCS_TASK_TYPE]            = "task.type",
301            [CCS_TASK_EXECUTE_HANDLER] = "execute_handler",
302            [CCS_EXEC_REALPATH]        = "exec.realpath",
303            [CCS_SYMLINK_TARGET]       = "symlink.target",
304            [CCS_PATH1_UID]            = "path1.uid",
305            [CCS_PATH1_GID]            = "path1.gid",
306            [CCS_PATH1_INO]            = "path1.ino",
307            [CCS_PATH1_MAJOR]          = "path1.major",
308            [CCS_PATH1_MINOR]          = "path1.minor",
309            [CCS_PATH1_PERM]           = "path1.perm",
310            [CCS_PATH1_TYPE]           = "path1.type",
311            [CCS_PATH1_DEV_MAJOR]      = "path1.dev_major",
312            [CCS_PATH1_DEV_MINOR]      = "path1.dev_minor",
313            [CCS_PATH2_UID]            = "path2.uid",
314            [CCS_PATH2_GID]            = "path2.gid",
315            [CCS_PATH2_INO]            = "path2.ino",
316            [CCS_PATH2_MAJOR]          = "path2.major",
317            [CCS_PATH2_MINOR]          = "path2.minor",
318            [CCS_PATH2_PERM]           = "path2.perm",
319            [CCS_PATH2_TYPE]           = "path2.type",
320            [CCS_PATH2_DEV_MAJOR]      = "path2.dev_major",
321            [CCS_PATH2_DEV_MINOR]      = "path2.dev_minor",
322            [CCS_PATH1_PARENT_UID]     = "path1.parent.uid",
323            [CCS_PATH1_PARENT_GID]     = "path1.parent.gid",
324            [CCS_PATH1_PARENT_INO]     = "path1.parent.ino",
325            [CCS_PATH1_PARENT_PERM]    = "path1.parent.perm",
326            [CCS_PATH2_PARENT_UID]     = "path2.parent.uid",
327            [CCS_PATH2_PARENT_GID]     = "path2.parent.gid",
328            [CCS_PATH2_PARENT_INO]     = "path2.parent.ino",
329            [CCS_PATH2_PARENT_PERM]    = "path2.parent.perm",
330    };
331    
332    /* String table for PREFERENCE keyword. */
333    static const char * const ccs_pref_keywords[CCS_MAX_PREF] = {
334            [CCS_PREF_MAX_AUDIT_LOG]      = "max_audit_log",
335            [CCS_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry",
336            [CCS_PREF_ENFORCING_PENALTY]  = "enforcing_penalty",
337    };
338    
339  /* String table for functionality that takes 4 modes. */  /* String table for domain flags. */
340  static const char *ccs_mode_4[4] = {  const char * const ccs_dif[CCS_MAX_DOMAIN_INFO_FLAGS] = {
341          "disabled", "learning", "permissive", "enforcing"          [CCS_DIF_QUOTA_WARNED]      = "quota_exceeded\n",
342            [CCS_DIF_TRANSITION_FAILED] = "transition_failed\n",
343  };  };
344    
345  /* String table for /proc/ccs/profile */  /* String table for domain transition control keywords. */
346  static const char *ccs_mac_keywords[CCS_MAX_MAC_INDEX +  static const char * const ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = {
347                                      CCS_MAX_CAPABILITY_INDEX +          [CCS_TRANSITION_CONTROL_NO_RESET]      = "no_reset_domain ",
348                                      CCS_MAX_MAC_CATEGORY_INDEX] = {          [CCS_TRANSITION_CONTROL_RESET]         = "reset_domain ",
349          [CCS_MAC_FILE_EXECUTE]          [CCS_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
350          = "file::execute",          [CCS_TRANSITION_CONTROL_INITIALIZE]    = "initialize_domain ",
351          [CCS_MAC_FILE_OPEN]          [CCS_TRANSITION_CONTROL_NO_KEEP]       = "no_keep_domain ",
352          = "file::open",          [CCS_TRANSITION_CONTROL_KEEP]          = "keep_domain ",
353          [CCS_MAC_FILE_CREATE]  };
354          = "file::create",  
355          [CCS_MAC_FILE_UNLINK]  /* String table for grouping keywords. */
356          = "file::unlink",  static const char * const ccs_group_name[CCS_MAX_GROUP] = {
357          [CCS_MAC_FILE_MKDIR]          [CCS_PATH_GROUP]    = "path_group ",
358          = "file::mkdir",          [CCS_NUMBER_GROUP]  = "number_group ",
359          [CCS_MAC_FILE_RMDIR]  #ifdef CONFIG_CCSECURITY_NETWORK
360          = "file::rmdir",          [CCS_ADDRESS_GROUP] = "address_group ",
361          [CCS_MAC_FILE_MKFIFO]  #endif
362          = "file::mkfifo",  };
363          [CCS_MAC_FILE_MKSOCK]  
364          = "file::mksock",  /* String table for /proc/ccs/stat interface. */
365          [CCS_MAC_FILE_TRUNCATE]  static const char * const ccs_policy_headers[CCS_MAX_POLICY_STAT] = {
366          = "file::truncate",          [CCS_STAT_POLICY_UPDATES]    = "update:",
367          [CCS_MAC_FILE_SYMLINK]          [CCS_STAT_POLICY_LEARNING]   = "violation in learning mode:",
368          = "file::symlink",          [CCS_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:",
369          [CCS_MAC_FILE_REWRITE]          [CCS_STAT_POLICY_ENFORCING]  = "violation in enforcing mode:",
370          = "file::rewrite",  };
371          [CCS_MAC_FILE_MKBLOCK]  
372          = "file::mkblock",  /* String table for /proc/ccs/stat interface. */
373          [CCS_MAC_FILE_MKCHAR]  static const char * const ccs_memory_headers[CCS_MAX_MEMORY_STAT] = {
374          = "file::mkchar",          [CCS_MEMORY_POLICY]     = "policy:",
375          [CCS_MAC_FILE_LINK]          [CCS_MEMORY_AUDIT]      = "audit log:",
376          = "file::link",          [CCS_MEMORY_QUERY]      = "query message:",
377          [CCS_MAC_FILE_RENAME]  };
378          = "file::rename",  
379          [CCS_MAC_FILE_CHMOD]  /***** SECTION2: Structure definition *****/
380          = "file::chmod",  
381          [CCS_MAC_FILE_CHOWN]  struct iattr;
382          = "file::chown",  
383          [CCS_MAC_FILE_CHGRP]  /* Structure for query. */
384          = "file::chgrp",  struct ccs_query {
385          [CCS_MAC_FILE_IOCTL]          struct list_head list;
386          = "file::ioctl",          struct ccs_domain_info *domain;
387          [CCS_MAC_FILE_CHROOT]          char *query;
388          = "file::chroot",          size_t query_len;
389          [CCS_MAC_FILE_MOUNT]          unsigned int serial;
390          = "file::mount",          u8 timer;
391          [CCS_MAC_FILE_UMOUNT]          u8 answer;
392          = "file::umount",          u8 retry;
         [CCS_MAC_FILE_PIVOT_ROOT]  
         = "file::pivot_root",  
         [CCS_MAC_FILE_TRANSIT]  
         = "file::transit",  
         [CCS_MAC_ENVIRON]  
         = "misc::env",  
         [CCS_MAC_NETWORK_UDP_BIND]  
         = "network::inet_udp_bind",  
         [CCS_MAC_NETWORK_UDP_CONNECT]  
         = "network::inet_udp_connect",  
         [CCS_MAC_NETWORK_TCP_BIND]  
         = "network::inet_tcp_bind",  
         [CCS_MAC_NETWORK_TCP_LISTEN]  
         = "network::inet_tcp_listen",  
         [CCS_MAC_NETWORK_TCP_CONNECT]  
         = "network::inet_tcp_connect",  
         [CCS_MAC_NETWORK_TCP_ACCEPT]  
         = "network::inet_tcp_accept",  
         [CCS_MAC_NETWORK_RAW_BIND]  
         = "network::inet_raw_bind",  
         [CCS_MAC_NETWORK_RAW_CONNECT]  
         = "network::inet_raw_connect",  
         [CCS_MAC_SIGNAL]  
         = "ipc::signal",  
         [CCS_MAX_MAC_INDEX + CCS_INET_STREAM_SOCKET_CREATE]  
         = "capability::inet_tcp_create",  
         [CCS_MAX_MAC_INDEX + CCS_INET_STREAM_SOCKET_LISTEN]  
         = "capability::inet_tcp_listen",  
         [CCS_MAX_MAC_INDEX + CCS_INET_STREAM_SOCKET_CONNECT]  
         = "capability::inet_tcp_connect",  
         [CCS_MAX_MAC_INDEX + CCS_USE_INET_DGRAM_SOCKET]  
         = "capability::use_inet_udp",  
         [CCS_MAX_MAC_INDEX + CCS_USE_INET_RAW_SOCKET]  
         = "capability::use_inet_ip",  
         [CCS_MAX_MAC_INDEX + CCS_USE_ROUTE_SOCKET]  
         = "capability::use_route",  
         [CCS_MAX_MAC_INDEX + CCS_USE_PACKET_SOCKET]  
         = "capability::use_packet",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_MOUNT]  
         = "capability::SYS_MOUNT",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_UMOUNT]  
         = "capability::SYS_UMOUNT",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_REBOOT]  
         = "capability::SYS_REBOOT",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_CHROOT]  
         = "capability::SYS_CHROOT",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_KILL]  
         = "capability::SYS_KILL",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_VHANGUP]  
         = "capability::SYS_VHANGUP",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_SETTIME]  
         = "capability::SYS_TIME",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_NICE]  
         = "capability::SYS_NICE",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_SETHOSTNAME]  
         = "capability::SYS_SETHOSTNAME",  
         [CCS_MAX_MAC_INDEX + CCS_USE_KERNEL_MODULE]  
         = "capability::use_kernel_module",  
         [CCS_MAX_MAC_INDEX + CCS_CREATE_FIFO]  
         = "capability::create_fifo",  
         [CCS_MAX_MAC_INDEX + CCS_CREATE_BLOCK_DEV]  
         = "capability::create_block_dev",  
         [CCS_MAX_MAC_INDEX + CCS_CREATE_CHAR_DEV]  
         = "capability::create_char_dev",  
         [CCS_MAX_MAC_INDEX + CCS_CREATE_UNIX_SOCKET]  
         = "capability::create_unix_socket",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_LINK]  
         = "capability::SYS_LINK",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_SYMLINK]  
         = "capability::SYS_SYMLINK",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_RENAME]  
         = "capability::SYS_RENAME",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_UNLINK]  
         = "capability::SYS_UNLINK",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_CHMOD]  
         = "capability::SYS_CHMOD",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_CHOWN]  
         = "capability::SYS_CHOWN",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_IOCTL]  
         = "capability::SYS_IOCTL",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_KEXEC_LOAD]  
         = "capability::SYS_KEXEC_LOAD",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_PIVOT_ROOT]  
         = "capability::SYS_PIVOT_ROOT",  
         [CCS_MAX_MAC_INDEX + CCS_SYS_PTRACE]  
         = "capability::SYS_PTRACE",  
         [CCS_MAX_MAC_INDEX + CCS_CONCEAL_MOUNT]  
         = "capability::conceal_mount",  
         [CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX  
          + CCS_MAC_CATEGORY_FILE] = "file",  
         [CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX  
          + CCS_MAC_CATEGORY_NETWORK] = "network",  
         [CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX  
          + CCS_MAC_CATEGORY_MISC] = "misc",  
         [CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX  
          + CCS_MAC_CATEGORY_IPC] = "ipc",  
         [CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX  
          + CCS_MAC_CATEGORY_CAPABILITY] = "capability",  
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_poll_log(struct file *file, poll_table *wait);
462    static int ccs_poll_query(struct file *file, poll_table *wait);
463    static int ccs_release(struct inode *inode, struct file *file);
464    static int ccs_set_mode(char *name, const char *value,
465                            struct ccs_profile *profile);
466    static int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...)
467            __printf(2, 3);
468    static int ccs_truncate(char *str);
469    static int ccs_update_acl(const int size, struct ccs_acl_param *param);
470    static int ccs_update_manager_entry(const char *manager, const bool is_delete);
471    static int ccs_update_policy(const int size, struct ccs_acl_param *param);
472    static int ccs_write_acl(struct ccs_policy_namespace *ns,
473                             struct list_head *list, char *data,
474                             const bool is_delete);
475    static int ccs_write_aggregator(struct ccs_acl_param *param);
476    static int ccs_write_answer(struct ccs_io_buffer *head);
477    static int ccs_write_domain(struct ccs_io_buffer *head);
478    static int ccs_write_exception(struct ccs_io_buffer *head);
479    static int ccs_write_file(struct ccs_acl_param *param);
480    static int ccs_write_group(struct ccs_acl_param *param, const u8 type);
481    static int ccs_write_manager(struct ccs_io_buffer *head);
482    static int ccs_write_pid(struct ccs_io_buffer *head);
483    static int ccs_write_profile(struct ccs_io_buffer *head);
484    static int ccs_write_stat(struct ccs_io_buffer *head);
485    static int ccs_write_task(struct ccs_acl_param *param);
486    static int ccs_write_transition_control(struct ccs_acl_param *param,
487                                            const u8 type);
488    static s8 ccs_find_yesno(const char *string, const char *find);
489    static ssize_t ccs_read(struct file *file, char __user *buf, size_t count,
490                            loff_t *ppos);
491    static ssize_t ccs_read_self(struct file *file, char __user *buf, size_t count,
492                                 loff_t *ppos);
493    static ssize_t ccs_write(struct file *file, const char __user *buf,
494                             size_t count, loff_t *ppos);
495    static struct ccs_condition *ccs_commit_condition(struct ccs_condition *entry);
496    static struct ccs_condition *ccs_get_condition(struct ccs_acl_param *param);
497    static struct ccs_domain_info *ccs_find_domain(const char *domainname);
498    static struct ccs_domain_info *ccs_find_domain_by_qid(unsigned int serial);
499    static struct ccs_group *ccs_get_group(struct ccs_acl_param *param,
500                                           const u8 idx);
501    static struct ccs_policy_namespace *ccs_assign_namespace
502    (const char *domainname);
503    static struct ccs_policy_namespace *ccs_find_namespace(const char *name,
504                                                           const unsigned int len);
505    static struct ccs_profile *ccs_assign_profile(struct ccs_policy_namespace *ns,
506                                                  const unsigned int profile);
507    static struct ccs_profile *ccs_profile(const u8 profile);
508    static u8 ccs_condition_type(const char *word);
509    static u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3);
510    static u8 ccs_parse_ulong(unsigned long *result, char **str);
511    static unsigned int ccs_poll(struct file *file, poll_table *wait);
512    static void __init ccs_create_entry(const char *name, const umode_t mode,
513                                        struct proc_dir_entry *parent,
514                                        const u8 key);
515    static void __init ccs_load_builtin_policy(void);
516    static void __init ccs_policy_io_init(void);
517    static void __init ccs_proc_init(void);
518    static void ccs_add_entry(char *header);
519    static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)
520            __printf(3, 4);
521    static void ccs_addprintf(char *buffer, int len, const char *fmt, ...);
522    static void ccs_check_profile(void);
523    static void ccs_convert_time(time_t time, struct ccs_time *stamp);
524    static void ccs_init_policy_namespace(struct ccs_policy_namespace *ns);
525    static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
526            __printf(2, 3);
527    static void ccs_normalize_line(unsigned char *buffer);
528    static void ccs_print_config(struct ccs_io_buffer *head, const u8 config);
529    static void ccs_print_name_union(struct ccs_io_buffer *head,
530                                     const struct ccs_name_union *ptr);
531    static void ccs_print_name_union_quoted(struct ccs_io_buffer *head,
532                                            const struct ccs_name_union *ptr);
533    static void ccs_print_namespace(struct ccs_io_buffer *head);
534    static void ccs_print_number_union(struct ccs_io_buffer *head,
535                                       const struct ccs_number_union *ptr);
536    static void ccs_print_number_union_nospace(struct ccs_io_buffer *head,
537                                               const struct ccs_number_union *ptr);
538    static void ccs_read_domain(struct ccs_io_buffer *head);
539    static void ccs_read_exception(struct ccs_io_buffer *head);
540    static void ccs_read_log(struct ccs_io_buffer *head);
541    static void ccs_read_manager(struct ccs_io_buffer *head);
542    static void ccs_read_pid(struct ccs_io_buffer *head);
543    static void ccs_read_profile(struct ccs_io_buffer *head);
544    static void ccs_read_query(struct ccs_io_buffer *head);
545    static void ccs_read_stat(struct ccs_io_buffer *head);
546    static void ccs_read_version(struct ccs_io_buffer *head);
547    static void ccs_set_group(struct ccs_io_buffer *head, const char *category);
548    static void ccs_set_namespace_cursor(struct ccs_io_buffer *head);
549    static void ccs_set_slash(struct ccs_io_buffer *head);
550    static void ccs_set_space(struct ccs_io_buffer *head);
551    static void ccs_set_string(struct ccs_io_buffer *head, const char *string);
552    static void ccs_set_uint(unsigned int *i, const char *string,
553                             const char *find);
554    static void ccs_update_stat(const u8 index);
555    static void ccs_update_task_domain(struct ccs_request_info *r);
556    static void ccs_write_log2(struct ccs_request_info *r, int len,
557                               const char *fmt, va_list args);
558    
559    #ifdef CONFIG_CCSECURITY_PORTRESERVE
560    static bool __ccs_lport_reserved(const u16 port);
561    static int ccs_write_reserved_port(struct ccs_acl_param *param);
562    #endif
563    
564    #ifdef CONFIG_CCSECURITY_NETWORK
565    static bool ccs_parse_ipaddr_union(struct ccs_acl_param *param,
566                                       struct ccs_ipaddr_union *ptr);
567    static int ccs_print_ipv4(char *buffer, const unsigned int buffer_len,
568                              const u32 *ip);
569    static int ccs_print_ipv6(char *buffer, const unsigned int buffer_len,
570                              const struct in6_addr *ip);
571    static int ccs_write_inet_network(struct ccs_acl_param *param);
572    static int ccs_write_unix_network(struct ccs_acl_param *param);
573    static void ccs_print_ip(char *buf, const unsigned int size,
574                             const struct ccs_ipaddr_union *ptr);
575    #endif
576    
577    #ifdef CONFIG_CCSECURITY_CAPABILITY
578    static int ccs_write_capability(struct ccs_acl_param *param);
579    #endif
580    
581    #ifdef CONFIG_CCSECURITY_MISC
582    static int ccs_write_misc(struct ccs_acl_param *param);
583    #endif
584    
585    #ifdef CONFIG_CCSECURITY_IPC
586    static int ccs_write_ipc(struct ccs_acl_param *param);
587    #endif
588    
589    #ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
590    static ssize_t ccs_write_self(struct file *file, const char __user *buf,
591                                  size_t count, loff_t *ppos);
592    #endif
593    
594    /***** SECTION4: Standalone functions section *****/
595    
596    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
597    
598    /**
599     * fatal_signal_pending - Check whether SIGKILL is pending or not.
600     *
601     * @p: Pointer to "struct task_struct".
602     *
603     * Returns true if SIGKILL is pending on @p, false otherwise.
604     *
605     * This is for compatibility with older kernels.
606     */
607    #define fatal_signal_pending(p) (signal_pending(p) &&                   \
608                                     sigismember(&p->pending.signal, SIGKILL))
609    
610    #endif
611    
612    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
613    
614    /**
615     * __wait_event_interruptible_timeout - Sleep until a condition gets true or a timeout elapses.
616     *
617     * @wq:        The waitqueue to wait on.
618     * @condition: A C expression for the event to wait for.
619     * @ret:       Timeout, in jiffies.
620     *
621     * Returns 0 if the @timeout elapsed, -ERESTARTSYS if it was interrupted by a
622     * signal, and the remaining jiffies otherwise if the condition evaluated to
623     * true before the timeout elapsed.
624     *
625     * This is for compatibility with older kernels.
626     */
627    #define __wait_event_interruptible_timeout(wq, condition, ret)          \
628    do {                                                                    \
629            wait_queue_t __wait;                                            \
630            init_waitqueue_entry(&__wait, current);                         \
631                                                                            \
632            add_wait_queue(&wq, &__wait);                                   \
633            for (;;) {                                                      \
634                    set_current_state(TASK_INTERRUPTIBLE);                  \
635                    if (condition)                                          \
636                            break;                                          \
637                    if (!signal_pending(current)) {                         \
638                            ret = schedule_timeout(ret);                    \
639                            if (!ret)                                       \
640                                    break;                                  \
641                            continue;                                       \
642                    }                                                       \
643                    ret = -ERESTARTSYS;                                     \
644                    break;                                                  \
645            }                                                               \
646            current->state = TASK_RUNNING;                                  \
647            remove_wait_queue(&wq, &__wait);                                \
648    } while (0)
649    
650    /**
651     * wait_event_interruptible_timeout - Sleep until a condition gets true or a timeout elapses.
652     *
653     * @wq:        The waitqueue to wait on.
654     * @condition: A C expression for the event to wait for.
655     * @timeout:   Timeout, in jiffies.
656     *
657     * Returns 0 if the @timeout elapsed, -ERESTARTSYS if it was interrupted by a
658     * signal, and the remaining jiffies otherwise if the condition evaluated to
659     * true before the timeout elapsed.
660     *
661     * This is for compatibility with older kernels.
662     */
663    #define wait_event_interruptible_timeout(wq, condition, timeout)        \
664    ({                                                                      \
665            long __ret = timeout;                                           \
666            if (!(condition))                                               \
667                    __wait_event_interruptible_timeout(wq, condition, __ret); \
668            __ret;                                                          \
669    })
670    
671    #endif
672    
673    /**
674     * ccs_convert_time - Convert time_t to YYYY/MM/DD hh/mm/ss.
675     *
676     * @time:  Seconds since 1970/01/01 00:00:00.
677     * @stamp: Pointer to "struct ccs_time".
678     *
679     * Returns nothing.
680     *
681     * This function does not handle Y2038 problem.
682     */
683    static void ccs_convert_time(time_t time, struct ccs_time *stamp)
684    {
685            static const u16 ccs_eom[2][12] = {
686                    { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
687                    { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
688            };
689            u16 y;
690            u8 m;
691            bool r;
692            stamp->sec = time % 60;
693            time /= 60;
694            stamp->min = time % 60;
695            time /= 60;
696            stamp->hour = time % 24;
697            time /= 24;
698            for (y = 1970; ; y++) {
699                    const unsigned short days = (y & 3) ? 365 : 366;
700                    if (time < days)
701                            break;
702                    time -= days;
703            }
704            r = (y & 3) == 0;
705            for (m = 0; m < 11 && time >= ccs_eom[r][m]; m++);
706            if (m)
707                    time -= ccs_eom[r][m - 1];
708            stamp->year = y;
709            stamp->month = ++m;
710            stamp->day = ++time;
711    }
712    
713    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 23)
714    #if !defined(RHEL_VERSION) || RHEL_VERSION != 3
715    
716    /**
717     * PDE - Get "struct proc_dir_entry".
718     *
719     * @inode: Pointer to "struct inode".
720     *
721     * Returns pointer to "struct proc_dir_entry".
722     *
723     * This is for compatibility with older kernels.
724     */
725    static inline struct proc_dir_entry *PDE(const struct inode *inode)
726    {
727            return (struct proc_dir_entry *) inode->u.generic_ip;
728    }
729    
730    #endif
731    #endif
732    
733    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
734    
735    /**
736     * proc_notify_change - Update inode's attributes and reflect to the dentry.
737     *
738     * @dentry: Pointer to "struct dentry".
739     * @iattr:  Pointer to "struct iattr".
740     *
741     * Returns 0 on success, negative value otherwise.
742     *
743     * The 2.4 kernels don't allow chmod()/chown() for files in /proc,
744     * while the 2.6 kernels allow.
745     * To permit management of /proc/ccs/ interface by non-root user,
746     * I modified to allow chmod()/chown() of /proc/ccs/ interface like 2.6 kernels
747     * by adding "struct inode_operations"->setattr hook.
748     */
749    static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
750    {
751            struct inode *inode = dentry->d_inode;
752            struct proc_dir_entry *de = PDE(inode);
753            int error;
754    
755            error = inode_change_ok(inode, iattr);
756            if (error)
757                    goto out;
758    
759            error = inode_setattr(inode, iattr);
760            if (error)
761                    goto out;
762    
763            de->uid = inode->i_uid;
764            de->gid = inode->i_gid;
765            de->mode = inode->i_mode;
766    out:
767            return error;
768    }
769    
770    #endif
771    
772    #ifdef CONFIG_CCSECURITY_NETWORK
773    
774    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) && defined(CONFIG_NET)
775    #define ccs_in4_pton in4_pton
776    #define ccs_in6_pton in6_pton
777    #else
778    /*
779     * Routines for parsing IPv4 or IPv6 address.
780     * These are copied from lib/hexdump.c net/core/utils.c .
781     */
782    #include <linux/ctype.h>
783    
784    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
785    static int hex_to_bin(char ch)
786    {
787            if ((ch >= '0') && (ch <= '9'))
788                    return ch - '0';
789            ch = tolower(ch);
790            if ((ch >= 'a') && (ch <= 'f'))
791                    return ch - 'a' + 10;
792            return -1;
793    }
794    #endif
795    
796    #define IN6PTON_XDIGIT          0x00010000
797    #define IN6PTON_DIGIT           0x00020000
798    #define IN6PTON_COLON_MASK      0x00700000
799    #define IN6PTON_COLON_1         0x00100000      /* single : requested */
800    #define IN6PTON_COLON_2         0x00200000      /* second : requested */
801    #define IN6PTON_COLON_1_2       0x00400000      /* :: requested */
802    #define IN6PTON_DOT             0x00800000      /* . */
803    #define IN6PTON_DELIM           0x10000000
804    #define IN6PTON_NULL            0x20000000      /* first/tail */
805    #define IN6PTON_UNKNOWN         0x40000000
806    
807    static inline int xdigit2bin(char c, int delim)
808    {
809            int val;
810    
811            if (c == delim || c == '\0')
812                    return IN6PTON_DELIM;
813            if (c == ':')
814                    return IN6PTON_COLON_MASK;
815            if (c == '.')
816                    return IN6PTON_DOT;
817    
818            val = hex_to_bin(c);
819            if (val >= 0)
820                    return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0);
821    
822            if (delim == -1)
823                    return IN6PTON_DELIM;
824            return IN6PTON_UNKNOWN;
825    }
826    
827    static int ccs_in4_pton(const char *src, int srclen, u8 *dst, int delim,
828                            const char **end)
829    {
830            const char *s;
831            u8 *d;
832            u8 dbuf[4];
833            int ret = 0;
834            int i;
835            int w = 0;
836    
837            if (srclen < 0)
838                    srclen = strlen(src);
839            s = src;
840            d = dbuf;
841            i = 0;
842            while (1) {
843                    int c;
844                    c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
845                    if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM |
846                               IN6PTON_COLON_MASK)))
847                            goto out;
848                    if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
849                            if (w == 0)
850                                    goto out;
851                            *d++ = w & 0xff;
852                            w = 0;
853                            i++;
854                            if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
855                                    if (i != 4)
856                                            goto out;
857                                    break;
858                            }
859                            goto cont;
860                    }
861                    w = (w * 10) + c;
862                    if ((w & 0xffff) > 255)
863                            goto out;
864    cont:
865                    if (i >= 4)
866                            goto out;
867                    s++;
868                    srclen--;
869            }
870            ret = 1;
871            memcpy(dst, dbuf, sizeof(dbuf));
872    out:
873            if (end)
874                    *end = s;
875            return ret;
876    }
877    
878    static int ccs_in6_pton(const char *src, int srclen, u8 *dst, int delim,
879                            const char **end)
880    {
881            const char *s, *tok = NULL;
882            u8 *d, *dc = NULL;
883            u8 dbuf[16];
884            int ret = 0;
885            int i;
886            int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
887            int w = 0;
888    
889            memset(dbuf, 0, sizeof(dbuf));
890    
891            s = src;
892            d = dbuf;
893            if (srclen < 0)
894                    srclen = strlen(src);
895    
896            while (1) {
897                    int c;
898    
899                    c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
900                    if (!(c & state))
901                            goto out;
902                    if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
903                            /* process one 16-bit word */
904                            if (!(state & IN6PTON_NULL)) {
905                                    *d++ = (w >> 8) & 0xff;
906                                    *d++ = w & 0xff;
907                            }
908                            w = 0;
909                            if (c & IN6PTON_DELIM) {
910                                    /* We've processed last word */
911                                    break;
912                            }
913                            /*
914                             * COLON_1 => XDIGIT
915                             * COLON_2 => XDIGIT|DELIM
916                             * COLON_1_2 => COLON_2
917                             */
918                            switch (state & IN6PTON_COLON_MASK) {
919                            case IN6PTON_COLON_2:
920                                    dc = d;
921                                    state = IN6PTON_XDIGIT | IN6PTON_DELIM;
922                                    if (dc - dbuf >= sizeof(dbuf))
923                                            state |= IN6PTON_NULL;
924                                    break;
925                            case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
926                                    state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
927                                    break;
928                            case IN6PTON_COLON_1:
929                                    state = IN6PTON_XDIGIT;
930                                    break;
931                            case IN6PTON_COLON_1_2:
932                                    state = IN6PTON_COLON_2;
933                                    break;
934                            default:
935                                    state = 0;
936                            }
937                            tok = s + 1;
938                            goto cont;
939                    }
940    
941                    if (c & IN6PTON_DOT) {
942                            ret = ccs_in4_pton(tok ? tok : s, srclen +
943                                               (int)(s - tok), d, delim, &s);
944                            if (ret > 0) {
945                                    d += 4;
946                                    break;
947                            }
948                            goto out;
949                    }
950    
951                    w = (w << 4) | (0xff & c);
952                    state = IN6PTON_COLON_1 | IN6PTON_DELIM;
953                    if (!(w & 0xf000))
954                            state |= IN6PTON_XDIGIT;
955                    if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
956                            state |= IN6PTON_COLON_1_2;
957                            state &= ~IN6PTON_DELIM;
958                    }
959                    if (d + 2 >= dbuf + sizeof(dbuf))
960                            state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
961    cont:
962                    if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
963                        d + 4 == dbuf + sizeof(dbuf))
964                            state |= IN6PTON_DOT;
965                    if (d >= dbuf + sizeof(dbuf))
966                            state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
967                    s++;
968                    srclen--;
969            }
970    
971            i = 15; d--;
972    
973            if (dc) {
974                    while (d >= dc)
975                            dst[i--] = *d--;
976                    while (i >= dc - dbuf)
977                            dst[i--] = 0;
978                    while (i >= 0)
979                            dst[i--] = *d--;
980            } else
981                    memcpy(dst, dbuf, sizeof(dbuf));
982    
983            ret = 1;
984    out:
985            if (end)
986                    *end = s;
987            return ret;
988    }
989    #endif
990    
991    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32)
992    
993    /*
994     * Routines for printing IPv4 or IPv6 address.
995     * These are copied from include/linux/kernel.h include/net/ipv6.h
996     * include/net/addrconf.h lib/hexdump.c lib/vsprintf.c and simplified.
997     */
998    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
999    static const char hex_asc[] = "0123456789abcdef";
1000    #define hex_asc_lo(x)   hex_asc[((x) & 0x0f)]
1001    #define hex_asc_hi(x)   hex_asc[((x) & 0xf0) >> 4]
1002    
1003    static inline char *pack_hex_byte(char *buf, u8 byte)
1004    {
1005            *buf++ = hex_asc_hi(byte);
1006            *buf++ = hex_asc_lo(byte);
1007            return buf;
1008    }
1009    #endif
1010    
1011    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
1012    static inline int ipv6_addr_v4mapped(const struct in6_addr *a)
1013    {
1014            return (a->s6_addr32[0] | a->s6_addr32[1] |
1015                    (a->s6_addr32[2] ^ htonl(0x0000ffff))) == 0;
1016    }
1017    #endif
1018    
1019    static inline int ipv6_addr_is_isatap(const struct in6_addr *addr)
1020    {
1021            return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE);
1022    }
1023    
1024    static char *ip4_string(char *p, const u8 *addr)
1025    {
1026            /*
1027             * Since this function is called outside vsnprintf(), I can use
1028             * sprintf() here.
1029             */
1030            return p +
1031                    sprintf(p, "%u.%u.%u.%u", addr[0], addr[1], addr[2], addr[3]);
1032    }
1033    
1034    static char *ip6_compressed_string(char *p, const char *addr)
1035    {
1036            int i, j, range;
1037            unsigned char zerolength[8];
1038            int longest = 1;
1039            int colonpos = -1;
1040            u16 word;
1041            u8 hi, lo;
1042            bool needcolon = false;
1043            bool useIPv4;
1044            struct in6_addr in6;
1045    
1046            memcpy(&in6, addr, sizeof(struct in6_addr));
1047    
1048            useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6);
1049    
1050            memset(zerolength, 0, sizeof(zerolength));
1051    
1052            if (useIPv4)
1053                    range = 6;
1054            else
1055                    range = 8;
1056    
1057            /* find position of longest 0 run */
1058            for (i = 0; i < range; i++) {
1059                    for (j = i; j < range; j++) {
1060                            if (in6.s6_addr16[j] != 0)
1061                                    break;
1062                            zerolength[i]++;
1063                    }
1064            }
1065            for (i = 0; i < range; i++) {
1066                    if (zerolength[i] > longest) {
1067                            longest = zerolength[i];
1068                            colonpos = i;
1069                    }
1070            }
1071            if (longest == 1)               /* don't compress a single 0 */
1072                    colonpos = -1;
1073    
1074            /* emit address */
1075            for (i = 0; i < range; i++) {
1076                    if (i == colonpos) {
1077                            if (needcolon || i == 0)
1078                                    *p++ = ':';
1079                            *p++ = ':';
1080                            needcolon = false;
1081                            i += longest - 1;
1082                            continue;
1083                    }
1084                    if (needcolon) {
1085                            *p++ = ':';
1086                            needcolon = false;
1087                    }
1088                    /* hex u16 without leading 0s */
1089                    word = ntohs(in6.s6_addr16[i]);
1090                    hi = word >> 8;
1091                    lo = word & 0xff;
1092                    if (hi) {
1093                            if (hi > 0x0f)
1094                                    p = pack_hex_byte(p, hi);
1095                            else
1096                                    *p++ = hex_asc_lo(hi);
1097                            p = pack_hex_byte(p, lo);
1098                    } else if (lo > 0x0f)
1099                            p = pack_hex_byte(p, lo);
1100                    else
1101                            *p++ = hex_asc_lo(lo);
1102                    needcolon = true;
1103            }
1104    
1105            if (useIPv4) {
1106                    if (needcolon)
1107                            *p++ = ':';
1108                    p = ip4_string(p, &in6.s6_addr[12]);
1109            }
1110            *p = '\0';
1111    
1112            return p;
1113    }
1114    #endif
1115    
1116    /**
1117     * ccs_print_ipv4 - Print an IPv4 address.
1118     *
1119     * @buffer:     Buffer to write to.
1120     * @buffer_len: Size of @buffer.
1121     * @ip:         Pointer to "u32 in network byte order".
1122     *
1123     * Returns written length.
1124     */
1125    static int ccs_print_ipv4(char *buffer, const unsigned int buffer_len,
1126                              const u32 *ip)
1127    {
1128    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
1129            return snprintf(buffer, buffer_len, "%pI4", ip);
1130    #else
1131            char addr[sizeof("255.255.255.255")];
1132            ip4_string(addr, (const u8 *) ip);
1133            return snprintf(buffer, buffer_len, "%s", addr);
1134    #endif
1135    }
1136    
1137    /**
1138     * ccs_print_ipv6 - Print an IPv6 address.
1139     *
1140     * @buffer:     Buffer to write to.
1141     * @buffer_len: Size of @buffer.
1142     * @ip:         Pointer to "struct in6_addr".
1143     *
1144     * Returns written length.
1145     */
1146    static int ccs_print_ipv6(char *buffer, const unsigned int buffer_len,
1147                              const struct in6_addr *ip)
1148    {
1149    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
1150            return snprintf(buffer, buffer_len, "%pI6c", ip);
1151    #else
1152            char addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
1153            ip6_compressed_string(addr, (const u8 *) ip);
1154            return snprintf(buffer, buffer_len, "%s", addr);
1155    #endif
1156    }
1157    
1158    /**
1159     * ccs_print_ip - Print an IP address.
1160     *
1161     * @buf:  Buffer to write to.
1162     * @size: Size of @buf.
1163     * @ptr:  Pointer to "struct ipaddr_union".
1164     *
1165     * Returns nothing.
1166     */
1167    static void ccs_print_ip(char *buf, const unsigned int size,
1168                             const struct ccs_ipaddr_union *ptr)
1169    {
1170            int len;
1171            if (ptr->is_ipv6)
1172                    len = ccs_print_ipv6(buf, size, &ptr->ip[0]);
1173            else
1174                    len = ccs_print_ipv4(buf, size, &ptr->ip[0].s6_addr32[0]);
1175            if (!memcmp(&ptr->ip[0], &ptr->ip[1], 16) || len >= size / 2)
1176                    return;
1177            buf[len++] = '-';
1178            if (ptr->is_ipv6)
1179                    ccs_print_ipv6(buf + len, size - len, &ptr->ip[1]);
1180            else
1181                    ccs_print_ipv4(buf + len, size - len,
1182                                   &ptr->ip[1].s6_addr32[0]);
1183    }
1184    
1185    #endif
1186    
1187    /***** SECTION5: Variables definition section *****/
1188    
1189  /* Permit policy management by non-root user? */  /* Permit policy management by non-root user? */
1190  static bool ccs_manage_by_non_root;  static bool ccs_manage_by_non_root;
1191    
1192    /* Lock for protecting policy. */
1193    DEFINE_MUTEX(ccs_policy_lock);
1194    
1195    /* Has /sbin/init started? */
1196    bool ccs_policy_loaded;
1197    
1198    /* List of namespaces. */
1199    LIST_HEAD(ccs_namespace_list);
1200    /* True if namespace other than ccs_kernel_namespace is defined. */
1201    static bool ccs_namespace_enabled;
1202    
1203    /* Initial namespace.*/
1204    static struct ccs_policy_namespace ccs_kernel_namespace;
1205    
1206    /* List of "struct ccs_condition". */
1207    LIST_HEAD(ccs_condition_list);
1208    
1209    #ifdef CONFIG_CCSECURITY_PORTRESERVE
1210    /* Bitmap for reserved local port numbers.*/
1211    static u8 ccs_reserved_port_map[8192];
1212    #endif
1213    
1214    /* Wait queue for kernel -> userspace notification. */
1215    static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait);
1216    /* Wait queue for userspace -> kernel notification. */
1217    static DECLARE_WAIT_QUEUE_HEAD(ccs_answer_wait);
1218    
1219    /* The list for "struct ccs_query". */
1220    static LIST_HEAD(ccs_query_list);
1221    
1222    /* Lock for manipulating ccs_query_list. */
1223    static DEFINE_SPINLOCK(ccs_query_list_lock);
1224    
1225    /* Number of "struct file" referring /proc/ccs/query interface. */
1226    static atomic_t ccs_query_observers = ATOMIC_INIT(0);
1227    
1228    /* Wait queue for /proc/ccs/audit. */
1229    static DECLARE_WAIT_QUEUE_HEAD(ccs_log_wait);
1230    
1231    /* The list for "struct ccs_log". */
1232    static LIST_HEAD(ccs_log);
1233    
1234    /* Lock for "struct list_head ccs_log". */
1235    static DEFINE_SPINLOCK(ccs_log_lock);
1236    
1237    /* Length of "stuct list_head ccs_log". */
1238    static unsigned int ccs_log_count;
1239    
1240    /* Timestamp counter for last updated. */
1241    static unsigned int ccs_stat_updated[CCS_MAX_POLICY_STAT];
1242    
1243    /* Counter for number of updates. */
1244    static unsigned int ccs_stat_modified[CCS_MAX_POLICY_STAT];
1245    
1246    /* Operations for /proc/ccs/self_domain interface. */
1247    static
1248    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
1249    const
1250    #endif
1251    struct file_operations ccs_self_operations = {
1252    #ifdef CONFIG_CCSECURITY_TASK_DOMAIN_TRANSITION
1253            .write = ccs_write_self,
1254    #endif
1255            .read  = ccs_read_self,
1256    };
1257    
1258    /* Operations for /proc/ccs/ interface. */
1259    static
1260    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17)
1261    const
1262    #endif
1263    struct file_operations ccs_operations = {
1264            .open    = ccs_open,
1265            .release = ccs_release,
1266            .poll    = ccs_poll,
1267            .read    = ccs_read,
1268            .write   = ccs_write,
1269    };
1270    
1271    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
1272    
1273    /* The inode operations for /proc/ccs/ directory. */
1274    static struct inode_operations ccs_dir_inode_operations;
1275    
1276    /* The inode operations for files under /proc/ccs/ directory. */
1277    static struct inode_operations ccs_file_inode_operations;
1278    
1279    #endif
1280    
1281    /***** SECTION6: Dependent functions section *****/
1282    
1283    /**
1284     * list_for_each_cookie - iterate over a list with cookie.
1285     *
1286     * @pos:  Pointer to "struct list_head".
1287     * @head: Pointer to "struct list_head".
1288     */
1289    #define list_for_each_cookie(pos, head)                                 \
1290            for (pos = pos ? pos : srcu_dereference((head)->next, &ccs_ss); \
1291                 pos != (head); pos = srcu_dereference(pos->next, &ccs_ss))
1292    
1293    /**
1294     * ccs_read_token - Read a word from a line.
1295     *
1296     * @param: Pointer to "struct ccs_acl_param".
1297     *
1298     * Returns a word on success, "" otherwise.
1299     *
1300     * To allow the caller to skip NULL check, this function returns "" rather than
1301     * NULL if there is no more words to read.
1302     */
1303    static char *ccs_read_token(struct ccs_acl_param *param)
1304    {
1305            char *pos = param->data;
1306            char *del = strchr(pos, ' ');
1307            if (del)
1308                    *del++ = '\0';
1309            else
1310                    del = pos + strlen(pos);
1311            param->data = del;
1312            return pos;
1313    }
1314    
1315    /**
1316     * ccs_make_byte - Make byte value from three octal characters.
1317     *
1318     * @c1: The first character.
1319     * @c2: The second character.
1320     * @c3: The third character.
1321     *
1322     * Returns byte value.
1323     */
1324    static u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3)
1325    {
1326            return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
1327    }
1328    
1329    /**
1330     * ccs_correct_word2 - Check whether the given string follows the naming rules.
1331     *
1332     * @string: The byte sequence to check. Not '\0'-terminated.
1333     * @len:    Length of @string.
1334     *
1335     * Returns true if @string follows the naming rules, false otherwise.
1336     */
1337    static bool ccs_correct_word2(const char *string, size_t len)
1338    {
1339            const char *const start = string;
1340            bool in_repetition = false;
1341            unsigned char c;
1342            unsigned char d;
1343            unsigned char e;
1344            if (!len)
1345                    goto out;
1346            while (len--) {
1347                    c = *string++;
1348                    if (c == '\\') {
1349                            if (!len--)
1350                                    goto out;
1351                            c = *string++;
1352                            switch (c) {
1353                            case '\\':  /* "\\" */
1354                                    continue;
1355                            case '$':   /* "\$" */
1356                            case '+':   /* "\+" */
1357                            case '?':   /* "\?" */
1358                            case '*':   /* "\*" */
1359                            case '@':   /* "\@" */
1360                            case 'x':   /* "\x" */
1361                            case 'X':   /* "\X" */
1362                            case 'a':   /* "\a" */
1363                            case 'A':   /* "\A" */
1364                            case '-':   /* "\-" */
1365                                    continue;
1366                            case '{':   /* "/\{" */
1367                                    if (string - 3 < start || *(string - 3) != '/')
1368                                            break;
1369                                    in_repetition = true;
1370                                    continue;
1371                            case '}':   /* "\}/" */
1372                                    if (*string != '/')
1373                                            break;
1374                                    if (!in_repetition)
1375                                            break;
1376                                    in_repetition = false;
1377                                    continue;
1378                            case '0':   /* "\ooo" */
1379                            case '1':
1380                            case '2':
1381                            case '3':
1382                                    if (!len-- || !len--)
1383                                            break;
1384                                    d = *string++;
1385                                    e = *string++;
1386                                    if (d < '0' || d > '7' || e < '0' || e > '7')
1387                                            break;
1388                                    c = ccs_make_byte(c, d, e);
1389                                    if (c <= ' ' || c >= 127)
1390                                            continue;
1391                            }
1392                            goto out;
1393                    } else if (in_repetition && c == '/') {
1394                            goto out;
1395                    } else if (c <= ' ' || c >= 127) {
1396                            goto out;
1397                    }
1398            }
1399            if (in_repetition)
1400                    goto out;
1401            return true;
1402    out:
1403            return false;
1404    }
1405    
1406    /**
1407     * ccs_correct_word - Check whether the given string follows the naming rules.
1408     *
1409     * @string: The string to check.
1410     *
1411     * Returns true if @string follows the naming rules, false otherwise.
1412     */
1413    static bool ccs_correct_word(const char *string)
1414    {
1415            return ccs_correct_word2(string, strlen(string));
1416    }
1417    
1418    /**
1419     * ccs_get_group - Allocate memory for "struct ccs_path_group"/"struct ccs_number_group"/"struct ccs_address_group".
1420     *
1421     * @param: Pointer to "struct ccs_acl_param".
1422     * @idx:   Index number.
1423     *
1424     * Returns pointer to "struct ccs_group" on success, NULL otherwise.
1425     */
1426    static struct ccs_group *ccs_get_group(struct ccs_acl_param *param,
1427                                           const u8 idx)
1428    {
1429            struct ccs_group e = { };
1430            struct ccs_group *group = NULL;
1431            struct list_head *list;
1432            const char *group_name = ccs_read_token(param);
1433            bool found = false;
1434            if (!ccs_correct_word(group_name) || idx >= CCS_MAX_GROUP)
1435                    return NULL;
1436            e.group_name = ccs_get_name(group_name);
1437            if (!e.group_name)
1438                    return NULL;
1439            if (mutex_lock_interruptible(&ccs_policy_lock))
1440                    goto out;
1441            list = &param->ns->group_list[idx];
1442            list_for_each_entry(group, list, head.list) {
1443                    if (e.group_name != group->group_name ||
1444                        atomic_read(&group->head.users) == CCS_GC_IN_PROGRESS)
1445                            continue;
1446                    atomic_inc(&group->head.users);
1447                    found = true;
1448                    break;
1449            }
1450            if (!found) {
1451                    struct ccs_group *entry = ccs_commit_ok(&e, sizeof(e));
1452                    if (entry) {
1453                            INIT_LIST_HEAD(&entry->member_list);
1454                            atomic_set(&entry->head.users, 1);
1455                            list_add_tail_rcu(&entry->head.list, list);
1456                            group = entry;
1457                            found = true;
1458                    }
1459            }
1460            mutex_unlock(&ccs_policy_lock);
1461    out:
1462            ccs_put_name(e.group_name);
1463            return found ? group : NULL;
1464    }
1465    
1466    /**
1467     * ccs_parse_name_union - Parse a ccs_name_union.
1468     *
1469     * @param: Pointer to "struct ccs_acl_param".
1470     * @ptr:   Pointer to "struct ccs_name_union".
1471     *
1472     * Returns true on success, false otherwise.
1473     */
1474    static bool ccs_parse_name_union(struct ccs_acl_param *param,
1475                                     struct ccs_name_union *ptr)
1476    {
1477            char *filename;
1478            if (param->data[0] == '@') {
1479                    param->data++;
1480                    ptr->group = ccs_get_group(param, CCS_PATH_GROUP);
1481                    return ptr->group != NULL;
1482            }
1483            filename = ccs_read_token(param);
1484            if (!ccs_correct_word(filename))
1485                    return false;
1486            ptr->filename = ccs_get_name(filename);
1487            return ptr->filename != NULL;
1488    }
1489    
1490    /**
1491     * ccs_parse_ulong - Parse an "unsigned long" value.
1492     *
1493     * @result: Pointer to "unsigned long".
1494     * @str:    Pointer to string to parse.
1495     *
1496     * Returns one of values in "enum ccs_value_type".
1497     *
1498     * The @src is updated to point the first character after the value
1499     * on success.
1500     */
1501    static u8 ccs_parse_ulong(unsigned long *result, char **str)
1502    {
1503            const char *cp = *str;
1504            char *ep;
1505            int base = 10;
1506            if (*cp == '0') {
1507                    char c = *(cp + 1);
1508                    if (c == 'x' || c == 'X') {
1509                            base = 16;
1510                            cp += 2;
1511                    } else if (c >= '0' && c <= '7') {
1512                            base = 8;
1513                            cp++;
1514                    }
1515            }
1516            *result = simple_strtoul(cp, &ep, base);
1517            if (cp == ep)
1518                    return CCS_VALUE_TYPE_INVALID;
1519            *str = ep;
1520            switch (base) {
1521            case 16:
1522                    return CCS_VALUE_TYPE_HEXADECIMAL;
1523            case 8:
1524                    return CCS_VALUE_TYPE_OCTAL;
1525            default:
1526                    return CCS_VALUE_TYPE_DECIMAL;
1527            }
1528    }
1529    
1530    /**
1531     * ccs_parse_number_union - Parse a ccs_number_union.
1532     *
1533     * @param: Pointer to "struct ccs_acl_param".
1534     * @ptr:   Pointer to "struct ccs_number_union".
1535     *
1536     * Returns true on success, false otherwise.
1537     */
1538    static bool ccs_parse_number_union(struct ccs_acl_param *param,
1539                                       struct ccs_number_union *ptr)
1540    {
1541            char *data;
1542            u8 type;
1543            unsigned long v;
1544            memset(ptr, 0, sizeof(*ptr));
1545            if (param->data[0] == '@') {
1546                    param->data++;
1547                    ptr->group = ccs_get_group(param, CCS_NUMBER_GROUP);
1548                    return ptr->group != NULL;
1549            }
1550            data = ccs_read_token(param);
1551            type = ccs_parse_ulong(&v, &data);
1552            if (type == CCS_VALUE_TYPE_INVALID)
1553                    return false;
1554            ptr->values[0] = v;
1555            ptr->value_type[0] = type;
1556            if (!*data) {
1557                    ptr->values[1] = v;
1558                    ptr->value_type[1] = type;
1559                    return true;
1560            }
1561            if (*data++ != '-')
1562                    return false;
1563            type = ccs_parse_ulong(&v, &data);
1564            if (type == CCS_VALUE_TYPE_INVALID || *data || ptr->values[0] > v)
1565                    return false;
1566            ptr->values[1] = v;
1567            ptr->value_type[1] = type;
1568            return true;
1569    }
1570    
1571    #ifdef CONFIG_CCSECURITY_NETWORK
1572    
1573    /**
1574     * ccs_parse_ipaddr_union - Parse an IP address.
1575     *
1576     * @param: Pointer to "struct ccs_acl_param".
1577     * @ptr:   Pointer to "struct ccs_ipaddr_union".
1578     *
1579     * Returns true on success, false otherwise.
1580     */
1581    static bool ccs_parse_ipaddr_union(struct ccs_acl_param *param,
1582                                       struct ccs_ipaddr_union *ptr)
1583    {
1584            u8 * const min = ptr->ip[0].in6_u.u6_addr8;
1585            u8 * const max = ptr->ip[1].in6_u.u6_addr8;
1586            char *address = ccs_read_token(param);
1587            const char *end;
1588            if (!strchr(address, ':') &&
1589                ccs_in4_pton(address, -1, min, '-', &end) > 0) {
1590                    ptr->is_ipv6 = false;
1591                    if (!*end)
1592                            ptr->ip[1].s6_addr32[0] = ptr->ip[0].s6_addr32[0];
1593                    else if (*end++ != '-' ||
1594                             ccs_in4_pton(end, -1, max, '\0', &end) <= 0 || *end)
1595                            return false;
1596                    return true;
1597            }
1598            if (ccs_in6_pton(address, -1, min, '-', &end) > 0) {
1599                    ptr->is_ipv6 = true;
1600                    if (!*end)
1601                            memmove(max, min, sizeof(u16) * 8);
1602                    else if (*end++ != '-' ||
1603                             ccs_in6_pton(end, -1, max, '\0', &end) <= 0 || *end)
1604                            return false;
1605                    return true;
1606            }
1607            return false;
1608    }
1609    
1610    #endif
1611    
1612    /**
1613     * ccs_get_dqword - ccs_get_name() for a quoted string.
1614     *
1615     * @start: String to save.
1616     *
1617     * Returns pointer to "struct ccs_path_info" on success, NULL otherwise.
1618     */
1619    static const struct ccs_path_info *ccs_get_dqword(char *start)
1620    {
1621            char *cp = start + strlen(start) - 1;
1622            if (cp == start || *start++ != '"' || *cp != '"')
1623                    return NULL;
1624            *cp = '\0';
1625            if (*start && !ccs_correct_word(start))
1626                    return NULL;
1627            return ccs_get_name(start);
1628    }
1629    
1630    /**
1631     * ccs_parse_name_union_quoted - Parse a quoted word.
1632     *
1633     * @param: Pointer to "struct ccs_acl_param".
1634     * @ptr:   Pointer to "struct ccs_name_union".
1635     *
1636     * Returns true on success, false otherwise.
1637     */
1638    static bool ccs_parse_name_union_quoted(struct ccs_acl_param *param,
1639                                            struct ccs_name_union *ptr)
1640    {
1641            char *filename = param->data;
1642            if (*filename == '@')
1643                    return ccs_parse_name_union(param, ptr);
1644            ptr->filename = ccs_get_dqword(filename);
1645            return ptr->filename != NULL;
1646    }
1647    
1648    /**
1649     * ccs_parse_argv - Parse an argv[] condition part.
1650     *
1651     * @left:  Lefthand value.
1652     * @right: Righthand value.
1653     * @argv:  Pointer to "struct ccs_argv".
1654     *
1655     * Returns true on success, false otherwise.
1656     */
1657    static bool ccs_parse_argv(char *left, char *right, struct ccs_argv *argv)
1658    {
1659            if (ccs_parse_ulong(&argv->index, &left) != CCS_VALUE_TYPE_DECIMAL ||
1660                *left++ != ']' || *left)
1661                    return false;
1662            argv->value = ccs_get_dqword(right);
1663            return argv->value != NULL;
1664    }
1665    
1666    /**
1667     * ccs_parse_envp - Parse an envp[] condition part.
1668     *
1669     * @left:  Lefthand value.
1670     * @right: Righthand value.
1671     * @envp:  Pointer to "struct ccs_envp".
1672     *
1673     * Returns true on success, false otherwise.
1674     */
1675    static bool ccs_parse_envp(char *left, char *right, struct ccs_envp *envp)
1676    {
1677            const struct ccs_path_info *name;
1678            const struct ccs_path_info *value;
1679            char *cp = left + strlen(left) - 1;
1680            if (*cp-- != ']' || *cp != '"')
1681                    goto out;
1682            *cp = '\0';
1683            if (!ccs_correct_word(left))
1684                    goto out;
1685            name = ccs_get_name(left);
1686            if (!name)
1687                    goto out;
1688            if (!strcmp(right, "NULL")) {
1689                    value = NULL;
1690            } else {
1691                    value = ccs_get_dqword(right);
1692                    if (!value) {
1693                            ccs_put_name(name);
1694                            goto out;
1695                    }
1696            }
1697            envp->name = name;
1698            envp->value = value;
1699            return true;
1700    out:
1701            return false;
1702    }
1703    
1704    /**
1705     * ccs_same_condition - Check for duplicated "struct ccs_condition" entry.
1706     *
1707     * @a: Pointer to "struct ccs_condition".
1708     * @b: Pointer to "struct ccs_condition".
1709     *
1710     * Returns true if @a == @b, false otherwise.
1711     */
1712    static bool ccs_same_condition(const struct ccs_condition *a,
1713                                   const struct ccs_condition *b)
1714    {
1715            return a->size == b->size && a->condc == b->condc &&
1716                    a->numbers_count == b->numbers_count &&
1717                    a->names_count == b->names_count &&
1718                    a->argc == b->argc && a->envc == b->envc &&
1719                    a->grant_log == b->grant_log &&
1720                    a->exec_transit == b->exec_transit && a->transit == b->transit
1721                    && !memcmp(a + 1, b + 1, a->size - sizeof(*a));
1722    }
1723    
1724    /**
1725     * ccs_condition_type - Get condition type.
1726     *
1727     * @word: Keyword string.
1728     *
1729     * Returns one of values in "enum ccs_conditions_index" on success,
1730     * CCS_MAX_CONDITION_KEYWORD otherwise.
1731     */
1732    static u8 ccs_condition_type(const char *word)
1733    {
1734            u8 i;
1735            for (i = 0; i < CCS_MAX_CONDITION_KEYWORD; i++) {
1736                    if (!strcmp(word, ccs_condition_keyword[i]))
1737                            break;
1738            }
1739            return i;
1740    }
1741    
1742    /**
1743     * ccs_commit_condition - Commit "struct ccs_condition".
1744     *
1745     * @entry: Pointer to "struct ccs_condition".
1746     *
1747     * Returns pointer to "struct ccs_condition" on success, NULL otherwise.
1748     *
1749     * This function merges duplicated entries. This function returns NULL if
1750     * @entry is not duplicated but memory quota for policy has exceeded.
1751     */
1752    static struct ccs_condition *ccs_commit_condition(struct ccs_condition *entry)
1753    {
1754            struct ccs_condition *ptr;
1755            bool found = false;
1756            if (mutex_lock_interruptible(&ccs_policy_lock)) {
1757                    dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
1758                    ptr = NULL;
1759                    found = true;
1760                    goto out;
1761            }
1762            list_for_each_entry(ptr, &ccs_condition_list, head.list) {
1763                    if (!ccs_same_condition(ptr, entry) ||
1764                        atomic_read(&ptr->head.users) == CCS_GC_IN_PROGRESS)
1765                            continue;
1766                    /* Same entry found. Share this entry. */
1767                    atomic_inc(&ptr->head.users);
1768                    found = true;
1769                    break;
1770            }
1771            if (!found) {
1772                    if (ccs_memory_ok(entry, entry->size)) {
1773                            atomic_set(&entry->head.users, 1);
1774                            list_add(&entry->head.list, &ccs_condition_list);
1775                    } else {
1776                            found = true;
1777                            ptr = NULL;
1778                    }
1779            }
1780            mutex_unlock(&ccs_policy_lock);
1781    out:
1782            if (found) {
1783                    ccs_del_condition(&entry->head.list);
1784                    kfree(entry);
1785                    entry = ptr;
1786            }
1787            return entry;
1788    }
1789    
1790    /**
1791     * ccs_correct_path - Check whether the given pathname follows the naming rules.
1792     *
1793     * @filename: The pathname to check.
1794     *
1795     * Returns true if @filename follows the naming rules, false otherwise.
1796     */
1797    static bool ccs_correct_path(const char *filename)
1798    {
1799            return *filename == '/' && ccs_correct_word(filename);
1800    }
1801    
1802    /**
1803     * ccs_domain_def - Check whether the given token can be a domainname.
1804     *
1805     * @buffer: The token to check.
1806     *
1807     * Returns true if @buffer possibly be a domainname, false otherwise.
1808     */
1809    static bool ccs_domain_def(const unsigned char *buffer)
1810    {
1811            const unsigned char *cp;
1812            int len;
1813            if (*buffer != '<')
1814                    return false;
1815            cp = strchr(buffer, ' ');
1816            if (!cp)
1817                    len = strlen(buffer);
1818            else
1819                    len = cp - buffer;
1820            if (buffer[len - 1] != '>' || !ccs_correct_word2(buffer + 1, len - 2))
1821                    return false;
1822            return true;
1823    }
1824    
1825    /**
1826     * ccs_correct_domain - Check whether the given domainname follows the naming rules.
1827     *
1828     * @domainname: The domainname to check.
1829     *
1830     * Returns true if @domainname follows the naming rules, false otherwise.
1831     */
1832    static bool ccs_correct_domain(const unsigned char *domainname)
1833    {
1834            if (!domainname || !ccs_domain_def(domainname))
1835                    return false;
1836            domainname = strchr(domainname, ' ');
1837            if (!domainname++)
1838                    return true;
1839            while (1) {
1840                    const unsigned char *cp = strchr(domainname, ' ');
1841                    if (!cp)
1842                            break;
1843                    if (*domainname != '/' ||
1844                        !ccs_correct_word2(domainname, cp - domainname))
1845                            return false;
1846                    domainname = cp + 1;
1847            }
1848            return ccs_correct_path(domainname);
1849    }
1850    
1851    /**
1852     * ccs_normalize_line - Format string.
1853     *
1854     * @buffer: The line to normalize.
1855     *
1856     * Returns nothing.
1857     *
1858     * Leading and trailing whitespaces are removed.
1859     * Multiple whitespaces are packed into single space.
1860     */
1861    static void ccs_normalize_line(unsigned char *buffer)
1862    {
1863            unsigned char *sp = buffer;
1864            unsigned char *dp = buffer;
1865            bool first = true;
1866            while (*sp && (*sp <= ' ' || *sp >= 127))
1867                    sp++;
1868            while (*sp) {
1869                    if (!first)
1870                            *dp++ = ' ';
1871                    first = false;
1872                    while (*sp > ' ' && *sp < 127)
1873                            *dp++ = *sp++;
1874                    while (*sp && (*sp <= ' ' || *sp >= 127))
1875                            sp++;
1876            }
1877            *dp = '\0';
1878    }
1879    
1880  /**  /**
1881   * ccs_cap2keyword - Convert capability operation to capability name.   * ccs_get_domainname - Read a domainname from a line.
1882   *   *
1883   * @operation: The capability index.   * @param: Pointer to "struct ccs_acl_param".
1884   *   *
1885   * Returns the name of the specified capability's name.   * Returns a domainname on success, NULL otherwise.
1886   */   */
1887  const char *ccs_cap2keyword(const u8 operation)  static const struct ccs_path_info *ccs_get_domainname
1888    (struct ccs_acl_param *param)
1889  {  {
1890          return operation < CCS_MAX_CAPABILITY_INDEX          char *start = param->data;
1891                  ? ccs_mac_keywords[CCS_MAX_MAC_INDEX + operation] + 12 : NULL;          char *pos = start;
1892            while (*pos) {
1893                    if (*pos++ != ' ' || *pos++ == '/')
1894                            continue;
1895                    pos -= 2;
1896                    *pos++ = '\0';
1897                    break;
1898            }
1899            param->data = pos;
1900            if (ccs_correct_domain(start))
1901                    return ccs_get_name(start);
1902            return NULL;
1903    }
1904    
1905    /**
1906     * ccs_get_transit_preference - Parse domain transition preference for execve().
1907     *
1908     * @param: Pointer to "struct ccs_acl_param".
1909     * @e:     Pointer to "struct ccs_condition".
1910     *
1911     * Returns the condition string part.
1912     */
1913    static char *ccs_get_transit_preference(struct ccs_acl_param *param,
1914                                            struct ccs_condition *e)
1915    {
1916            char * const pos = param->data;
1917            bool flag;
1918            if (*pos == '<') {
1919                    e->transit = ccs_get_domainname(param);
1920                    goto done;
1921            }
1922            {
1923                    char *cp = strchr(pos, ' ');
1924                    if (cp)
1925                            *cp = '\0';
1926                    flag = ccs_correct_path(pos) || !strcmp(pos, "keep") ||
1927                            !strcmp(pos, "initialize") || !strcmp(pos, "reset") ||
1928                            !strcmp(pos, "child") || !strcmp(pos, "parent");
1929                    if (cp)
1930                            *cp = ' ';
1931            }
1932            if (!flag)
1933                    return pos;
1934            e->transit = ccs_get_name(ccs_read_token(param));
1935    done:
1936            if (e->transit) {
1937                    e->exec_transit = true;
1938                    return param->data;
1939            }
1940            /*
1941             * Return a bad read-only condition string that will let
1942             * ccs_get_condition() return NULL.
1943             */
1944            return "/";
1945    }
1946    
1947    /**
1948     * ccs_get_condition - Parse condition part.
1949     *
1950     * @param: Pointer to "struct ccs_acl_param".
1951     *
1952     * Returns pointer to "struct ccs_condition" on success, NULL otherwise.
1953     */
1954    struct ccs_condition *ccs_get_condition(struct ccs_acl_param *param)
1955    {
1956            struct ccs_condition *entry = NULL;
1957            struct ccs_condition_element *condp = NULL;
1958            struct ccs_number_union *numbers_p = NULL;
1959            struct ccs_name_union *names_p = NULL;
1960            struct ccs_argv *argv = NULL;
1961            struct ccs_envp *envp = NULL;
1962            struct ccs_condition e = { };
1963            char * const start_of_string = ccs_get_transit_preference(param, &e);
1964            char * const end_of_string = start_of_string + strlen(start_of_string);
1965            char *pos;
1966    rerun:
1967            pos = start_of_string;
1968            while (1) {
1969                    u8 left = -1;
1970                    u8 right = -1;
1971                    char *left_word = pos;
1972                    char *cp;
1973                    char *right_word;
1974                    bool is_not;
1975                    if (!*left_word)
1976                            break;
1977                    /*
1978                     * Since left-hand condition does not allow use of "path_group"
1979                     * or "number_group" and environment variable's names do not
1980                     * accept '=', it is guaranteed that the original line consists
1981                     * of one or more repetition of $left$operator$right blocks
1982                     * where "$left is free from '=' and ' '" and "$operator is
1983                     * either '=' or '!='" and "$right is free from ' '".
1984                     * Therefore, we can reconstruct the original line at the end
1985                     * of dry run even if we overwrite $operator with '\0'.
1986                     */
1987                    cp = strchr(pos, ' ');
1988                    if (cp) {
1989                            *cp = '\0'; /* Will restore later. */
1990                            pos = cp + 1;
1991                    } else {
1992                            pos = "";
1993                    }
1994                    right_word = strchr(left_word, '=');
1995                    if (!right_word || right_word == left_word)
1996                            goto out;
1997                    is_not = *(right_word - 1) == '!';
1998                    if (is_not)
1999                            *(right_word++ - 1) = '\0'; /* Will restore later. */
2000                    else if (*(right_word + 1) != '=')
2001                            *right_word++ = '\0'; /* Will restore later. */
2002                    else
2003                            goto out;
2004                    dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
2005                            is_not ? "!" : "", right_word);
2006                    if (!strcmp(left_word, "grant_log")) {
2007                            if (entry) {
2008                                    if (is_not ||
2009                                        entry->grant_log != CCS_GRANTLOG_AUTO)
2010                                            goto out;
2011                                    else if (!strcmp(right_word, "yes"))
2012                                            entry->grant_log = CCS_GRANTLOG_YES;
2013                                    else if (!strcmp(right_word, "no"))
2014                                            entry->grant_log = CCS_GRANTLOG_NO;
2015                                    else
2016                                            goto out;
2017                            }
2018                            continue;
2019                    }
2020                    if (!strcmp(left_word, "auto_domain_transition")) {
2021                            if (entry) {
2022                                    if (is_not || entry->transit)
2023                                            goto out;
2024                                    entry->transit = ccs_get_dqword(right_word);
2025                                    if (!entry->transit ||
2026                                        (entry->transit->name[0] != '/' &&
2027                                         !ccs_domain_def(entry->transit->name)))
2028                                            goto out;
2029                            }
2030                            continue;
2031                    }
2032                    if (!strncmp(left_word, "exec.argv[", 10)) {
2033                            if (!argv) {
2034                                    e.argc++;
2035                                    e.condc++;
2036                            } else {
2037                                    e.argc--;
2038                                    e.condc--;
2039                                    left = CCS_ARGV_ENTRY;
2040                                    argv->is_not = is_not;
2041                                    if (!ccs_parse_argv(left_word + 10,
2042                                                        right_word, argv++))
2043                                            goto out;
2044                            }
2045                            goto store_value;
2046                    }
2047                    if (!strncmp(left_word, "exec.envp[\"", 11)) {
2048                            if (!envp) {
2049                                    e.envc++;
2050                                    e.condc++;
2051                            } else {
2052                                    e.envc--;
2053                                    e.condc--;
2054                                    left = CCS_ENVP_ENTRY;
2055                                    envp->is_not = is_not;
2056                                    if (!ccs_parse_envp(left_word + 11,
2057                                                        right_word, envp++))
2058                                            goto out;
2059                            }
2060                            goto store_value;
2061                    }
2062                    left = ccs_condition_type(left_word);
2063                    dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
2064                            left);
2065                    if (left == CCS_MAX_CONDITION_KEYWORD) {
2066                            if (!numbers_p) {
2067                                    e.numbers_count++;
2068                            } else {
2069                                    e.numbers_count--;
2070                                    left = CCS_NUMBER_UNION;
2071                                    param->data = left_word;
2072                                    if (*left_word == '@' ||
2073                                        !ccs_parse_number_union(param,
2074                                                                numbers_p++))
2075                                            goto out;
2076                            }
2077                    }
2078                    if (!condp)
2079                            e.condc++;
2080                    else
2081                            e.condc--;
2082                    if (left == CCS_EXEC_REALPATH || left == CCS_SYMLINK_TARGET) {
2083                            if (!names_p) {
2084                                    e.names_count++;
2085                            } else {
2086                                    e.names_count--;
2087                                    right = CCS_NAME_UNION;
2088                                    param->data = right_word;
2089                                    if (!ccs_parse_name_union_quoted(param,
2090                                                                     names_p++))
2091                                            goto out;
2092                            }
2093                            goto store_value;
2094                    }
2095                    right = ccs_condition_type(right_word);
2096                    if (right == CCS_MAX_CONDITION_KEYWORD) {
2097                            if (!numbers_p) {
2098                                    e.numbers_count++;
2099                            } else {
2100                                    e.numbers_count--;
2101                                    right = CCS_NUMBER_UNION;
2102                                    param->data = right_word;
2103                                    if (!ccs_parse_number_union(param,
2104                                                                numbers_p++))
2105                                            goto out;
2106                            }
2107                    }
2108    store_value:
2109                    if (!condp) {
2110                            dprintk(KERN_WARNING "%u: dry_run left=%u right=%u "
2111                                    "match=%u\n", __LINE__, left, right, !is_not);
2112                            continue;
2113                    }
2114                    condp->left = left;
2115                    condp->right = right;
2116                    condp->equals = !is_not;
2117                    dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
2118                            __LINE__, condp->left, condp->right,
2119                            condp->equals);
2120                    condp++;
2121            }
2122            dprintk(KERN_INFO "%u: cond=%u numbers=%u names=%u ac=%u ec=%u\n",
2123                    __LINE__, e.condc, e.numbers_count, e.names_count, e.argc,
2124                    e.envc);
2125            if (entry) {
2126                    BUG_ON(e.names_count | e.numbers_count | e.argc | e.envc |
2127                           e.condc);
2128                    return ccs_commit_condition(entry);
2129            }
2130            e.size = sizeof(*entry)
2131                    + e.condc * sizeof(struct ccs_condition_element)
2132                    + e.numbers_count * sizeof(struct ccs_number_union)
2133                    + e.names_count * sizeof(struct ccs_name_union)
2134                    + e.argc * sizeof(struct ccs_argv)
2135                    + e.envc * sizeof(struct ccs_envp);
2136            entry = kzalloc(e.size, CCS_GFP_FLAGS);
2137            if (!entry)
2138                    goto out2;
2139            *entry = e;
2140            e.transit = NULL;
2141            condp = (struct ccs_condition_element *) (entry + 1);
2142            numbers_p = (struct ccs_number_union *) (condp + e.condc);
2143            names_p = (struct ccs_name_union *) (numbers_p + e.numbers_count);
2144            argv = (struct ccs_argv *) (names_p + e.names_count);
2145            envp = (struct ccs_envp *) (argv + e.argc);
2146            {
2147                    bool flag = false;
2148                    for (pos = start_of_string; pos < end_of_string; pos++) {
2149                            if (*pos)
2150                                    continue;
2151                            if (flag) /* Restore " ". */
2152                                    *pos = ' ';
2153                            else if (*(pos + 1) == '=') /* Restore "!=". */
2154                                    *pos = '!';
2155                            else /* Restore "=". */
2156                                    *pos = '=';
2157                            flag = !flag;
2158                    }
2159            }
2160            goto rerun;
2161    out:
2162            dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
2163            if (entry) {
2164                    ccs_del_condition(&entry->head.list);
2165                    kfree(entry);
2166            }
2167    out2:
2168            ccs_put_name(e.transit);
2169            return NULL;
2170  }  }
2171    
2172  /**  /**
2173   * ccs_yesno - Return "yes" or "no".   * ccs_yesno - Return "yes" or "no".
2174   *   *
2175   * @value: Bool value.   * @value: Bool value.
2176     *
2177     * Returns "yes" if @value is not 0, "no" otherwise.
2178   */   */
2179  static const char *ccs_yesno(const unsigned int value)  static const char *ccs_yesno(const unsigned int value)
2180  {  {
# Line 219  static const char *ccs_yesno(const unsig Line 2182  static const char *ccs_yesno(const unsig
2182  }  }
2183    
2184  /**  /**
2185   * ccs_io_printf - Transactional printf() to "struct ccs_io_buffer" structure.   * ccs_addprintf - strncat()-like-snprintf().
2186     *
2187     * @buffer: Buffer to write to. Must be '\0'-terminated.
2188     * @len:    Size of @buffer.
2189     * @fmt:    The printf()'s format string, followed by parameters.
2190     *
2191     * Returns nothing.
2192     */
2193    static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)
2194    {
2195            va_list args;
2196            const int pos = strlen(buffer);
2197            va_start(args, fmt);
2198            vsnprintf(buffer + pos, len - pos - 1, fmt, args);
2199            va_end(args);
2200    }
2201    
2202    /**
2203     * ccs_flush - Flush queued string to userspace's buffer.
2204   *   *
2205   * @head: Pointer to "struct ccs_io_buffer".   * @head: Pointer to "struct ccs_io_buffer".
  * @fmt:  The printf()'s format string, followed by parameters.  
2206   *   *
2207   * Returns true on success, false otherwise.   * Returns true if all data was flushed, false otherwise.
2208     */
2209    static bool ccs_flush(struct ccs_io_buffer *head)
2210    {
2211            while (head->r.w_pos) {
2212                    const char *w = head->r.w[0];
2213                    size_t len = strlen(w);
2214                    if (len) {
2215                            if (len > head->read_user_buf_avail)
2216                                    len = head->read_user_buf_avail;
2217                            if (!len)
2218                                    return false;
2219                            if (copy_to_user(head->read_user_buf, w, len))
2220                                    return false;
2221                            head->read_user_buf_avail -= len;
2222                            head->read_user_buf += len;
2223                            w += len;
2224                    }
2225                    head->r.w[0] = w;
2226                    if (*w)
2227                            return false;
2228                    /* Add '\0' for audit logs and query. */
2229                    if (head->type == CCS_AUDIT || head->type == CCS_QUERY) {
2230                            if (!head->read_user_buf_avail ||
2231                                copy_to_user(head->read_user_buf, "", 1))
2232                                    return false;
2233                            head->read_user_buf_avail--;
2234                            head->read_user_buf++;
2235                    }
2236                    head->r.w_pos--;
2237                    for (len = 0; len < head->r.w_pos; len++)
2238                            head->r.w[len] = head->r.w[len + 1];
2239            }
2240            head->r.avail = 0;
2241            return true;
2242    }
2243    
2244    /**
2245     * ccs_set_string - Queue string to "struct ccs_io_buffer" structure.
2246     *
2247     * @head:   Pointer to "struct ccs_io_buffer".
2248     * @string: String to print.
2249     *
2250     * Returns nothing.
2251     *
2252     * Note that @string has to be kept valid until @head is kfree()d.
2253     * This means that char[] allocated on stack memory cannot be passed to
2254     * this function. Use ccs_io_printf() for char[] allocated on stack memory.
2255     */
2256    static void ccs_set_string(struct ccs_io_buffer *head, const char *string)
2257    {
2258            if (head->r.w_pos < CCS_MAX_IO_READ_QUEUE) {
2259                    head->r.w[head->r.w_pos++] = string;
2260                    ccs_flush(head);
2261            } else
2262                    printk(KERN_WARNING "Too many words in a line.\n");
2263    }
2264    
2265    /**
2266     * ccs_io_printf - printf() to "struct ccs_io_buffer" structure.
2267     *
2268     * @head: Pointer to "struct ccs_io_buffer".
2269     * @fmt:  The printf()'s format string, followed by parameters.
2270   *   *
2271   * The snprintf() will truncate, but ccs_io_printf() won't.   * Returns nothing.
2272   */   */
2273  bool ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)  static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
2274  {  {
2275          va_list args;          va_list args;
2276          int len;          size_t len;
2277          int pos = head->read_avail;          size_t pos = head->r.avail;
2278          int size = head->readbuf_size - pos;          int size = head->readbuf_size - pos;
2279          if (size <= 0)          if (size <= 0)
2280                  return false;                  return;
2281          va_start(args, fmt);          va_start(args, fmt);
2282          len = vsnprintf(head->read_buf + pos, size, fmt, args);          len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
2283          va_end(args);          va_end(args);
2284          if (pos + len >= head->readbuf_size)          if (pos + len >= head->readbuf_size) {
2285                  return false;                  printk(KERN_WARNING "Too many words in a line.\n");
2286          head->read_avail += len;                  return;
2287          return true;          }
2288            head->r.avail += len;
2289            ccs_set_string(head, head->read_buf + pos);
2290    }
2291    
2292    /**
2293     * ccs_set_space - Put a space to "struct ccs_io_buffer" structure.
2294     *
2295     * @head: Pointer to "struct ccs_io_buffer".
2296     *
2297     * Returns nothing.
2298     */
2299    static void ccs_set_space(struct ccs_io_buffer *head)
2300    {
2301            ccs_set_string(head, " ");
2302    }
2303    
2304    /**
2305     * ccs_set_lf - Put a line feed to "struct ccs_io_buffer" structure.
2306     *
2307     * @head: Pointer to "struct ccs_io_buffer".
2308     *
2309     * Returns true if all data was flushed, false otherwise.
2310     */
2311    static bool ccs_set_lf(struct ccs_io_buffer *head)
2312    {
2313            ccs_set_string(head, "\n");
2314            return !head->r.w_pos;
2315    }
2316    
2317    /**
2318     * ccs_set_slash - Put a shash to "struct ccs_io_buffer" structure.
2319     *
2320     * @head: Pointer to "struct ccs_io_buffer".
2321     *
2322     * Returns nothing.
2323     */
2324    static void ccs_set_slash(struct ccs_io_buffer *head)
2325    {
2326            ccs_set_string(head, "/");
2327    }
2328    
2329    /**
2330     * ccs_init_policy_namespace - Initialize namespace.
2331     *
2332     * @ns: Pointer to "struct ccs_policy_namespace".
2333     *
2334     * Returns nothing.
2335     */
2336    static void ccs_init_policy_namespace(struct ccs_policy_namespace *ns)
2337    {
2338            unsigned int idx;
2339            for (idx = 0; idx < CCS_MAX_ACL_GROUPS; idx++)
2340                    INIT_LIST_HEAD(&ns->acl_group[idx]);
2341            for (idx = 0; idx < CCS_MAX_GROUP; idx++)
2342                    INIT_LIST_HEAD(&ns->group_list[idx]);
2343            for (idx = 0; idx < CCS_MAX_POLICY; idx++)
2344                    INIT_LIST_HEAD(&ns->policy_list[idx]);
2345            ns->profile_version = 20100903;
2346            ccs_namespace_enabled = !list_empty(&ccs_namespace_list);
2347            list_add_tail_rcu(&ns->namespace_list, &ccs_namespace_list);
2348    }
2349    
2350    /**
2351     * ccs_print_namespace - Print namespace header.
2352     *
2353     * @head: Pointer to "struct ccs_io_buffer".
2354     *
2355     * Returns nothing.
2356     */
2357    static void ccs_print_namespace(struct ccs_io_buffer *head)
2358    {
2359            if (!ccs_namespace_enabled)
2360                    return;
2361            ccs_set_string(head,
2362                           container_of(head->r.ns, struct ccs_policy_namespace,
2363                                        namespace_list)->name);
2364            ccs_set_space(head);
2365  }  }
2366    
2367  /**  /**
2368   * ccs_find_or_assign_new_profile - Create a new profile.   * ccs_assign_profile - Create a new profile.
2369   *   *
2370     * @ns:      Pointer to "struct ccs_policy_namespace".
2371   * @profile: Profile number to create.   * @profile: Profile number to create.
2372   *   *
2373   * Returns pointer to "struct ccs_profile" on success, NULL otherwise.   * Returns pointer to "struct ccs_profile" on success, NULL otherwise.
2374   */   */
2375  static struct ccs_profile *ccs_find_or_assign_new_profile(const unsigned int  static struct ccs_profile *ccs_assign_profile(struct ccs_policy_namespace *ns,
2376                                                            profile)                                                const unsigned int profile)
2377  {  {
2378          struct ccs_profile *ptr;          struct ccs_profile *ptr;
2379          struct ccs_profile *entry;          struct ccs_profile *entry;
2380          if (profile >= CCS_MAX_PROFILES)          if (profile >= CCS_MAX_PROFILES)
2381                  return NULL;                  return NULL;
2382          ptr = ccs_profile_ptr[profile];          ptr = ns->profile_ptr[profile];
2383          if (ptr)          if (ptr)
2384                  return ptr;                  return ptr;
2385          entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);          entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
2386          mutex_lock(&ccs_policy_lock);          if (mutex_lock_interruptible(&ccs_policy_lock))
2387          ptr = ccs_profile_ptr[profile];                  goto out;
2388            ptr = ns->profile_ptr[profile];
2389          if (!ptr && ccs_memory_ok(entry, sizeof(*entry))) {          if (!ptr && ccs_memory_ok(entry, sizeof(*entry))) {
2390                  ptr = entry;                  ptr = entry;
                 ptr->audit = &ccs_default_profile.preference;  
                 ptr->learning = &ccs_default_profile.preference;  
                 ptr->permissive = &ccs_default_profile.preference;  
                 ptr->enforcing = &ccs_default_profile.preference;  
2391                  ptr->default_config = CCS_CONFIG_DISABLED |                  ptr->default_config = CCS_CONFIG_DISABLED |
2392                          CCS_CONFIG_WANT_GRANT_LOG | CCS_CONFIG_WANT_REJECT_LOG;                          CCS_CONFIG_WANT_GRANT_LOG | CCS_CONFIG_WANT_REJECT_LOG;
2393                  memset(ptr->config, CCS_CONFIG_USE_DEFAULT,                  memset(ptr->config, CCS_CONFIG_USE_DEFAULT,
2394                         sizeof(ptr->config));                         sizeof(ptr->config));
2395                    ptr->pref[CCS_PREF_MAX_AUDIT_LOG] =
2396                            CONFIG_CCSECURITY_MAX_AUDIT_LOG;
2397                    ptr->pref[CCS_PREF_MAX_LEARNING_ENTRY] =
2398                            CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY;
2399                  mb(); /* Avoid out-of-order execution. */                  mb(); /* Avoid out-of-order execution. */
2400                  ccs_profile_ptr[profile] = ptr;                  ns->profile_ptr[profile] = ptr;
2401                  entry = NULL;                  entry = NULL;
2402          }          }
2403          mutex_unlock(&ccs_policy_lock);          mutex_unlock(&ccs_policy_lock);
2404    out:
2405          kfree(entry);          kfree(entry);
2406          return ptr;          return ptr;
2407  }  }
2408    
2409  /**  /**
2410   * ccs_check_profile - Check all profiles currently assigned to domains are defined.   * ccs_check_profile - Check all profiles currently assigned to domains are defined.
2411     *
2412     * Returns nothing.
2413   */   */
2414  static void ccs_check_profile(void)  static void ccs_check_profile(void)
2415  {  {
2416          struct ccs_domain_info *domain;          struct ccs_domain_info *domain;
2417            const int idx = ccs_read_lock();
2418          ccs_policy_loaded = true;          ccs_policy_loaded = true;
2419          list_for_each_entry_rcu(domain, &ccs_domain_list, list) {          printk(KERN_INFO "CCSecurity: 1.8.3+   2012/02/29\n");
2420            list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
2421                  const u8 profile = domain->profile;                  const u8 profile = domain->profile;
2422                  if (ccs_profile_ptr[profile])                  const struct ccs_policy_namespace *ns = domain->ns;
2423                    if (ns->profile_version != 20100903)
2424                            printk(KERN_ERR
2425                                   "Profile version %u is not supported.\n",
2426                                   ns->profile_version);
2427                    else if (!ns->profile_ptr[profile])
2428                            printk(KERN_ERR
2429                                   "Profile %u (used by '%s') is not defined.\n",
2430                                   profile, domain->domainname->name);
2431                    else
2432                          continue;                          continue;
2433                  panic("Profile %u (used by '%s') not defined.\n",                  printk(KERN_ERR
2434                        profile, domain->domainname->name);                         "Userland tools for TOMOYO 1.8 must be installed and "
2435                           "policy must be initialized.\n");
2436                    printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/1.8/ "
2437                           "for more information.\n");
2438                    panic("STOP!");
2439          }          }
2440          if (ccs_profile_version != 20090903)          ccs_read_unlock(idx);
                 panic("Profile version %u is not supported.\n",  
                       ccs_profile_version);  
         printk(KERN_INFO "CCSecurity: 1.7.2-pre   2010/03/08\n");  
2441          printk(KERN_INFO "Mandatory Access Control activated.\n");          printk(KERN_INFO "Mandatory Access Control activated.\n");
2442  }  }
2443    
# Line 312  static void ccs_check_profile(void) Line 2448  static void ccs_check_profile(void)
2448   *   *
2449   * Returns pointer to "struct ccs_profile".   * Returns pointer to "struct ccs_profile".
2450   */   */
2451  struct ccs_profile *ccs_profile(const u8 profile)  static struct ccs_profile *ccs_profile(const u8 profile)
2452  {  {
2453          struct ccs_profile *ptr = ccs_profile_ptr[profile];          static struct ccs_profile ccs_null_profile;
2454          if (!ccs_policy_loaded)          struct ccs_profile *ptr = ccs_current_namespace()->
2455                  return &ccs_default_profile;                  profile_ptr[profile];
2456          BUG_ON(!ptr);          if (!ptr)
2457                    ptr = &ccs_null_profile;
2458          return ptr;          return ptr;
2459  }  }
2460    
2461  /**  /**
2462   * ccs_write_profile - Write profile table.   * ccs_get_config - Get config for specified profile's specified functionality.
2463   *   *
2464   * @head: Pointer to "struct ccs_io_buffer".   * @profile: Profile number.
2465     * @index:   Index number of functionality.
2466   *   *
2467   * Returns 0 on success, negative value otherwise.   * Returns config.
2468     *
2469     * First, check for CONFIG::category::functionality.
2470     * If CONFIG::category::functionality is set to use default, then check
2471     * CONFIG::category. If CONFIG::category is set to use default, then use
2472     * CONFIG. CONFIG cannot be set to use default.
2473   */   */
2474  static int ccs_write_profile(struct ccs_io_buffer *head)  u8 ccs_get_config(const u8 profile, const u8 index)
2475  {  {
         char *data = head->write_buf;  
         unsigned int i;  
         int value;  
         int mode;  
2476          u8 config;          u8 config;
2477          bool use_default = false;          const struct ccs_profile *p;
2478          char *cp;          if (!ccs_policy_loaded)
2479          struct ccs_profile *profile;                  return CCS_CONFIG_DISABLED;
2480          if (sscanf(data, "PROFILE_VERSION=%u", &ccs_profile_version) == 1)          p = ccs_profile(profile);
2481                  return 0;          config = p->config[index];
2482          i = simple_strtoul(data, &cp, 10);          if (config == CCS_CONFIG_USE_DEFAULT)
2483          if (data == cp) {                  config = p->config[ccs_index2category[index]
2484                  profile = &ccs_default_profile;                                     + CCS_MAX_MAC_INDEX];
2485          } else {          if (config == CCS_CONFIG_USE_DEFAULT)
2486                  if (*cp != '-')                  config = p->default_config;
2487                          return -EINVAL;          return config;
2488                  data = cp + 1;  }
2489                  profile = ccs_find_or_assign_new_profile(i);  
2490                  if (!profile)  /**
2491                          return -EINVAL;   * ccs_find_yesno - Find values for specified keyword.
2492          }   *
2493          cp = strchr(data, '=');   * @string: String to check.
2494          if (!cp)   * @find:   Name of keyword.
2495                  return -EINVAL;   *
2496          *cp++ = '\0';   * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise.
2497          if (profile != &ccs_default_profile)   */
2498                  use_default = strstr(cp, "use_default") != NULL;  static s8 ccs_find_yesno(const char *string, const char *find)
2499          if (strstr(cp, "verbose=yes"))  {
2500                  value = 1;          const char *cp = strstr(string, find);
2501          else if (strstr(cp, "verbose=no"))          if (cp) {
2502                  value = 0;                  cp += strlen(find);
2503          else                  if (!strncmp(cp, "=yes", 4))
2504                  value = -1;                          return 1;
2505          if (!strcmp(data, "PREFERENCE::audit")) {                  else if (!strncmp(cp, "=no", 3))
 #ifdef CONFIG_CCSECURITY_AUDIT  
                 char *cp2;  
 #endif  
                 if (use_default) {  
                         profile->audit = &ccs_default_profile.preference;  
                         return 0;  
                 }  
                 profile->audit = &profile->preference;  
 #ifdef CONFIG_CCSECURITY_AUDIT  
                 cp2 = strstr(cp, "max_grant_log=");  
                 if (cp2)  
                         sscanf(cp2 + 14, "%u",  
                                &profile->preference.audit_max_grant_log);  
                 cp2 = strstr(cp, "max_reject_log=");  
                 if (cp2)  
                         sscanf(cp2 + 15, "%u",  
                                &profile->preference.audit_max_reject_log);  
 #endif  
                 if (strstr(cp, "task_info=yes"))  
                         profile->preference.audit_task_info = true;  
                 else if (strstr(cp, "task_info=no"))  
                         profile->preference.audit_task_info = false;  
                 if (strstr(cp, "path_info=yes"))  
                         profile->preference.audit_path_info = true;  
                 else if (strstr(cp, "path_info=no"))  
                         profile->preference.audit_path_info = false;  
                 return 0;  
         }  
         if (!strcmp(data, "PREFERENCE::enforcing")) {  
                 char *cp2;  
                 if (use_default) {  
                         profile->enforcing = &ccs_default_profile.preference;  
                         return 0;  
                 }  
                 profile->enforcing = &profile->preference;  
                 if (value >= 0)  
                         profile->preference.enforcing_verbose = value;  
                 cp2 = strstr(cp, "penalty=");  
                 if (cp2)  
                         sscanf(cp2 + 8, "%u",  
                                &profile->preference.enforcing_penalty);  
                 return 0;  
         }  
         if (!strcmp(data, "PREFERENCE::permissive")) {  
                 if (use_default) {  
                         profile->permissive = &ccs_default_profile.preference;  
                         return 0;  
                 }  
                 profile->permissive = &profile->preference;  
                 if (value >= 0)  
                         profile->preference.permissive_verbose = value;  
                 return 0;  
         }  
         if (!strcmp(data, "PREFERENCE::learning")) {  
                 char *cp2;  
                 if (use_default) {  
                         profile->learning = &ccs_default_profile.preference;  
2506                          return 0;                          return 0;
                 }  
                 profile->learning = &profile->preference;  
                 if (value >= 0)  
                         profile->preference.learning_verbose = value;  
                 cp2 = strstr(cp, "max_entry=");  
                 if (cp2)  
                         sscanf(cp2 + 10, "%u",  
                                &profile->preference.learning_max_entry);  
                 if (strstr(cp, "exec.realpath=yes"))  
                         profile->preference.learning_exec_realpath = true;  
                 else if (strstr(cp, "exec.realpath=no"))  
                         profile->preference.learning_exec_realpath = false;  
                 if (strstr(cp, "exec.argv0=yes"))  
                         profile->preference.learning_exec_argv0 = true;  
                 else if (strstr(cp, "exec.argv0=no"))  
                         profile->preference.learning_exec_argv0 = false;  
                 if (strstr(cp, "symlink.target=yes"))  
                         profile->preference.learning_symlink_target = true;  
                 else if (strstr(cp, "symlink.target=no"))  
                         profile->preference.learning_symlink_target = false;  
                 return 0;  
2507          }          }
2508          if (profile == &ccs_default_profile)          return -1;
2509                  return -EINVAL;  }
2510          if (!strcmp(data, "COMMENT")) {  
2511                  const struct ccs_path_info *old_comment = profile->comment;  /**
2512                  profile->comment = ccs_get_name(cp);   * ccs_set_uint - Set value for specified preference.
2513                  ccs_put_name(old_comment);   *
2514                  return 0;   * @i:      Pointer to "unsigned int".
2515     * @string: String to check.
2516     * @find:   Name of keyword.
2517     *
2518     * Returns nothing.
2519     */
2520    static void ccs_set_uint(unsigned int *i, const char *string, const char *find)
2521    {
2522            const char *cp = strstr(string, find);
2523            if (cp)
2524                    sscanf(cp + strlen(find), "=%u", i);
2525    }
2526    
2527    /**
2528     * ccs_str_starts - Check whether the given string starts with the given keyword.
2529     *
2530     * @src:  Pointer to pointer to the string.
2531     * @find: Pointer to the keyword.
2532     *
2533     * Returns true if @src starts with @find, false otherwise.
2534     *
2535     * The @src is updated to point the first character after the @find
2536     * if @src starts with @find.
2537     */
2538    static bool ccs_str_starts(char **src, const char *find)
2539    {
2540            const int len = strlen(find);
2541            char *tmp = *src;
2542            if (strncmp(tmp, find, len))
2543                    return false;
2544            tmp += len;
2545            *src = tmp;
2546            return true;
2547    }
2548    
2549    /**
2550     * ccs_print_group - Print group's name.
2551     *
2552     * @head:  Pointer to "struct ccs_io_buffer".
2553     * @group: Pointer to "struct ccsgroup". Maybe NULL.
2554     *
2555     * Returns true if @group is not NULL. false otherwise.
2556     */
2557    static bool ccs_print_group(struct ccs_io_buffer *head,
2558                                const struct ccs_group *group)
2559    {
2560            if (group) {
2561                    ccs_set_string(head, "@");
2562                    ccs_set_string(head, group->group_name->name);
2563                    return true;
2564          }          }
2565          if (!strcmp(data, "CONFIG")) {          return false;
2566                  i = CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX  }
2567                          + CCS_MAX_MAC_CATEGORY_INDEX;  
2568    /**
2569     * ccs_set_mode - Set mode for specified profile.
2570     *
2571     * @name:    Name of functionality.
2572     * @value:   Mode for @name.
2573     * @profile: Pointer to "struct ccs_profile".
2574     *
2575     * Returns 0 on success, negative value otherwise.
2576     */
2577    static int ccs_set_mode(char *name, const char *value,
2578                            struct ccs_profile *profile)
2579    {
2580            u8 i;
2581            u8 config;
2582            if (!strcmp(name, "CONFIG")) {
2583                    i = CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
2584                  config = profile->default_config;                  config = profile->default_config;
2585          } else if (ccs_str_starts(&data, "CONFIG::")) {          } else if (ccs_str_starts(&name, "CONFIG::")) {
2586                  config = 0;                  config = 0;
2587                  for (i = 0; i < CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX                  for (i = 0; i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
2588                               + CCS_MAX_MAC_CATEGORY_INDEX; i++) {                       i++) {
2589                          if (strcmp(data, ccs_mac_keywords[i]))                          int len = 0;
2590                            if (i < CCS_MAX_MAC_INDEX) {
2591                                    const u8 c = ccs_index2category[i];
2592                                    const char *category =
2593                                            ccs_category_keywords[c];
2594                                    len = strlen(category);
2595                                    if (strncmp(name, category, len) ||
2596                                        name[len++] != ':' || name[len++] != ':')
2597                                            continue;
2598                            }
2599                            if (strcmp(name + len, ccs_mac_keywords[i]))
2600                                  continue;                                  continue;
2601                          config = profile->config[i];                          config = profile->config[i];
2602                          break;                          break;
2603                  }                  }
2604                  if (i == CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX                  if (i == CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
                     + CCS_MAX_MAC_CATEGORY_INDEX)  
2605                          return -EINVAL;                          return -EINVAL;
2606          } else {          } else {
2607                  return -EINVAL;                  return -EINVAL;
2608          }          }
2609          if (use_default) {          if (strstr(value, "use_default")) {
2610                  config = CCS_CONFIG_USE_DEFAULT;                  config = CCS_CONFIG_USE_DEFAULT;
2611          } else {          } else {
2612                  for (mode = 3; mode >= 0; mode--)                  u8 mode;
2613                          if (strstr(cp, ccs_mode_4[mode]))                  for (mode = 0; mode < CCS_CONFIG_MAX_MODE; mode++)
2614                            if (strstr(value, ccs_mode[mode]))
2615                                  /*                                  /*
2616                                   * Update lower 3 bits in order to distinguish                                   * Update lower 3 bits in order to distinguish
2617                                   * 'config' from 'CCS_CONFIG_USE_DEAFULT'.                                   * 'config' from 'CCS_CONFIG_USE_DEAFULT'.
2618                                   */                                   */
2619                                  config = (config & ~7) | mode;                                  config = (config & ~7) | mode;
 #ifdef CONFIG_CCSECURITY_AUDIT  
2620                  if (config != CCS_CONFIG_USE_DEFAULT) {                  if (config != CCS_CONFIG_USE_DEFAULT) {
2621                          if (strstr(cp, "grant_log=yes"))                          switch (ccs_find_yesno(value, "grant_log")) {
2622                            case 1:
2623                                  config |= CCS_CONFIG_WANT_GRANT_LOG;                                  config |= CCS_CONFIG_WANT_GRANT_LOG;
2624                          else if (strstr(cp, "grant_log=no"))                                  break;
2625                            case 0:
2626                                  config &= ~CCS_CONFIG_WANT_GRANT_LOG;                                  config &= ~CCS_CONFIG_WANT_GRANT_LOG;
2627                          if (strstr(cp, "reject_log=yes"))                                  break;
2628                            }
2629                            switch (ccs_find_yesno(value, "reject_log")) {
2630                            case 1:
2631                                  config |= CCS_CONFIG_WANT_REJECT_LOG;                                  config |= CCS_CONFIG_WANT_REJECT_LOG;
2632                          else if (strstr(cp, "reject_log=no"))                                  break;
2633                            case 0:
2634                                  config &= ~CCS_CONFIG_WANT_REJECT_LOG;                                  config &= ~CCS_CONFIG_WANT_REJECT_LOG;
2635                                    break;
2636                            }
2637                  }                  }
 #endif  
2638          }          }
2639          if (i < CCS_MAX_MAC_INDEX + CCS_MAX_CAPABILITY_INDEX          if (i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
             + CCS_MAX_MAC_CATEGORY_INDEX)  
2640                  profile->config[i] = config;                  profile->config[i] = config;
2641          else if (config != CCS_CONFIG_USE_DEFAULT)          else if (config != CCS_CONFIG_USE_DEFAULT)
2642                  profile->default_config = config;                  profile->default_config = config;
# Line 503  static int ccs_write_profile(struct ccs_ Line 2644  static int ccs_write_profile(struct ccs_
2644  }  }
2645    
2646  /**  /**