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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2392 - (show annotations) (download) (as text)
Mon Apr 6 03:26:15 2009 UTC (15 years, 1 month ago) by kumaneko
Original Path: trunk/1.6.x/ccs-patch/fs/realpath.c
File MIME type: text/x-csrc
File size: 20568 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.6.7 2009/04/01
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/realpath.h>
32 #include <linux/proc_fs.h>
33 #include <linux/ccs_common.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 int ccs_realpath_from_dentry2(struct dentry *dentry, struct vfsmount *mnt,
199 char *newname, int newname_len)
200 {
201 int error = -EINVAL;
202 struct dentry *d_dentry;
203 struct vfsmount *d_mnt;
204 if (!dentry || !newname || newname_len <= 2048)
205 goto out;
206 /* Get better name for socket. */
207 if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
208 struct inode *inode = dentry->d_inode;
209 struct socket *sock = inode ? SOCKET_I(inode) : NULL;
210 struct sock *sk = sock ? sock->sk : NULL;
211 if (sk) {
212 snprintf(newname, newname_len - 1,
213 "socket:[family=%u:type=%u:protocol=%u]",
214 sk->sk_family, sk->sk_type, sk->sk_protocol);
215 } else {
216 snprintf(newname, newname_len - 1, "socket:[unknown]");
217 }
218 return 0;
219 }
220 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
221 if (dentry->d_op && dentry->d_op->d_dname) {
222 /* For "socket:[\$]" and "pipe:[\$]". */
223 static const int offset = 1536;
224 char *dp = newname;
225 char *sp = dentry->d_op->d_dname(dentry, newname + offset,
226 newname_len - offset);
227 if (IS_ERR(sp)) {
228 error = PTR_ERR(sp);
229 goto out;
230 }
231 error = -ENOMEM;
232 newname += offset;
233 while (1) {
234 const unsigned char c = *(unsigned char *) sp++;
235 if (c == '\\') {
236 if (dp + 2 >= newname)
237 break;
238 *dp++ = '\\';
239 *dp++ = '\\';
240 } else if (c > ' ' && c < 127) {
241 if (dp + 1 >= newname)
242 break;
243 *dp++ = (char) c;
244 } else if (c) {
245 if (dp + 4 >= newname)
246 break;
247 *dp++ = '\\';
248 *dp++ = (c >> 6) + '0';
249 *dp++ = ((c >> 3) & 7) + '0';
250 *dp++ = (c & 7) + '0';
251 } else {
252 *dp = '\0';
253 return 0;
254 }
255 }
256 goto out;
257 }
258 #endif
259 if (!mnt)
260 goto out;
261 d_dentry = dget(dentry);
262 d_mnt = mntget(mnt);
263 /***** CRITICAL SECTION START *****/
264 ccs_realpath_lock();
265 error = ccs_get_absolute_path(d_dentry, d_mnt, newname, newname_len);
266 ccs_realpath_unlock();
267 /***** CRITICAL SECTION END *****/
268 dput(d_dentry);
269 mntput(d_mnt);
270 out:
271 if (error)
272 printk(KERN_WARNING "ccs_realpath: Pathname too long. (%d)\n",
273 error);
274 return error;
275 }
276
277 /**
278 * ccs_realpath_from_dentry - Returns realpath(3) of the given pathname but ignores chroot'ed root.
279 *
280 * @dentry: Pointer to "struct dentry".
281 * @mnt: Pointer to "struct vfsmount".
282 *
283 * Returns the realpath of the given @dentry and @mnt on success,
284 * NULL otherwise.
285 *
286 * These functions use ccs_alloc(), so caller must ccs_free()
287 * if these functions didn't return NULL.
288 */
289 char *ccs_realpath_from_dentry(struct dentry *dentry, struct vfsmount *mnt)
290 {
291 char *buf = ccs_alloc(CCS_MAX_PATHNAME_LEN, false);
292 if (buf && ccs_realpath_from_dentry2(dentry, mnt, buf,
293 CCS_MAX_PATHNAME_LEN - 1) == 0)
294 return buf;
295 ccs_free(buf);
296 return NULL;
297 }
298
299 /**
300 * ccs_realpath - Get realpath of a pathname.
301 *
302 * @pathname: The pathname to solve.
303 *
304 * Returns the realpath of @pathname on success, NULL otherwise.
305 */
306 char *ccs_realpath(const char *pathname)
307 {
308 struct nameidata nd;
309 if (pathname && path_lookup(pathname, ccs_lookup_flags, &nd) == 0) {
310 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
311 char *buf = ccs_realpath_from_dentry(nd.path.dentry,
312 nd.path.mnt);
313 path_put(&nd.path);
314 #else
315 char *buf = ccs_realpath_from_dentry(nd.dentry, nd.mnt);
316 path_release(&nd);
317 #endif
318 return buf;
319 }
320 return NULL;
321 }
322
323 /**
324 * ccs_realpath_both - Get realpath of a pathname and symlink.
325 *
326 * @pathname: The pathname to solve.
327 * @ee: Pointer to "struct ccs_execve_entry".
328 *
329 * Returns 0 on success, negative value otherwise.
330 */
331 int ccs_realpath_both(const char *pathname, struct ccs_execve_entry *ee)
332 {
333 struct nameidata nd;
334 int ret;
335 bool is_symlink;
336 if (!pathname ||
337 path_lookup(pathname, ccs_lookup_flags ^ LOOKUP_FOLLOW, &nd))
338 return -ENOENT;
339 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
340 is_symlink = nd.path.dentry->d_inode &&
341 S_ISLNK(nd.path.dentry->d_inode->i_mode);
342 ret = ccs_realpath_from_dentry2(nd.path.dentry, nd.path.mnt,
343 ee->tmp, CCS_EXEC_TMPSIZE - 1);
344 path_put(&nd.path);
345 #else
346 is_symlink = nd.dentry->d_inode && S_ISLNK(nd.dentry->d_inode->i_mode);
347 ret = ccs_realpath_from_dentry2(nd.dentry, nd.mnt, ee->tmp,
348 CCS_EXEC_TMPSIZE - 1);
349 path_release(&nd);
350 #endif
351 if (ret)
352 return -ENOMEM;
353 if (strlen(ee->tmp) > CCS_MAX_PATHNAME_LEN - 1)
354 return -ENOMEM;
355 ee->program_path[CCS_MAX_PATHNAME_LEN - 1] = '\0';
356 if (!is_symlink) {
357 strncpy(ee->program_path, ee->tmp,
358 CCS_MAX_PATHNAME_LEN - 1);
359 return 0;
360 }
361 if (path_lookup(pathname, ccs_lookup_flags, &nd))
362 return -ENOENT;
363 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
364 ret = ccs_realpath_from_dentry2(nd.path.dentry, nd.path.mnt,
365 ee->program_path,
366 CCS_MAX_PATHNAME_LEN - 1);
367 path_put(&nd.path);
368 #else
369 ret = ccs_realpath_from_dentry2(nd.dentry, nd.mnt, ee->program_path,
370 CCS_MAX_PATHNAME_LEN - 1);
371 path_release(&nd);
372 #endif
373 return ret ? -ENOMEM : 0;
374 }
375
376 /**
377 * ccs_round_up - Round up an integer so that the returned pointers are appropriately aligned.
378 *
379 * @size: Size in bytes.
380 *
381 * Returns rounded value of @size.
382 *
383 * FIXME: Are there more requirements that is needed for assigning value
384 * atomically?
385 */
386 static inline unsigned int ccs_round_up(const unsigned int size)
387 {
388 if (sizeof(void *) >= sizeof(long))
389 return ((size + sizeof(void *) - 1)
390 / sizeof(void *)) * sizeof(void *);
391 else
392 return ((size + sizeof(long) - 1)
393 / sizeof(long)) * sizeof(long);
394 }
395
396 static unsigned int ccs_allocated_memory_for_elements;
397 static unsigned int ccs_quota_for_elements;
398
399 /**
400 * ccs_alloc_element - Allocate permanent memory for structures.
401 *
402 * @size: Size in bytes.
403 *
404 * Returns pointer to allocated memory on success, NULL otherwise.
405 *
406 * The RAM is chunked, so NEVER try to kfree() the returned pointer.
407 */
408 void *ccs_alloc_element(const unsigned int size)
409 {
410 static DEFINE_MUTEX(lock);
411 static char *ccs_buf;
412 static unsigned int ccs_buf_used_len = PAGE_SIZE;
413 char *ptr = NULL;
414 const unsigned int word_aligned_size = ccs_round_up(size);
415 if (word_aligned_size > PAGE_SIZE)
416 return NULL;
417 mutex_lock(&lock);
418 if (ccs_buf_used_len + word_aligned_size > PAGE_SIZE) {
419 if (!ccs_quota_for_elements || ccs_allocated_memory_for_elements
420 + PAGE_SIZE <= ccs_quota_for_elements)
421 ptr = kzalloc(PAGE_SIZE, GFP_KERNEL);
422 if (!ptr) {
423 printk(KERN_WARNING "ERROR: Out of memory "
424 "for ccs_alloc_element().\n");
425 if (!ccs_policy_loaded)
426 panic("MAC Initialization failed.\n");
427 } else {
428 ccs_buf = ptr;
429 ccs_allocated_memory_for_elements += PAGE_SIZE;
430 ccs_buf_used_len = word_aligned_size;
431 }
432 } else if (word_aligned_size) {
433 int i;
434 ptr = ccs_buf + ccs_buf_used_len;
435 ccs_buf_used_len += word_aligned_size;
436 for (i = 0; i < word_aligned_size; i++) {
437 if (!ptr[i])
438 continue;
439 printk(KERN_ERR "WARNING: Reserved memory was tainted! "
440 "The system might go wrong.\n");
441 ptr[i] = '\0';
442 }
443 }
444 mutex_unlock(&lock);
445 return ptr;
446 }
447
448 static unsigned int ccs_allocated_memory_for_savename;
449 static unsigned int ccs_quota_for_savename;
450
451 #define MAX_HASH 256
452
453 /* Structure for string data. */
454 struct ccs_name_entry {
455 struct list1_head list;
456 struct ccs_path_info entry;
457 };
458
459 /* Structure for available memory region. */
460 struct ccs_free_memory_block_list {
461 struct list_head list;
462 char *ptr; /* Pointer to a free area. */
463 int len; /* Length of the area. */
464 };
465
466 /* The list for "struct ccs_name_entry". */
467 static struct list1_head ccs_name_list[MAX_HASH];
468
469 /**
470 * ccs_save_name - Allocate permanent memory for string data.
471 *
472 * @name: The string to store into the permernent memory.
473 *
474 * Returns pointer to "struct ccs_path_info" on success, NULL otherwise.
475 *
476 * The RAM is shared, so NEVER try to modify or kfree() the returned name.
477 */
478 const struct ccs_path_info *ccs_save_name(const char *name)
479 {
480 static LIST_HEAD(ccs_fmb_list);
481 static DEFINE_MUTEX(lock);
482 struct ccs_name_entry *ptr;
483 unsigned int hash;
484 struct ccs_free_memory_block_list *fmb;
485 int len;
486 char *cp;
487 if (!name)
488 return NULL;
489 len = strlen(name) + 1;
490 if (len > CCS_MAX_PATHNAME_LEN) {
491 printk(KERN_WARNING "ERROR: Name too long "
492 "for ccs_save_name().\n");
493 return NULL;
494 }
495 hash = full_name_hash((const unsigned char *) name, len - 1);
496 mutex_lock(&lock);
497 list1_for_each_entry(ptr, &ccs_name_list[hash % MAX_HASH], list) {
498 if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name))
499 goto out;
500 }
501 list_for_each_entry(fmb, &ccs_fmb_list, list) {
502 if (len <= fmb->len)
503 goto ready;
504 }
505 if (!ccs_quota_for_savename ||
506 ccs_allocated_memory_for_savename + PAGE_SIZE
507 <= ccs_quota_for_savename)
508 cp = kzalloc(PAGE_SIZE, GFP_KERNEL);
509 else
510 cp = NULL;
511 fmb = kzalloc(sizeof(*fmb), GFP_KERNEL);
512 if (!cp || !fmb) {
513 kfree(cp);
514 kfree(fmb);
515 printk(KERN_WARNING "ERROR: Out of memory "
516 "for ccs_save_name().\n");
517 if (!ccs_policy_loaded)
518 panic("MAC Initialization failed.\n");
519 ptr = NULL;
520 goto out;
521 }
522 ccs_allocated_memory_for_savename += PAGE_SIZE;
523 list_add(&fmb->list, &ccs_fmb_list);
524 fmb->ptr = cp;
525 fmb->len = PAGE_SIZE;
526 ready:
527 ptr = ccs_alloc_element(sizeof(*ptr));
528 if (!ptr)
529 goto out;
530 ptr->entry.name = fmb->ptr;
531 memmove(fmb->ptr, name, len);
532 ccs_fill_path_info(&ptr->entry);
533 fmb->ptr += len;
534 fmb->len -= len;
535 list1_add_tail_mb(&ptr->list, &ccs_name_list[hash % MAX_HASH]);
536 if (fmb->len == 0) {
537 list_del(&fmb->list);
538 kfree(fmb);
539 }
540 out:
541 mutex_unlock(&lock);
542 return ptr ? &ptr->entry : NULL;
543 }
544
545 /* Structure for temporarily allocated memory. */
546 struct ccs_cache_entry {
547 struct list_head list;
548 void *ptr;
549 int size;
550 };
551
552 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
553 static struct kmem_cache *ccs_cachep;
554 #else
555 static kmem_cache_t *ccs_cachep;
556 #endif
557
558 /**
559 * ccs_realpath_init - Initialize realpath related code.
560 *
561 * Returns 0.
562 */
563 static int __init ccs_realpath_init(void)
564 {
565 int i;
566 /* Constraint for ccs_save_name(). */
567 if (CCS_MAX_PATHNAME_LEN > PAGE_SIZE)
568 panic("Bad size.");
569 /* Constraint for "struct ccs_execve_entry"->tmp users. */
570 if (CCS_MAX_PATHNAME_LEN > CCS_EXEC_TMPSIZE)
571 panic("Bad size.");
572 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
573 ccs_cachep = kmem_cache_create("ccs_cache",
574 sizeof(struct ccs_cache_entry),
575 0, 0, NULL);
576 #else
577 ccs_cachep = kmem_cache_create("ccs_cache",
578 sizeof(struct ccs_cache_entry),
579 0, 0, NULL, NULL);
580 #endif
581 if (!ccs_cachep)
582 panic("Can't create cache.\n");
583 for (i = 0; i < MAX_HASH; i++)
584 INIT_LIST1_HEAD(&ccs_name_list[i]);
585 INIT_LIST1_HEAD(&ccs_kernel_domain.acl_info_list);
586 ccs_kernel_domain.domainname = ccs_save_name(ROOT_NAME);
587 list1_add_tail_mb(&ccs_kernel_domain.list, &ccs_domain_list);
588 if (ccs_find_domain(ROOT_NAME) != &ccs_kernel_domain)
589 panic("Can't register ccs_kernel_domain");
590 #ifdef CONFIG_TOMOYO_BUILTIN_INITIALIZERS
591 {
592 /* Load built-in policy. */
593 static char ccs_builtin_initializers[] __initdata
594 = CONFIG_TOMOYO_BUILTIN_INITIALIZERS;
595 char *cp = ccs_builtin_initializers;
596 ccs_normalize_line(cp);
597 while (cp && *cp) {
598 char *cp2 = strchr(cp, ' ');
599 if (cp2)
600 *cp2++ = '\0';
601 ccs_write_domain_initializer_policy(cp, false, false);
602 cp = cp2;
603 }
604 }
605 #endif
606 return 0;
607 }
608
609 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
610 __initcall(ccs_realpath_init);
611 #else
612 core_initcall(ccs_realpath_init);
613 #endif
614
615 /* The list for "struct ccs_cache_entry". */
616 static LIST_HEAD(ccs_audit_cache_list);
617 static LIST_HEAD(ccs_acl_cache_list);
618 static DEFINE_SPINLOCK(ccs_cache_list_lock);
619
620 static unsigned int ccs_dynamic_memory_size;
621 static unsigned int ccs_quota_for_dynamic;
622
623 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
624 /**
625 * ccs_round2 - Rounded up to power-of-two value.
626 *
627 * @size: Size in bytes.
628 *
629 * Returns power-of-two of @size.
630 */
631 static int ccs_round2(size_t size)
632 {
633 #if PAGE_SIZE == 4096
634 size_t bsize = 32;
635 #else
636 size_t bsize = 64;
637 #endif
638 while (size > bsize)
639 bsize <<= 1;
640 return bsize;
641 }
642 #endif
643
644 /**
645 * ccs_alloc - Allocate memory for temporary purpose.
646 *
647 * @size: Size in bytes.
648 *
649 * Returns pointer to allocated memory on success, NULL otherwise.
650 */
651 void *ccs_alloc(const size_t size, const _Bool check_quota)
652 {
653 struct ccs_cache_entry *new_entry;
654 void *ret = kzalloc(size, GFP_KERNEL);
655 if (!ret)
656 goto out;
657 new_entry = kmem_cache_alloc(ccs_cachep, GFP_KERNEL);
658 if (!new_entry) {
659 kfree(ret);
660 ret = NULL;
661 goto out;
662 }
663 INIT_LIST_HEAD(&new_entry->list);
664 new_entry->ptr = ret;
665 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
666 new_entry->size = ksize(ret);
667 #else
668 new_entry->size = ccs_round2(size);
669 #endif
670 if (check_quota) {
671 bool quota_exceeded = false;
672 /***** CRITICAL SECTION START *****/
673 spin_lock(&ccs_cache_list_lock);
674 if (!ccs_quota_for_dynamic ||
675 ccs_dynamic_memory_size + new_entry->size
676 <= ccs_quota_for_dynamic) {
677 list_add_tail(&new_entry->list, &ccs_audit_cache_list);
678 ccs_dynamic_memory_size += new_entry->size;
679 } else {
680 quota_exceeded = true;
681 }
682 spin_unlock(&ccs_cache_list_lock);
683 /***** CRITICAL SECTION END *****/
684 if (quota_exceeded) {
685 kfree(ret);
686 kmem_cache_free(ccs_cachep, new_entry);
687 ret = NULL;
688 }
689 } else {
690 /***** CRITICAL SECTION START *****/
691 spin_lock(&ccs_cache_list_lock);
692 list_add(&new_entry->list, &ccs_acl_cache_list);
693 ccs_dynamic_memory_size += new_entry->size;
694 spin_unlock(&ccs_cache_list_lock);
695 /***** CRITICAL SECTION END *****/
696 }
697 out:
698 return ret;
699 }
700
701 /**
702 * ccs_free - Release memory allocated by ccs_alloc().
703 *
704 * @p: Pointer returned by ccs_alloc(). May be NULL.
705 *
706 * Returns nothing.
707 */
708 void ccs_free(const void *p)
709 {
710 struct list_head *v;
711 struct ccs_cache_entry *entry = NULL;
712 if (!p)
713 return;
714 /***** CRITICAL SECTION START *****/
715 spin_lock(&ccs_cache_list_lock);
716 list_for_each(v, &ccs_acl_cache_list) {
717 entry = list_entry(v, struct ccs_cache_entry, list);
718 if (entry->ptr == p)
719 break;
720 entry = NULL;
721 }
722 if (!entry) {
723 list_for_each(v, &ccs_audit_cache_list) {
724 entry = list_entry(v, struct ccs_cache_entry, list);
725 if (entry->ptr == p)
726 break;
727 entry = NULL;
728 }
729 }
730 if (entry) {
731 list_del(&entry->list);
732 ccs_dynamic_memory_size -= entry->size;
733 }
734 spin_unlock(&ccs_cache_list_lock);
735 /***** CRITICAL SECTION END *****/
736 if (entry) {
737 kfree(p);
738 kmem_cache_free(ccs_cachep, entry);
739 } else {
740 printk(KERN_WARNING "BUG: ccs_free() with invalid pointer.\n");
741 }
742 }
743
744 /**
745 * ccs_read_memory_counter - Check for memory usage.
746 *
747 * @head: Pointer to "struct ccs_io_buffer".
748 *
749 * Returns memory usage.
750 */
751 int ccs_read_memory_counter(struct ccs_io_buffer *head)
752 {
753 if (!head->read_eof) {
754 const unsigned int shared = ccs_allocated_memory_for_savename;
755 const unsigned int private = ccs_allocated_memory_for_elements;
756 const unsigned int dynamic = ccs_dynamic_memory_size;
757 char buffer[64];
758 memset(buffer, 0, sizeof(buffer));
759 if (ccs_quota_for_savename)
760 snprintf(buffer, sizeof(buffer) - 1,
761 " (Quota: %10u)", ccs_quota_for_savename);
762 else
763 buffer[0] = '\0';
764 ccs_io_printf(head, "Shared: %10u%s\n", shared, buffer);
765 if (ccs_quota_for_elements)
766 snprintf(buffer, sizeof(buffer) - 1,
767 " (Quota: %10u)", ccs_quota_for_elements);
768 else
769 buffer[0] = '\0';
770 ccs_io_printf(head, "Private: %10u%s\n", private, buffer);
771 if (ccs_quota_for_dynamic)
772 snprintf(buffer, sizeof(buffer) - 1,
773 " (Quota: %10u)", ccs_quota_for_dynamic);
774 else
775 buffer[0] = '\0';
776 ccs_io_printf(head, "Dynamic: %10u%s\n", dynamic, buffer);
777 ccs_io_printf(head, "Total: %10u\n",
778 shared + private + dynamic);
779 head->read_eof = true;
780 }
781 return 0;
782 }
783
784 /**
785 * ccs_write_memory_quota - Set memory quota.
786 *
787 * @head: Pointer to "struct ccs_io_buffer".
788 *
789 * Returns 0.
790 */
791 int ccs_write_memory_quota(struct ccs_io_buffer *head)
792 {
793 char *data = head->write_buf;
794 unsigned int size;
795 if (sscanf(data, "Shared: %u", &size) == 1)
796 ccs_quota_for_savename = size;
797 else if (sscanf(data, "Private: %u", &size) == 1)
798 ccs_quota_for_elements = size;
799 else if (sscanf(data, "Dynamic: %u", &size) == 1)
800 ccs_quota_for_dynamic = size;
801 return 0;
802 }

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