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

Subversion リポジトリの参照

Contents of /trunk/1.7.x/ccs-patch/security/ccsecurity/realpath.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2717 - (show annotations) (download) (as text)
Wed Jul 1 12:59:55 2009 UTC (14 years, 10 months ago) by kumaneko
Original Path: branches/ccs-patch/fs/realpath.c
File MIME type: text/x-csrc
File size: 38969 byte(s)


1 /*
2 * fs/realpath.c
3 *
4 * Get the canonicalized absolute pathnames. The basis for SAKURA and TOMOYO.
5 *
6 * Copyright (C) 2005-2009 NTT DATA CORPORATION
7 *
8 * Version: 1.7.0-pre 2009/05/28
9 *
10 * This file is applicable to both 2.4.30 and 2.6.11 and later.
11 * See README.ccs for ChangeLog.
12 *
13 */
14 #include <linux/string.h>
15 #include <linux/mm.h>
16 #include <linux/utime.h>
17 #include <linux/file.h>
18 #include <linux/smp_lock.h>
19 #include <linux/module.h>
20 #include <linux/slab.h>
21 #include <asm/uaccess.h>
22 #include <asm/atomic.h>
23 #include <linux/version.h>
24 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
25 #include <linux/namei.h>
26 #include <linux/mount.h>
27 static const int ccs_lookup_flags = LOOKUP_FOLLOW;
28 #else
29 static const int ccs_lookup_flags = LOOKUP_FOLLOW | LOOKUP_POSITIVE;
30 #endif
31 #include <linux/proc_fs.h>
32 #include <linux/ccs_common.h>
33 #include <linux/realpath.h>
34 #include <net/sock.h>
35
36 /**
37 * ccs_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
38 *
39 * @dentry: Pointer to "struct dentry".
40 * @vfsmnt: Pointer to "struct vfsmount".
41 * @buffer: Pointer to buffer to return value in.
42 * @buflen: Sizeof @buffer.
43 *
44 * Returns 0 on success, -ENOMEM otherwise.
45 *
46 * Caller holds the dcache_lock and vfsmount_lock.
47 * Based on __d_path() in fs/dcache.c
48 *
49 * If dentry is a directory, trailing '/' is appended.
50 * Characters out of 0x20 < c < 0x7F range are converted to
51 * \ooo style octal string.
52 * Character \ is converted to \\ string.
53 */
54 static int ccs_get_absolute_path(struct dentry *dentry, struct vfsmount *vfsmnt,
55 char *buffer, int buflen)
56 {
57 /***** CRITICAL SECTION START *****/
58 char *start = buffer;
59 char *end = buffer + buflen;
60 bool is_dir = (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode));
61
62 if (buflen < 256)
63 goto out;
64
65 *--end = '\0';
66 buflen--;
67
68 for (;;) {
69 struct dentry *parent;
70
71 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
72 /* Global root? */
73 if (vfsmnt->mnt_parent == vfsmnt)
74 break;
75 dentry = vfsmnt->mnt_mountpoint;
76 vfsmnt = vfsmnt->mnt_parent;
77 continue;
78 }
79 if (is_dir) {
80 is_dir = false;
81 *--end = '/';
82 buflen--;
83 }
84 parent = dentry->d_parent;
85 {
86 const char *sp = dentry->d_name.name;
87 const char *cp = sp + dentry->d_name.len - 1;
88 unsigned char c;
89
90 /*
91 * Exception: Use /proc/self/ rather than
92 * /proc/\$/ for current process.
93 */
94 if (IS_ROOT(parent) && *sp > '0' && *sp <= '9' &&
95 parent->d_sb &&
96 parent->d_sb->s_magic == PROC_SUPER_MAGIC) {
97 char *ep;
98 const pid_t pid
99 = (pid_t) simple_strtoul(sp, &ep, 10);
100 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
101 const pid_t tgid
102 = task_tgid_nr_ns(current,
103 dentry->d_sb->
104 s_fs_info);
105 if (!*ep && pid == tgid && tgid) {
106 sp = "self";
107 cp = sp + 3;
108 }
109 #else
110 if (!*ep && pid == sys_getpid()) {
111 sp = "self";
112 cp = sp + 3;
113 }
114 #endif
115 }
116
117 while (sp <= cp) {
118 c = *(unsigned char *) cp;
119 if (c == '\\') {
120 buflen -= 2;
121 if (buflen < 0)
122 goto out;
123 *--end = '\\';
124 *--end = '\\';
125 } else if (c > ' ' && c < 127) {
126 if (--buflen < 0)
127 goto out;
128 *--end = (char) c;
129 } else {
130 buflen -= 4;
131 if (buflen < 0)
132 goto out;
133 *--end = (c & 7) + '0';
134 *--end = ((c >> 3) & 7) + '0';
135 *--end = (c >> 6) + '0';
136 *--end = '\\';
137 }
138 cp--;
139 }
140 if (--buflen < 0)
141 goto out;
142 *--end = '/';
143 }
144 dentry = parent;
145 }
146 if (*end == '/') {
147 buflen++;
148 end++;
149 }
150 {
151 const char *sp = dentry->d_name.name;
152 const char *cp = sp + dentry->d_name.len - 1;
153 unsigned char c;
154 while (sp <= cp) {
155 c = *(unsigned char *) cp;
156 if (c == '\\') {
157 buflen -= 2;
158 if (buflen < 0)
159 goto out;
160 *--end = '\\';
161 *--end = '\\';
162 } else if (c > ' ' && c < 127) {
163 if (--buflen < 0)
164 goto out;
165 *--end = (char) c;
166 } else {
167 buflen -= 4;
168 if (buflen < 0)
169 goto out;
170 *--end = (c & 7) + '0';
171 *--end = ((c >> 3) & 7) + '0';
172 *--end = (c >> 6) + '0';
173 *--end = '\\';
174 }
175 cp--;
176 }
177 }
178 /* Move the pathname to the top of the buffer. */
179 memmove(start, end, strlen(end) + 1);
180 return 0;
181 out:
182 return -ENOMEM;
183 /***** CRITICAL SECTION END *****/
184 }
185
186 #define SOCKFS_MAGIC 0x534F434B
187
188 /**
189 * ccs_realpath_from_dentry2 - Returns realpath(3) of the given dentry but ignores chroot'ed root.
190 *
191 * @dentry: Pointer to "struct dentry".
192 * @mnt: Pointer to "struct vfsmount".
193 * @newname: Pointer to buffer to return value in.
194 * @newname_len: Size of @newname.
195 *
196 * Returns 0 on success, negative value otherwise.
197 */
198 static int ccs_realpath_from_dentry2(struct dentry *dentry,
199 struct vfsmount *mnt,
200 char *newname, int newname_len)
201 {
202 int error = -EINVAL;
203 struct dentry *d_dentry;
204 struct vfsmount *d_mnt;
205 if (!dentry || !newname || newname_len <= 2048)
206 goto out;
207 /* Get better name for socket. */
208 if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
209 struct inode *inode = dentry->d_inode;
210 struct socket *sock = inode ? SOCKET_I(inode) : NULL;
211 struct sock *sk = sock ? sock->sk : NULL;
212 if (sk) {
213 snprintf(newname, newname_len - 1,
214 "socket:[family=%u:type=%u:protocol=%u]",
215 sk->sk_family, sk->sk_type, sk->sk_protocol);
216 } else {
217 snprintf(newname, newname_len - 1, "socket:[unknown]");
218 }
219 return 0;
220 }
221 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
222 if (dentry->d_op && dentry->d_op->d_dname) {
223 /* For "socket:[\$]" and "pipe:[\$]". */
224 static const int offset = 1536;
225 char *dp = newname;
226 char *sp = dentry->d_op->d_dname(dentry, newname + offset,
227 newname_len - offset);
228 if (IS_ERR(sp)) {
229 error = PTR_ERR(sp);
230 goto out;
231 }
232 error = -ENOMEM;
233 newname += offset;
234 while (1) {
235 const unsigned char c = *(unsigned char *) sp++;
236 if (c == '\\') {
237 if (dp + 2 >= newname)
238 break;
239 *dp++ = '\\';
240 *dp++ = '\\';
241 } else if (c > ' ' && c < 127) {
242 if (dp + 1 >= newname)
243 break;
244 *dp++ = (char) c;
245 } else if (c) {
246 if (dp + 4 >= newname)
247 break;
248 *dp++ = '\\';
249 *dp++ = (c >> 6) + '0';
250 *dp++ = ((c >> 3) & 7) + '0';
251 *dp++ = (c & 7) + '0';
252 } else {
253 *dp = '\0';
254 return 0;
255 }
256 }
257 goto out;
258 }
259 #endif
260 if (!mnt)
261 goto out;
262 d_dentry = dget(dentry);
263 d_mnt = mntget(mnt);
264 /***** CRITICAL SECTION START *****/
265 ccs_realpath_lock();
266 error = ccs_get_absolute_path(d_dentry, d_mnt, newname, newname_len);
267 ccs_realpath_unlock();
268 /***** CRITICAL SECTION END *****/
269 dput(d_dentry);
270 mntput(d_mnt);
271 out:
272 if (error)
273 printk(KERN_WARNING "ccs_realpath: Pathname too long. (%d)\n",
274 error);
275 return error;
276 }
277
278 /**
279 * ccs_realpath_from_dentry - Returns realpath(3) of the given pathname but ignores chroot'ed root.
280 *
281 * @dentry: Pointer to "struct dentry".
282 * @mnt: Pointer to "struct vfsmount".
283 *
284 * Returns the realpath of the given @dentry and @mnt on success,
285 * NULL otherwise.
286 *
287 * These functions use kzalloc(), so caller must kfree()
288 * if these functions didn't return NULL.
289 */
290 char *ccs_realpath_from_dentry(struct dentry *dentry, struct vfsmount *mnt)
291 {
292 char *buf = kzalloc(CCS_MAX_PATHNAME_LEN, GFP_KERNEL);
293 if (buf && ccs_realpath_from_dentry2(dentry, mnt, buf,
294 CCS_MAX_PATHNAME_LEN - 2) == 0)
295 return buf;
296 kfree(buf);
297 return NULL;
298 }
299
300 /**
301 * ccs_realpath - Get realpath of a pathname.
302 *
303 * @pathname: The pathname to solve.
304 *
305 * Returns the realpath of @pathname on success, NULL otherwise.
306 */
307 char *ccs_realpath(const char *pathname)
308 {
309 struct nameidata nd;
310 if (pathname && path_lookup(pathname, ccs_lookup_flags, &nd) == 0) {
311 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
312 char *buf = ccs_realpath_from_dentry(nd.path.dentry,
313 nd.path.mnt);
314 path_put(&nd.path);
315 #else
316 char *buf = ccs_realpath_from_dentry(nd.dentry, nd.mnt);
317 path_release(&nd);
318 #endif
319 return buf;
320 }
321 return NULL;
322 }
323
324 /**
325 * ccs_realpath_both - Get realpath of a pathname and symlink.
326 *
327 * @pathname: The pathname to solve.
328 * @ee: Pointer to "struct ccs_execve_entry".
329 *
330 * Returns 0 on success, negative value otherwise.
331 */
332 int ccs_realpath_both(const char *pathname, struct ccs_execve_entry *ee)
333 {
334 struct nameidata nd;
335 int ret;
336 bool is_symlink;
337 if (!pathname ||
338 path_lookup(pathname, ccs_lookup_flags ^ LOOKUP_FOLLOW, &nd))
339 return -ENOENT;
340 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
341 is_symlink = nd.path.dentry->d_inode &&
342 S_ISLNK(nd.path.dentry->d_inode->i_mode);
343 ret = ccs_realpath_from_dentry2(nd.path.dentry, nd.path.mnt,
344 ee->tmp, CCS_EXEC_TMPSIZE - 1);
345 path_put(&nd.path);
346 #else
347 is_symlink = nd.dentry->d_inode && S_ISLNK(nd.dentry->d_inode->i_mode);
348 ret = ccs_realpath_from_dentry2(nd.dentry, nd.mnt, ee->tmp,
349 CCS_EXEC_TMPSIZE - 1);
350 path_release(&nd);
351 #endif
352 if (ret)
353 return -ENOMEM;
354 if (strlen(ee->tmp) > CCS_MAX_PATHNAME_LEN - 1)
355 return -ENOMEM;
356 ee->program_path[CCS_MAX_PATHNAME_LEN - 1] = '\0';
357 if (!is_symlink) {
358 strncpy(ee->program_path, ee->tmp,
359 CCS_MAX_PATHNAME_LEN - 1);
360 return 0;
361 }
362 if (path_lookup(pathname, ccs_lookup_flags, &nd))
363 return -ENOENT;
364 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
365 ret = ccs_realpath_from_dentry2(nd.path.dentry, nd.path.mnt,
366 ee->program_path,
367 CCS_MAX_PATHNAME_LEN - 1);
368 path_put(&nd.path);
369 #else
370 ret = ccs_realpath_from_dentry2(nd.dentry, nd.mnt, ee->program_path,
371 CCS_MAX_PATHNAME_LEN - 1);
372 path_release(&nd);
373 #endif
374 return ret ? -ENOMEM : 0;
375 }
376
377 /**
378 * ccs_encode: Encode binary string to ascii string.
379 *
380 * @str: String in binary format.
381 *
382 * Returns pointer to @str in ascii format on success, NULL otherwise.
383 *
384 * This function uses kzalloc(), so caller must kfree() if this function
385 * didn't return NULL.
386 */
387 char *ccs_encode(const char *str)
388 {
389 int len = 0;
390 const char *p = str;
391 char *cp;
392 char *cp0;
393 if (!p)
394 return NULL;
395 while (*p) {
396 const unsigned char c = *p++;
397 if (c == '\\')
398 len += 2;
399 else if (c > ' ' && c < 127)
400 len++;
401 else
402 len += 4;
403 }
404 len++;
405 cp = kzalloc(len, GFP_KERNEL);
406 if (!cp)
407 return NULL;
408 cp0 = cp;
409 p = str;
410 while (*p) {
411 const unsigned char c = *p++;
412 if (c == '\\') {
413 *cp++ = '\\';
414 *cp++ = '\\';
415 } else if (c > ' ' && c < 127) {
416 *cp++ = c;
417 } else {
418 *cp++ = '\\';
419 *cp++ = (c >> 6) + '0';
420 *cp++ = ((c >> 3) & 7) + '0';
421 *cp++ = (c & 7) + '0';
422 }
423 }
424 return cp0;
425 }
426
427 /**
428 * ccs_round_up - Round up an integer so that the returned pointers are appropriately aligned.
429 *
430 * @size: Size in bytes.
431 *
432 * Returns rounded value of @size.
433 *
434 * FIXME: Are there more requirements that is needed for assigning value
435 * atomically?
436 */
437 static inline unsigned int ccs_round_up(const unsigned int size)
438 {
439 if (sizeof(void *) >= sizeof(long))
440 return ((size + sizeof(void *) - 1)
441 / sizeof(void *)) * sizeof(void *);
442 else
443 return ((size + sizeof(long) - 1)
444 / sizeof(long)) * sizeof(long);
445 }
446
447 static atomic_t ccs_allocated_memory_for_elements;
448 static unsigned int ccs_quota_for_elements;
449
450 /**
451 * ccs_memory_ok - Check memory quota.
452 *
453 * @ptr: Pointer to allocated memory.
454 *
455 * Returns true if @ptr is not NULL and quota not exceeded, false otehrwise.
456 */
457 bool ccs_memory_ok(const void *ptr)
458 {
459 const unsigned int len = ptr ? ksize(ptr) : 0;
460 if (len && (!ccs_quota_for_elements ||
461 atomic_read(&ccs_allocated_memory_for_elements) + len
462 <= ccs_quota_for_elements)) {
463 atomic_add(len, &ccs_allocated_memory_for_elements);
464 return true;
465 }
466 printk(KERN_WARNING "ERROR: Out of memory. (%s)\n", __func__);
467 if (!ccs_policy_loaded)
468 panic("MAC Initialization failed.\n");
469 return false;
470 }
471
472 /**
473 * ccs_memory_free - Free memory for elements.
474 *
475 * @ptr: Pointer to allocated memory.
476 * @size: Size of @ptr .
477 */
478 static void ccs_memory_free(const void *ptr, size_t size)
479 {
480 atomic_sub(size, &ccs_allocated_memory_for_elements);
481 kfree(ptr);
482 }
483
484 /**
485 * ccs_put_path_group - Delete memory for "struct ccs_path_group_entry".
486 *
487 * @group: Pointer to "struct ccs_path_group_entry".
488 */
489 void ccs_put_path_group(struct ccs_path_group_entry *group)
490 {
491 struct ccs_path_group_member *member;
492 struct ccs_path_group_member *next_member;
493 LIST_HEAD(q);
494 bool can_delete_group = false;
495 if (!group)
496 return;
497 mutex_lock(&ccs_policy_lock);
498 if (atomic_dec_and_test(&group->users)) {
499 list_for_each_entry_safe(member, next_member,
500 &group->path_group_member_list,
501 list) {
502 if (!member->is_deleted)
503 break;
504 list_del(&member->list);
505 list_add(&member->list, &q);
506 }
507 if (list_empty(&group->path_group_member_list)) {
508 list_del(&group->list);
509 can_delete_group = true;
510 }
511 }
512 mutex_unlock(&ccs_policy_lock);
513 list_for_each_entry_safe(member, next_member, &q, list) {
514 list_del(&member->list);
515 ccs_put_name(member->member_name);
516 ccs_memory_free(member, sizeof(*member));
517 }
518 if (can_delete_group) {
519 ccs_put_name(group->group_name);
520 ccs_memory_free(group, sizeof(*group));
521 }
522 }
523
524 /**
525 * ccs_put_address_group - Delete memory for "struct ccs_address_group_entry".
526 *
527 * @group: Pointer to "struct ccs_address_group_entry".
528 */
529 void ccs_put_address_group(struct ccs_address_group_entry *group)
530 {
531 struct ccs_address_group_member *member;
532 struct ccs_address_group_member *next_member;
533 LIST_HEAD(q);
534 bool can_delete_group = false;
535 if (!group)
536 return;
537 mutex_lock(&ccs_policy_lock);
538 if (atomic_dec_and_test(&group->users)) {
539 list_for_each_entry_safe(member, next_member,
540 &group->address_group_member_list,
541 list) {
542 if (!member->is_deleted)
543 break;
544 list_del(&member->list);
545 list_add(&member->list, &q);
546 }
547 if (list_empty(&group->address_group_member_list)) {
548 list_del(&group->list);
549 can_delete_group = true;
550 }
551 }
552 mutex_unlock(&ccs_policy_lock);
553 list_for_each_entry_safe(member, next_member, &q, list) {
554 list_del(&member->list);
555 if (member->is_ipv6) {
556 ccs_put_ipv6_address(member->min.ipv6);
557 ccs_put_ipv6_address(member->max.ipv6);
558 }
559 ccs_memory_free(member, sizeof(*member));
560 }
561 if (can_delete_group) {
562 ccs_put_name(group->group_name);
563 ccs_memory_free(group, sizeof(*group));
564 }
565 }
566
567 static LIST_HEAD(ccs_address_list);
568
569 /**
570 * ccs_get_ipv6_address - Keep the given IPv6 address on the RAM.
571 *
572 * @addr: Pointer to "struct in6_addr".
573 *
574 * Returns pointer to "struct in6_addr" on success, NULL otherwise.
575 *
576 * The RAM is shared, so NEVER try to modify or kfree() the returned address.
577 */
578 const struct in6_addr *ccs_get_ipv6_address(const struct in6_addr *addr)
579 {
580 struct ccs_ipv6addr_entry *entry;
581 struct ccs_ipv6addr_entry *ptr;
582 int error = -ENOMEM;
583 if (!addr)
584 return NULL;
585 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
586 mutex_lock(&ccs_policy_lock);
587 list_for_each_entry(ptr, &ccs_address_list, list) {
588 if (memcmp(&ptr->addr, addr, sizeof(*addr)))
589 continue;
590 atomic_inc(&ptr->users);
591 error = 0;
592 break;
593 }
594 if (error && ccs_memory_ok(entry)) {
595 ptr = entry;
596 ptr->addr = *addr;
597 atomic_set(&ptr->users, 1);
598 list_add_tail(&ptr->list, &ccs_address_list);
599 entry = NULL;
600 }
601 mutex_unlock(&ccs_policy_lock);
602 kfree(entry);
603 return ptr ? &ptr->addr : NULL;
604 }
605
606 /**
607 * ccs_put_ipv6_address - Delete the given IPv6 address on the RAM.
608 *
609 * @addr: Pointer to "struct in6_addr".
610 */
611 void ccs_put_ipv6_address(const struct in6_addr *addr)
612 {
613 struct ccs_ipv6addr_entry *ptr;
614 bool can_delete = false;
615 if (!addr)
616 return;
617 ptr = container_of(addr, struct ccs_ipv6addr_entry, addr);
618 mutex_lock(&ccs_policy_lock);
619 if (atomic_dec_and_test(&ptr->users)) {
620 list_del(&ptr->list);
621 can_delete = true;
622 }
623 mutex_unlock(&ccs_policy_lock);
624 if (can_delete)
625 ccs_memory_free(ptr, sizeof(*ptr));
626 }
627
628 /**
629 * ccs_put_condition - Delete memory for "struct ccs_condition".
630 *
631 * @cond: Pointer to "struct ccs_condition".
632 */
633 void ccs_put_condition(struct ccs_condition *cond)
634 {
635 const unsigned long *ptr;
636 const struct ccs_argv_entry *argv;
637 const struct ccs_envp_entry *envp;
638 const struct ccs_symlinkp_entry *symlinkp;
639 u16 condc;
640 u16 argc;
641 u16 envc;
642 u16 symlinkc;
643 u16 i;
644 bool can_delete = false;
645 if (!cond)
646 return;
647 mutex_lock(&ccs_policy_lock);
648 if (atomic_dec_and_test(&cond->users)) {
649 list_del(&cond->list);
650 can_delete = true;
651 }
652 mutex_unlock(&ccs_policy_lock);
653 if (!can_delete)
654 return;
655 condc = cond->condc;
656 argc = cond->argc;
657 envc = cond->envc;
658 symlinkc = cond->symlinkc;
659 ptr = (const unsigned long *) (cond + 1);
660 argv = (const struct ccs_argv_entry *) (ptr + condc);
661 envp = (const struct ccs_envp_entry *) (argv + argc);
662 symlinkp = (const struct ccs_symlinkp_entry *) (envp + envc);
663 for (i = 0; i < argc; argv++, i++)
664 ccs_put_name(argv->value);
665 for (i = 0; i < envc; envp++, i++) {
666 ccs_put_name(envp->name);
667 ccs_put_name(envp->value);
668 }
669 for (i = 0; i < symlinkc; symlinkp++, i++)
670 ccs_put_name(symlinkp->value);
671 ccs_memory_free(cond, ksize(cond));
672 }
673
674 static atomic_t ccs_allocated_memory_for_savename;
675 static unsigned int ccs_quota_for_savename;
676
677 #define MAX_HASH 256
678
679 /* Structure for string data. */
680 struct ccs_name_entry {
681 struct list_head list;
682 atomic_t users;
683 struct ccs_path_info entry;
684 };
685
686 /* The list for "struct ccs_name_entry". */
687 static struct list_head ccs_name_list[MAX_HASH];
688 static DEFINE_MUTEX(ccs_name_list_lock);
689
690 /**
691 * ccs_get_name - Allocate memory for string data.
692 *
693 * @name: The string to store into the permernent memory.
694 *
695 * Returns pointer to "struct ccs_path_info" on success, NULL otherwise.
696 */
697 const struct ccs_path_info *ccs_get_name(const char *name)
698 {
699 struct ccs_name_entry *ptr;
700 unsigned int hash;
701 int len;
702 int allocated_len;
703
704 if (!name)
705 return NULL;
706 len = strlen(name) + 1;
707 if (len > CCS_MAX_PATHNAME_LEN) {
708 printk(KERN_WARNING "ERROR: Name too long. (%s)\n", __func__);
709 return NULL;
710 }
711 hash = full_name_hash((const unsigned char *) name, len - 1);
712 /***** EXCLUSIVE SECTION START *****/
713 mutex_lock(&ccs_name_list_lock);
714 list_for_each_entry(ptr, &ccs_name_list[hash % MAX_HASH], list) {
715 if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
716 continue;
717 atomic_inc(&ptr->users);
718 goto out;
719 }
720 ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL);
721 allocated_len = ptr ? ksize(ptr) : 0;
722 if (!allocated_len ||
723 (ccs_quota_for_savename &&
724 atomic_read(&ccs_allocated_memory_for_savename) + allocated_len
725 > ccs_quota_for_savename)) {
726 kfree(ptr);
727 ptr = NULL;
728 printk(KERN_WARNING "ERROR: Out of memory. (%s)\n", __func__);
729 if (!ccs_policy_loaded)
730 panic("MAC Initialization failed.\n");
731 goto out;
732 }
733 atomic_add(allocated_len, &ccs_allocated_memory_for_savename);
734 ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
735 memmove((char *) ptr->entry.name, name, len);
736 atomic_set(&ptr->users, 1);
737 ccs_fill_path_info(&ptr->entry);
738 list_add_tail(&ptr->list, &ccs_name_list[hash % MAX_HASH]);
739 out:
740 mutex_unlock(&ccs_name_list_lock);
741 /***** EXCLUSIVE SECTION END *****/
742 return ptr ? &ptr->entry : NULL;
743 }
744
745 /**
746 * ccs_put_name - Delete shared memory for string data.
747 *
748 * @name: Pointer to "struct ccs_path_info".
749 */
750 void ccs_put_name(const struct ccs_path_info *name)
751 {
752 struct ccs_name_entry *ptr;
753 bool can_delete = false;
754 if (!name)
755 return;
756 ptr = container_of(name, struct ccs_name_entry, entry);
757 /***** EXCLUSIVE SECTION START *****/
758 mutex_lock(&ccs_name_list_lock);
759 if (atomic_dec_and_test(&ptr->users)) {
760 list_del(&ptr->list);
761 can_delete = true;
762 }
763 mutex_unlock(&ccs_name_list_lock);
764 /***** EXCLUSIVE SECTION END *****/
765 if (can_delete) {
766 atomic_sub(ksize(ptr), &ccs_allocated_memory_for_savename);
767 kfree(ptr);
768 }
769 }
770
771 struct srcu_struct ccs_ss;
772
773 /**
774 * ccs_realpath_init - Initialize realpath related code.
775 *
776 * Returns 0.
777 */
778 static int __init ccs_realpath_init(void)
779 {
780 int i;
781 /* Constraint for ccs_get_name(). */
782 if (CCS_MAX_PATHNAME_LEN > PAGE_SIZE)
783 panic("Bad size.");
784 /* Constraint for "struct ccs_execve_entry"->tmp users. */
785 if (CCS_MAX_PATHNAME_LEN > CCS_EXEC_TMPSIZE)
786 panic("Bad size.");
787 if (init_srcu_struct(&ccs_ss))
788 panic("Out of memory.");
789 for (i = 0; i < MAX_HASH; i++)
790 INIT_LIST_HEAD(&ccs_name_list[i]);
791 INIT_LIST_HEAD(&ccs_kernel_domain.acl_info_list);
792 ccs_kernel_domain.domainname = ccs_get_name(ROOT_NAME);
793 list_add_tail_rcu(&ccs_kernel_domain.list, &ccs_domain_list);
794 if (ccs_find_domain(ROOT_NAME) != &ccs_kernel_domain)
795 panic("Can't register ccs_kernel_domain");
796 #ifdef CONFIG_CCSECURITY_BUILTIN_INITIALIZERS
797 {
798 /* Load built-in policy. */
799 static char ccs_builtin_initializers[] __initdata
800 = CONFIG_CCSECURITY_BUILTIN_INITIALIZERS;
801 char *cp = ccs_builtin_initializers;
802 ccs_normalize_line(cp);
803 while (cp && *cp) {
804 char *cp2 = strchr(cp, ' ');
805 if (cp2)
806 *cp2++ = '\0';
807 ccs_write_domain_initializer_policy(cp, false, false);
808 cp = cp2;
809 }
810 }
811 #endif
812 return 0;
813 }
814
815 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
816 __initcall(ccs_realpath_init);
817 #else
818 core_initcall(ccs_realpath_init);
819 #endif
820
821 unsigned int ccs_audit_log_memory_size;
822 unsigned int ccs_quota_for_audit_log;
823
824 unsigned int ccs_query_memory_size;
825 unsigned int ccs_quota_for_query;
826
827 /**
828 * ccs_read_memory_counter - Check for memory usage.
829 *
830 * @head: Pointer to "struct ccs_io_buffer".
831 *
832 * Returns memory usage.
833 */
834 int ccs_read_memory_counter(struct ccs_io_buffer *head)
835 {
836 if (!head->read_eof) {
837 const unsigned int shared
838 = atomic_read(&ccs_allocated_memory_for_savename);
839 const unsigned int private
840 = atomic_read(&ccs_allocated_memory_for_elements);
841 const unsigned int audit_log = ccs_audit_log_memory_size;
842 const unsigned int query = ccs_query_memory_size;
843 char buffer[64];
844 memset(buffer, 0, sizeof(buffer));
845 if (ccs_quota_for_savename)
846 snprintf(buffer, sizeof(buffer) - 1,
847 " (Quota: %10u)", ccs_quota_for_savename);
848 else
849 buffer[0] = '\0';
850 ccs_io_printf(head, "Policy (string): %10u%s\n",
851 shared, buffer);
852 if (ccs_quota_for_elements)
853 snprintf(buffer, sizeof(buffer) - 1,
854 " (Quota: %10u)", ccs_quota_for_elements);
855 else
856 buffer[0] = '\0';
857 ccs_io_printf(head, "Policy (non-string): %10u%s\n",
858 private, buffer);
859 if (ccs_quota_for_audit_log)
860 snprintf(buffer, sizeof(buffer) - 1,
861 " (Quota: %10u)", ccs_quota_for_audit_log);
862 else
863 buffer[0] = '\0';
864 ccs_io_printf(head, "Audit logs: %10u%s\n",
865 audit_log, buffer);
866 if (ccs_quota_for_query)
867 snprintf(buffer, sizeof(buffer) - 1,
868 " (Quota: %10u)", ccs_quota_for_query);
869 else
870 buffer[0] = '\0';
871 ccs_io_printf(head, "Interactive enforcement: %10u%s\n",
872 query, buffer);
873 ccs_io_printf(head, "Total: %10u\n",
874 shared + private + audit_log + query);
875 head->read_eof = true;
876 }
877 return 0;
878 }
879
880 /**
881 * ccs_write_memory_quota - Set memory quota.
882 *
883 * @head: Pointer to "struct ccs_io_buffer".
884 *
885 * Returns 0.
886 */
887 int ccs_write_memory_quota(struct ccs_io_buffer *head)
888 {
889 char *data = head->write_buf;
890 unsigned int size;
891 if (sscanf(data, "Policy (string): %u", &size) == 1)
892 ccs_quota_for_savename = size;
893 else if (sscanf(data, "Policy (non-string): %u", &size) == 1)
894 ccs_quota_for_elements = size;
895 else if (sscanf(data, "Audit logs: %u", &size) == 1)
896 ccs_quota_for_audit_log = size;
897 else if (sscanf(data, "Interactive enforcement: %u", &size) == 1)
898 ccs_quota_for_query = size;
899 return 0;
900 }
901
902 /* Garbage collector functions */
903
904 enum ccs_gc_id {
905 CCS_ID_CONDITION,
906 CCS_ID_RESERVEDPORT,
907 CCS_ID_ADDRESS_GROUP,
908 CCS_ID_ADDRESS_GROUP_MEMBER,
909 CCS_ID_PATH_GROUP,
910 CCS_ID_PATH_GROUP_MEMBER,
911 CCS_ID_GLOBAL_ENV,
912 CCS_ID_AGGREGATOR,
913 CCS_ID_DOMAIN_INITIALIZER,
914 CCS_ID_DOMAIN_KEEPER,
915 CCS_ID_ALIAS,
916 CCS_ID_GLOBALLY_READABLE,
917 CCS_ID_PATTERN,
918 CCS_ID_NO_REWRITE,
919 CCS_ID_MANAGER,
920 CCS_ID_ACL,
921 CCS_ID_DOMAIN
922 };
923
924 struct ccs_gc_entry {
925 struct list_head list;
926 int type;
927 void *element;
928 };
929
930 /* Caller holds ccs_policy_lock mutex. */
931 static bool ccs_add_to_gc(const int type, void *element, struct list_head *head)
932 {
933 struct ccs_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
934 if (!entry)
935 return false;
936 entry->type = type;
937 entry->element = element;
938 list_add(&entry->list, head);
939 return true;
940 }
941
942 static inline void ccs_gc_del_domain_initializer
943 (struct ccs_domain_initializer_entry *ptr)
944 {
945 ccs_put_name(ptr->domainname);
946 ccs_put_name(ptr->program);
947 }
948
949 static inline void ccs_gc_del_domain_keeper
950 (struct ccs_domain_keeper_entry *ptr)
951 {
952 ccs_put_name(ptr->domainname);
953 ccs_put_name(ptr->program);
954 }
955
956 static void ccs_del_allow_read(struct ccs_globally_readable_file_entry *ptr)
957 {
958 ccs_put_name(ptr->filename);
959 ccs_memory_free(ptr, sizeof(*ptr));
960 }
961
962 static void ccs_del_allow_env(struct ccs_globally_usable_env_entry *ptr)
963 {
964 ccs_put_name(ptr->env);
965 ccs_memory_free(ptr, sizeof(*ptr));
966 }
967
968 static void ccs_del_file_pattern(struct ccs_pattern_entry *ptr)
969 {
970 ccs_put_name(ptr->pattern);
971 ccs_memory_free(ptr, sizeof(*ptr));
972 }
973
974 static void ccs_del_no_rewrite(struct ccs_no_rewrite_entry *ptr)
975 {
976 ccs_put_name(ptr->pattern);
977 ccs_memory_free(ptr, sizeof(*ptr));
978 }
979
980 static void ccs_del_domain_initializer(struct ccs_domain_initializer_entry *ptr)
981 {
982 ccs_put_name(ptr->domainname);
983 ccs_put_name(ptr->program);
984 ccs_memory_free(ptr, sizeof(*ptr));
985 }
986
987 static void ccs_del_domain_keeper(struct ccs_domain_keeper_entry *ptr)
988 {
989 ccs_put_name(ptr->domainname);
990 ccs_put_name(ptr->program);
991 ccs_memory_free(ptr, sizeof(*ptr));
992 }
993
994 static void ccs_del_alias(struct ccs_alias_entry *ptr)
995 {
996 ccs_put_name(ptr->original_name);
997 ccs_put_name(ptr->aliased_name);
998 ccs_memory_free(ptr, sizeof(*ptr));
999 }
1000
1001 static void ccs_del_aggregator(struct ccs_aggregator_entry *ptr)
1002 {
1003 ccs_put_name(ptr->original_name);
1004 ccs_put_name(ptr->aggregated_name);
1005 ccs_memory_free(ptr, sizeof(*ptr));
1006 }
1007
1008 static void ccs_del_manager(struct ccs_policy_manager_entry *ptr)
1009 {
1010 ccs_put_name(ptr->manager);
1011 ccs_memory_free(ptr, sizeof(*ptr));
1012 }
1013
1014 /* For compatibility with older kernels. */
1015 #ifndef for_each_process
1016 #define for_each_process for_each_task
1017 #endif
1018
1019 /**
1020 * ccs_used_by_task - Check whether the given pointer is referenced by a task.
1021 *
1022 * @domain: Pointer to "struct ccs_domain_info".
1023 *
1024 * Returns true if @ptr is in use, false otherwise.
1025 */
1026 static bool ccs_used_by_task(struct ccs_domain_info *domain)
1027 {
1028 bool in_use = false;
1029 struct task_struct *p;
1030 /***** CRITICAL SECTION START *****/
1031 read_lock(&tasklist_lock);
1032 for_each_process(p) {
1033 if (p->ccs_domain_info != domain)
1034 continue;
1035 in_use = true;
1036 break;
1037 }
1038 read_unlock(&tasklist_lock);
1039 /***** CRITICAL SECTION END *****/
1040 return in_use;
1041 }
1042
1043 static void ccs_del_acl(struct ccs_acl_info *acl)
1044 {
1045 size_t size;
1046 ccs_put_condition(acl->cond);
1047 switch (ccs_acl_type1(acl)) {
1048 case TYPE_SINGLE_PATH_ACL:
1049 {
1050 struct ccs_single_path_acl_record *entry;
1051 size = sizeof(*entry);
1052 entry = container_of(acl, typeof(*entry), head);
1053 if (entry->u_is_group)
1054 ccs_put_path_group(entry->u.group);
1055 else
1056 ccs_put_name(entry->u.filename);
1057 }
1058 break;
1059 case TYPE_DOUBLE_PATH_ACL:
1060 {
1061 struct ccs_double_path_acl_record *entry;
1062 size = sizeof(*entry);
1063 entry = container_of(acl, typeof(*entry), head);
1064 if (entry->u1_is_group)
1065 ccs_put_path_group(entry->u1.group1);
1066 else
1067 ccs_put_name(entry->u1.filename1);
1068 if (entry->u2_is_group)
1069 ccs_put_path_group(entry->u2.group2);
1070 else
1071 ccs_put_name(entry->u2.filename2);
1072 }
1073 break;
1074 case TYPE_IP_NETWORK_ACL:
1075 {
1076 struct ccs_ip_network_acl_record *entry;
1077 size = sizeof(*entry);
1078 entry = container_of(acl, typeof(*entry), head);
1079 if (entry->record_type == IP_RECORD_TYPE_ADDRESS_GROUP)
1080 ccs_put_address_group(entry->u.group);
1081 else if (entry->record_type == IP_RECORD_TYPE_IPv6) {
1082 ccs_put_ipv6_address(entry->u.ipv6.min);
1083 ccs_put_ipv6_address(entry->u.ipv6.max);
1084 }
1085 }
1086 break;
1087 case TYPE_IOCTL_ACL:
1088 {
1089 struct ccs_ioctl_acl_record *entry;
1090 size = sizeof(*entry);
1091 entry = container_of(acl, typeof(*entry), head);
1092 if (entry->u_is_group)
1093 ccs_put_path_group(entry->u.group);
1094 else
1095 ccs_put_name(entry->u.filename);
1096 }
1097 break;
1098 case TYPE_ARGV0_ACL:
1099 {
1100 struct ccs_argv0_acl_record *entry;
1101 size = sizeof(*entry);
1102 entry = container_of(acl, typeof(*entry), head);
1103 ccs_put_name(entry->argv0);
1104 }
1105 break;
1106 case TYPE_ENV_ACL:
1107 {
1108 struct ccs_env_acl_record *entry;
1109 size = sizeof(*entry);
1110 entry = container_of(acl, typeof(*entry), head);
1111 ccs_put_name(entry->env);
1112 }
1113 break;
1114 case TYPE_CAPABILITY_ACL:
1115 {
1116 struct ccs_capability_acl_record *entry;
1117 size = sizeof(*entry);
1118 entry = container_of(acl, typeof(*entry), head);
1119 }
1120 break;
1121 case TYPE_SIGNAL_ACL:
1122 {
1123 struct ccs_signal_acl_record *entry;
1124 size = sizeof(*entry);
1125 entry = container_of(acl, typeof(*entry), head);
1126 ccs_put_name(entry->domainname);
1127 }
1128 break;
1129 case TYPE_EXECUTE_HANDLER:
1130 case TYPE_DENIED_EXECUTE_HANDLER:
1131 {
1132 struct ccs_execute_handler_record *entry;
1133 size = sizeof(*entry);
1134 entry = container_of(acl, typeof(*entry), head);
1135 ccs_put_name(entry->handler);
1136 }
1137 break;
1138 case TYPE_MOUNT_ACL:
1139 {
1140 struct ccs_mount_acl_record *entry;
1141 size = sizeof(*entry);
1142 entry = container_of(acl, typeof(*entry), head);
1143 ccs_put_name(entry->dev_name);
1144 ccs_put_name(entry->dir_name);
1145 ccs_put_name(entry->fs_type);
1146 }
1147 break;
1148 case TYPE_UMOUNT_ACL:
1149 {
1150 struct ccs_umount_acl_record *entry;
1151 size = sizeof(*entry);
1152 entry = container_of(acl, typeof(*entry), head);
1153 ccs_put_name(entry->dir);
1154 }
1155 break;
1156 case TYPE_CHROOT_ACL:
1157 {
1158 struct ccs_chroot_acl_record *entry;
1159 size = sizeof(*entry);
1160 entry = container_of(acl, typeof(*entry), head);
1161 ccs_put_name(entry->dir);
1162 }
1163 break;
1164 case TYPE_PIVOT_ROOT_ACL:
1165 {
1166 struct ccs_pivot_root_acl_record *entry;
1167 size = sizeof(*entry);
1168 entry = container_of(acl, typeof(*entry), head);
1169 ccs_put_name(entry->old_root);
1170 ccs_put_name(entry->new_root);
1171 }
1172 break;
1173 default:
1174 size = 0;
1175 printk(KERN_WARNING "Unknown type\n");
1176 break;
1177 }
1178 ccs_memory_free(acl, size);
1179 }
1180
1181 static bool ccs_del_domain(struct ccs_domain_info *domain)
1182 {
1183 if (ccs_used_by_task(domain))
1184 return false;
1185 ccs_put_name(domain->domainname);
1186 ccs_memory_free(domain, sizeof(*domain));
1187 return true;
1188 }
1189
1190 static void ccs_del_path_group_member(struct ccs_path_group_member *member)
1191 {
1192 ccs_put_name(member->member_name);
1193 ccs_memory_free(member, sizeof(*member));
1194 }
1195
1196 static void ccs_del_path_group(struct ccs_path_group_entry *group)
1197 {
1198 ccs_put_name(group->group_name);
1199 ccs_memory_free(group, sizeof(*group));
1200 }
1201
1202 static void ccs_del_address_group_member
1203 (struct ccs_address_group_member *member)
1204 {
1205 if (member->is_ipv6) {
1206 ccs_put_ipv6_address(member->min.ipv6);
1207 ccs_put_ipv6_address(member->max.ipv6);
1208 }
1209 ccs_memory_free(member, sizeof(*member));
1210 }
1211
1212 static void ccs_del_address_group(struct ccs_address_group_entry *group)
1213 {
1214 ccs_put_name(group->group_name);
1215 ccs_memory_free(group, sizeof(*group));
1216 }
1217
1218 static void ccs_del_reservedport(struct ccs_reserved_entry *ptr)
1219 {
1220 ccs_memory_free(ptr, sizeof(*ptr));
1221 }
1222
1223 static void ccs_del_condition(struct ccs_condition *ptr)
1224 {
1225 int i;
1226 u16 condc = ptr->condc;
1227 u16 argc = ptr->argc;
1228 u16 envc = ptr->envc;
1229 u16 symlinkc = ptr->symlinkc;
1230 unsigned long *ptr2 = (unsigned long *) (ptr + 1);
1231 struct ccs_argv_entry *argv = (struct ccs_argv_entry *) (ptr2 + condc);
1232 struct ccs_envp_entry *envp = (struct ccs_envp_entry *) (argv + argc);
1233 struct ccs_symlinkp_entry *symlinkp
1234 = (struct ccs_symlinkp_entry *) (envp + envc);
1235 for (i = 0; i < argc; i++)
1236 ccs_put_name(argv[i].value);
1237 for (i = 0; i < envc; i++) {
1238 ccs_put_name(envp[i].name);
1239 ccs_put_name(envp[i].value);
1240 }
1241 for (i = 0; i < symlinkc; i++)
1242 ccs_put_name(symlinkp[i].value);
1243 ccs_memory_free(ptr, sizeof(*ptr));
1244 }
1245
1246 static int ccs_gc_thread(void *unused)
1247 {
1248 static DEFINE_MUTEX(ccs_gc_mutex);
1249 static LIST_HEAD(ccs_gc_queue);
1250 if (!mutex_trylock(&ccs_gc_mutex))
1251 return 0;
1252 mutex_lock(&ccs_policy_lock);
1253 {
1254 struct ccs_globally_readable_file_entry *ptr;
1255 list_for_each_entry_rcu(ptr, &ccs_globally_readable_list,
1256 list) {
1257 if (!ptr->is_deleted)
1258 continue;
1259 if (ccs_add_to_gc(CCS_ID_GLOBALLY_READABLE, ptr,
1260 &ccs_gc_queue))
1261 list_del_rcu(&ptr->list);
1262 else
1263 break;
1264 }
1265 }
1266 {
1267 struct ccs_globally_usable_env_entry *ptr;
1268 list_for_each_entry_rcu(ptr, &ccs_globally_usable_env_list,
1269 list) {
1270 if (!ptr->is_deleted)
1271 continue;
1272 if (ccs_add_to_gc(CCS_ID_GLOBAL_ENV, ptr,
1273 &ccs_gc_queue))
1274 list_del_rcu(&ptr->list);
1275 else
1276 break;
1277 }
1278 }
1279 {
1280 struct ccs_pattern_entry *ptr;
1281 list_for_each_entry_rcu(ptr, &ccs_pattern_list, list) {
1282 if (!ptr->is_deleted)
1283 continue;
1284 if (ccs_add_to_gc(CCS_ID_PATTERN, ptr,
1285 &ccs_gc_queue))
1286 list_del_rcu(&ptr->list);
1287 else
1288 break;
1289 }
1290 }
1291 {
1292 struct ccs_no_rewrite_entry *ptr;
1293 list_for_each_entry_rcu(ptr, &ccs_no_rewrite_list, list) {
1294 if (!ptr->is_deleted)
1295 continue;
1296 if (ccs_add_to_gc(CCS_ID_NO_REWRITE, ptr,
1297 &ccs_gc_queue))
1298 list_del_rcu(&ptr->list);
1299 else
1300 break;
1301 }
1302 }
1303 {
1304 struct ccs_domain_initializer_entry *ptr;
1305 list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list,
1306 list) {
1307 if (!ptr->is_deleted)
1308 continue;
1309 if (ccs_add_to_gc(CCS_ID_DOMAIN_INITIALIZER,
1310 ptr, &ccs_gc_queue))
1311 list_del_rcu(&ptr->list);
1312 else
1313 break;
1314 }
1315 }
1316 {
1317 struct ccs_domain_keeper_entry *ptr;
1318 list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
1319 if (!ptr->is_deleted)
1320 continue;
1321 if (ccs_add_to_gc(CCS_ID_DOMAIN_KEEPER, ptr,
1322 &ccs_gc_queue))
1323 list_del_rcu(&ptr->list);
1324 else
1325 break;
1326 }
1327 }
1328 {
1329 struct ccs_alias_entry *ptr;
1330 list_for_each_entry_rcu(ptr, &ccs_alias_list, list) {
1331 if (!ptr->is_deleted)
1332 continue;
1333 if (ccs_add_to_gc(CCS_ID_ALIAS, ptr, &ccs_gc_queue))
1334 list_del_rcu(&ptr->list);
1335 else
1336 break;
1337 }
1338 }
1339 {
1340 struct ccs_policy_manager_entry *ptr;
1341 list_for_each_entry_rcu(ptr, &ccs_policy_manager_list, list) {
1342 if (!ptr->is_deleted)
1343 continue;
1344 if (ccs_add_to_gc(CCS_ID_MANAGER, ptr, &ccs_gc_queue))
1345 list_del_rcu(&ptr->list);
1346 else
1347 break;
1348 }
1349 }
1350 {
1351 struct ccs_aggregator_entry *ptr;
1352 list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
1353 if (!ptr->is_deleted)
1354 continue;
1355 if (ccs_add_to_gc(CCS_ID_AGGREGATOR, ptr,
1356 &ccs_gc_queue))
1357 list_del_rcu(&ptr->list);
1358 else
1359 break;
1360 }
1361 }
1362 mutex_unlock(&ccs_policy_lock);
1363 {
1364 struct ccs_domain_info *domain;
1365 list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
1366 struct ccs_acl_info *acl;
1367 list_for_each_entry_rcu(acl, &domain->acl_info_list,
1368 list) {
1369 if (!(acl->type & ACL_DELETED))
1370 continue;
1371 if (ccs_add_to_gc(CCS_ID_ACL, acl,
1372 &ccs_gc_queue))
1373 list_del_rcu(&acl->list);
1374 else
1375 break;
1376 }
1377 if (!domain->is_deleted ||
1378 ccs_used_by_task(domain))
1379 continue;
1380 if (ccs_add_to_gc(CCS_ID_DOMAIN, domain, &ccs_gc_queue))
1381 list_del_rcu(&domain->list);
1382 else
1383 break;
1384 }
1385 }
1386 {
1387 struct ccs_path_group_entry *group;
1388 list_for_each_entry_rcu(group, &ccs_path_group_list, list) {
1389 struct ccs_path_group_member *member;
1390 list_for_each_entry_rcu(member,
1391 &group->path_group_member_list,
1392 list) {
1393 if (!member->is_deleted)
1394 continue;
1395 if (ccs_add_to_gc(CCS_ID_PATH_GROUP_MEMBER,
1396 member, &ccs_gc_queue))
1397 list_del_rcu(&member->list);
1398 else
1399 break;
1400 }
1401 if (!list_empty(&group->path_group_member_list) ||
1402 atomic_read(&group->users))
1403 continue;
1404 if (ccs_add_to_gc(CCS_ID_PATH_GROUP, group,
1405 &ccs_gc_queue))
1406 list_del_rcu(&group->list);
1407 else
1408 break;
1409 }
1410 }
1411 {
1412 struct ccs_address_group_entry *group;
1413 list_for_each_entry_rcu(group, &ccs_address_group_list, list) {
1414 struct ccs_address_group_member *member;
1415 list_for_each_entry_rcu(member,
1416 &group->address_group_member_list,
1417 list) {
1418 if (!member->is_deleted)
1419 break;
1420 if (ccs_add_to_gc(CCS_ID_ADDRESS_GROUP_MEMBER,
1421 member, &ccs_gc_queue))
1422 list_del_rcu(&member->list);
1423 else
1424 break;
1425 }
1426 if (!list_empty(&group->address_group_member_list) ||
1427 atomic_read(&group->users))
1428 continue;
1429 if (ccs_add_to_gc(CCS_ID_ADDRESS_GROUP, group,
1430 &ccs_gc_queue))
1431 list_del_rcu(&group->list);
1432 else
1433 break;
1434 }
1435 }
1436 {
1437 struct ccs_reserved_entry *ptr;
1438 list_for_each_entry_rcu(ptr, &ccs_reservedport_list, list) {
1439 if (!ptr->is_deleted)
1440 continue;
1441 if (ccs_add_to_gc(CCS_ID_RESERVEDPORT, ptr,
1442 &ccs_gc_queue))
1443 list_del_rcu(&ptr->list);
1444 else
1445 break;
1446 }
1447 }
1448 {
1449 struct ccs_condition *ptr;
1450 list_for_each_entry_rcu(ptr, &ccs_condition_list, list) {
1451 if (atomic_read(&ptr->users))
1452 continue;
1453 if (ccs_add_to_gc(CCS_ID_CONDITION, ptr, &ccs_gc_queue))
1454 list_del_rcu(&ptr->list);
1455 else
1456 break;
1457 }
1458 }
1459 mutex_unlock(&ccs_policy_lock);
1460 if (list_empty(&ccs_gc_queue))
1461 goto done;
1462 synchronize_srcu(&ccs_ss);
1463 {
1464 struct ccs_gc_entry *p;
1465 struct ccs_gc_entry *tmp;
1466 size_t size = 0;
1467 list_for_each_entry_safe(p, tmp, &ccs_gc_queue, list) {
1468 switch (p->type) {
1469 case CCS_ID_DOMAIN_INITIALIZER:
1470 ccs_del_domain_initializer(p->element);
1471 break;
1472 case CCS_ID_DOMAIN_KEEPER:
1473 ccs_del_domain_keeper(p->element);
1474 break;
1475 case CCS_ID_ALIAS:
1476 ccs_del_alias(p->element);
1477 break;
1478 case CCS_ID_GLOBALLY_READABLE:
1479 ccs_del_allow_read(p->element);
1480 break;
1481 case CCS_ID_PATTERN:
1482 ccs_del_file_pattern(p->element);
1483 break;
1484 case CCS_ID_NO_REWRITE:
1485 ccs_del_no_rewrite(p->element);
1486 break;
1487 case CCS_ID_MANAGER:
1488 ccs_del_manager(p->element);
1489 break;
1490 case CCS_ID_GLOBAL_ENV:
1491 ccs_del_allow_env(p->element);
1492 break;
1493 case CCS_ID_AGGREGATOR:
1494 ccs_del_aggregator(p->element);
1495 break;
1496 case CCS_ID_PATH_GROUP_MEMBER:
1497 ccs_del_path_group_member(p->element);
1498 break;
1499 case CCS_ID_PATH_GROUP:
1500 ccs_del_path_group(p->element);
1501 break;
1502 case CCS_ID_ADDRESS_GROUP_MEMBER:
1503 ccs_del_address_group_member(p->element);
1504 break;
1505 case CCS_ID_ADDRESS_GROUP:
1506 ccs_del_address_group(p->element);
1507 break;
1508 case CCS_ID_RESERVEDPORT:
1509 ccs_del_reservedport(p->element);
1510 break;
1511 case CCS_ID_CONDITION:
1512 ccs_del_condition(p->element);
1513 break;
1514 case CCS_ID_ACL:
1515 ccs_del_acl(p->element);
1516 break;
1517 case CCS_ID_DOMAIN:
1518 if (!ccs_del_domain(p->element))
1519 continue;
1520 break;
1521 }
1522 ccs_memory_free(p->element, size);
1523 list_del(&p->list);
1524 kfree(p);
1525 }
1526 }
1527 done:
1528 mutex_unlock(&ccs_gc_mutex);
1529 return 0;
1530 }
1531
1532 #ifndef _LINUX_SRCU_H
1533
1534 static DEFINE_SPINLOCK(ccs_counter_lock);
1535
1536 int srcu_read_lock(struct srcu_struct *sp)
1537 {
1538 int idx;
1539 spin_lock(&ccs_counter_lock);
1540 idx = sp->counter_idx;
1541 sp->counter[idx]++;
1542 spin_unlock(&ccs_counter_lock);
1543 return idx;
1544 }
1545
1546 void srcu_read_unlock(struct srcu_struct *sp, const int idx)
1547 {
1548 spin_lock(&ccs_counter_lock);
1549 sp->counter[idx]--;
1550 spin_unlock(&ccs_counter_lock);
1551 }
1552
1553 void synchronize_srcu(struct srcu_struct *sp)
1554 {
1555 int idx;
1556 int v;
1557 spin_lock(&ccs_counter_lock);
1558 idx = sp->counter_idx;
1559 sp->counter_idx ^= 1;
1560 v = sp->counter[idx];
1561 spin_unlock(&ccs_counter_lock);
1562 while (v) {
1563 msleep(1000);
1564 spin_lock(&ccs_counter_lock);
1565 v = sp->counter[idx];
1566 spin_unlock(&ccs_counter_lock);
1567 }
1568 }
1569
1570 #endif

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