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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2830 - (show annotations) (download) (as text)
Mon Aug 3 08:18:47 2009 UTC (14 years, 9 months ago) by kumaneko
Original Path: branches/ccs-patch/fs/realpath.c
File MIME type: text/x-csrc
File size: 39505 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
15 #include <linux/string.h>
16 #include <linux/mm.h>
17 #include <linux/utime.h>
18 #include <linux/file.h>
19 #include <linux/smp_lock.h>
20 #include <linux/module.h>
21 #include <linux/slab.h>
22 #include <asm/uaccess.h>
23 #include <asm/atomic.h>
24 #include <linux/version.h>
25 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
26 #include <linux/namei.h>
27 #include <linux/mount.h>
28 static const int ccs_lookup_flags = LOOKUP_FOLLOW;
29 #else
30 static const int ccs_lookup_flags = LOOKUP_FOLLOW | LOOKUP_POSITIVE;
31 #endif
32 #include <net/sock.h>
33 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
34 #include <linux/kthread.h>
35 #endif
36 #include <linux/proc_fs.h>
37 #include <linux/ccs_common.h>
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_symlink_path - Get symlink's pathname.
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_symlink_path(const char *pathname, struct ccs_execve_entry *ee)
336 {
337 struct nameidata nd;
338 int ret;
339 if (!pathname ||
340 path_lookup(pathname, ccs_lookup_flags ^ LOOKUP_FOLLOW, &nd))
341 return -ENOENT;
342 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
343 ret = ccs_realpath_from_dentry2(nd.path.dentry, nd.path.mnt,
344 ee->program_path,
345 CCS_MAX_PATHNAME_LEN - 1);
346 path_put(&nd.path);
347 #else
348 ret = ccs_realpath_from_dentry2(nd.dentry, nd.mnt, ee->program_path,
349 CCS_MAX_PATHNAME_LEN - 1);
350 path_release(&nd);
351 #endif
352 return ret;
353 }
354
355 /**
356 * ccs_encode: Encode binary string to ascii string.
357 *
358 * @str: String in binary format.
359 *
360 * Returns pointer to @str in ascii format on success, NULL otherwise.
361 *
362 * This function uses kzalloc(), so caller must kfree() if this function
363 * didn't return NULL.
364 */
365 char *ccs_encode(const char *str)
366 {
367 int len = 0;
368 const char *p = str;
369 char *cp;
370 char *cp0;
371 if (!p)
372 return NULL;
373 while (*p) {
374 const unsigned char c = *p++;
375 if (c == '\\')
376 len += 2;
377 else if (c > ' ' && c < 127)
378 len++;
379 else
380 len += 4;
381 }
382 len++;
383 cp = kzalloc(len, GFP_KERNEL);
384 if (!cp)
385 return NULL;
386 cp0 = cp;
387 p = str;
388 while (*p) {
389 const unsigned char c = *p++;
390 if (c == '\\') {
391 *cp++ = '\\';
392 *cp++ = '\\';
393 } else if (c > ' ' && c < 127) {
394 *cp++ = c;
395 } else {
396 *cp++ = '\\';
397 *cp++ = (c >> 6) + '0';
398 *cp++ = ((c >> 3) & 7) + '0';
399 *cp++ = (c & 7) + '0';
400 }
401 }
402 return cp0;
403 }
404
405 static atomic_t ccs_non_string_memory_size;
406 static unsigned int ccs_quota_for_non_string;
407
408 /**
409 * ccs_memory_ok - Check memory quota.
410 *
411 * @ptr: Pointer to allocated memory.
412 * @size: Size in byte.
413 *
414 * Returns true if @ptr is not NULL and quota not exceeded, false otehrwise.
415 */
416 bool ccs_memory_ok(const void *ptr, const unsigned int size)
417 {
418 atomic_add(size, &ccs_non_string_memory_size);
419 if (ptr && (!ccs_quota_for_non_string ||
420 atomic_read(&ccs_non_string_memory_size)
421 <= ccs_quota_for_non_string))
422 return true;
423 atomic_sub(size, &ccs_non_string_memory_size);
424 printk(KERN_WARNING "ERROR: Out of memory. (%s)\n", __func__);
425 if (!ccs_policy_loaded)
426 panic("MAC Initialization failed.\n");
427 return false;
428 }
429
430 /**
431 * ccs_memory_free - Free memory for elements.
432 *
433 * @ptr: Pointer to allocated memory.
434 * @size: Size in byte.
435 */
436 static void ccs_memory_free(const void *ptr, size_t size)
437 {
438 atomic_sub(size, &ccs_non_string_memory_size);
439 kfree(ptr);
440 }
441
442 /**
443 * ccs_put_path_group - Delete memory for "struct ccs_path_group_entry".
444 *
445 * @group: Pointer to "struct ccs_path_group_entry".
446 */
447 void ccs_put_path_group(struct ccs_path_group_entry *group)
448 {
449 struct ccs_path_group_member *member;
450 struct ccs_path_group_member *next_member;
451 LIST_HEAD(q);
452 bool can_delete_group = false;
453 if (!group)
454 return;
455 mutex_lock(&ccs_policy_lock);
456 if (atomic_dec_and_test(&group->users)) {
457 list_for_each_entry_safe(member, next_member,
458 &group->path_group_member_list,
459 list) {
460 if (!member->is_deleted)
461 break;
462 list_del(&member->list);
463 list_add(&member->list, &q);
464 }
465 if (list_empty(&group->path_group_member_list)) {
466 list_del(&group->list);
467 can_delete_group = true;
468 }
469 }
470 mutex_unlock(&ccs_policy_lock);
471 list_for_each_entry_safe(member, next_member, &q, list) {
472 list_del(&member->list);
473 ccs_put_name(member->member_name);
474 ccs_memory_free(member, sizeof(*member));
475 }
476 if (can_delete_group) {
477 ccs_put_name(group->group_name);
478 ccs_memory_free(group, sizeof(*group));
479 }
480 }
481
482 /**
483 * ccs_put_address_group - Delete memory for "struct ccs_address_group_entry".
484 *
485 * @group: Pointer to "struct ccs_address_group_entry".
486 */
487 void ccs_put_address_group(struct ccs_address_group_entry *group)
488 {
489 struct ccs_address_group_member *member;
490 struct ccs_address_group_member *next_member;
491 LIST_HEAD(q);
492 bool can_delete_group = false;
493 if (!group)
494 return;
495 mutex_lock(&ccs_policy_lock);
496 if (atomic_dec_and_test(&group->users)) {
497 list_for_each_entry_safe(member, next_member,
498 &group->address_group_member_list,
499 list) {
500 if (!member->is_deleted)
501 break;
502 list_del(&member->list);
503 list_add(&member->list, &q);
504 }
505 if (list_empty(&group->address_group_member_list)) {
506 list_del(&group->list);
507 can_delete_group = true;
508 }
509 }
510 mutex_unlock(&ccs_policy_lock);
511 list_for_each_entry_safe(member, next_member, &q, list) {
512 list_del(&member->list);
513 if (member->is_ipv6) {
514 ccs_put_ipv6_address(member->min.ipv6);
515 ccs_put_ipv6_address(member->max.ipv6);
516 }
517 ccs_memory_free(member, sizeof(*member));
518 }
519 if (can_delete_group) {
520 ccs_put_name(group->group_name);
521 ccs_memory_free(group, sizeof(*group));
522 }
523 }
524
525 /**
526 * ccs_put_number_group - Delete memory for "struct ccs_number_group_entry".
527 *
528 * @group: Pointer to "struct ccs_number_group_entry".
529 */
530 void ccs_put_number_group(struct ccs_number_group_entry *group)
531 {
532 struct ccs_number_group_member *member;
533 struct ccs_number_group_member *next_member;
534 LIST_HEAD(q);
535 bool can_delete_group = false;
536 if (!group)
537 return;
538 mutex_lock(&ccs_policy_lock);
539 if (atomic_dec_and_test(&group->users)) {
540 list_for_each_entry_safe(member, next_member,
541 &group->number_group_member_list,
542 list) {
543 if (!member->is_deleted)
544 break;
545 list_del(&member->list);
546 list_add(&member->list, &q);
547 }
548 if (list_empty(&group->number_group_member_list)) {
549 list_del(&group->list);
550 can_delete_group = true;
551 }
552 }
553 mutex_unlock(&ccs_policy_lock);
554 list_for_each_entry_safe(member, next_member, &q, list) {
555 list_del(&member->list);
556 ccs_memory_free(member, sizeof(*member));
557 }
558 if (can_delete_group) {
559 ccs_put_name(group->group_name);
560 ccs_memory_free(group, sizeof(*group));
561 }
562 }
563
564 static LIST_HEAD(ccs_address_list);
565
566 /**
567 * ccs_get_ipv6_address - Keep the given IPv6 address on the RAM.
568 *
569 * @addr: Pointer to "struct in6_addr".
570 *
571 * Returns pointer to "struct in6_addr" on success, NULL otherwise.
572 *
573 * The RAM is shared, so NEVER try to modify or kfree() the returned address.
574 */
575 const struct in6_addr *ccs_get_ipv6_address(const struct in6_addr *addr)
576 {
577 struct ccs_ipv6addr_entry *entry;
578 struct ccs_ipv6addr_entry *ptr;
579 int error = -ENOMEM;
580 if (!addr)
581 return NULL;
582 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
583 mutex_lock(&ccs_policy_lock);
584 list_for_each_entry(ptr, &ccs_address_list, list) {
585 if (memcmp(&ptr->addr, addr, sizeof(*addr)))
586 continue;
587 atomic_inc(&ptr->users);
588 error = 0;
589 break;
590 }
591 if (error && ccs_memory_ok(entry, sizeof(*entry))) {
592 ptr = entry;
593 ptr->addr = *addr;
594 atomic_set(&ptr->users, 1);
595 list_add_tail(&ptr->list, &ccs_address_list);
596 entry = NULL;
597 }
598 mutex_unlock(&ccs_policy_lock);
599 kfree(entry);
600 return ptr ? &ptr->addr : NULL;
601 }
602
603 /**
604 * ccs_put_ipv6_address - Delete the given IPv6 address on the RAM.
605 *
606 * @addr: Pointer to "struct in6_addr".
607 */
608 void ccs_put_ipv6_address(const struct in6_addr *addr)
609 {
610 struct ccs_ipv6addr_entry *ptr;
611 bool can_delete = false;
612 if (!addr)
613 return;
614 ptr = container_of(addr, struct ccs_ipv6addr_entry, addr);
615 mutex_lock(&ccs_policy_lock);
616 if (atomic_dec_and_test(&ptr->users)) {
617 list_del(&ptr->list);
618 can_delete = true;
619 }
620 mutex_unlock(&ccs_policy_lock);
621 if (can_delete)
622 ccs_memory_free(ptr, sizeof(*ptr));
623 }
624
625 struct ccs_condition_element {
626 u8 left;
627 u8 right;
628 u8 equals;
629 u8 type;
630 };
631
632 /**
633 * ccs_put_condition - Delete memory for "struct ccs_condition".
634 *
635 * @cond: Pointer to "struct ccs_condition".
636 */
637 void ccs_put_condition(struct ccs_condition *cond)
638 {
639 const struct ccs_condition_element *condp;
640 const unsigned long *ulong_p;
641 struct ccs_number_group_entry **number_group_p;
642 const struct ccs_path_info **path_info_p;
643 struct ccs_path_group_entry **path_group_p;
644 const struct ccs_argv_entry *argv;
645 const struct ccs_envp_entry *envp;
646 u16 condc;
647 u16 number_group_count;
648 u16 path_info_count;
649 u16 path_group_count;
650 u16 argc;
651 u16 envc;
652 u16 i;
653 bool can_delete = false;
654 if (!cond)
655 return;
656 mutex_lock(&ccs_policy_lock);
657 if (atomic_dec_and_test(&cond->users)) {
658 list_del(&cond->list);
659 can_delete = true;
660 }
661 mutex_unlock(&ccs_policy_lock);
662 if (!can_delete)
663 return;
664 condc = cond->condc;
665 number_group_count = cond->number_group_count;
666 path_info_count = cond->path_info_count;
667 path_group_count = cond->path_group_count;
668 argc = cond->argc;
669 envc = cond->envc;
670 condp = (const struct ccs_condition_element *) (cond + 1);
671 ulong_p = (unsigned long *) (condp + condc);
672 number_group_p = (struct ccs_number_group_entry **)
673 (ulong_p + cond->ulong_count);
674 path_info_p = (const struct ccs_path_info **)
675 (number_group_p + number_group_count);
676 path_group_p = (struct ccs_path_group_entry **)
677 (path_info_p + path_info_count);
678 argv = (const struct ccs_argv_entry *)
679 (path_group_p + path_group_count);
680 envp = (const struct ccs_envp_entry *) (argv + argc);
681 for (i = 0; i < cond->number_group_count; i++)
682 ccs_put_number_group(*number_group_p++);
683 for (i = 0; i < cond->path_info_count; i++)
684 ccs_put_name(*path_info_p++);
685 for (i = 0; i < cond->path_group_count; i++)
686 ccs_put_path_group(*path_group_p++);
687 for (i = 0; i < argc; argv++, i++)
688 ccs_put_name(argv->value);
689 for (i = 0; i < envc; envp++, i++) {
690 ccs_put_name(envp->name);
691 ccs_put_name(envp->value);
692 }
693 ccs_memory_free(cond, cond->size);
694 }
695
696 static unsigned int ccs_string_memory_size;
697 static unsigned int ccs_quota_for_string;
698
699 #define MAX_HASH 256
700
701 /* Structure for string data. */
702 struct ccs_name_entry {
703 struct list_head list;
704 atomic_t users;
705 int size;
706 struct ccs_path_info entry;
707 };
708
709 /* The list for "struct ccs_name_entry". */
710 static struct list_head ccs_name_list[MAX_HASH];
711 static DEFINE_MUTEX(ccs_name_list_lock);
712
713 /**
714 * ccs_get_name - Allocate memory for string data.
715 *
716 * @name: The string to store into the permernent memory.
717 *
718 * Returns pointer to "struct ccs_path_info" on success, NULL otherwise.
719 */
720 const struct ccs_path_info *ccs_get_name(const char *name)
721 {
722 struct ccs_name_entry *ptr;
723 unsigned int hash;
724 int len;
725 int allocated_len;
726
727 if (!name)
728 return NULL;
729 len = strlen(name) + 1;
730 if (len > CCS_MAX_PATHNAME_LEN) {
731 printk(KERN_WARNING "ERROR: Name too long. (%s)\n", __func__);
732 return NULL;
733 }
734 hash = full_name_hash((const unsigned char *) name, len - 1);
735 /***** EXCLUSIVE SECTION START *****/
736 mutex_lock(&ccs_name_list_lock);
737 list_for_each_entry(ptr, &ccs_name_list[hash % MAX_HASH], list) {
738 if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
739 continue;
740 atomic_inc(&ptr->users);
741 goto out;
742 }
743 ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL);
744 allocated_len = ptr ? sizeof(*ptr) + len : 0;
745 ccs_string_memory_size += allocated_len;
746 if (!allocated_len ||
747 (ccs_quota_for_string &&
748 ccs_string_memory_size > ccs_quota_for_string)) {
749 ccs_string_memory_size -= allocated_len;
750 kfree(ptr);
751 ptr = NULL;
752 printk(KERN_WARNING "ERROR: Out of memory. (%s)\n", __func__);
753 if (!ccs_policy_loaded)
754 panic("MAC Initialization failed.\n");
755 goto out;
756 }
757 ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
758 memmove((char *) ptr->entry.name, name, len);
759 atomic_set(&ptr->users, 1);
760 ccs_fill_path_info(&ptr->entry);
761 ptr->size = allocated_len;
762 list_add_tail(&ptr->list, &ccs_name_list[hash % MAX_HASH]);
763 out:
764 mutex_unlock(&ccs_name_list_lock);
765 /***** EXCLUSIVE SECTION END *****/
766 return ptr ? &ptr->entry : NULL;
767 }
768
769 /**
770 * ccs_put_name - Delete shared memory for string data.
771 *
772 * @name: Pointer to "struct ccs_path_info".
773 */
774 void ccs_put_name(const struct ccs_path_info *name)
775 {
776 struct ccs_name_entry *ptr;
777 bool can_delete = false;
778 if (!name)
779 return;
780 ptr = container_of(name, struct ccs_name_entry, entry);
781 /***** EXCLUSIVE SECTION START *****/
782 mutex_lock(&ccs_name_list_lock);
783 if (atomic_dec_and_test(&ptr->users)) {
784 list_del(&ptr->list);
785 ccs_string_memory_size -= ptr->size;
786 can_delete = true;
787 }
788 mutex_unlock(&ccs_name_list_lock);
789 /***** EXCLUSIVE SECTION END *****/
790 if (can_delete)
791 kfree(ptr);
792 }
793
794 struct srcu_struct ccs_ss;
795
796 /**
797 * ccs_realpath_init - Initialize realpath related code.
798 *
799 * Returns 0.
800 */
801 static int __init ccs_realpath_init(void)
802 {
803 int i;
804 /* Constraint for ccs_get_name(). */
805 if (CCS_MAX_PATHNAME_LEN > PAGE_SIZE)
806 panic("Bad size.");
807 /* Constraint for "struct ccs_execve_entry"->tmp users. */
808 if (CCS_MAX_PATHNAME_LEN > CCS_EXEC_TMPSIZE)
809 panic("Bad size.");
810 if (init_srcu_struct(&ccs_ss))
811 panic("Out of memory.");
812 for (i = 0; i < MAX_HASH; i++)
813 INIT_LIST_HEAD(&ccs_name_list[i]);
814 INIT_LIST_HEAD(&ccs_kernel_domain.acl_info_list);
815 ccs_kernel_domain.domainname = ccs_get_name(ROOT_NAME);
816 list_add_tail_rcu(&ccs_kernel_domain.list, &ccs_domain_list);
817 if (ccs_find_domain(ROOT_NAME) != &ccs_kernel_domain)
818 panic("Can't register ccs_kernel_domain");
819 #ifdef CONFIG_CCSECURITY_BUILTIN_INITIALIZERS
820 {
821 /* Load built-in policy. */
822 static char ccs_builtin_initializers[] __initdata
823 = CONFIG_CCSECURITY_BUILTIN_INITIALIZERS;
824 char *cp = ccs_builtin_initializers;
825 ccs_normalize_line(cp);
826 while (cp && *cp) {
827 char *cp2 = strchr(cp, ' ');
828 if (cp2)
829 *cp2++ = '\0';
830 ccs_write_domain_initializer_policy(cp, false, false);
831 cp = cp2;
832 }
833 }
834 #endif
835 return 0;
836 }
837
838 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
839 __initcall(ccs_realpath_init);
840 #else
841 core_initcall(ccs_realpath_init);
842 #endif
843
844 unsigned int ccs_audit_log_memory_size;
845 unsigned int ccs_quota_for_audit_log;
846
847 unsigned int ccs_query_memory_size;
848 unsigned int ccs_quota_for_query;
849
850 /**
851 * ccs_read_memory_counter - Check for memory usage.
852 *
853 * @head: Pointer to "struct ccs_io_buffer".
854 *
855 * Returns memory usage.
856 */
857 int ccs_read_memory_counter(struct ccs_io_buffer *head)
858 {
859 if (!head->read_eof) {
860 const unsigned int string = ccs_string_memory_size;
861 const unsigned int nonstring
862 = atomic_read(&ccs_non_string_memory_size);
863 const unsigned int audit_log = ccs_audit_log_memory_size;
864 const unsigned int query = ccs_query_memory_size;
865 char buffer[64];
866 memset(buffer, 0, sizeof(buffer));
867 if (ccs_quota_for_string)
868 snprintf(buffer, sizeof(buffer) - 1,
869 " (Quota: %10u)", ccs_quota_for_string);
870 else
871 buffer[0] = '\0';
872 ccs_io_printf(head, "Policy (string): %10u%s\n",
873 string, buffer);
874 if (ccs_quota_for_non_string)
875 snprintf(buffer, sizeof(buffer) - 1,
876 " (Quota: %10u)", ccs_quota_for_non_string);
877 else
878 buffer[0] = '\0';
879 ccs_io_printf(head, "Policy (non-string): %10u%s\n",
880 nonstring, buffer);
881 if (ccs_quota_for_audit_log)
882 snprintf(buffer, sizeof(buffer) - 1,
883 " (Quota: %10u)", ccs_quota_for_audit_log);
884 else
885 buffer[0] = '\0';
886 ccs_io_printf(head, "Audit logs: %10u%s\n",
887 audit_log, buffer);
888 if (ccs_quota_for_query)
889 snprintf(buffer, sizeof(buffer) - 1,
890 " (Quota: %10u)", ccs_quota_for_query);
891 else
892 buffer[0] = '\0';
893 ccs_io_printf(head, "Interactive enforcement: %10u%s\n",
894 query, buffer);
895 ccs_io_printf(head, "Total: %10u\n",
896 string + nonstring + audit_log + query);
897 head->read_eof = true;
898 }
899 return 0;
900 }
901
902 /**
903 * ccs_write_memory_quota - Set memory quota.
904 *
905 * @head: Pointer to "struct ccs_io_buffer".
906 *
907 * Returns 0.
908 */
909 int ccs_write_memory_quota(struct ccs_io_buffer *head)
910 {
911 char *data = head->write_buf;
912 unsigned int size;
913 if (sscanf(data, "Policy (string): %u", &size) == 1)
914 ccs_quota_for_string = size;
915 else if (sscanf(data, "Policy (non-string): %u", &size) == 1)
916 ccs_quota_for_non_string = size;
917 else if (sscanf(data, "Audit logs: %u", &size) == 1)
918 ccs_quota_for_audit_log = size;
919 else if (sscanf(data, "Interactive enforcement: %u", &size) == 1)
920 ccs_quota_for_query = size;
921 return 0;
922 }
923
924 /* Garbage collector functions */
925
926 enum ccs_gc_id {
927 CCS_ID_RESERVEDPORT,
928 CCS_ID_ADDRESS_GROUP,
929 CCS_ID_ADDRESS_GROUP_MEMBER,
930 CCS_ID_PATH_GROUP,
931 CCS_ID_PATH_GROUP_MEMBER,
932 CCS_ID_NUMBER_GROUP,
933 CCS_ID_NUMBER_GROUP_MEMBER,
934 CCS_ID_GLOBAL_ENV,
935 CCS_ID_AGGREGATOR,
936 CCS_ID_DOMAIN_INITIALIZER,
937 CCS_ID_DOMAIN_KEEPER,
938 CCS_ID_GLOBALLY_READABLE,
939 CCS_ID_PATTERN,
940 CCS_ID_NO_REWRITE,
941 CCS_ID_MANAGER,
942 CCS_ID_ACL,
943 CCS_ID_DOMAIN
944 };
945
946 struct ccs_gc_entry {
947 struct list_head list;
948 int type;
949 void *element;
950 };
951
952 /* Caller holds ccs_policy_lock mutex. */
953 static bool ccs_add_to_gc(const int type, void *element, struct list_head *head)
954 {
955 struct ccs_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
956 if (!entry)
957 return false;
958 entry->type = type;
959 entry->element = element;
960 list_add(&entry->list, head);
961 return true;
962 }
963
964 static size_t ccs_del_allow_read(struct ccs_globally_readable_file_entry *ptr)
965 {
966 ccs_put_name(ptr->filename);
967 return sizeof(*ptr);
968 }
969
970 static size_t ccs_del_allow_env(struct ccs_globally_usable_env_entry *ptr)
971 {
972 ccs_put_name(ptr->env);
973 return sizeof(*ptr);
974 }
975
976 static size_t ccs_del_file_pattern(struct ccs_pattern_entry *ptr)
977 {
978 ccs_put_name(ptr->pattern);
979 return sizeof(*ptr);
980 }
981
982 static size_t ccs_del_no_rewrite(struct ccs_no_rewrite_entry *ptr)
983 {
984 ccs_put_name(ptr->pattern);
985 return sizeof(*ptr);
986 }
987
988 static size_t ccs_del_domain_initializer(struct ccs_domain_initializer_entry *
989 ptr)
990 {
991 ccs_put_name(ptr->domainname);
992 ccs_put_name(ptr->program);
993 return sizeof(*ptr);
994 }
995
996 static size_t ccs_del_domain_keeper(struct ccs_domain_keeper_entry *ptr)
997 {
998 ccs_put_name(ptr->domainname);
999 ccs_put_name(ptr->program);
1000 return sizeof(*ptr);
1001 }
1002
1003 static size_t ccs_del_aggregator(struct ccs_aggregator_entry *ptr)
1004 {
1005 ccs_put_name(ptr->original_name);
1006 ccs_put_name(ptr->aggregated_name);
1007 return sizeof(*ptr);
1008 }
1009
1010 static size_t ccs_del_manager(struct ccs_policy_manager_entry *ptr)
1011 {
1012 ccs_put_name(ptr->manager);
1013 return sizeof(*ptr);
1014 }
1015
1016 /* For compatibility with older kernels. */
1017 #ifndef for_each_process
1018 #define for_each_process for_each_task
1019 #endif
1020
1021 /**
1022 * ccs_used_by_task - Check whether the given pointer is referenced by a task.
1023 *
1024 * @domain: Pointer to "struct ccs_domain_info".
1025 *
1026 * Returns true if @ptr is in use, false otherwise.
1027 */
1028 static bool ccs_used_by_task(struct ccs_domain_info *domain)
1029 {
1030 bool in_use = false;
1031 struct task_struct *p;
1032 /***** CRITICAL SECTION START *****/
1033 read_lock(&tasklist_lock);
1034 for_each_process(p) {
1035 if (p->ccs_domain_info != domain)
1036 continue;
1037 in_use = true;
1038 break;
1039 }
1040 read_unlock(&tasklist_lock);
1041 /***** CRITICAL SECTION END *****/
1042 return in_use;
1043 }
1044
1045 static size_t ccs_del_acl(struct ccs_acl_info *acl)
1046 {
1047 size_t size;
1048 ccs_put_condition(acl->cond);
1049 switch (ccs_acl_type1(acl)) {
1050 case TYPE_SINGLE_PATH_ACL:
1051 {
1052 struct ccs_single_path_acl_record *entry;
1053 size = sizeof(*entry);
1054 entry = container_of(acl, typeof(*entry), head);
1055 if (entry->u_is_group)
1056 ccs_put_path_group(entry->u.group);
1057 else
1058 ccs_put_name(entry->u.filename);
1059 }
1060 break;
1061 case TYPE_MKDEV_ACL:
1062 {
1063 struct ccs_mkdev_acl_record *entry;
1064 size = sizeof(*entry);
1065 entry = container_of(acl, typeof(*entry), head);
1066 if (entry->u_is_group)
1067 ccs_put_path_group(entry->u.group);
1068 else
1069 ccs_put_name(entry->u.filename);
1070 }
1071 break;
1072 case TYPE_DOUBLE_PATH_ACL:
1073 {
1074 struct ccs_double_path_acl_record *entry;
1075 size = sizeof(*entry);
1076 entry = container_of(acl, typeof(*entry), head);
1077 if (entry->u1_is_group)
1078 ccs_put_path_group(entry->u1.group1);
1079 else
1080 ccs_put_name(entry->u1.filename1);
1081 if (entry->u2_is_group)
1082 ccs_put_path_group(entry->u2.group2);
1083 else
1084 ccs_put_name(entry->u2.filename2);
1085 }
1086 break;
1087 case TYPE_IP_NETWORK_ACL:
1088 {
1089 struct ccs_ip_network_acl_record *entry;
1090 size = sizeof(*entry);
1091 entry = container_of(acl, typeof(*entry), head);
1092 if (entry->record_type == IP_RECORD_TYPE_ADDRESS_GROUP)
1093 ccs_put_address_group(entry->u.group);
1094 else if (entry->record_type == IP_RECORD_TYPE_IPv6) {
1095 ccs_put_ipv6_address(entry->u.ipv6.min);
1096 ccs_put_ipv6_address(entry->u.ipv6.max);
1097 }
1098 }
1099 break;
1100 case TYPE_IOCTL_ACL:
1101 {
1102 struct ccs_ioctl_acl_record *entry;
1103 size = sizeof(*entry);
1104 entry = container_of(acl, typeof(*entry), head);
1105 if (entry->u_is_group)
1106 ccs_put_path_group(entry->u.group);
1107 else
1108 ccs_put_name(entry->u.filename);
1109 }
1110 break;
1111 case TYPE_ARGV0_ACL:
1112 {
1113 struct ccs_argv0_acl_record *entry;
1114 size = sizeof(*entry);
1115 entry = container_of(acl, typeof(*entry), head);
1116 ccs_put_name(entry->argv0);
1117 }
1118 break;
1119 case TYPE_ENV_ACL:
1120 {
1121 struct ccs_env_acl_record *entry;
1122 size = sizeof(*entry);
1123 entry = container_of(acl, typeof(*entry), head);
1124 ccs_put_name(entry->env);
1125 }
1126 break;
1127 case TYPE_CAPABILITY_ACL:
1128 {
1129 struct ccs_capability_acl_record *entry;
1130 size = sizeof(*entry);
1131 entry = container_of(acl, typeof(*entry), head);
1132 }
1133 break;
1134 case TYPE_SIGNAL_ACL:
1135 {
1136 struct ccs_signal_acl_record *entry;
1137 size = sizeof(*entry);
1138 entry = container_of(acl, typeof(*entry), head);
1139 ccs_put_name(entry->domainname);
1140 }
1141 break;
1142 case TYPE_EXECUTE_HANDLER:
1143 case TYPE_DENIED_EXECUTE_HANDLER:
1144 {
1145 struct ccs_execute_handler_record *entry;
1146 size = sizeof(*entry);
1147 entry = container_of(acl, typeof(*entry), head);
1148 ccs_put_name(entry->handler);
1149 }
1150 break;
1151 case TYPE_MOUNT_ACL:
1152 {
1153 struct ccs_mount_acl_record *entry;
1154 size = sizeof(*entry);
1155 entry = container_of(acl, typeof(*entry), head);
1156 ccs_put_name(entry->dev_name);
1157 ccs_put_name(entry->dir_name);
1158 ccs_put_name(entry->fs_type);
1159 }
1160 break;
1161 case TYPE_UMOUNT_ACL:
1162 {
1163 struct ccs_umount_acl_record *entry;
1164 size = sizeof(*entry);
1165 entry = container_of(acl, typeof(*entry), head);
1166 ccs_put_name(entry->dir);
1167 }
1168 break;
1169 case TYPE_CHROOT_ACL:
1170 {
1171 struct ccs_chroot_acl_record *entry;
1172 size = sizeof(*entry);
1173 entry = container_of(acl, typeof(*entry), head);
1174 ccs_put_name(entry->dir);
1175 }
1176 break;
1177 case TYPE_PIVOT_ROOT_ACL:
1178 {
1179 struct ccs_pivot_root_acl_record *entry;
1180 size = sizeof(*entry);
1181 entry = container_of(acl, typeof(*entry), head);
1182 ccs_put_name(entry->old_root);
1183 ccs_put_name(entry->new_root);
1184 }
1185 break;
1186 default:
1187 size = 0;
1188 printk(KERN_WARNING "Unknown type\n");
1189 break;
1190 }
1191 return size;
1192 }
1193
1194 static size_t ccs_del_domain(struct ccs_domain_info *domain)
1195 {
1196 struct ccs_acl_info *acl;
1197 struct ccs_acl_info *tmp;
1198 if (ccs_used_by_task(domain))
1199 return 0;
1200 list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
1201 size_t size = ccs_del_acl(acl);
1202 ccs_memory_free(acl, size);
1203 }
1204 ccs_put_name(domain->domainname);
1205 return sizeof(*domain);
1206 }
1207
1208 static size_t ccs_del_path_group_member(struct ccs_path_group_member *member)
1209 {
1210 ccs_put_name(member->member_name);
1211 return sizeof(*member);
1212 }
1213
1214 static size_t ccs_del_path_group(struct ccs_path_group_entry *group)
1215 {
1216 ccs_put_name(group->group_name);
1217 return sizeof(*group);
1218 }
1219
1220 static size_t ccs_del_address_group_member(struct ccs_address_group_member *member)
1221 {
1222 if (member->is_ipv6) {
1223 ccs_put_ipv6_address(member->min.ipv6);
1224 ccs_put_ipv6_address(member->max.ipv6);
1225 }
1226 return sizeof(*member);
1227 }
1228
1229 static size_t ccs_del_address_group(struct ccs_address_group_entry *group)
1230 {
1231 ccs_put_name(group->group_name);
1232 return sizeof(*group);
1233 }
1234
1235 static size_t ccs_del_number_group_member
1236 (struct ccs_number_group_member *member)
1237 {
1238 return sizeof(*member);
1239 }
1240
1241 static size_t ccs_del_number_group(struct ccs_number_group_entry *group)
1242 {
1243 ccs_put_name(group->group_name);
1244 return sizeof(*group);
1245 }
1246
1247 static size_t ccs_del_reservedport(struct ccs_reserved_entry *ptr)
1248 {
1249 return sizeof(*ptr);
1250 }
1251
1252 static int ccs_gc_thread(void *unused)
1253 {
1254 static DEFINE_MUTEX(ccs_gc_mutex);
1255 static LIST_HEAD(ccs_gc_queue);
1256 if (!mutex_trylock(&ccs_gc_mutex))
1257 goto out;
1258 mutex_lock(&ccs_policy_lock);
1259 {
1260 struct ccs_globally_readable_file_entry *ptr;
1261 list_for_each_entry_rcu(ptr, &ccs_globally_readable_list,
1262 list) {
1263 if (!ptr->is_deleted)
1264 continue;
1265 if (ccs_add_to_gc(CCS_ID_GLOBALLY_READABLE, ptr,
1266 &ccs_gc_queue))
1267 list_del_rcu(&ptr->list);
1268 else
1269 break;
1270 }
1271 }
1272 {
1273 struct ccs_globally_usable_env_entry *ptr;
1274 list_for_each_entry_rcu(ptr, &ccs_globally_usable_env_list,
1275 list) {
1276 if (!ptr->is_deleted)
1277 continue;
1278 if (ccs_add_to_gc(CCS_ID_GLOBAL_ENV, ptr,
1279 &ccs_gc_queue))
1280 list_del_rcu(&ptr->list);
1281 else
1282 break;
1283 }
1284 }
1285 {
1286 struct ccs_pattern_entry *ptr;
1287 list_for_each_entry_rcu(ptr, &ccs_pattern_list, list) {
1288 if (!ptr->is_deleted)
1289 continue;
1290 if (ccs_add_to_gc(CCS_ID_PATTERN, ptr,
1291 &ccs_gc_queue))
1292 list_del_rcu(&ptr->list);
1293 else
1294 break;
1295 }
1296 }
1297 {
1298 struct ccs_no_rewrite_entry *ptr;
1299 list_for_each_entry_rcu(ptr, &ccs_no_rewrite_list, list) {
1300 if (!ptr->is_deleted)
1301 continue;
1302 if (ccs_add_to_gc(CCS_ID_NO_REWRITE, ptr,
1303 &ccs_gc_queue))
1304 list_del_rcu(&ptr->list);
1305 else
1306 break;
1307 }
1308 }
1309 {
1310 struct ccs_domain_initializer_entry *ptr;
1311 list_for_each_entry_rcu(ptr, &ccs_domain_initializer_list,
1312 list) {
1313 if (!ptr->is_deleted)
1314 continue;
1315 if (ccs_add_to_gc(CCS_ID_DOMAIN_INITIALIZER,
1316 ptr, &ccs_gc_queue))
1317 list_del_rcu(&ptr->list);
1318 else
1319 break;
1320 }
1321 }
1322 {
1323 struct ccs_domain_keeper_entry *ptr;
1324 list_for_each_entry_rcu(ptr, &ccs_domain_keeper_list, list) {
1325 if (!ptr->is_deleted)
1326 continue;
1327 if (ccs_add_to_gc(CCS_ID_DOMAIN_KEEPER, ptr,
1328 &ccs_gc_queue))
1329 list_del_rcu(&ptr->list);
1330 else
1331 break;
1332 }
1333 }
1334 {
1335 struct ccs_policy_manager_entry *ptr;
1336 list_for_each_entry_rcu(ptr, &ccs_policy_manager_list, list) {
1337 if (!ptr->is_deleted)
1338 continue;
1339 if (ccs_add_to_gc(CCS_ID_MANAGER, ptr, &ccs_gc_queue))
1340 list_del_rcu(&ptr->list);
1341 else
1342 break;
1343 }
1344 }
1345 {
1346 struct ccs_aggregator_entry *ptr;
1347 list_for_each_entry_rcu(ptr, &ccs_aggregator_list, list) {
1348 if (!ptr->is_deleted)
1349 continue;
1350 if (ccs_add_to_gc(CCS_ID_AGGREGATOR, ptr,
1351 &ccs_gc_queue))
1352 list_del_rcu(&ptr->list);
1353 else
1354 break;
1355 }
1356 }
1357 {
1358 struct ccs_domain_info *domain;
1359 list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
1360 struct ccs_acl_info *acl;
1361 list_for_each_entry_rcu(acl, &domain->acl_info_list,
1362 list) {
1363 if (!(acl->type & ACL_DELETED))
1364 continue;
1365 if (ccs_add_to_gc(CCS_ID_ACL, acl,
1366 &ccs_gc_queue))
1367 list_del_rcu(&acl->list);
1368 else
1369 break;
1370 }
1371 if (!domain->is_deleted ||
1372 ccs_used_by_task(domain))
1373 continue;
1374 if (ccs_add_to_gc(CCS_ID_DOMAIN, domain, &ccs_gc_queue))
1375 list_del_rcu(&domain->list);
1376 else
1377 break;
1378 }
1379 }
1380 {
1381 struct ccs_path_group_entry *group;
1382 list_for_each_entry_rcu(group, &ccs_path_group_list, list) {
1383 struct ccs_path_group_member *member;
1384 list_for_each_entry_rcu(member,
1385 &group->path_group_member_list,
1386 list) {
1387 if (!member->is_deleted)
1388 continue;
1389 if (ccs_add_to_gc(CCS_ID_PATH_GROUP_MEMBER,
1390 member, &ccs_gc_queue))
1391 list_del_rcu(&member->list);
1392 else
1393 break;
1394 }
1395 if (!list_empty(&group->path_group_member_list) ||
1396 atomic_read(&group->users))
1397 continue;
1398 if (ccs_add_to_gc(CCS_ID_PATH_GROUP, group,
1399 &ccs_gc_queue))
1400 list_del_rcu(&group->list);
1401 else
1402 break;
1403 }
1404 }
1405 {
1406 struct ccs_address_group_entry *group;
1407 list_for_each_entry_rcu(group, &ccs_address_group_list, list) {
1408 struct ccs_address_group_member *member;
1409 list_for_each_entry_rcu(member,
1410 &group->address_group_member_list,
1411 list) {
1412 if (!member->is_deleted)
1413 break;
1414 if (ccs_add_to_gc(CCS_ID_ADDRESS_GROUP_MEMBER,
1415 member, &ccs_gc_queue))
1416 list_del_rcu(&member->list);
1417 else
1418 break;
1419 }
1420 if (!list_empty(&group->address_group_member_list) ||
1421 atomic_read(&group->users))
1422 continue;
1423 if (ccs_add_to_gc(CCS_ID_ADDRESS_GROUP, group,
1424 &ccs_gc_queue))
1425 list_del_rcu(&group->list);
1426 else
1427 break;
1428 }
1429 }
1430 {
1431 struct ccs_number_group_entry *group;
1432 list_for_each_entry_rcu(group, &ccs_number_group_list, list) {
1433 struct ccs_number_group_member *member;
1434 list_for_each_entry_rcu(member,
1435 &group->
1436 number_group_member_list,
1437 list) {
1438 if (!member->is_deleted)
1439 continue;
1440 if (ccs_add_to_gc(CCS_ID_NUMBER_GROUP_MEMBER,
1441 member, &ccs_gc_queue))
1442 list_del_rcu(&member->list);
1443 else
1444 break;
1445 }
1446 if (!list_empty(&group->number_group_member_list) ||
1447 atomic_read(&group->users))
1448 continue;
1449 if (ccs_add_to_gc(CCS_ID_NUMBER_GROUP, group,
1450 &ccs_gc_queue))
1451 list_del_rcu(&group->list);
1452 else
1453 break;
1454 }
1455 }
1456 {
1457 struct ccs_reserved_entry *ptr;
1458 list_for_each_entry_rcu(ptr, &ccs_reservedport_list, list) {
1459 if (!ptr->is_deleted)
1460 continue;
1461 if (ccs_add_to_gc(CCS_ID_RESERVEDPORT, ptr,
1462 &ccs_gc_queue))
1463 list_del_rcu(&ptr->list);
1464 else
1465 break;
1466 }
1467 }
1468 mutex_unlock(&ccs_policy_lock);
1469 if (list_empty(&ccs_gc_queue))
1470 goto done;
1471 synchronize_srcu(&ccs_ss);
1472 {
1473 struct ccs_gc_entry *p;
1474 struct ccs_gc_entry *tmp;
1475 size_t size = 0;
1476 list_for_each_entry_safe(p, tmp, &ccs_gc_queue, list) {
1477 switch (p->type) {
1478 case CCS_ID_DOMAIN_INITIALIZER:
1479 size = ccs_del_domain_initializer(p->element);
1480 break;
1481 case CCS_ID_DOMAIN_KEEPER:
1482 size = ccs_del_domain_keeper(p->element);
1483 break;
1484 case CCS_ID_GLOBALLY_READABLE:
1485 size = ccs_del_allow_read(p->element);
1486 break;
1487 case CCS_ID_PATTERN:
1488 size = ccs_del_file_pattern(p->element);
1489 break;
1490 case CCS_ID_NO_REWRITE:
1491 size = ccs_del_no_rewrite(p->element);
1492 break;
1493 case CCS_ID_MANAGER:
1494 size = ccs_del_manager(p->element);
1495 break;
1496 case CCS_ID_GLOBAL_ENV:
1497 size = ccs_del_allow_env(p->element);
1498 break;
1499 case CCS_ID_AGGREGATOR:
1500 size = ccs_del_aggregator(p->element);
1501 break;
1502 case CCS_ID_PATH_GROUP_MEMBER:
1503 size = ccs_del_path_group_member(p->element);
1504 break;
1505 case CCS_ID_PATH_GROUP:
1506 size = ccs_del_path_group(p->element);
1507 break;
1508 case CCS_ID_ADDRESS_GROUP_MEMBER:
1509 size = ccs_del_address_group_member(p->element);
1510 break;
1511 case CCS_ID_ADDRESS_GROUP:
1512 size = ccs_del_address_group(p->element);
1513 break;
1514 case CCS_ID_NUMBER_GROUP_MEMBER:
1515 size = ccs_del_number_group_member(p->element);
1516 break;
1517 case CCS_ID_NUMBER_GROUP:
1518 size = ccs_del_number_group(p->element);
1519 break;
1520 case CCS_ID_RESERVEDPORT:
1521 size = ccs_del_reservedport(p->element);
1522 break;
1523 case CCS_ID_ACL:
1524 size = ccs_del_acl(p->element);
1525 break;
1526 case CCS_ID_DOMAIN:
1527 size = ccs_del_domain(p->element);
1528 if (!size)
1529 continue;
1530 break;
1531 default:
1532 size = 0;
1533 printk(KERN_WARNING "Unknown type\n");
1534 break;
1535 }
1536 ccs_memory_free(p->element, size);
1537 list_del(&p->list);
1538 kfree(p);
1539 }
1540 }
1541 done:
1542 mutex_unlock(&ccs_gc_mutex);
1543 out:
1544 do_exit(0);
1545 }
1546
1547 void ccs_run_gc(void)
1548 {
1549 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
1550 struct task_struct *task = kthread_create(ccs_gc_thread, NULL,
1551 "GC for CCS");
1552 if (!IS_ERR(task))
1553 wake_up_process(task);
1554 #else
1555 kernel_thread(ccs_gc_thread, NULL, 0);
1556 #endif
1557 }
1558
1559 #ifndef _LINUX_SRCU_H
1560
1561 static DEFINE_SPINLOCK(ccs_counter_lock);
1562
1563 int srcu_read_lock(struct srcu_struct *sp)
1564 {
1565 int idx;
1566 spin_lock(&ccs_counter_lock);
1567 idx = sp->counter_idx;
1568 sp->counter[idx]++;
1569 spin_unlock(&ccs_counter_lock);
1570 return idx;
1571 }
1572
1573 void srcu_read_unlock(struct srcu_struct *sp, const int idx)
1574 {
1575 spin_lock(&ccs_counter_lock);
1576 sp->counter[idx]--;
1577 spin_unlock(&ccs_counter_lock);
1578 }
1579
1580 void synchronize_srcu(struct srcu_struct *sp)
1581 {
1582 int idx;
1583 int v;
1584 spin_lock(&ccs_counter_lock);
1585 idx = sp->counter_idx;
1586 sp->counter_idx ^= 1;
1587 v = sp->counter[idx];
1588 spin_unlock(&ccs_counter_lock);
1589 while (v) {
1590 ssleep(1);
1591 spin_lock(&ccs_counter_lock);
1592 v = sp->counter[idx];
1593 spin_unlock(&ccs_counter_lock);
1594 }
1595 }
1596
1597 #endif

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