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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5596 - (show annotations) (download) (as text)
Sun Nov 6 03:38:08 2011 UTC (12 years, 6 months ago) by kumaneko
File MIME type: text/x-csrc
File size: 135373 byte(s)


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