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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4724 - (show annotations) (download) (as text)
Tue Mar 15 05:23:03 2011 UTC (13 years, 2 months ago) by kumaneko
File MIME type: text/x-csrc
File size: 77548 byte(s)
Use packed policy for both input and output.
1 /*
2 * security/ccsecurity/policy_io.c
3 *
4 * Copyright (C) 2005-2011 NTT DATA CORPORATION
5 *
6 * Version: 1.8.0+ 2011/03/15
7 */
8
9 #include "internal.h"
10
11 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
12
13 /**
14 * __wait_event_interruptible_timeout - Sleep until a condition gets true or a timeout elapses.
15 *
16 * @wq: The waitqueue to wait on.
17 * @condition: A C expression for the event to wait for.
18 * @ret: Timeout, in jiffies.
19 *
20 * Returns 0 if the @timeout elapsed, -ERESTARTSYS if it was interrupted by a
21 * signal, and the remaining jiffies otherwise if the condition evaluated to
22 * true before the timeout elapsed.
23 *
24 * This is for compatibility with older kernels.
25 */
26 #define __wait_event_interruptible_timeout(wq, condition, ret) \
27 do { \
28 wait_queue_t __wait; \
29 init_waitqueue_entry(&__wait, current); \
30 \
31 add_wait_queue(&wq, &__wait); \
32 for (;;) { \
33 set_current_state(TASK_INTERRUPTIBLE); \
34 if (condition) \
35 break; \
36 if (!signal_pending(current)) { \
37 ret = schedule_timeout(ret); \
38 if (!ret) \
39 break; \
40 continue; \
41 } \
42 ret = -ERESTARTSYS; \
43 break; \
44 } \
45 current->state = TASK_RUNNING; \
46 remove_wait_queue(&wq, &__wait); \
47 } while (0)
48
49 /**
50 * wait_event_interruptible_timeout - Sleep until a condition gets true or a timeout elapses.
51 *
52 * @wq: The waitqueue to wait on.
53 * @condition: A C expression for the event to wait for.
54 * @timeout: Timeout, in jiffies.
55 *
56 * Returns 0 if the @timeout elapsed, -ERESTARTSYS if it was interrupted by a
57 * signal, and the remaining jiffies otherwise if the condition evaluated to
58 * true before the timeout elapsed.
59 *
60 * This is for compatibility with older kernels.
61 */
62 #define wait_event_interruptible_timeout(wq, condition, timeout) \
63 ({ \
64 long __ret = timeout; \
65 if (!(condition)) \
66 __wait_event_interruptible_timeout(wq, condition, __ret); \
67 __ret; \
68 })
69
70 #endif
71
72 /**
73 * list_for_each_cookie - iterate over a list with cookie.
74 *
75 * @pos: Pointer to "struct list_head".
76 * @head: Pointer to "struct list_head".
77 */
78 #define list_for_each_cookie(pos, head) \
79 for (pos = pos ? pos : srcu_dereference((head)->next, &ccs_ss); \
80 pos != (head); pos = srcu_dereference(pos->next, &ccs_ss))
81
82
83 /* Profile version. Currently only 20100903 is defined. */
84 static unsigned int ccs_profile_version;
85
86 /* Profile table. Memory is allocated as needed. */
87 static struct ccs_profile *ccs_profile_ptr[CCS_MAX_PROFILES];
88
89 /* String table for operation mode. */
90 const char * const ccs_mode[CCS_CONFIG_MAX_MODE] = {
91 [CCS_CONFIG_DISABLED] = "disabled",
92 [CCS_CONFIG_LEARNING] = "learning",
93 [CCS_CONFIG_PERMISSIVE] = "permissive",
94 [CCS_CONFIG_ENFORCING] = "enforcing"
95 };
96
97 /* String table for /proc/ccs/profile interface. */
98 const char * const ccs_mac_keywords[CCS_MAX_MAC_INDEX
99 + CCS_MAX_MAC_CATEGORY_INDEX] = {
100 /* CONFIG::file group */
101 [CCS_MAC_FILE_EXECUTE] = "execute",
102 [CCS_MAC_FILE_OPEN] = "open",
103 [CCS_MAC_FILE_CREATE] = "create",
104 [CCS_MAC_FILE_UNLINK] = "unlink",
105 [CCS_MAC_FILE_GETATTR] = "getattr",
106 [CCS_MAC_FILE_MKDIR] = "mkdir",
107 [CCS_MAC_FILE_RMDIR] = "rmdir",
108 [CCS_MAC_FILE_MKFIFO] = "mkfifo",
109 [CCS_MAC_FILE_MKSOCK] = "mksock",
110 [CCS_MAC_FILE_TRUNCATE] = "truncate",
111 [CCS_MAC_FILE_SYMLINK] = "symlink",
112 [CCS_MAC_FILE_MKBLOCK] = "mkblock",
113 [CCS_MAC_FILE_MKCHAR] = "mkchar",
114 [CCS_MAC_FILE_LINK] = "link",
115 [CCS_MAC_FILE_RENAME] = "rename",
116 [CCS_MAC_FILE_CHMOD] = "chmod",
117 [CCS_MAC_FILE_CHOWN] = "chown",
118 [CCS_MAC_FILE_CHGRP] = "chgrp",
119 [CCS_MAC_FILE_IOCTL] = "ioctl",
120 [CCS_MAC_FILE_CHROOT] = "chroot",
121 [CCS_MAC_FILE_MOUNT] = "mount",
122 [CCS_MAC_FILE_UMOUNT] = "unmount",
123 [CCS_MAC_FILE_PIVOT_ROOT] = "pivot_root",
124 /* CONFIG::misc group */
125 [CCS_MAC_ENVIRON] = "env",
126 /* CONFIG::network group */
127 [CCS_MAC_NETWORK_INET_STREAM_BIND] = "inet_stream_bind",
128 [CCS_MAC_NETWORK_INET_STREAM_LISTEN] = "inet_stream_listen",
129 [CCS_MAC_NETWORK_INET_STREAM_CONNECT] = "inet_stream_connect",
130 [CCS_MAC_NETWORK_INET_STREAM_ACCEPT] = "inet_stream_accept",
131 [CCS_MAC_NETWORK_INET_DGRAM_BIND] = "inet_dgram_bind",
132 [CCS_MAC_NETWORK_INET_DGRAM_SEND] = "inet_dgram_send",
133 [CCS_MAC_NETWORK_INET_DGRAM_RECV] = "inet_dgram_recv",
134 [CCS_MAC_NETWORK_INET_RAW_BIND] = "inet_raw_bind",
135 [CCS_MAC_NETWORK_INET_RAW_SEND] = "inet_raw_send",
136 [CCS_MAC_NETWORK_INET_RAW_RECV] = "inet_raw_recv",
137 [CCS_MAC_NETWORK_UNIX_STREAM_BIND] = "unix_stream_bind",
138 [CCS_MAC_NETWORK_UNIX_STREAM_LISTEN] = "unix_stream_listen",
139 [CCS_MAC_NETWORK_UNIX_STREAM_CONNECT] = "unix_stream_connect",
140 [CCS_MAC_NETWORK_UNIX_STREAM_ACCEPT] = "unix_stream_accept",
141 [CCS_MAC_NETWORK_UNIX_DGRAM_BIND] = "unix_dgram_bind",
142 [CCS_MAC_NETWORK_UNIX_DGRAM_SEND] = "unix_dgram_send",
143 [CCS_MAC_NETWORK_UNIX_DGRAM_RECV] = "unix_dgram_recv",
144 [CCS_MAC_NETWORK_UNIX_SEQPACKET_BIND] = "unix_seqpacket_bind",
145 [CCS_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = "unix_seqpacket_listen",
146 [CCS_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
147 [CCS_MAC_NETWORK_UNIX_SEQPACKET_ACCEPT] = "unix_seqpacket_accept",
148 /* CONFIG::ipc group */
149 [CCS_MAC_SIGNAL] = "signal",
150 /* CONFIG::capability group */
151 [CCS_MAC_CAPABILITY_USE_ROUTE_SOCKET] = "use_route",
152 [CCS_MAC_CAPABILITY_USE_PACKET_SOCKET] = "use_packet",
153 [CCS_MAC_CAPABILITY_SYS_REBOOT] = "SYS_REBOOT",
154 [CCS_MAC_CAPABILITY_SYS_VHANGUP] = "SYS_VHANGUP",
155 [CCS_MAC_CAPABILITY_SYS_SETTIME] = "SYS_TIME",
156 [CCS_MAC_CAPABILITY_SYS_NICE] = "SYS_NICE",
157 [CCS_MAC_CAPABILITY_SYS_SETHOSTNAME] = "SYS_SETHOSTNAME",
158 [CCS_MAC_CAPABILITY_USE_KERNEL_MODULE] = "use_kernel_module",
159 [CCS_MAC_CAPABILITY_SYS_KEXEC_LOAD] = "SYS_KEXEC_LOAD",
160 [CCS_MAC_CAPABILITY_SYS_PTRACE] = "SYS_PTRACE",
161 /* CONFIG group */
162 [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_FILE] = "file",
163 [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_NETWORK] = "network",
164 [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_MISC] = "misc",
165 [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_IPC] = "ipc",
166 [CCS_MAX_MAC_INDEX + CCS_MAC_CATEGORY_CAPABILITY] = "capability",
167 };
168
169 /* String table for path operation. */
170 const char * const ccs_path_keyword[CCS_MAX_PATH_OPERATION] = {
171 [CCS_TYPE_EXECUTE] = "execute",
172 [CCS_TYPE_READ] = "read",
173 [CCS_TYPE_WRITE] = "write",
174 [CCS_TYPE_APPEND] = "append",
175 [CCS_TYPE_UNLINK] = "unlink",
176 [CCS_TYPE_GETATTR] = "getattr",
177 [CCS_TYPE_RMDIR] = "rmdir",
178 [CCS_TYPE_TRUNCATE] = "truncate",
179 [CCS_TYPE_SYMLINK] = "symlink",
180 [CCS_TYPE_CHROOT] = "chroot",
181 [CCS_TYPE_UMOUNT] = "unmount",
182 };
183
184 /* String table for categories. */
185 static const char * const ccs_category_keywords[CCS_MAX_MAC_CATEGORY_INDEX] = {
186 [CCS_MAC_CATEGORY_FILE] = "file",
187 [CCS_MAC_CATEGORY_NETWORK] = "network",
188 [CCS_MAC_CATEGORY_MISC] = "misc",
189 [CCS_MAC_CATEGORY_IPC] = "ipc",
190 [CCS_MAC_CATEGORY_CAPABILITY] = "capability",
191 };
192
193 /* String table for conditions. */
194 const char * const ccs_condition_keyword[CCS_MAX_CONDITION_KEYWORD] = {
195 [CCS_TASK_UID] = "task.uid",
196 [CCS_TASK_EUID] = "task.euid",
197 [CCS_TASK_SUID] = "task.suid",
198 [CCS_TASK_FSUID] = "task.fsuid",
199 [CCS_TASK_GID] = "task.gid",
200 [CCS_TASK_EGID] = "task.egid",
201 [CCS_TASK_SGID] = "task.sgid",
202 [CCS_TASK_FSGID] = "task.fsgid",
203 [CCS_TASK_PID] = "task.pid",
204 [CCS_TASK_PPID] = "task.ppid",
205 [CCS_EXEC_ARGC] = "exec.argc",
206 [CCS_EXEC_ENVC] = "exec.envc",
207 [CCS_TYPE_IS_SOCKET] = "socket",
208 [CCS_TYPE_IS_SYMLINK] = "symlink",
209 [CCS_TYPE_IS_FILE] = "file",
210 [CCS_TYPE_IS_BLOCK_DEV] = "block",
211 [CCS_TYPE_IS_DIRECTORY] = "directory",
212 [CCS_TYPE_IS_CHAR_DEV] = "char",
213 [CCS_TYPE_IS_FIFO] = "fifo",
214 [CCS_MODE_SETUID] = "setuid",
215 [CCS_MODE_SETGID] = "setgid",
216 [CCS_MODE_STICKY] = "sticky",
217 [CCS_MODE_OWNER_READ] = "owner_read",
218 [CCS_MODE_OWNER_WRITE] = "owner_write",
219 [CCS_MODE_OWNER_EXECUTE] = "owner_execute",
220 [CCS_MODE_GROUP_READ] = "group_read",
221 [CCS_MODE_GROUP_WRITE] = "group_write",
222 [CCS_MODE_GROUP_EXECUTE] = "group_execute",
223 [CCS_MODE_OTHERS_READ] = "others_read",
224 [CCS_MODE_OTHERS_WRITE] = "others_write",
225 [CCS_MODE_OTHERS_EXECUTE] = "others_execute",
226 [CCS_TASK_TYPE] = "task.type",
227 [CCS_TASK_EXECUTE_HANDLER] = "execute_handler",
228 [CCS_EXEC_REALPATH] = "exec.realpath",
229 [CCS_SYMLINK_TARGET] = "symlink.target",
230 [CCS_PATH1_UID] = "path1.uid",
231 [CCS_PATH1_GID] = "path1.gid",
232 [CCS_PATH1_INO] = "path1.ino",
233 [CCS_PATH1_MAJOR] = "path1.major",
234 [CCS_PATH1_MINOR] = "path1.minor",
235 [CCS_PATH1_PERM] = "path1.perm",
236 [CCS_PATH1_TYPE] = "path1.type",
237 [CCS_PATH1_DEV_MAJOR] = "path1.dev_major",
238 [CCS_PATH1_DEV_MINOR] = "path1.dev_minor",
239 [CCS_PATH2_UID] = "path2.uid",
240 [CCS_PATH2_GID] = "path2.gid",
241 [CCS_PATH2_INO] = "path2.ino",
242 [CCS_PATH2_MAJOR] = "path2.major",
243 [CCS_PATH2_MINOR] = "path2.minor",
244 [CCS_PATH2_PERM] = "path2.perm",
245 [CCS_PATH2_TYPE] = "path2.type",
246 [CCS_PATH2_DEV_MAJOR] = "path2.dev_major",
247 [CCS_PATH2_DEV_MINOR] = "path2.dev_minor",
248 [CCS_PATH1_PARENT_UID] = "path1.parent.uid",
249 [CCS_PATH1_PARENT_GID] = "path1.parent.gid",
250 [CCS_PATH1_PARENT_INO] = "path1.parent.ino",
251 [CCS_PATH1_PARENT_PERM] = "path1.parent.perm",
252 [CCS_PATH2_PARENT_UID] = "path2.parent.uid",
253 [CCS_PATH2_PARENT_GID] = "path2.parent.gid",
254 [CCS_PATH2_PARENT_INO] = "path2.parent.ino",
255 [CCS_PATH2_PARENT_PERM] = "path2.parent.perm",
256 };
257
258 /* String table for PREFERENCE keyword. */
259 static const char * const ccs_pref_keywords[CCS_MAX_PREF] = {
260 [CCS_PREF_MAX_AUDIT_LOG] = "max_audit_log",
261 [CCS_PREF_MAX_LEARNING_ENTRY] = "max_learning_entry",
262 [CCS_PREF_ENFORCING_PENALTY] = "enforcing_penalty",
263 };
264
265 /* Permit policy management by non-root user? */
266 static bool ccs_manage_by_non_root;
267
268 /**
269 * ccs_yesno - Return "yes" or "no".
270 *
271 * @value: Bool value.
272 *
273 * Returns "yes" if @value is not 0, "no" otherwise.
274 */
275 const char *ccs_yesno(const unsigned int value)
276 {
277 return value ? "yes" : "no";
278 }
279
280 /* Prototype for ccs_addprintf(). */
281 static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)
282 __attribute__ ((format(printf, 3, 4)));
283
284 /**
285 * ccs_addprintf - strncat()-like-snprintf().
286 *
287 * @buffer: Buffer to write to. Must be '\0'-terminated.
288 * @len: Size of @buffer.
289 * @fmt: The printf()'s format string, followed by parameters.
290 *
291 * Returns nothing.
292 */
293 static void ccs_addprintf(char *buffer, int len, const char *fmt, ...)
294 {
295 va_list args;
296 const int pos = strlen(buffer);
297 va_start(args, fmt);
298 vsnprintf(buffer + pos, len - pos - 1, fmt, args);
299 va_end(args);
300 }
301
302 /**
303 * ccs_flush - Flush queued string to userspace's buffer.
304 *
305 * @head: Pointer to "struct ccs_io_buffer".
306 *
307 * Returns true if all data was flushed, false otherwise.
308 */
309 static bool ccs_flush(struct ccs_io_buffer *head)
310 {
311 while (head->r.w_pos) {
312 const char *w = head->r.w[0];
313 size_t len = strlen(w);
314 if (len) {
315 if (len > head->read_user_buf_avail)
316 len = head->read_user_buf_avail;
317 if (!len)
318 return false;
319 if (copy_to_user(head->read_user_buf, w, len))
320 return false;
321 head->read_user_buf_avail -= len;
322 head->read_user_buf += len;
323 w += len;
324 }
325 head->r.w[0] = w;
326 if (*w)
327 return false;
328 /* Add '\0' for audit logs and query. */
329 if (head->poll) {
330 if (!head->read_user_buf_avail ||
331 copy_to_user(head->read_user_buf, "", 1))
332 return false;
333 head->read_user_buf_avail--;
334 head->read_user_buf++;
335 }
336 head->r.w_pos--;
337 for (len = 0; len < head->r.w_pos; len++)
338 head->r.w[len] = head->r.w[len + 1];
339 }
340 head->r.avail = 0;
341 return true;
342 }
343
344 /**
345 * ccs_set_string - Queue string to "struct ccs_io_buffer" structure.
346 *
347 * @head: Pointer to "struct ccs_io_buffer".
348 * @string: String to print.
349 *
350 * Returns nothing.
351 *
352 * Note that @string has to be kept valid until @head is kfree()d.
353 * This means that char[] allocated on stack memory cannot be passed to
354 * this function. Use ccs_io_printf() for char[] allocated on stack memory.
355 */
356 static void ccs_set_string(struct ccs_io_buffer *head, const char *string)
357 {
358 if (head->r.w_pos < CCS_MAX_IO_READ_QUEUE) {
359 head->r.w[head->r.w_pos++] = string;
360 ccs_flush(head);
361 } else
362 printk(KERN_WARNING "Too many words in a line.\n");
363 }
364
365 /* Prototype for ccs_io_printf(). */
366 static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
367 __attribute__ ((format(printf, 2, 3)));
368
369 /**
370 * ccs_io_printf - printf() to "struct ccs_io_buffer" structure.
371 *
372 * @head: Pointer to "struct ccs_io_buffer".
373 * @fmt: The printf()'s format string, followed by parameters.
374 *
375 * Returns nothing.
376 */
377 static void ccs_io_printf(struct ccs_io_buffer *head, const char *fmt, ...)
378 {
379 va_list args;
380 size_t len;
381 size_t pos = head->r.avail;
382 int size = head->readbuf_size - pos;
383 if (size <= 0)
384 return;
385 va_start(args, fmt);
386 len = vsnprintf(head->read_buf + pos, size, fmt, args) + 1;
387 va_end(args);
388 if (pos + len >= head->readbuf_size) {
389 printk(KERN_WARNING "Too many words in a line.\n");
390 return;
391 }
392 head->r.avail += len;
393 ccs_set_string(head, head->read_buf + pos);
394 }
395
396 /**
397 * ccs_set_space - Put a space to "struct ccs_io_buffer" structure.
398 *
399 * @head: Pointer to "struct ccs_io_buffer".
400 *
401 * Returns nothing.
402 */
403 static void ccs_set_space(struct ccs_io_buffer *head)
404 {
405 ccs_set_string(head, " ");
406 }
407
408 /**
409 * ccs_set_lf - Put a line feed to "struct ccs_io_buffer" structure.
410 *
411 * @head: Pointer to "struct ccs_io_buffer".
412 *
413 * Returns nothing.
414 */
415 static bool ccs_set_lf(struct ccs_io_buffer *head)
416 {
417 ccs_set_string(head, "\n");
418 return !head->r.w_pos;
419 }
420
421 /**
422 * ccs_set_slash - Put a shash to "struct ccs_io_buffer" structure.
423 *
424 * @head: Pointer to "struct ccs_io_buffer".
425 *
426 * Returns nothing.
427 */
428 static void ccs_set_slash(struct ccs_io_buffer *head)
429 {
430 ccs_set_string(head, "/");
431 }
432
433 /**
434 * ccs_assign_profile - Create a new profile.
435 *
436 * @profile: Profile number to create.
437 *
438 * Returns pointer to "struct ccs_profile" on success, NULL otherwise.
439 */
440 static struct ccs_profile *ccs_assign_profile(const unsigned int profile)
441 {
442 struct ccs_profile *ptr;
443 struct ccs_profile *entry;
444 if (profile >= CCS_MAX_PROFILES)
445 return NULL;
446 ptr = ccs_profile_ptr[profile];
447 if (ptr)
448 return ptr;
449 entry = kzalloc(sizeof(*entry), CCS_GFP_FLAGS);
450 if (mutex_lock_interruptible(&ccs_policy_lock))
451 goto out;
452 ptr = ccs_profile_ptr[profile];
453 if (!ptr && ccs_memory_ok(entry, sizeof(*entry))) {
454 ptr = entry;
455 ptr->default_config = CCS_CONFIG_DISABLED |
456 CCS_CONFIG_WANT_GRANT_LOG | CCS_CONFIG_WANT_REJECT_LOG;
457 memset(ptr->config, CCS_CONFIG_USE_DEFAULT,
458 sizeof(ptr->config));
459 ptr->pref[CCS_PREF_MAX_AUDIT_LOG] =
460 CONFIG_CCSECURITY_MAX_AUDIT_LOG;
461 ptr->pref[CCS_PREF_MAX_LEARNING_ENTRY] =
462 CONFIG_CCSECURITY_MAX_ACCEPT_ENTRY;
463 mb(); /* Avoid out-of-order execution. */
464 ccs_profile_ptr[profile] = ptr;
465 entry = NULL;
466 }
467 mutex_unlock(&ccs_policy_lock);
468 out:
469 kfree(entry);
470 return ptr;
471 }
472
473 /**
474 * ccs_check_profile - Check all profiles currently assigned to domains are defined.
475 *
476 * Returns nothing.
477 */
478 static void ccs_check_profile(void)
479 {
480 struct ccs_domain_info *domain;
481 const int idx = ccs_read_lock();
482 ccs_policy_loaded = true;
483 list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) {
484 const u8 profile = domain->profile;
485 if (ccs_profile_ptr[profile])
486 continue;
487 printk(KERN_ERR "Profile %u must be defined before using it.\n",
488 profile);
489 printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/1.8/ "
490 "for more information.\n");
491 panic("Profile %u (used by '%s') not defined.\n",
492 profile, domain->domainname->name);
493 }
494 ccs_read_unlock(idx);
495 if (ccs_profile_version != 20100903) {
496 printk(KERN_ERR "Userland tools must be installed for "
497 "TOMOYO 1.8, and policy must be initialized.\n");
498 printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/1.8/ "
499 "for more information.\n");
500 panic("Profile version %u is not supported.\n",
501 ccs_profile_version);
502 }
503 printk(KERN_INFO "CCSecurity: 1.8.0+ 2011/03/15\n");
504 printk(KERN_INFO "Mandatory Access Control activated.\n");
505 }
506
507 /**
508 * ccs_profile - Find a profile.
509 *
510 * @profile: Profile number to find.
511 *
512 * Returns pointer to "struct ccs_profile".
513 */
514 struct ccs_profile *ccs_profile(const u8 profile)
515 {
516 static struct ccs_profile ccs_null_profile;
517 struct ccs_profile *ptr = ccs_profile_ptr[profile];
518 if (!ptr)
519 ptr = &ccs_null_profile;
520 return ptr;
521 }
522
523 /**
524 * ccs_find_yesno - Find values for specified keyword.
525 *
526 * @string: String to check.
527 * @find: Name of keyword.
528 *
529 * Returns 1 if "@find=yes" was found, 0 if "@find=no" was found, -1 otherwise.
530 */
531 static s8 ccs_find_yesno(const char *string, const char *find)
532 {
533 const char *cp = strstr(string, find);
534 if (cp) {
535 cp += strlen(find);
536 if (!strncmp(cp, "=yes", 4))
537 return 1;
538 else if (!strncmp(cp, "=no", 3))
539 return 0;
540 }
541 return -1;
542 }
543
544 /**
545 * ccs_set_uint - Set value for specified preference.
546 *
547 * @i: Pointer to "unsigned int".
548 * @string: String to check.
549 * @find: Name of keyword.
550 *
551 * Returns nothing.
552 */
553 static void ccs_set_uint(unsigned int *i, const char *string, const char *find)
554 {
555 const char *cp = strstr(string, find);
556 if (cp)
557 sscanf(cp + strlen(find), "=%u", i);
558 }
559
560 /**
561 * ccs_set_mode - Set mode for specified profile.
562 *
563 * @name: Name of functionality.
564 * @value: Mode for @name.
565 * @profile: Pointer to "struct ccs_profile".
566 *
567 * Returns 0 on success, negative value otherwise.
568 */
569 static int ccs_set_mode(char *name, const char *value,
570 struct ccs_profile *profile)
571 {
572 u8 i;
573 u8 config;
574 if (!strcmp(name, "CONFIG")) {
575 i = CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
576 config = profile->default_config;
577 } else if (ccs_str_starts(&name, "CONFIG::")) {
578 config = 0;
579 for (i = 0; i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX;
580 i++) {
581 int len = 0;
582 if (i < CCS_MAX_MAC_INDEX) {
583 const u8 c = ccs_index2category[i];
584 const char *category =
585 ccs_category_keywords[c];
586 len = strlen(category);
587 if (strncmp(name, category, len) ||
588 name[len++] != ':' || name[len++] != ':')
589 continue;
590 }
591 if (strcmp(name + len, ccs_mac_keywords[i]))
592 continue;
593 config = profile->config[i];
594 break;
595 }
596 if (i == CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
597 return -EINVAL;
598 } else {
599 return -EINVAL;
600 }
601 if (strstr(value, "use_default")) {
602 config = CCS_CONFIG_USE_DEFAULT;
603 } else {
604 u8 mode;
605 for (mode = 0; mode < CCS_CONFIG_MAX_MODE; mode++)
606 if (strstr(value, ccs_mode[mode]))
607 /*
608 * Update lower 3 bits in order to distinguish
609 * 'config' from 'CCS_CONFIG_USE_DEAFULT'.
610 */
611 config = (config & ~7) | mode;
612 if (config != CCS_CONFIG_USE_DEFAULT) {
613 switch (ccs_find_yesno(value, "grant_log")) {
614 case 1:
615 config |= CCS_CONFIG_WANT_GRANT_LOG;
616 break;
617 case 0:
618 config &= ~CCS_CONFIG_WANT_GRANT_LOG;
619 break;
620 }
621 switch (ccs_find_yesno(value, "reject_log")) {
622 case 1:
623 config |= CCS_CONFIG_WANT_REJECT_LOG;
624 break;
625 case 0:
626 config &= ~CCS_CONFIG_WANT_REJECT_LOG;
627 break;
628 }
629 }
630 }
631 if (i < CCS_MAX_MAC_INDEX + CCS_MAX_MAC_CATEGORY_INDEX)
632 profile->config[i] = config;
633 else if (config != CCS_CONFIG_USE_DEFAULT)
634 profile->default_config = config;
635 return 0;
636 }
637
638 /**
639 * ccs_write_profile - Write profile table.
640 *
641 * @head: Pointer to "struct ccs_io_buffer".
642 *
643 * Returns 0 on success, negative value otherwise.
644 */
645 static int ccs_write_profile(struct ccs_io_buffer *head)
646 {
647 char *data = head->write_buf;
648 unsigned int i;
649 char *cp;
650 struct ccs_profile *profile;
651 if (sscanf(data, "PROFILE_VERSION=%u", &ccs_profile_version) == 1)
652 return 0;
653 i = simple_strtoul(data, &cp, 10);
654 if (*cp != '-')
655 return -EINVAL;
656 data = cp + 1;
657 profile = ccs_assign_profile(i);
658 if (!profile)
659 return -EINVAL;
660 cp = strchr(data, '=');
661 if (!cp)
662 return -EINVAL;
663 *cp++ = '\0';
664 if (!strcmp(data, "COMMENT")) {
665 const struct ccs_path_info *old_comment = profile->comment;
666 profile->comment = ccs_get_name(cp);
667 ccs_put_name(old_comment);
668 return 0;
669 }
670 if (!strcmp(data, "PREFERENCE")) {
671 for (i = 0; i < CCS_MAX_PREF; i++)
672 ccs_set_uint(&profile->pref[i], cp,
673 ccs_pref_keywords[i]);
674 return 0;
675 }
676 return ccs_set_mode(data, cp, profile);
677 }
678
679 /**
680 * ccs_print_config - Print mode for specified functionality.
681 *
682 * @head: Pointer to "struct ccs_io_buffer".
683 * @config: Mode for that functionality.
684 *
685 * Returns nothing.
686 *
687 * Caller prints functionality's name.
688 */
689 static void ccs_print_config(struct ccs_io_buffer *head, const u8 config)
690 {
691 ccs_io_printf(head, "={ mode=%s grant_log=%s reject_log=%s }\n",
692 ccs_mode[config & 3],
693 ccs_yesno(config & CCS_CONFIG_WANT_GRANT_LOG),
694 ccs_yesno(config & CCS_CONFIG_WANT_REJECT_LOG));
695 }
696
697 /**
698 * ccs_read_profile - Read profile table.
699 *
700 * @head: Pointer to "struct ccs_io_buffer".
701 *
702 * Returns nothing.
703 */
704 static void ccs_read_profile(struct ccs_io_buffer *head)
705 {
706 u8 index;
707 const struct ccs_profile *profile;
708 next:
709 index = head->r.index;
710 profile = ccs_profile_ptr[index];
711 switch (head->r.step) {
712 case 0:
713 ccs_io_printf(head, "PROFILE_VERSION=%s\n", "20100903");
714 head->r.step++;
715 break;
716 case 1:
717 for ( ; head->r.index < CCS_MAX_PROFILES;
718 head->r.index++)
719 if (ccs_profile_ptr[head->r.index])
720 break;
721 if (head->r.index == CCS_MAX_PROFILES)
722 return;
723 head->r.step++;
724 break;
725 case 2:
726 {
727 u8 i;
728 const struct ccs_path_info *comment = profile->comment;
729 ccs_io_printf(head, "%u-COMMENT=", index);
730 ccs_set_string(head, comment ? comment->name : "");
731 ccs_set_lf(head);
732 ccs_io_printf(head, "%u-PREFERENCE={ ", index);
733 for (i = 0; i < CCS_MAX_PREF; i++)
734 ccs_io_printf(head, "%s=%u ",
735 ccs_pref_keywords[i],
736 profile->pref[i]);
737 ccs_set_string(head, " }\n");
738 head->r.step++;
739 }
740 break;
741 case 3:
742 {
743 ccs_io_printf(head, "%u-%s", index, "CONFIG");
744 ccs_print_config(head, profile->default_config);
745 head->r.bit = 0;
746 head->r.step++;
747 }
748 break;
749 case 4:
750 for ( ; head->r.bit < CCS_MAX_MAC_INDEX
751 + CCS_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
752 const u8 i = head->r.bit;
753 const u8 config = profile->config[i];
754 if (config == CCS_CONFIG_USE_DEFAULT)
755 continue;
756 if (i < CCS_MAX_MAC_INDEX)
757 ccs_io_printf(head, "%u-CONFIG::%s::%s", index,
758 ccs_category_keywords
759 [ccs_index2category[i]],
760 ccs_mac_keywords[i]);
761 else
762 ccs_io_printf(head, "%u-CONFIG::%s", index,
763 ccs_mac_keywords[i]);
764 ccs_print_config(head, config);
765 head->r.bit++;
766 break;
767 }
768 if (head->r.bit == CCS_MAX_MAC_INDEX
769 + CCS_MAX_MAC_CATEGORY_INDEX) {
770 head->r.index++;
771 head->r.step = 1;
772 }
773 break;
774 }
775 if (ccs_flush(head))
776 goto next;
777 }
778
779 /**
780 * ccs_same_manager - Check for duplicated "struct ccs_manager" entry.
781 *
782 * @a: Pointer to "struct ccs_acl_head".
783 * @b: Pointer to "struct ccs_acl_head".
784 *
785 * Returns true if @a == @b, false otherwise.
786 */
787 static bool ccs_same_manager(const struct ccs_acl_head *a,
788 const struct ccs_acl_head *b)
789 {
790 return container_of(a, struct ccs_manager, head)->manager
791 == container_of(b, struct ccs_manager, head)->manager;
792 }
793
794 /**
795 * ccs_update_manager_entry - Add a manager entry.
796 *
797 * @manager: The path to manager or the domainnamme.
798 * @is_delete: True if it is a delete request.
799 *
800 * Returns 0 on success, negative value otherwise.
801 */
802 static int ccs_update_manager_entry(const char *manager, const bool is_delete)
803 {
804 struct ccs_manager e = { };
805 int error = is_delete ? -ENOENT : -ENOMEM;
806 if (ccs_domain_def(manager)) {
807 if (!ccs_correct_domain(manager))
808 return -EINVAL;
809 e.is_domain = true;
810 } else {
811 if (!ccs_correct_path(manager))
812 return -EINVAL;
813 }
814 e.manager = ccs_get_name(manager);
815 if (!e.manager)
816 return error;
817 error = ccs_update_policy(&e.head, sizeof(e), is_delete,
818 &ccs_policy_list[CCS_ID_MANAGER],
819 ccs_same_manager);
820 ccs_put_name(e.manager);
821 return error;
822 }
823
824 /**
825 * ccs_write_manager - Write manager policy.
826 *
827 * @head: Pointer to "struct ccs_io_buffer".
828 *
829 * Returns 0 on success, negative value otherwise.
830 */
831 static int ccs_write_manager(struct ccs_io_buffer *head)
832 {
833 char *data = head->write_buf;
834 bool is_delete = ccs_str_starts(&data, "delete ");
835 if (!strcmp(data, "manage_by_non_root")) {
836 ccs_manage_by_non_root = !is_delete;
837 return 0;
838 }
839 return ccs_update_manager_entry(data, is_delete);
840 }
841
842 /**
843 * ccs_read_manager - Read manager policy.
844 *
845 * @head: Pointer to "struct ccs_io_buffer".
846 *
847 * Returns nothing.
848 *
849 * Caller holds ccs_read_lock().
850 */
851 static void ccs_read_manager(struct ccs_io_buffer *head)
852 {
853 if (head->r.eof)
854 return;
855 list_for_each_cookie(head->r.acl, &ccs_policy_list[CCS_ID_MANAGER]) {
856 struct ccs_manager *ptr =
857 list_entry(head->r.acl, typeof(*ptr), head.list);
858 if (ptr->head.is_deleted)
859 continue;
860 if (!ccs_flush(head))
861 return;
862 ccs_set_string(head, ptr->manager->name);
863 ccs_set_lf(head);
864 }
865 head->r.eof = true;
866 }
867
868 /**
869 * ccs_manager - Check whether the current process is a policy manager.
870 *
871 * Returns true if the current process is permitted to modify policy
872 * via /proc/ccs/ interface.
873 *
874 * Caller holds ccs_read_lock().
875 */
876 static bool ccs_manager(void)
877 {
878 struct ccs_manager *ptr;
879 const char *exe;
880 struct ccs_security *task = ccs_current_security();
881 const struct ccs_path_info *domainname
882 = ccs_current_domain()->domainname;
883 bool found = false;
884 if (!ccs_policy_loaded)
885 return true;
886 if (task->ccs_flags & CCS_TASK_IS_MANAGER)
887 return true;
888 if (!ccs_manage_by_non_root && (current_uid() || current_euid()))
889 return false;
890 exe = ccs_get_exe();
891 list_for_each_entry_srcu(ptr, &ccs_policy_list[CCS_ID_MANAGER],
892 head.list, &ccs_ss) {
893 if (ptr->head.is_deleted)
894 continue;
895 if (ptr->is_domain) {
896 if (ccs_pathcmp(domainname, ptr->manager))
897 continue;
898 } else {
899 if (!exe || strcmp(exe, ptr->manager->name))
900 continue;
901 }
902 /* Set manager flag. */
903 task->ccs_flags |= CCS_TASK_IS_MANAGER;
904 found = true;
905 break;
906 }
907 if (!found) { /* Reduce error messages. */
908 static pid_t ccs_last_pid;
909 const pid_t pid = current->pid;
910 if (ccs_last_pid != pid) {
911 printk(KERN_WARNING "%s ( %s ) is not permitted to "
912 "update policies.\n", domainname->name, exe);
913 ccs_last_pid = pid;
914 }
915 }
916 kfree(exe);
917 return found;
918 }
919
920 /**
921 * ccs_select_one - Parse select command.
922 *
923 * @head: Pointer to "struct ccs_io_buffer".
924 * @data: String to parse.
925 *
926 * Returns true on success, false otherwise.
927 *
928 * Caller holds ccs_read_lock().
929 */
930 static bool ccs_select_one(struct ccs_io_buffer *head, const char *data)
931 {
932 unsigned int pid;
933 struct ccs_domain_info *domain = NULL;
934 bool global_pid = false;
935 if (!strcmp(data, "transition_only")) {
936 head->r.print_transition_related_only = true;
937 return true;
938 }
939 if (sscanf(data, "pid=%u", &pid) == 1 ||
940 (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
941 struct task_struct *p;
942 ccs_tasklist_lock();
943 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
944 if (global_pid)
945 p = ccsecurity_exports.find_task_by_pid_ns(pid,
946 &init_pid_ns);
947 else
948 p = ccsecurity_exports.find_task_by_vpid(pid);
949 #else
950 p = find_task_by_pid(pid);
951 #endif
952 if (p)
953 domain = ccs_task_domain(p);
954 ccs_tasklist_unlock();
955 } else if (!strncmp(data, "domain=", 7)) {
956 if (ccs_domain_def(data + 7))
957 domain = ccs_find_domain(data + 7);
958 } else
959 return false;
960 head->w.domain = domain;
961 /* Accessing read_buf is safe because head->io_sem is held. */
962 if (!head->read_buf)
963 return true; /* Do nothing if open(O_WRONLY). */
964 memset(&head->r, 0, sizeof(head->r));
965 head->r.print_this_domain_only = true;
966 if (domain)
967 head->r.domain = &domain->list;
968 else
969 head->r.eof = true;
970 ccs_io_printf(head, "# select %s\n", data);
971 if (domain && domain->is_deleted)
972 ccs_set_string(head, "# This is a deleted domain.\n");
973 return true;
974 }
975
976 /**
977 * ccs_same_handler_acl - Check for duplicated "struct ccs_handler_acl" entry.
978 *
979 * @a: Pointer to "struct ccs_acl_info".
980 * @b: Pointer to "struct ccs_acl_info".
981 *
982 * Returns true if @a == @b, false otherwise.
983 */
984 static bool ccs_same_handler_acl(const struct ccs_acl_info *a,
985 const struct ccs_acl_info *b)
986 {
987 const struct ccs_handler_acl *p1 = container_of(a, typeof(*p1), head);
988 const struct ccs_handler_acl *p2 = container_of(b, typeof(*p2), head);
989 return p1->handler == p2->handler;
990 }
991
992 /**
993 * ccs_same_task_acl - Check for duplicated "struct ccs_task_acl" entry.
994 *
995 * @a: Pointer to "struct ccs_acl_info".
996 * @b: Pointer to "struct ccs_acl_info".
997 *
998 * Returns true if @a == @b, false otherwise.
999 */
1000 static bool ccs_same_task_acl(const struct ccs_acl_info *a,
1001 const struct ccs_acl_info *b)
1002 {
1003 const struct ccs_task_acl *p1 = container_of(a, typeof(*p1), head);
1004 const struct ccs_task_acl *p2 = container_of(b, typeof(*p2), head);
1005 return p1->domainname == p2->domainname;
1006 }
1007
1008 /**
1009 * ccs_write_task - Update task related list.
1010 *
1011 * @param: Pointer to "struct ccs_acl_param".
1012 *
1013 * Returns 0 on success, negative value otherwise.
1014 */
1015 static int ccs_write_task(struct ccs_acl_param *param)
1016 {
1017 int error;
1018 const bool is_auto = ccs_str_starts(&param->data,
1019 "auto_domain_transition ");
1020 if (!is_auto && !ccs_str_starts(&param->data,
1021 "manual_domain_transition ")) {
1022 struct ccs_handler_acl e = { };
1023 char *handler;
1024 if (ccs_str_starts(&param->data, "auto_execute_handler "))
1025 e.head.type = CCS_TYPE_AUTO_EXECUTE_HANDLER;
1026 else if (ccs_str_starts(&param->data,
1027 "denied_execute_handler "))
1028 e.head.type = CCS_TYPE_DENIED_EXECUTE_HANDLER;
1029 else
1030 return -EINVAL;
1031 handler = ccs_read_token(param);
1032 if (!ccs_correct_path(handler))
1033 return -EINVAL;
1034 e.handler = ccs_get_name(handler);
1035 if (!e.handler)
1036 return -ENOMEM;
1037 if (e.handler->is_patterned)
1038 error = -EINVAL; /* No patterns allowed. */
1039 else
1040 error = ccs_update_domain(&e.head, sizeof(e), param,
1041 ccs_same_handler_acl, NULL);
1042 ccs_put_name(e.handler);
1043 } else {
1044 struct ccs_task_acl e = {
1045 .head.type = is_auto ?
1046 CCS_TYPE_AUTO_TASK_ACL : CCS_TYPE_MANUAL_TASK_ACL,
1047 .domainname = ccs_get_domainname(param),
1048 };
1049 if (!e.domainname)
1050 error = -EINVAL;
1051 else
1052 error = ccs_update_domain(&e.head, sizeof(e), param,
1053 ccs_same_task_acl, NULL);
1054 ccs_put_name(e.domainname);
1055 }
1056 return error;
1057 }
1058
1059 /**
1060 * ccs_write_domain2 - Write domain policy.
1061 *
1062 * @data: Policy to be interpreted.
1063 * @domain: Pointer to "struct ccs_domain_info".
1064 * @is_delete: True if it is a delete request.
1065 *
1066 * Returns 0 on success, negative value otherwise.
1067 */
1068 static int ccs_write_domain2(char *data, struct ccs_domain_info *domain,
1069 const bool is_delete)
1070 {
1071 struct ccs_acl_param param = {
1072 .data = data,
1073 .domain = domain,
1074 .is_delete = is_delete,
1075 };
1076 static const struct {
1077 const char *keyword;
1078 int (*write) (struct ccs_acl_param *);
1079 } ccs_callback[7] = {
1080 { "file ", ccs_write_file },
1081 { "network inet ", ccs_write_inet_network },
1082 { "network unix ", ccs_write_unix_network },
1083 { "misc ", ccs_write_misc },
1084 { "capability ", ccs_write_capability },
1085 { "ipc ", ccs_write_ipc },
1086 { "task ", ccs_write_task },
1087 };
1088 u8 i;
1089 for (i = 0; i < 7; i++) {
1090 if (!ccs_str_starts(&param.data, ccs_callback[i].keyword))
1091 continue;
1092 return ccs_callback[i].write(&param);
1093 }
1094 return -EINVAL;
1095 }
1096
1097 /* String table for domain flags. */
1098 const char * const ccs_dif[CCS_MAX_DOMAIN_INFO_FLAGS] = {
1099 [CCS_DIF_QUOTA_WARNED] = "quota_exceeded\n",
1100 [CCS_DIF_TRANSITION_FAILED] = "transition_failed\n",
1101 };
1102
1103 /**
1104 * ccs_write_domain - Write domain policy.
1105 *
1106 * @head: Pointer to "struct ccs_io_buffer".
1107 *
1108 * Returns 0 on success, negative value otherwise.
1109 */
1110 static int ccs_write_domain(struct ccs_io_buffer *head)
1111 {
1112 char *data = head->write_buf;
1113 struct ccs_domain_info *domain = head->w.domain;
1114 bool is_delete = false;
1115 bool is_select = false;
1116 unsigned int profile;
1117 if (ccs_str_starts(&data, "delete "))
1118 is_delete = true;
1119 else if (ccs_str_starts(&data, "select "))
1120 is_select = true;
1121 if (is_select && ccs_select_one(head, data))
1122 return 0;
1123 /* Don't allow updating policies by non manager programs. */
1124 if (!ccs_manager())
1125 return -EPERM;
1126 if (ccs_domain_def(data)) {
1127 domain = NULL;
1128 if (is_delete)
1129 ccs_delete_domain(data);
1130 else if (is_select)
1131 domain = ccs_find_domain(data);
1132 else
1133 domain = ccs_assign_domain(data, 0, 0, false);
1134 head->w.domain = domain;
1135 return 0;
1136 }
1137 if (!domain)
1138 return -EINVAL;
1139
1140 if (sscanf(data, "use_profile %u\n", &profile) == 1
1141 && profile < CCS_MAX_PROFILES) {
1142 if (!ccs_policy_loaded || ccs_profile_ptr[(u8) profile])
1143 if (!is_delete)
1144 domain->profile = (u8) profile;
1145 return 0;
1146 }
1147 if (sscanf(data, "use_group %u\n", &profile) == 1
1148 && profile < CCS_MAX_ACL_GROUPS) {
1149 if (!is_delete)
1150 domain->group = (u8) profile;
1151 return 0;
1152 }
1153 for (profile = 0; profile < CCS_MAX_DOMAIN_INFO_FLAGS; profile++) {
1154 const char *cp = ccs_dif[profile];
1155 if (strncmp(data, cp, strlen(cp) - 1))
1156 continue;
1157 domain->flags[profile] = !is_delete;
1158 return 0;
1159 }
1160 return ccs_write_domain2(data, domain, is_delete);
1161 }
1162
1163 /**
1164 * ccs_print_name_union - Print a ccs_name_union.
1165 *
1166 * @head: Pointer to "struct ccs_io_buffer".
1167 * @ptr: Pointer to "struct ccs_name_union".
1168 *
1169 * Returns nothing.
1170 */
1171 static void ccs_print_name_union(struct ccs_io_buffer *head,
1172 const struct ccs_name_union *ptr)
1173 {
1174 const bool cond = head->r.print_cond_part;
1175 if (!cond)
1176 ccs_set_space(head);
1177 if (ptr->is_group) {
1178 ccs_set_string(head, "@");
1179 ccs_set_string(head, ptr->group->group_name->name);
1180 } else {
1181 if (cond)
1182 ccs_set_string(head, "\"");
1183 ccs_set_string(head, ptr->filename->name);
1184 if (cond)
1185 ccs_set_string(head, "\"");
1186 }
1187 }
1188
1189 /**
1190 * ccs_print_number_union - Print a ccs_number_union.
1191 *
1192 * @head: Pointer to "struct ccs_io_buffer".
1193 * @ptr: Pointer to "struct ccs_number_union".
1194 *
1195 * Returns nothing.
1196 */
1197 static void ccs_print_number_union(struct ccs_io_buffer *head,
1198 const struct ccs_number_union *ptr)
1199 {
1200 if (!head->r.print_cond_part)
1201 ccs_set_space(head);
1202 if (ptr->is_group) {
1203 ccs_set_string(head, "@");
1204 ccs_set_string(head, ptr->group->group_name->name);
1205 } else {
1206 int i;
1207 unsigned long min = ptr->values[0];
1208 const unsigned long max = ptr->values[1];
1209 u8 min_type = ptr->value_type[0];
1210 const u8 max_type = ptr->value_type[1];
1211 char buffer[128];
1212 buffer[0] = '\0';
1213 for (i = 0; i < 2; i++) {
1214 switch (min_type) {
1215 case CCS_VALUE_TYPE_HEXADECIMAL:
1216 ccs_addprintf(buffer, sizeof(buffer), "0x%lX",
1217 min);
1218 break;
1219 case CCS_VALUE_TYPE_OCTAL:
1220 ccs_addprintf(buffer, sizeof(buffer), "0%lo",
1221 min);
1222 break;
1223 default:
1224 ccs_addprintf(buffer, sizeof(buffer), "%lu",
1225 min);
1226 break;
1227 }
1228 if (min == max && min_type == max_type)
1229 break;
1230 ccs_addprintf(buffer, sizeof(buffer), "-");
1231 min_type = max_type;
1232 min = max;
1233 }
1234 ccs_io_printf(head, "%s", buffer);
1235 }
1236 }
1237
1238 /**
1239 * ccs_print_condition - Print condition part.
1240 *
1241 * @head: Pointer to "struct ccs_io_buffer".
1242 * @cond: Pointer to "struct ccs_condition".
1243 *
1244 * Returns true on success, false otherwise.
1245 */
1246 static bool ccs_print_condition(struct ccs_io_buffer *head,
1247 const struct ccs_condition *cond)
1248 {
1249 switch (head->r.cond_step) {
1250 case 0:
1251 head->r.cond_index = 0;
1252 head->r.cond_step++;
1253 /* fall through */
1254 case 1:
1255 {
1256 const u16 condc = cond->condc;
1257 const struct ccs_condition_element *condp =
1258 (typeof(condp)) (cond + 1);
1259 const struct ccs_number_union *numbers_p =
1260 (typeof(numbers_p)) (condp + condc);
1261 const struct ccs_name_union *names_p =
1262 (typeof(names_p))
1263 (numbers_p + cond->numbers_count);
1264 const struct ccs_argv *argv =
1265 (typeof(argv)) (names_p + cond->names_count);
1266 const struct ccs_envp *envp =
1267 (typeof(envp)) (argv + cond->argc);
1268 u16 skip;
1269 for (skip = 0; skip < head->r.cond_index; skip++) {
1270 const u8 left = condp->left;
1271 const u8 right = condp->right;
1272 condp++;
1273 switch (left) {
1274 case CCS_ARGV_ENTRY:
1275 argv++;
1276 continue;
1277 case CCS_ENVP_ENTRY:
1278 envp++;
1279 continue;
1280 case CCS_NUMBER_UNION:
1281 numbers_p++;
1282 break;
1283 }
1284 switch (right) {
1285 case CCS_NAME_UNION:
1286 names_p++;
1287 break;
1288 case CCS_NUMBER_UNION:
1289 numbers_p++;
1290 break;
1291 }
1292 }
1293 while (head->r.cond_index < condc) {
1294 const u8 match = condp->equals;
1295 const u8 left = condp->left;
1296 const u8 right = condp->right;
1297 if (!ccs_flush(head))
1298 return false;
1299 condp++;
1300 head->r.cond_index++;
1301 ccs_set_space(head);
1302 switch (left) {
1303 case CCS_ARGV_ENTRY:
1304 ccs_io_printf(head,
1305 "exec.argv[%u]%s\"%s\"",
1306 argv->index,
1307 argv->is_not ?
1308 "!=" : "=",
1309 argv->value->name);
1310 argv++;
1311 continue;
1312 case CCS_ENVP_ENTRY:
1313 ccs_io_printf(head,
1314 "exec.envp[\"%s\"]%s",
1315 envp->name->name,
1316 envp->is_not ?
1317 "!=" : "=");
1318 if (envp->value) {
1319 ccs_set_string(head, "\"");
1320 ccs_set_string(head, envp->
1321 value->name);
1322 ccs_set_string(head, "\"");
1323 } else {
1324 ccs_set_string(head, "NULL");
1325 }
1326 envp++;
1327 continue;
1328 case CCS_NUMBER_UNION:
1329 ccs_print_number_union(head,
1330 numbers_p++);
1331 break;
1332 default:
1333 ccs_set_string(head,
1334 ccs_condition_keyword[left]);
1335 break;
1336 }
1337 ccs_set_string(head, match ? "=" : "!=");
1338 switch (right) {
1339 case CCS_NAME_UNION:
1340 ccs_print_name_union(head, names_p++);
1341 break;
1342 case CCS_NUMBER_UNION:
1343 ccs_print_number_union(head,
1344 numbers_p++);
1345 break;
1346 default:
1347 ccs_set_string(head,
1348 ccs_condition_keyword[right]);
1349 break;
1350 }
1351 }
1352 }
1353 head->r.cond_step++;
1354 /* fall through */
1355 case 2:
1356 if (!ccs_flush(head))
1357 break;
1358 head->r.cond_step++;
1359 /* fall through */
1360 case 3:
1361 if (cond->grant_log != CCS_GRANTLOG_AUTO)
1362 ccs_io_printf(head, " grant_log=%s",
1363 ccs_yesno(cond->grant_log ==
1364 CCS_GRANTLOG_YES));
1365 if (cond->transit) {
1366 ccs_set_string(head, " auto_domain_transition=\"");
1367 ccs_set_string(head, cond->transit->name);
1368 ccs_set_string(head, "\"");
1369 }
1370 ccs_set_lf(head);
1371 return true;
1372 }
1373 return false;
1374 }
1375
1376 /**
1377 * ccs_set_group - Print "acl_group " header keyword and category name.
1378 *
1379 * @head: Pointer to "struct ccs_io_buffer".
1380 * @category: Category name.
1381 *
1382 * Returns nothing.
1383 */
1384 static void ccs_set_group(struct ccs_io_buffer *head, const char *category)
1385 {
1386 if (head->type == CCS_EXCEPTIONPOLICY)
1387 ccs_io_printf(head, "acl_group %u ", head->r.acl_group_index);
1388 ccs_set_string(head, category);
1389 }
1390
1391 /**
1392 * ccs_print_entry - Print an ACL entry.
1393 *
1394 * @head: Pointer to "struct ccs_io_buffer".
1395 * @acl: Pointer to an ACL entry.
1396 *
1397 * Returns true on success, false otherwise.
1398 */
1399 static bool ccs_print_entry(struct ccs_io_buffer *head,
1400 const struct ccs_acl_info *acl)
1401 {
1402 const u8 acl_type = acl->type;
1403 const bool may_trigger_transition = acl->cond && acl->cond->transit;
1404 bool first = true;
1405 u8 bit;
1406 if (head->r.print_cond_part)
1407 goto print_cond_part;
1408 if (acl->is_deleted)
1409 return true;
1410 if (!ccs_flush(head))
1411 return false;
1412 else if (acl_type == CCS_TYPE_PATH_ACL) {
1413 struct ccs_path_acl *ptr
1414 = container_of(acl, typeof(*ptr), head);
1415 const u16 perm = ptr->perm;
1416 for (bit = 0; bit < CCS_MAX_PATH_OPERATION; bit++) {
1417 if (!(perm & (1 << bit)))
1418 continue;
1419 if (head->r.print_transition_related_only &&
1420 bit != CCS_TYPE_EXECUTE && !may_trigger_transition)
1421 continue;
1422 if (first) {
1423 ccs_set_group(head, "file ");
1424 first = false;
1425 } else {
1426 ccs_set_slash(head);
1427 }
1428 ccs_set_string(head, ccs_path_keyword[bit]);
1429 }
1430 if (first)
1431 return true;
1432 ccs_print_name_union(head, &ptr->name);
1433 } else if (acl_type == CCS_TYPE_AUTO_EXECUTE_HANDLER ||
1434 acl_type == CCS_TYPE_DENIED_EXECUTE_HANDLER) {
1435 struct ccs_handler_acl *ptr
1436 = container_of(acl, typeof(*ptr), head);
1437 ccs_set_group(head, "task ");
1438 ccs_set_string(head, acl_type == CCS_TYPE_AUTO_EXECUTE_HANDLER
1439 ? "auto_execute_handler " :
1440 "denied_execute_handler ");
1441 ccs_set_string(head, ptr->handler->name);
1442 } else if (acl_type == CCS_TYPE_AUTO_TASK_ACL ||
1443 acl_type == CCS_TYPE_MANUAL_TASK_ACL) {
1444 struct ccs_task_acl *ptr =
1445 container_of(acl, typeof(*ptr), head);
1446 ccs_set_group(head, "task ");
1447 ccs_set_string(head, acl_type == CCS_TYPE_AUTO_TASK_ACL ?
1448 "auto_domain_transition " :
1449 "manual_domain_transition ");
1450 ccs_set_string(head, ptr->domainname->name);
1451 } else if (head->r.print_transition_related_only &&
1452 !may_trigger_transition) {
1453 return true;
1454 } else if (acl_type == CCS_TYPE_MKDEV_ACL) {
1455 struct ccs_mkdev_acl *ptr =
1456 container_of(acl, typeof(*ptr), head);
1457 const u8 perm = ptr->perm;
1458 for (bit = 0; bit < CCS_MAX_MKDEV_OPERATION; bit++) {
1459 if (!(perm & (1 << bit)))
1460 continue;
1461 if (first) {
1462 ccs_set_group(head, "file ");
1463 first = false;
1464 } else {
1465 ccs_set_slash(head);
1466 }
1467 ccs_set_string(head, ccs_mac_keywords
1468 [ccs_pnnn2mac[bit]]);
1469 }
1470 if (first)
1471 return true;
1472 ccs_print_name_union(head, &ptr->name);
1473 ccs_print_number_union(head, &ptr->mode);
1474 ccs_print_number_union(head, &ptr->major);
1475 ccs_print_number_union(head, &ptr->minor);
1476 } else if (acl_type == CCS_TYPE_PATH2_ACL) {
1477 struct ccs_path2_acl *ptr =
1478 container_of(acl, typeof(*ptr), head);
1479 const u8 perm = ptr->perm;
1480 for (bit = 0; bit < CCS_MAX_PATH2_OPERATION; bit++) {
1481 if (!(perm & (1 << bit)))
1482 continue;
1483 if (first) {
1484 ccs_set_group(head, "file ");
1485 first = false;
1486 } else {
1487 ccs_set_slash(head);
1488 }
1489 ccs_set_string(head, ccs_mac_keywords
1490 [ccs_pp2mac[bit]]);
1491 }
1492 if (first)
1493 return true;
1494 ccs_print_name_union(head, &ptr->name1);
1495 ccs_print_name_union(head, &ptr->name2);
1496 } else if (acl_type == CCS_TYPE_PATH_NUMBER_ACL) {
1497 struct ccs_path_number_acl *ptr =
1498 container_of(acl, typeof(*ptr), head);
1499 const u8 perm = ptr->perm;
1500 for (bit = 0; bit < CCS_MAX_PATH_NUMBER_OPERATION; bit++) {
1501 if (!(perm & (1 << bit)))
1502 continue;
1503 if (first) {
1504 ccs_set_group(head, "file ");
1505 first = false;
1506 } else {
1507 ccs_set_slash(head);
1508 }
1509 ccs_set_string(head, ccs_mac_keywords
1510 [ccs_pn2mac[bit]]);
1511 }
1512 if (first)
1513 return true;
1514 ccs_print_name_union(head, &ptr->name);
1515 ccs_print_number_union(head, &ptr->number);
1516 } else if (acl_type == CCS_TYPE_ENV_ACL) {
1517 struct ccs_env_acl *ptr =
1518 container_of(acl, typeof(*ptr), head);
1519 ccs_set_group(head, "misc env ");
1520 ccs_set_string(head, ptr->env->name);
1521 } else if (acl_type == CCS_TYPE_CAPABILITY_ACL) {
1522 struct ccs_capability_acl *ptr =
1523 container_of(acl, typeof(*ptr), head);
1524 ccs_set_group(head, "capability ");
1525 ccs_set_string(head, ccs_mac_keywords
1526 [ccs_c2mac[ptr->operation]]);
1527 } else if (acl_type == CCS_TYPE_INET_ACL) {
1528 struct ccs_inet_acl *ptr =
1529 container_of(acl, typeof(*ptr), head);
1530 const u8 perm = ptr->perm;
1531 for (bit = 0; bit < CCS_MAX_NETWORK_OPERATION; bit++) {
1532 if (!(perm & (1 << bit)))
1533 continue;
1534 if (first) {
1535 ccs_set_group(head, "network inet ");
1536 ccs_set_string(head, ccs_proto_keyword
1537 [ptr->protocol]);
1538 ccs_set_space(head);
1539 first = false;
1540 } else {
1541 ccs_set_slash(head);
1542 }
1543 ccs_set_string(head, ccs_socket_keyword[bit]);
1544 }
1545 if (first)
1546 return true;
1547 ccs_set_space(head);
1548 switch (ptr->address_type) {
1549 char buf[128];
1550 case CCS_IP_ADDRESS_TYPE_ADDRESS_GROUP:
1551 ccs_set_string(head, "@");
1552 ccs_set_string(head,
1553 ptr->address.group->group_name->name);
1554 break;
1555 case CCS_IP_ADDRESS_TYPE_IPv4:
1556 ccs_print_ipv4(buf, sizeof(buf), ptr->address.ipv4.min,
1557 ptr->address.ipv4.max);
1558 ccs_io_printf(head, "%s", buf);
1559 break;
1560 case CCS_IP_ADDRESS_TYPE_IPv6:
1561 ccs_print_ipv6(buf, sizeof(buf), ptr->address.ipv6.min,
1562 ptr->address.ipv6.max);
1563 ccs_io_printf(head, "%s", buf);
1564 break;
1565 }
1566 ccs_print_number_union(head, &ptr->port);
1567 } else if (acl_type == CCS_TYPE_UNIX_ACL) {
1568 struct ccs_unix_acl *ptr =
1569 container_of(acl, typeof(*ptr), head);
1570 const u8 perm = ptr->perm;
1571 for (bit = 0; bit < CCS_MAX_NETWORK_OPERATION; bit++) {
1572 if (!(perm & (1 << bit)))
1573 continue;
1574 if (first) {
1575 ccs_set_group(head, "network unix ");
1576 ccs_set_string(head, ccs_proto_keyword
1577 [ptr->protocol]);
1578 ccs_set_space(head);
1579 first = false;
1580 } else {
1581 ccs_set_slash(head);
1582 }
1583 ccs_set_string(head, ccs_socket_keyword[bit]);
1584 }
1585 if (first)
1586 return true;
1587 ccs_print_name_union(head, &ptr->name);
1588 } else if (acl_type == CCS_TYPE_SIGNAL_ACL) {
1589 struct ccs_signal_acl *ptr =
1590 container_of(acl, typeof(*ptr), head);
1591 ccs_set_group(head, "ipc signal ");
1592 ccs_io_printf(head, "%u ", ptr->sig);
1593 ccs_set_string(head, ptr->domainname->name);
1594 } else if (acl_type == CCS_TYPE_MOUNT_ACL) {
1595 struct ccs_mount_acl *ptr =
1596 container_of(acl, typeof(*ptr), head);
1597 ccs_set_group(head, "file mount");
1598 ccs_print_name_union(head, &ptr->dev_name);
1599 ccs_print_name_union(head, &ptr->dir_name);
1600 ccs_print_name_union(head, &ptr->fs_type);
1601 ccs_print_number_union(head, &ptr->flags);
1602 }
1603 if (acl->cond) {
1604 head->r.print_cond_part = true;
1605 head->r.cond_step = 0;
1606 if (!ccs_flush(head))
1607 return false;
1608 print_cond_part:
1609 if (!ccs_print_condition(head, acl->cond))
1610 return false;
1611 head->r.print_cond_part = false;
1612 } else {
1613 ccs_set_lf(head);
1614 }
1615 return true;
1616 }
1617
1618 /**
1619 * ccs_read_domain2 - Read domain policy.
1620 *
1621 * @head: Pointer to "struct ccs_io_buffer".
1622 * @domain: Pointer to "struct ccs_domain_info".
1623 * @index: Index number.
1624 *
1625 * Returns true on success, false otherwise.
1626 *
1627 * Caller holds ccs_read_lock().
1628 */
1629 static bool ccs_read_domain2(struct ccs_io_buffer *head,
1630 struct ccs_domain_info *domain,
1631 const u8 index)
1632 {
1633 list_for_each_cookie(head->r.acl, &domain->acl_info_list[index]) {
1634 struct ccs_acl_info *ptr =
1635 list_entry(head->r.acl, typeof(*ptr), list);
1636 if (!ccs_print_entry(head, ptr))
1637 return false;
1638 }
1639 head->r.acl = NULL;
1640 return true;
1641 }
1642
1643 /**
1644 * ccs_read_domain - Read domain policy.
1645 *
1646 * @head: Pointer to "struct ccs_io_buffer".
1647 *
1648 * Returns nothing.
1649 *
1650 * Caller holds ccs_read_lock().
1651 */
1652 static void ccs_read_domain(struct ccs_io_buffer *head)
1653 {
1654 if (head->r.eof)
1655 return;
1656 list_for_each_cookie(head->r.domain, &ccs_domain_list) {
1657 struct ccs_domain_info *domain =
1658 list_entry(head->r.domain, typeof(*domain), list);
1659 switch (head->r.step) {
1660 u8 i;
1661 case 0:
1662 if (domain->is_deleted &&
1663 !head->r.print_this_domain_only)
1664 continue;
1665 /* Print domainname and flags. */
1666 ccs_set_string(head, domain->domainname->name);
1667 ccs_set_lf(head);
1668 ccs_io_printf(head, "use_profile %u\n",
1669 domain->profile);
1670 ccs_io_printf(head, "use_group %u\n", domain->group);
1671 for (i = 0; i < CCS_MAX_DOMAIN_INFO_FLAGS; i++)
1672 if (domain->flags[i])
1673 ccs_set_string(head, ccs_dif[i]);
1674 head->r.step++;
1675 ccs_set_lf(head);
1676 /* fall through */
1677 case 1:
1678 if (!ccs_read_domain2(head, domain, 0))
1679 return;
1680 head->r.step++;
1681 /* fall through */
1682 case 2:
1683 if (!ccs_read_domain2(head, domain, 1))
1684 return;
1685 head->r.step++;
1686 if (!ccs_set_lf(head))
1687 return;
1688 /* fall through */
1689 case 3:
1690 head->r.step = 0;
1691 if (head->r.print_this_domain_only)
1692 goto done;
1693 }
1694 }
1695 done:
1696 head->r.eof = true;
1697 }
1698
1699 /**
1700 * ccs_write_domain_profile - Assign profile for specified domain.
1701 *
1702 * @head: Pointer to "struct ccs_io_buffer".
1703 *
1704 * Returns 0 on success, -EINVAL otherwise.
1705 *
1706 * This is equivalent to doing
1707 *
1708 * ( echo "select " $domainname; echo "use_profile " $profile ) |
1709 * /usr/sbin/ccs-loadpolicy -d
1710 *
1711 * Caller holds ccs_read_lock().
1712 */
1713 static int ccs_write_domain_profile(struct ccs_io_buffer *head)
1714 {
1715 char *data = head->write_buf;
1716 char *cp = strchr(data, ' ');
1717 struct ccs_domain_info *domain;
1718 unsigned int profile;
1719 if (!cp)
1720 return -EINVAL;
1721 *cp = '\0';
1722 profile = simple_strtoul(data, NULL, 10);
1723 if (profile >= CCS_MAX_PROFILES)
1724 return -EINVAL;
1725 domain = ccs_find_domain(cp + 1);
1726 if (domain && (!ccs_policy_loaded || ccs_profile_ptr[(u8) profile]))
1727 domain->profile = (u8) profile;
1728 return 0;
1729 }
1730
1731 /**
1732 * ccs_read_domain_profile - Read only domainname and profile.
1733 *
1734 * @head: Pointer to "struct ccs_io_buffer".
1735 *
1736 * Returns nothing.
1737 *
1738 * This is equivalent to doing
1739 *
1740 * grep -A 1 '^<kernel>' /proc/ccs/domain_policy |
1741 * awk ' { if ( domainname == "" ) { if ( $1 == "<kernel>" )
1742 * domainname = $0; } else if ( $1 == "use_profile" ) {
1743 * print $2 " " domainname; domainname = ""; } } ; '
1744 *
1745 * Caller holds ccs_read_lock().
1746 */
1747 static void ccs_read_domain_profile(struct ccs_io_buffer *head)
1748 {
1749 if (head->r.eof)
1750 return;
1751 list_for_each_cookie(head->r.domain, &ccs_domain_list) {
1752 struct ccs_domain_info *domain =
1753 list_entry(head->r.domain, typeof(*domain), list);
1754 if (domain->is_deleted)
1755 continue;
1756 if (!ccs_flush(head))
1757 return;
1758 ccs_io_printf(head, "%u ", domain->profile);
1759 ccs_set_string(head, domain->domainname->name);
1760 ccs_set_lf(head);
1761 }
1762 head->r.eof = true;
1763 }
1764
1765 /**
1766 * ccs_write_pid - Specify PID to obtain domainname.
1767 *
1768 * @head: Pointer to "struct ccs_io_buffer".
1769 *
1770 * Returns 0.
1771 */
1772 static int ccs_write_pid(struct ccs_io_buffer *head)
1773 {
1774 head->r.eof = false;
1775 return 0;
1776 }
1777
1778 /**
1779 * ccs_read_pid - Read information of a process.
1780 *
1781 * @head: Pointer to "struct ccs_io_buffer".
1782 *
1783 * Returns the domainname which the specified PID is in or
1784 * process information of the specified PID on success,
1785 * empty string otherwise.
1786 *
1787 * Caller holds ccs_read_lock().
1788 */
1789 static void ccs_read_pid(struct ccs_io_buffer *head)
1790 {
1791 char *buf = head->write_buf;
1792 bool task_info = false;
1793 bool global_pid = false;
1794 unsigned int pid;
1795 struct task_struct *p;
1796 struct ccs_domain_info *domain = NULL;
1797 u32 ccs_flags = 0;
1798 /* Accessing write_buf is safe because head->io_sem is held. */
1799 if (!buf) {
1800 head->r.eof = true;
1801 return; /* Do nothing if open(O_RDONLY). */
1802 }
1803 if (head->r.w_pos || head->r.eof)
1804 return;
1805 head->r.eof = true;
1806 if (ccs_str_starts(&buf, "info "))
1807 task_info = true;
1808 if (ccs_str_starts(&buf, "global-pid "))
1809 global_pid = true;
1810 pid = (unsigned int) simple_strtoul(buf, NULL, 10);
1811 ccs_tasklist_lock();
1812 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
1813 if (global_pid)
1814 p = ccsecurity_exports.find_task_by_pid_ns(pid, &init_pid_ns);
1815 else
1816 p = ccsecurity_exports.find_task_by_vpid(pid);
1817 #else
1818 p = find_task_by_pid(pid);
1819 #endif
1820 if (p) {
1821 domain = ccs_task_domain(p);
1822 ccs_flags = ccs_task_flags(p);
1823 }
1824 ccs_tasklist_unlock();
1825 if (!domain)
1826 return;
1827 if (!task_info) {
1828 ccs_io_printf(head, "%u %u ", pid, domain->profile);
1829 ccs_set_string(head, domain->domainname->name);
1830 } else {
1831 ccs_io_printf(head, "%u manager=%s execute_handler=%s ", pid,
1832 ccs_yesno(ccs_flags &
1833 CCS_TASK_IS_MANAGER),
1834 ccs_yesno(ccs_flags &
1835 CCS_TASK_IS_EXECUTE_HANDLER));
1836 }
1837 }
1838
1839 /* String table for domain transition control keywords. */
1840 static const char * const ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = {
1841 [CCS_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
1842 [CCS_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ",
1843 [CCS_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ",
1844 [CCS_TRANSITION_CONTROL_KEEP] = "keep_domain ",
1845 };
1846
1847 /* String table for grouping keywords. */
1848 static const char * const ccs_group_name[CCS_MAX_GROUP] = {
1849 [CCS_PATH_GROUP] = "path_group ",
1850 [CCS_NUMBER_GROUP] = "number_group ",
1851 [CCS_ADDRESS_GROUP] = "address_group ",
1852 };
1853
1854 /**
1855 * ccs_write_exception - Write exception policy.
1856 *
1857 * @head: Pointer to "struct ccs_io_buffer".
1858 *
1859 * Returns 0 on success, negative value otherwise.
1860 */
1861 static int ccs_write_exception(struct ccs_io_buffer *head)
1862 {
1863 char *data = head->write_buf;
1864 const bool is_delete = ccs_str_starts(&data, "delete ");
1865 u8 i;
1866 static const struct {
1867 const char *keyword;
1868 int (*write) (char *, const bool);
1869 } ccs_callback[2] = {
1870 { "aggregator ", ccs_write_aggregator },
1871 { "deny_autobind ", ccs_write_reserved_port },
1872 };
1873 for (i = 0; i < 2; i++)
1874 if (ccs_str_starts(&data, ccs_callback[i].keyword))
1875 return ccs_callback[i].write(data, is_delete);
1876 for (i = 0; i < CCS_MAX_TRANSITION_TYPE; i++)
1877 if (ccs_str_starts(&data, ccs_transition_type[i]))
1878 return ccs_write_transition_control(data, is_delete,
1879 i);
1880 for (i = 0; i < CCS_MAX_GROUP; i++)
1881 if (ccs_str_starts(&data, ccs_group_name[i]))
1882 return ccs_write_group(data, is_delete, i);
1883 if (ccs_str_starts(&data, "acl_group ")) {
1884 unsigned int group;
1885 if (sscanf(data, "%u", &group) == 1 &&
1886 group < CCS_MAX_ACL_GROUPS) {
1887 data = strchr(data, ' ');
1888 if (data)
1889 return ccs_write_domain2(data + 1,
1890 &ccs_acl_group[group],
1891 is_delete);
1892 }
1893 }
1894 return -EINVAL;
1895 }
1896
1897 /**
1898 * ccs_read_group - Read "struct ccs_path_group"/"struct ccs_number_group"/"struct ccs_address_group" list.
1899 *
1900 * @head: Pointer to "struct ccs_io_buffer".
1901 * @idx: Index number.
1902 *
1903 * Returns true on success, false otherwise.
1904 *
1905 * Caller holds ccs_read_lock().
1906 */
1907 static bool ccs_read_group(struct ccs_io_buffer *head, const int idx)
1908 {
1909 list_for_each_cookie(head->r.group, &ccs_group_list[idx]) {
1910 struct ccs_group *group =
1911 list_entry(head->r.group, typeof(*group), head.list);
1912 list_for_each_cookie(head->r.acl, &group->member_list) {
1913 struct ccs_acl_head *ptr =
1914 list_entry(head->r.acl, typeof(*ptr), list);
1915 if (ptr->is_deleted)
1916 continue;
1917 if (!ccs_flush(head))
1918 return false;
1919 ccs_set_string(head, ccs_group_name[idx]);
1920 ccs_set_string(head, group->group_name->name);
1921 if (idx == CCS_PATH_GROUP) {
1922 ccs_set_space(head);
1923 ccs_set_string(head, container_of
1924 (ptr, struct ccs_path_group,
1925 head)->member_name->name);
1926 } else if (idx == CCS_NUMBER_GROUP) {
1927 ccs_print_number_union(head, &container_of
1928 (ptr, struct ccs_number_group,
1929 head)->number);
1930 } else if (idx == CCS_ADDRESS_GROUP) {
1931 char buffer[128];
1932 struct ccs_address_group *member =
1933 container_of(ptr, typeof(*member),
1934 head);
1935 if (member->is_ipv6)
1936 ccs_print_ipv6(buffer, sizeof(buffer),
1937 member->min.ipv6,
1938 member->max.ipv6);
1939 else
1940 ccs_print_ipv4(buffer, sizeof(buffer),
1941 member->min.ipv4,
1942 member->max.ipv4);
1943 ccs_io_printf(head, " %s", buffer);
1944 }
1945 ccs_set_lf(head);
1946 }
1947 head->r.acl = NULL;
1948 }
1949 head->r.group = NULL;
1950 return true;
1951 }
1952
1953 /**
1954 * ccs_read_policy - Read "struct ccs_..._entry" list.
1955 *
1956 * @head: Pointer to "struct ccs_io_buffer".
1957 * @idx: Index number.
1958 *
1959 * Returns true on success, false otherwise.
1960 *
1961 * Caller holds ccs_read_lock().
1962 */
1963 static bool ccs_read_policy(struct ccs_io_buffer *head, const int idx)
1964 {
1965 list_for_each_cookie(head->r.acl, &ccs_policy_list[idx]) {
1966 struct ccs_acl_head *acl =
1967 container_of(head->r.acl, typeof(*acl), list);
1968 if (acl->is_deleted)
1969 continue;
1970 if (head->r.print_transition_related_only &&
1971 idx != CCS_ID_TRANSITION_CONTROL)
1972 continue;
1973 if (!ccs_flush(head))
1974 return false;
1975 switch (idx) {
1976 case CCS_ID_TRANSITION_CONTROL:
1977 {
1978 struct ccs_transition_control *ptr =
1979 container_of(acl, typeof(*ptr), head);
1980 ccs_set_string(head,
1981 ccs_transition_type[ptr->type]);
1982 ccs_set_string(head, ptr->program ?
1983 ptr->program->name : "any");
1984 ccs_set_string(head, " from ");
1985 ccs_set_string(head, ptr->domainname ?
1986 ptr->domainname->name : "any");
1987 }
1988 break;
1989 case CCS_ID_AGGREGATOR:
1990 {
1991 struct ccs_aggregator *ptr =
1992 container_of(acl, typeof(*ptr), head);
1993 ccs_set_string(head, "aggregator ");
1994 ccs_set_string(head, ptr->original_name->name);
1995 ccs_set_space(head);
1996 ccs_set_string(head,
1997 ptr->aggregated_name->name);
1998 }
1999 break;
2000 case CCS_ID_RESERVEDPORT:
2001 {
2002 struct ccs_reserved *ptr =
2003 container_of(acl, typeof(*ptr), head);
2004 const u16 min_port = ptr->min_port;
2005 const u16 max_port = ptr->max_port;
2006 ccs_set_string(head, "deny_autobind ");
2007 ccs_io_printf(head, "%u", min_port);
2008 if (min_port != max_port)
2009 ccs_io_printf(head, "-%u", max_port);
2010 }
2011 break;
2012 default:
2013 continue;
2014 }
2015 ccs_set_lf(head);
2016 }
2017 head->r.acl = NULL;
2018 return true;
2019 }
2020
2021 /**
2022 * ccs_read_exception - Read exception policy.
2023 *
2024 * @head: Pointer to "struct ccs_io_buffer".
2025 *
2026 * Returns nothing.
2027 *
2028 * Caller holds ccs_read_lock().
2029 */
2030 static void ccs_read_exception(struct ccs_io_buffer *head)
2031 {
2032 if (head->r.eof)
2033 return;
2034 while (head->r.step < CCS_MAX_POLICY &&
2035 ccs_read_policy(head, head->r.step))
2036 head->r.step++;
2037 if (head->r.step < CCS_MAX_POLICY)
2038 return;
2039 while (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP &&
2040 ccs_read_group(head, head->r.step - CCS_MAX_POLICY))
2041 head->r.step++;
2042 if (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP)
2043 return;
2044 while (head->r.step < CCS_MAX_POLICY + CCS_MAX_GROUP
2045 + CCS_MAX_ACL_GROUPS * 2) {
2046 head->r.acl_group_index = (head->r.step - CCS_MAX_POLICY
2047 - CCS_MAX_GROUP) / 2;
2048 if (!ccs_read_domain2(head,
2049 &ccs_acl_group[head->r.acl_group_index],
2050 head->r.step & 1))
2051 return;
2052 head->r.step++;
2053 }
2054 head->r.eof = true;
2055 }
2056
2057 /* Wait queue for kernel -> userspace notification. */
2058 static DECLARE_WAIT_QUEUE_HEAD(ccs_query_wait);
2059 /* Wait queue for userspace -> kernel notification. */
2060 static DECLARE_WAIT_QUEUE_HEAD(ccs_answer_wait);
2061
2062 /* Structure for query. */
2063 struct ccs_query {
2064 struct list_head list;
2065 char *query;
2066 size_t query_len;
2067 unsigned int serial;
2068 u8 timer;
2069 u8 answer;
2070 u8 retry;
2071 };
2072
2073 /* The list for "struct ccs_query". */
2074 static LIST_HEAD(ccs_query_list);
2075
2076 /* Lock for manipulating ccs_query_list. */
2077 static DEFINE_SPINLOCK(ccs_query_list_lock);
2078
2079 /* Number of "struct file" referring /proc/ccs/query interface. */
2080 static atomic_t ccs_query_observers = ATOMIC_INIT(0);
2081
2082 /**
2083 * ccs_truncate - Truncate a line.
2084 *
2085 * @str: String to truncate.
2086 *
2087 * Returns length of truncated @str.
2088 */
2089 static int ccs_truncate(char *str)
2090 {
2091 char *start = str;
2092 while (*(unsigned char *) str > (unsigned char) ' ')
2093 str++;
2094 *str = '\0';
2095 return strlen(start) + 1;
2096 }
2097
2098 /**
2099 * ccs_add_entry - Add an ACL to current thread's domain. Used by learning mode.
2100 *
2101 * @header: Lines containing ACL.
2102 *
2103 * Returns nothing.
2104 */
2105 static void ccs_add_entry(char *header)
2106 {
2107 char *buffer;
2108 char *realpath = NULL;
2109 char *argv0 = NULL;
2110 char *symlink = NULL;
2111 char *handler;
2112 char *cp = strchr(header, '\n');
2113 int len;
2114 if (!cp)
2115 return;
2116 cp = strchr(cp + 1, '\n');
2117 if (!cp)
2118 return;
2119 *cp++ = '\0';
2120 len = strlen(cp) + 1;
2121 /* strstr() will return NULL if ordering is wrong. */
2122 if (*cp == 'f') {
2123 argv0 = strstr(header, " argv[]={ \"");
2124 if (argv0) {
2125 argv0 += 10;
2126 len += ccs_truncate(argv0) + 14;
2127 }
2128 realpath = strstr(header, " exec={ realpath=\"");
2129 if (realpath) {
2130 realpath += 8;
2131 len += ccs_truncate(realpath) + 6;
2132 }
2133 symlink = strstr(header, " symlink.target=\"");
2134 if (symlink)
2135 len += ccs_truncate(symlink + 1) + 1;
2136 }
2137 handler = strstr(header, "type=execute_handler");
2138 if (handler)
2139 len += ccs_truncate(handler) + 6;
2140 buffer = kmalloc(len, CCS_GFP_FLAGS);
2141 if (!buffer)
2142 return;
2143 snprintf(buffer, len - 1, "%s", cp);
2144 if (handler)
2145 ccs_addprintf(buffer, len, " task.%s", handler);
2146 if (realpath)
2147 ccs_addprintf(buffer, len, " exec.%s", realpath);
2148 if (argv0)
2149 ccs_addprintf(buffer, len, " exec.argv[0]=%s", argv0);
2150 if (symlink)
2151 ccs_addprintf(buffer, len, "%s", symlink);
2152 ccs_normalize_line(buffer);
2153 if (!ccs_write_domain2(buffer, ccs_current_domain(), false))
2154 ccs_update_stat(CCS_STAT_POLICY_UPDATES);
2155 kfree(buffer);
2156 }
2157
2158 /**
2159 * ccs_supervisor - Ask for the supervisor's decision.
2160 *
2161 * @r: Pointer to "struct ccs_request_info".
2162 * @fmt: The printf()'s format string, followed by parameters.
2163 *
2164 * Returns 0 if the supervisor decided to permit the access request which
2165 * violated the policy in enforcing mode, CCS_RETRY_REQUEST if the supervisor
2166 * decided to retry the access request which violated the policy in enforcing
2167 * mode, 0 if it is not in enforcing mode, -EPERM otherwise.
2168 */
2169 int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...)
2170 {
2171 va_list args;
2172 int error;
2173 int len;
2174 static unsigned int ccs_serial;
2175 struct ccs_query entry = { };
2176 bool quota_exceeded = false;
2177 va_start(args, fmt);
2178 len = vsnprintf((char *) &len, 1, fmt, args) + 1;
2179 va_end(args);
2180 /* Write /proc/ccs/audit. */
2181 va_start(args, fmt);
2182 ccs_write_log2(r, len, fmt, args);
2183 va_end(args);
2184 /* Nothing more to do if granted. */
2185 if (r->granted)
2186 return 0;
2187 if (r->mode)
2188 ccs_update_stat(r->mode);
2189 switch (r->mode) {
2190 int i;
2191 struct ccs_profile *p;
2192 case CCS_CONFIG_ENFORCING:
2193 error = -EPERM;
2194 if (atomic_read(&ccs_query_observers))
2195 break;
2196 if (r->dont_sleep_on_enforce_error)
2197 goto out;
2198 p = ccs_profile(r->profile);
2199 /* Check enforcing_penalty parameter. */
2200 for (i = 0; i < p->pref[CCS_PREF_ENFORCING_PENALTY]; i++) {
2201 set_current_state(TASK_INTERRUPTIBLE);
2202 schedule_timeout(HZ / 10);
2203 }
2204 goto out;
2205 case CCS_CONFIG_LEARNING:
2206 error = 0;
2207 /* Check mac_learning_entry parameter. */
2208 if (ccs_domain_quota_ok(r))
2209 break;
2210 /* fall through */
2211 default:
2212 return 0;
2213 }
2214 /* Get message. */
2215 va_start(args, fmt);
2216 entry.query = ccs_init_log(r, len, fmt, args);
2217 va_end(args);
2218 if (!entry.query)
2219 goto out;
2220 entry.query_len = strlen(entry.query) + 1;
2221 if (!error) {
2222 ccs_add_entry(entry.query);
2223 goto out;
2224 }
2225 len = ccs_round2(entry.query_len);
2226 spin_lock(&ccs_query_list_lock);
2227 if (ccs_memory_quota[CCS_MEMORY_QUERY] &&
2228 ccs_memory_used[CCS_MEMORY_QUERY] + len
2229 >= ccs_memory_quota[CCS_MEMORY_QUERY]) {
2230 quota_exceeded = true;
2231 } else {
2232 entry.serial = ccs_serial++;
2233 entry.retry = r->retry;
2234 ccs_memory_used[CCS_MEMORY_QUERY] += len;
2235 list_add_tail(&entry.list, &ccs_query_list);
2236 }
2237 spin_unlock(&ccs_query_list_lock);
2238 if (quota_exceeded)
2239 goto out;
2240 /* Give 10 seconds for supervisor's opinion. */
2241 while (entry.timer < 10) {
2242 wake_up_all(&ccs_query_wait);
2243 if (wait_event_interruptible_timeout
2244 (ccs_answer_wait, entry.answer ||
2245 !atomic_read(&ccs_query_observers), HZ))
2246 break;
2247 else
2248 entry.timer++;
2249 }
2250 spin_lock(&ccs_query_list_lock);
2251 list_del(&entry.list);
2252 ccs_memory_used[CCS_MEMORY_QUERY] -= len;
2253 spin_unlock(&ccs_query_list_lock);
2254 switch (entry.answer) {
2255 case 3: /* Asked to retry by administrator. */
2256 error = CCS_RETRY_REQUEST;
2257 r->retry++;
2258 break;
2259 case 1:
2260 /* Granted by administrator. */
2261 error = 0;
2262 break;
2263 default:
2264 /* Timed out or rejected by administrator. */
2265 break;
2266 }
2267 out:
2268 kfree(entry.query);
2269 return error;
2270 }
2271
2272 /**
2273 * ccs_poll_query - poll() for /proc/ccs/query.
2274 *
2275 * @file: Pointer to "struct file".
2276 * @wait: Pointer to "poll_table".
2277 *
2278 * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise.
2279 *
2280 * Waits for access requests which violated policy in enforcing mode.
2281 */
2282 static int ccs_poll_query(struct file *file, poll_table *wait)
2283 {
2284 struct list_head *tmp;
2285 bool found = false;
2286 u8 i;
2287 for (i = 0; i < 2; i++) {
2288 spin_lock(&ccs_query_list_lock);
2289 list_for_each(tmp, &ccs_query_list) {
2290 struct ccs_query *ptr =
2291 list_entry(tmp, typeof(*ptr), list);
2292 if (ptr->answer)
2293 continue;
2294 found = true;
2295 break;
2296 }
2297 spin_unlock(&ccs_query_list_lock);
2298 if (found)
2299 return POLLIN | POLLRDNORM;
2300 if (i)
2301 break;
2302 poll_wait(file, &ccs_query_wait, wait);
2303 }
2304 return 0;
2305 }
2306
2307 /**
2308 * ccs_read_query - Read access requests which violated policy in enforcing mode.
2309 *
2310 * @head: Pointer to "struct ccs_io_buffer".
2311 *
2312 * Returns nothing.
2313 */
2314 static void ccs_read_query(struct ccs_io_buffer *head)
2315 {
2316 struct list_head *tmp;
2317 unsigned int pos = 0;
2318 size_t len = 0;
2319 char *buf;
2320 if (head->r.w_pos)
2321 return;
2322 kfree(head->read_buf);
2323 head->read_buf = NULL;
2324 spin_lock(&ccs_query_list_lock);
2325 list_for_each(tmp, &ccs_query_list) {
2326 struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
2327 if (ptr->answer)
2328 continue;
2329 if (pos++ != head->r.query_index)
2330 continue;
2331 len = ptr->query_len;
2332 break;
2333 }
2334 spin_unlock(&ccs_query_list_lock);
2335 if (!len) {
2336 head->r.query_index = 0;
2337 return;
2338 }
2339 buf = kzalloc(len + 32, CCS_GFP_FLAGS);
2340 if (!buf)
2341 return;
2342 pos = 0;
2343 spin_lock(&ccs_query_list_lock);
2344 list_for_each(tmp, &ccs_query_list) {
2345 struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
2346 if (ptr->answer)
2347 continue;
2348 if (pos++ != head->r.query_index)
2349 continue;
2350 /*
2351 * Some query can be skipped because ccs_query_list
2352 * can change, but I don't care.
2353 */
2354 if (len == ptr->query_len)
2355 snprintf(buf, len + 32, "Q%u-%hu\n%s", ptr->serial,
2356 ptr->retry, ptr->query);
2357 break;
2358 }
2359 spin_unlock(&ccs_query_list_lock);
2360 if (buf[0]) {
2361 head->read_buf = buf;
2362 head->r.w[head->r.w_pos++] = buf;
2363 head->r.query_index++;
2364 } else {
2365 kfree(buf);
2366 }
2367 }
2368
2369 /**
2370 * ccs_write_answer - Write the supervisor's decision.
2371 *
2372 * @head: Pointer to "struct ccs_io_buffer".
2373 *
2374 * Returns 0 on success, -EINVAL otherwise.
2375 */
2376 static int ccs_write_answer(struct ccs_io_buffer *head)
2377 {
2378 char *data = head->write_buf;
2379 struct list_head *tmp;
2380 unsigned int serial;
2381 unsigned int answer;
2382 spin_lock(&ccs_query_list_lock);
2383 list_for_each(tmp, &ccs_query_list) {
2384 struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
2385 ptr->timer = 0;
2386 }
2387 spin_unlock(&ccs_query_list_lock);
2388 if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
2389 return -EINVAL;
2390 spin_lock(&ccs_query_list_lock);
2391 list_for_each(tmp, &ccs_query_list) {
2392 struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list);
2393 if (ptr->serial != serial)
2394 continue;
2395 if (!ptr->answer)
2396 ptr->answer = (u8) answer;
2397 break;
2398 }
2399 spin_unlock(&ccs_query_list_lock);
2400 wake_up_all(&ccs_answer_wait);
2401 return 0;
2402 }
2403
2404 /**
2405 * ccs_read_version - Get version.
2406 *
2407 * @head: Pointer to "struct ccs_io_buffer".
2408 *
2409 * Returns nothing.
2410 */
2411 static void ccs_read_version(struct ccs_io_buffer *head)
2412 {
2413 if (head->r.eof)
2414 return;
2415 ccs_set_string(head, "1.8.0");
2416 head->r.eof = true;
2417 }
2418
2419 /* String table for /proc/ccs/stat interface. */
2420 static const char * const ccs_policy_headers[CCS_MAX_POLICY_STAT] = {
2421 [CCS_STAT_POLICY_UPDATES] = "update:",
2422 [CCS_STAT_POLICY_LEARNING] = "violation in learning mode:",
2423 [CCS_STAT_POLICY_PERMISSIVE] = "violation in permissive mode:",
2424 [CCS_STAT_POLICY_ENFORCING] = "violation in enforcing mode:",
2425 };
2426
2427 /* String table for /proc/ccs/stat interface. */
2428 static const char * const ccs_memory_headers[CCS_MAX_MEMORY_STAT] = {
2429 [CCS_MEMORY_POLICY] = "policy:",
2430 [CCS_MEMORY_AUDIT] = "audit log:",
2431 [CCS_MEMORY_QUERY] = "query message:",
2432 };
2433
2434 /* Timestamp counter for last updated. */
2435 static unsigned int ccs_stat_updated[CCS_MAX_POLICY_STAT];
2436 /* Counter for number of updates. */
2437 static unsigned int ccs_stat_modified[CCS_MAX_POLICY_STAT];
2438
2439 /**
2440 * ccs_update_stat - Update statistic counters.
2441 *
2442 * @index: Index for policy type.
2443 *
2444 * Returns nothing.
2445 */
2446 void ccs_update_stat(const u8 index)
2447 {
2448 struct timeval tv;
2449 do_gettimeofday(&tv);
2450 /*
2451 * I don't use atomic operations because race condition is not fatal.
2452 */
2453 ccs_stat_updated[index]++;
2454 ccs_stat_modified[index] = tv.tv_sec;
2455 }
2456
2457 /**
2458 * ccs_read_stat - Read statistic data.
2459 *
2460 * @head: Pointer to "struct ccs_io_buffer".
2461 *
2462 * Returns nothing.
2463 */
2464 static void ccs_read_stat(struct ccs_io_buffer *head)
2465 {
2466 u8 i;
2467 unsigned int total = 0;
2468 if (head->r.eof)
2469 return;
2470 for (i = 0; i < CCS_MAX_POLICY_STAT; i++) {
2471 ccs_io_printf(head, "Policy %-30s %10u", ccs_policy_headers[i],
2472 ccs_stat_updated[i]);
2473 if (ccs_stat_modified[i]) {
2474 struct ccs_time stamp;
2475 ccs_convert_time(ccs_stat_modified[i], &stamp);
2476 ccs_io_printf(head, " (Last: %04u/%02u/%02u "
2477 "%02u:%02u:%02u)",
2478 stamp.year, stamp.month, stamp.day,
2479 stamp.hour, stamp.min, stamp.sec);
2480 }
2481 ccs_set_lf(head);
2482 }
2483 for (i = 0; i < CCS_MAX_MEMORY_STAT; i++) {
2484 unsigned int used = ccs_memory_used[i];
2485 total += used;
2486 ccs_io_printf(head, "Memory used by %-22s %10u",
2487 ccs_memory_headers[i], used);
2488 used = ccs_memory_quota[i];
2489 if (used)
2490 ccs_io_printf(head, " (Quota: %10u)", used);
2491 ccs_set_lf(head);
2492 }
2493 ccs_io_printf(head, "Total memory used: %10u\n",
2494 total);
2495 head->r.eof = true;
2496 }
2497
2498 /**
2499 * ccs_write_stat - Set memory quota.
2500 *
2501 * @head: Pointer to "struct ccs_io_buffer".
2502 *
2503 * Returns 0.
2504 */
2505 static int ccs_write_stat(struct ccs_io_buffer *head)
2506 {
2507 char *data = head->write_buf;
2508 u8 i;
2509 if (ccs_str_starts(&data, "Memory used by "))
2510 for (i = 0; i < CCS_MAX_MEMORY_STAT; i++)
2511 if (ccs_str_starts(&data, ccs_memory_headers[i]))
2512 sscanf(data, "%u", &ccs_memory_quota[i]);
2513 return 0;
2514 }
2515
2516 /**
2517 * ccs_open_control - open() for /proc/ccs/ interface.
2518 *
2519 * @type: Type of interface.
2520 * @file: Pointer to "struct file".
2521 *
2522 * Returns 0 on success, negative value otherwise.
2523 */
2524 int ccs_open_control(const u8 type, struct file *file)
2525 {
2526 struct ccs_io_buffer *head = kzalloc(sizeof(*head), CCS_GFP_FLAGS);
2527 if (!head)
2528 return -ENOMEM;
2529 mutex_init(&head->io_sem);
2530 head->type = type;
2531 switch (type) {
2532 case CCS_DOMAINPOLICY: /* /proc/ccs/domain_policy */
2533 head->write = ccs_write_domain;
2534 head->read = ccs_read_domain;
2535 break;
2536 case CCS_EXCEPTIONPOLICY: /* /proc/ccs/exception_policy */
2537 head->write = ccs_write_exception;
2538 head->read = ccs_read_exception;
2539 break;
2540 case CCS_AUDIT: /* /proc/ccs/audit */
2541 head->poll = ccs_poll_log;
2542 head->read = ccs_read_log;
2543 break;
2544 case CCS_DOMAIN_STATUS: /* /proc/ccs/.domain_status */
2545 head->write = ccs_write_domain_profile;
2546 head->read = ccs_read_domain_profile;
2547 break;
2548 case CCS_EXECUTE_HANDLER: /* /proc/ccs/.execute_handler */
2549 /* Allow execute_handler to read process's status. */
2550 if (!(ccs_current_flags() & CCS_TASK_IS_EXECUTE_HANDLER)) {
2551 kfree(head);
2552 return -EPERM;
2553 }
2554 /* fall through */
2555 case CCS_PROCESS_STATUS: /* /proc/ccs/.process_status */
2556 head->write = ccs_write_pid;
2557 head->read = ccs_read_pid;
2558 break;
2559 case CCS_VERSION: /* /proc/ccs/version */
2560 head->read = ccs_read_version;
2561 head->readbuf_size = 128;
2562 break;
2563 case CCS_STAT: /* /proc/ccs/stat */
2564 head->write = ccs_write_stat;
2565 head->read = ccs_read_stat;
2566 head->readbuf_size = 1024;
2567 break;
2568 case CCS_PROFILE: /* /proc/ccs/profile */
2569 head->write = ccs_write_profile;
2570 head->read = ccs_read_profile;
2571 break;
2572 case CCS_QUERY: /* /proc/ccs/query */
2573 head->poll = ccs_poll_query;
2574 head->write = ccs_write_answer;
2575 head->read = ccs_read_query;
2576 break;
2577 case CCS_MANAGER: /* /proc/ccs/manager */
2578 head->write = ccs_write_manager;
2579 head->read = ccs_read_manager;
2580 break;
2581 }
2582 if (!(file->f_mode & FMODE_READ)) {
2583 /*
2584 * No need to allocate read_buf since it is not opened
2585 * for reading.
2586 */
2587 head->read = NULL;
2588 head->poll = NULL;
2589 } else if (!head->poll) {
2590 /* Don't allocate read_buf for poll() access. */
2591 if (!head->readbuf_size)
2592 head->readbuf_size = 4096;
2593 head->read_buf = kzalloc(head->readbuf_size, CCS_GFP_FLAGS);
2594 if (!head->read_buf) {
2595 kfree(head);
2596 return -ENOMEM;
2597 }
2598 }
2599 if (!(file->f_mode & FMODE_WRITE)) {
2600 /*
2601 * No need to allocate write_buf since it is not opened
2602 * for writing.
2603 */
2604 head->write = NULL;
2605 } else if (head->write) {
2606 head->writebuf_size = 4096;
2607 head->write_buf = kzalloc(head->writebuf_size, CCS_GFP_FLAGS);
2608 if (!head->write_buf) {
2609 kfree(head->read_buf);
2610 kfree(head);
2611 return -ENOMEM;
2612 }
2613 }
2614 /*
2615 * If the file is /proc/ccs/query, increment the observer counter.
2616 * The obserber counter is used by ccs_supervisor() to see if
2617 * there is some process monitoring /proc/ccs/query.
2618 */
2619 if (type == CCS_QUERY)
2620 atomic_inc(&ccs_query_observers);
2621 file->private_data = head;
2622 ccs_notify_gc(head, true);
2623 return 0;
2624 }
2625
2626 /**
2627 * ccs_poll_control - poll() for /proc/ccs/ interface.
2628 *
2629 * @file: Pointer to "struct file".
2630 * @wait: Pointer to "poll_table".
2631 *
2632 * Returns return value of poll().
2633 *
2634 * Waits for read readiness.
2635 * /proc/ccs/query is handled by /usr/sbin/ccs-queryd and
2636 * /proc/ccs/audit is handled by /usr/sbin/ccs-auditd.
2637 */
2638 int ccs_poll_control(struct file *file, poll_table *wait)
2639 {
2640 struct ccs_io_buffer *head = file->private_data;
2641 if (!head->poll)
2642 return -ENOSYS;
2643 return head->poll(file, wait);
2644 }
2645
2646 /**
2647 * ccs_read_control - read() for /proc/ccs/ interface.
2648 *
2649 * @file: Pointer to "struct file".
2650 * @buffer: Poiner to buffer to write to.
2651 * @buffer_len: Size of @buffer.
2652 *
2653 * Returns bytes read on success, negative value otherwise.
2654 */
2655 ssize_t ccs_read_control(struct file *file, char __user *buffer,
2656 const size_t buffer_len)
2657 {
2658 int len;
2659 struct ccs_io_buffer *head = file->private_data;
2660 int idx;
2661 if (!head->read)
2662 return -ENOSYS;
2663 if (!access_ok(VERIFY_WRITE, buffer, buffer_len))
2664 return -EFAULT;
2665 if (mutex_lock_interruptible(&head->io_sem))
2666 return -EINTR;
2667 head->read_user_buf = buffer;
2668 head->read_user_buf_avail = buffer_len;
2669 idx = ccs_read_lock();
2670 if (ccs_flush(head))
2671 /* Call the policy handler. */
2672 head->read(head);
2673 ccs_flush(head);
2674 ccs_read_unlock(idx);
2675 len = head->read_user_buf - buffer;
2676 mutex_unlock(&head->io_sem);
2677 return len;
2678 }
2679
2680 /**
2681 * ccs_write_control - write() for /proc/ccs/ interface.
2682 *
2683 * @file: Pointer to "struct file".
2684 * @buffer: Pointer to buffer to read from.
2685 * @buffer_len: Size of @buffer.
2686 *
2687 * Returns @buffer_len on success, negative value otherwise.
2688 */
2689 ssize_t ccs_write_control(struct file *file, const char __user *buffer,
2690 const size_t buffer_len)
2691 {
2692 struct ccs_io_buffer *head = file->private_data;
2693 int error = buffer_len;
2694 size_t avail_len = buffer_len;
2695 char *cp0 = head->write_buf;
2696 int idx;
2697 if (!head->write)
2698 return -ENOSYS;
2699 if (!access_ok(VERIFY_READ, buffer, buffer_len))
2700 return -EFAULT;
2701 if (mutex_lock_interruptible(&head->io_sem))
2702 return -EINTR;
2703 idx = ccs_read_lock();
2704 /* Don't allow updating policies by non manager programs. */
2705 if (head->write != ccs_write_pid && head->write != ccs_write_domain &&
2706 !ccs_manager()) {
2707 ccs_read_unlock(idx);
2708 mutex_unlock(&head->io_sem);
2709 return -EPERM;
2710 }
2711 /* Read a line and dispatch it to the policy handler. */
2712 while (avail_len > 0) {
2713 char c;
2714 if (head->w.avail >= head->writebuf_size - 1) {
2715 const int len = head->writebuf_size * 2;
2716 char *cp = kzalloc(len, CCS_GFP_FLAGS);
2717 if (!cp) {
2718 error = -ENOMEM;
2719 break;
2720 }
2721 memmove(cp, cp0, head->w.avail);
2722 kfree(cp0);
2723 head->write_buf = cp;
2724 cp0 = cp;
2725 head->writebuf_size = len;
2726 }
2727 if (get_user(c, buffer)) {
2728 error = -EFAULT;
2729 break;
2730 }
2731 buffer++;
2732 avail_len--;
2733 cp0[head->w.avail++] = c;
2734 if (c != '\n')
2735 continue;
2736 cp0[head->w.avail - 1] = '\0';
2737 head->w.avail = 0;
2738 ccs_normalize_line(cp0);
2739 if (head->write(head))
2740 continue;
2741 switch (head->type) {
2742 case CCS_DOMAINPOLICY:
2743 case CCS_EXCEPTIONPOLICY:
2744 case CCS_DOMAIN_STATUS:
2745 case CCS_STAT:
2746 case CCS_PROFILE:
2747 case CCS_MANAGER:
2748 ccs_update_stat(CCS_STAT_POLICY_UPDATES);
2749 break;
2750 default:
2751 break;
2752 }
2753 }
2754 ccs_read_unlock(idx);
2755 mutex_unlock(&head->io_sem);
2756 return error;
2757 }
2758
2759 /**
2760 * ccs_close_control - close() for /proc/ccs/ interface.
2761 *
2762 * @file: Pointer to "struct file".
2763 *
2764 * Returns 0.
2765 */
2766 int ccs_close_control(struct file *file)
2767 {
2768 struct ccs_io_buffer *head = file->private_data;
2769 file->private_data = NULL;
2770 /*
2771 * If the file is /proc/ccs/query, decrement the observer counter.
2772 */
2773 if (head->type == CCS_QUERY &&
2774 atomic_dec_and_test(&ccs_query_observers))
2775 wake_up_all(&ccs_answer_wait);
2776 ccs_notify_gc(head, false);
2777 return 0;
2778 }
2779
2780 /**
2781 * ccs_policy_io_init - Register hooks for policy I/O.
2782 *
2783 * Returns nothing.
2784 */
2785 void __init ccs_policy_io_init(void)
2786 {
2787 ccsecurity_ops.check_profile = ccs_check_profile;
2788 }
2789
2790 #ifdef CONFIG_CCSECURITY_USE_BUILTIN_POLICY
2791 /**
2792 * ccs_load_builtin_policy - Load built-in policy.
2793 *
2794 * Returns nothing.
2795 */
2796 void __init ccs_load_builtin_policy(void)
2797 {
2798 /*
2799 * This include file is manually created and contains built-in policy
2800 * named "ccs_builtin_profile", "ccs_builtin_exception_policy",
2801 * "ccs_builtin_domain_policy", "ccs_builtin_manager",
2802 * "ccs_builtin_stat" in the form of "static char [] __initdata".
2803 */
2804 #include "builtin-policy.h"
2805 struct ccs_io_buffer head;
2806 u8 i;
2807 const int idx = ccs_read_lock();
2808 for (i = 0; i < 5; i++) {
2809 char *start = "";
2810 memset(&head, 0, sizeof(head));
2811 switch (i) {
2812 case 0:
2813 start = ccs_builtin_profile;
2814 head.write = ccs_write_profile;
2815 break;
2816 case 1:
2817 start = ccs_builtin_exception_policy;
2818 head.write = ccs_write_exception;
2819 break;
2820 case 2:
2821 start = ccs_builtin_domain_policy;
2822 head.write = ccs_write_domain;
2823 break;
2824 case 3:
2825 start = ccs_builtin_manager;
2826 head.write = ccs_write_manager;
2827 break;
2828 case 4:
2829 start = ccs_builtin_stat;
2830 head.write = ccs_write_stat;
2831 break;
2832 }
2833 while (1) {
2834 char *end = strchr(start, '\n');
2835 if (!end)
2836 break;
2837 *end = '\0';
2838 ccs_normalize_line(start);
2839 head.write_buf = start;
2840 head.write(&head);
2841 start = end + 1;
2842 }
2843 }
2844 ccs_read_unlock(idx);
2845 #ifdef CONFIG_CCSECURITY_ACTIVATE_FROM_THE_BEGINNING
2846 ccs_check_profile();
2847 #endif
2848 }
2849 #endif

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26