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

Subversion リポジトリの参照

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

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

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