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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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