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

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