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

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