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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/1.6.x/ccs-patch/fs/realpath.c revision 1052 by kumaneko, Mon Mar 24 03:50:04 2008 UTC branches/ccs-patch/fs/realpath.c revision 2719 by kumaneko, Thu Jul 2 06:07:47 2009 UTC
# Line 3  Line 3 
3   *   *
4   * Get the canonicalized absolute pathnames. The basis for SAKURA and TOMOYO.   * Get the canonicalized absolute pathnames. The basis for SAKURA and TOMOYO.
5   *   *
6   * Copyright (C) 2005-2008  NTT DATA CORPORATION   * Copyright (C) 2005-2009  NTT DATA CORPORATION
7   *   *
8   * Version: 1.6.0-pre   2008/03/24   * Version: 1.7.0-pre   2009/05/28
9   *   *
10   * This file is applicable to both 2.4.30 and 2.6.11 and later.   * This file is applicable to both 2.4.30 and 2.6.11 and later.
11   * See README.ccs for ChangeLog.   * See README.ccs for ChangeLog.
# Line 24  Line 24 
24  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
25  #include <linux/namei.h>  #include <linux/namei.h>
26  #include <linux/mount.h>  #include <linux/mount.h>
27  static const int lookup_flags = LOOKUP_FOLLOW;  static const int ccs_lookup_flags = LOOKUP_FOLLOW;
28  #else  #else
29  static const int lookup_flags = LOOKUP_FOLLOW | LOOKUP_POSITIVE;  static const int ccs_lookup_flags = LOOKUP_FOLLOW | LOOKUP_POSITIVE;
30  #endif  #endif
 #include <linux/realpath.h>  
31  #include <linux/proc_fs.h>  #include <linux/proc_fs.h>
32  #include <linux/ccs_common.h>  #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   * get_absolute_path - Get the path of a dentry but ignores chroot'ed root.   * ccs_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
41   *   *
42   * @dentry: Pointer to "struct dentry".   * @dentry: Pointer to "struct dentry".
43   * @vfsmnt: Pointer to "struct vfsmount".   * @vfsmnt: Pointer to "struct vfsmount".
# Line 42  static const int lookup_flags = LOOKUP_F Line 46  static const int lookup_flags = LOOKUP_F
46   *   *
47   * Returns 0 on success, -ENOMEM otherwise.   * Returns 0 on success, -ENOMEM otherwise.
48   *   *
49   * Caller holds the dcache_lock and vfsmount_lock .   * Caller holds the dcache_lock and vfsmount_lock.
50   * Based on __d_path() in fs/dcache.c   * Based on __d_path() in fs/dcache.c
51   *   *
52   * If dentry is a directory, trailing '/' is appended.   * If dentry is a directory, trailing '/' is appended.
# Line 50  static const int lookup_flags = LOOKUP_F Line 54  static const int lookup_flags = LOOKUP_F
54   * \ooo style octal string.   * \ooo style octal string.
55   * Character \ is converted to \\ string.   * Character \ is converted to \\ string.
56   */   */
57  static int get_absolute_path(struct dentry *dentry, struct vfsmount *vfsmnt,  static int ccs_get_absolute_path(struct dentry *dentry, struct vfsmount *vfsmnt,
58                               char *buffer, int buflen)                                   char *buffer, int buflen)
59  {  {
60          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
61          char *start = buffer;          char *start = buffer;
# Line 96  static int get_absolute_path(struct dent Line 100  static int get_absolute_path(struct dent
100                                  char *ep;                                  char *ep;
101                                  const pid_t pid                                  const pid_t pid
102                                          = (pid_t) simple_strtoul(sp, &ep, 10);                                          = (pid_t) simple_strtoul(sp, &ep, 10);
103  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
104                                  if (!*ep && pid == current->tgid) {                                  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";                                          sp = "self";
110                                          cp = sp + 3;                                          cp = sp + 3;
111                                  }                                  }
112  #else  #else
113                                  if (!*ep && pid == current->pid) {                                  if (!*ep && pid == sys_getpid()) {
114                                          sp = "self";                                          sp = "self";
115                                          cp = sp + 3;                                          cp = sp + 3;
116                                  }                                  }
# Line 178  static int get_absolute_path(struct dent Line 186  static int get_absolute_path(struct dent
186          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
187  }  }
188    
189    #define SOCKFS_MAGIC 0x534F434B
190    
191  /**  /**
192   * ccs_realpath_from_dentry2 - Returns realpath(3) of the given dentry   * ccs_realpath_from_dentry2 - Returns realpath(3) of the given dentry but ignores chroot'ed root.
  *                             but ignores chroot'ed root.  
193   *   *
194   * @dentry:      Pointer to "struct dentry".   * @dentry:      Pointer to "struct dentry".
195   * @mnt:         Pointer to "struct vfsmount".   * @mnt:         Pointer to "struct vfsmount".
196   * @newname:     Pointer to buffer to return value in.   * @newname:     Pointer to buffer to return value in.
197   * @newname_len: Size of @newname .   * @newname_len: Size of @newname.
198   *   *
199   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
200   */   */
201  int ccs_realpath_from_dentry2(struct dentry *dentry, struct vfsmount *mnt,  static int ccs_realpath_from_dentry2(struct dentry *dentry,
202                                char *newname, int newname_len)                                       struct vfsmount *mnt,
203                                         char *newname, int newname_len)
204  {  {
205          int error;          int error = -EINVAL;
206          struct dentry *d_dentry;          struct dentry *d_dentry;
207          struct vfsmount *d_mnt;          struct vfsmount *d_mnt;
208          if (!dentry || !mnt || !newname || newname_len <= 0)          if (!dentry || !newname || newname_len <= 2048)
209                  return -EINVAL;                  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);          d_dentry = dget(dentry);
266          d_mnt = mntget(mnt);          d_mnt = mntget(mnt);
267          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
268          spin_lock(&dcache_lock);          ccs_realpath_lock();
269  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)          error = ccs_get_absolute_path(d_dentry, d_mnt, newname, newname_len);
270          spin_lock(&vfsmount_lock);          ccs_realpath_unlock();
 #endif  
         error = get_absolute_path(d_dentry, d_mnt, newname, newname_len);  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  
         spin_unlock(&vfsmount_lock);  
 #endif  
         spin_unlock(&dcache_lock);  
271          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
272          dput(d_dentry);          dput(d_dentry);
273          mntput(d_mnt);          mntput(d_mnt);
274     out:
275            if (error)
276                    printk(KERN_WARNING "ccs_realpath: Pathname too long. (%d)\n",
277                           error);
278          return error;          return error;
279  }  }
280    
281  /**  /**
282   * ccs_realpath_from_dentry - Returns realpath(3) of the given pathname   * ccs_realpath_from_dentry - Returns realpath(3) of the given pathname but ignores chroot'ed root.
  *                            but ignores chroot'ed root.  
283   *   *
284   * @dentry: Pointer to "struct dentry".   * @dentry: Pointer to "struct dentry".
285   * @mnt:    Pointer to "struct vfsmount".   * @mnt:    Pointer to "struct vfsmount".
# Line 225  int ccs_realpath_from_dentry2(struct den Line 287  int ccs_realpath_from_dentry2(struct den
287   * Returns the realpath of the given @dentry and @mnt on success,   * Returns the realpath of the given @dentry and @mnt on success,
288   * NULL otherwise.   * NULL otherwise.
289   *   *
290   * These functions use ccs_alloc(), so caller must ccs_free()   * These functions use kzalloc(), so caller must kfree()
291   * if these functions didn't return NULL.   * if these functions didn't return NULL.
292   */   */
293  char *ccs_realpath_from_dentry(struct dentry *dentry, struct vfsmount *mnt)  char *ccs_realpath_from_dentry(struct dentry *dentry, struct vfsmount *mnt)
294  {  {
295          char *buf = ccs_alloc(sizeof(struct ccs_page_buffer));          char *buf = kzalloc(CCS_MAX_PATHNAME_LEN, GFP_KERNEL);
296          if (buf && ccs_realpath_from_dentry2(dentry, mnt, buf,          if (buf && ccs_realpath_from_dentry2(dentry, mnt, buf,
297                                               CCS_MAX_PATHNAME_LEN - 1) == 0)                                               CCS_MAX_PATHNAME_LEN - 2) == 0)
298                  return buf;                  return buf;
299          ccs_free(buf);          kfree(buf);
300          return NULL;          return NULL;
301  }  }
302    
# Line 248  char *ccs_realpath_from_dentry(struct de Line 310  char *ccs_realpath_from_dentry(struct de
310  char *ccs_realpath(const char *pathname)  char *ccs_realpath(const char *pathname)
311  {  {
312          struct nameidata nd;          struct nameidata nd;
313          if (pathname && path_lookup(pathname, lookup_flags, &nd) == 0) {          if (pathname && path_lookup(pathname, ccs_lookup_flags, &nd) == 0) {
314  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
315                  char *buf = ccs_realpath_from_dentry(nd.path.dentry,                  char *buf = ccs_realpath_from_dentry(nd.path.dentry,
316                                                       nd.path.mnt);                                                       nd.path.mnt);
# Line 263  char *ccs_realpath(const char *pathname) Line 325  char *ccs_realpath(const char *pathname)
325  }  }
326    
327  /**  /**
328   * ccs_realpath_nofollow - Get realpath of a pathname.   * ccs_realpath_both - Get realpath of a pathname and symlink.
329   *   *
330   * @pathname: The pathname to solve.   * @pathname: The pathname to solve.
331     * @ee:       Pointer to "struct ccs_execve_entry".
332   *   *
333   * Returns the realpath of @pathname on success, NULL otherwise.   * Returns 0 on success, negative value otherwise.
334   */   */
335  char *ccs_realpath_nofollow(const char *pathname)  int ccs_realpath_both(const char *pathname, struct ccs_execve_entry *ee)
336  {  {
337          struct nameidata nd;          struct nameidata nd;
338          if (pathname && path_lookup(pathname, lookup_flags ^ LOOKUP_FOLLOW,          int ret;
339                                      &nd) == 0) {          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)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
344                  char *buf = ccs_realpath_from_dentry(nd.path.dentry,          is_symlink = nd.path.dentry->d_inode &&
345                                                       nd.path.mnt);                  S_ISLNK(nd.path.dentry->d_inode->i_mode);
346                  path_put(&nd.path);          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  #else
350                  char *buf = ccs_realpath_from_dentry(nd.dentry, nd.mnt);          is_symlink = nd.dentry->d_inode && S_ISLNK(nd.dentry->d_inode->i_mode);
351                  path_release(&nd);          ret = ccs_realpath_from_dentry2(nd.dentry, nd.mnt, ee->tmp,
352                                            CCS_EXEC_TMPSIZE - 1);
353            path_release(&nd);
354  #endif  #endif
355                  return buf;          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          return NULL;          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   * round_up - Round up an integer so that the returned pointers are   * ccs_encode: Encode binary string to ascii string.
  *            appropriately aligned.  
382   *   *
383   * @size: Size in bytes.   * @str: String in binary format.
384   *   *
385   * Returns rounded value of @size.   * Returns pointer to @str in ascii format on success, NULL otherwise.
386   *   *
387   * FIXME: Are there more requirements that is needed for assigning value   * This function uses kzalloc(), so caller must kfree() if this function
388   * atomically?   * didn't return NULL.
389   */   */
390  static inline unsigned int round_up(const unsigned int size)  char *ccs_encode(const char *str)
391  {  {
392          if (sizeof(void *) >= sizeof(long))          int len = 0;
393                  return ((size + sizeof(void *) - 1)          const char *p = str;
394                          / sizeof(void *)) * sizeof(void *);          char *cp;
395          else          char *cp0;
396                  return ((size + sizeof(long) - 1)          if (!p)
397                          / sizeof(long)) * sizeof(long);                  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 unsigned int allocated_memory_for_elements;  static atomic_t ccs_non_string_memory_size;
431    static unsigned int ccs_quota_for_non_string;
432    
433  /**  /**
434   * ccs_get_memory_used_for_elements - Get memory used for keeping   * ccs_memory_ok - Check memory quota.
435   *                                    ACL structures.   *
436     * @ptr:  Pointer to allocated memory.
437     * @size: Size in byte.
438   *   *
439   * Returns memory used for keeping ACL structures.   * Returns true if @ptr is not NULL and quota not exceeded, false otehrwise.
440   */   */
441  unsigned int ccs_get_memory_used_for_elements(void)  bool ccs_memory_ok(const void *ptr, const unsigned int size)
442  {  {
443          return allocated_memory_for_elements;          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_alloc_element - Allocate permanent memory for structures.   * ccs_memory_free - Free memory for elements.
457   *   *
458   * @size: Size in bytes.   * @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   * Returns pointer to allocated memory on success, NULL otherwise.   * @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   * The RAM is chunked, so NEVER try to kfree() the returned pointer.   * @group: Pointer to "struct ccs_address_group_entry".
511   */   */
512  void *ccs_alloc_element(const unsigned int size)  void ccs_put_address_group(struct ccs_address_group_entry *group)
513  {  {
514          static DEFINE_MUTEX(lock);          struct ccs_address_group_member *member;
515          static char *buf;          struct ccs_address_group_member *next_member;
516          static unsigned int buf_used_len = PAGE_SIZE;          LIST_HEAD(q);
517          char *ptr = NULL;          bool can_delete_group = false;
518          const unsigned int word_aligned_size = round_up(size);          if (!group)
519          if (word_aligned_size > PAGE_SIZE)                  return;
520                  return NULL;          mutex_lock(&ccs_policy_lock);
521          mutex_lock(&lock);          if (atomic_dec_and_test(&group->users)) {
522          if (buf_used_len + word_aligned_size > PAGE_SIZE) {                  list_for_each_entry_safe(member, next_member,
523                  ptr = kzalloc(PAGE_SIZE, GFP_KERNEL);                                           &group->address_group_member_list,
524                  if (!ptr) {                                           list) {
525                          printk(KERN_WARNING "ERROR: Out of memory "                          if (!member->is_deleted)
526                                 "for ccs_alloc_element().\n");                                  break;
527                          if (!sbin_init_started)                          list_del(&member->list);
528                                  panic("MAC Initialization failed.\n");                          list_add(&member->list, &q);
                 } else {  
                         buf = ptr;  
                         allocated_memory_for_elements += PAGE_SIZE;  
                         buf_used_len = word_aligned_size;  
                         ptr = buf;  
529                  }                  }
530          } else if (word_aligned_size) {                  if (list_empty(&group->address_group_member_list)) {
531                  int i;                          list_del(&group->list);
532                  ptr = buf + buf_used_len;                          can_delete_group = true;
533                  buf_used_len += word_aligned_size;                  }
534                  for (i = 0; i < word_aligned_size; i++) {          }
535                          if (!ptr[i])          mutex_unlock(&ccs_policy_lock);
536                                  continue;          list_for_each_entry_safe(member, next_member, &q, list) {
537                          printk(KERN_ERR "WARNING: Reserved memory was tainted! "                  list_del(&member->list);
538                                 "The system might go wrong.\n");                  if (member->is_ipv6) {
539                          ptr[i] = '\0';                          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          }          }
         mutex_unlock(&lock);  
         return ptr;  
548  }  }
549    
550  static unsigned int allocated_memory_for_savename;  static LIST_HEAD(ccs_address_list);
 static unsigned int allocated_memory_for_pool;  
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_get_memory_used_for_save_name - Get memory used for keeping   * ccs_put_condition - Delete memory for "struct ccs_condition".
  *                                     string data.  
613   *   *
614   * Returns memory used for keeping string data.   * @cond: Pointer to "struct ccs_condition".
615   */   */
616  unsigned int ccs_get_memory_used_for_save_name(void)  void ccs_put_condition(struct ccs_condition *cond)
617  {  {
618          return allocated_memory_for_savename + allocated_memory_for_pool;          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  #define MAX_HASH 256
661    
662  /* Structure for string data. */  /* Structure for string data. */
663  struct name_entry {  struct ccs_name_entry {
         struct list1_head list;  
         struct path_info entry;  
 };  
   
 /* Structure for available memory region. */  
 struct free_memory_block_list {  
664          struct list_head list;          struct list_head list;
665          char *ptr;             /* Pointer to a free area. */          atomic_t users;
666          int len;               /* Length of the area.     */          int size;
667            struct ccs_path_info entry;
668  };  };
669    
670  /* The list for "struct name_entry". */  /* The list for "struct ccs_name_entry". */
671  static struct list1_head name_list[MAX_HASH];  static struct list_head ccs_name_list[MAX_HASH];
672    static DEFINE_MUTEX(ccs_name_list_lock);
673    
674  /**  /**
675   * ccs_save_name - Allocate permanent memory for string data.   * ccs_get_name - Allocate memory for string data.
676   *   *
677   * @name: The string to store into the permernent memory.   * @name: The string to store into the permernent memory.
678   *   *
679   * Returns pointer to "struct path_info" on success, NULL otherwise.   * Returns pointer to "struct ccs_path_info" on success, NULL otherwise.
  *  
  * The RAM is shared, so NEVER try to modify or kfree() the returned name.  
680   */   */
681  const struct path_info *ccs_save_name(const char *name)  const struct ccs_path_info *ccs_get_name(const char *name)
682  {  {
683          static LIST_HEAD(fmb_list);          struct ccs_name_entry *ptr;
         static DEFINE_MUTEX(lock);  
         struct name_entry *ptr;  
684          unsigned int hash;          unsigned int hash;
         struct free_memory_block_list *fmb;  
685          int len;          int len;
686          char *cp;          int allocated_len;
687    
688          if (!name)          if (!name)
689                  return NULL;                  return NULL;
690          len = strlen(name) + 1;          len = strlen(name) + 1;
691          if (len > CCS_MAX_PATHNAME_LEN) {          if (len > CCS_MAX_PATHNAME_LEN) {
692                  printk(KERN_WARNING "ERROR: Name too long "                  printk(KERN_WARNING "ERROR: Name too long. (%s)\n", __func__);
                        "for ccs_save_name().\n");  
693                  return NULL;                  return NULL;
694          }          }
695          hash = full_name_hash((const unsigned char *) name, len - 1);          hash = full_name_hash((const unsigned char *) name, len - 1);
696          mutex_lock(&lock);          /***** EXCLUSIVE SECTION START *****/
697          list1_for_each_entry(ptr, &name_list[hash % MAX_HASH], list) {          mutex_lock(&ccs_name_list_lock);
698                  if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name))          list_for_each_entry(ptr, &ccs_name_list[hash % MAX_HASH], list) {
699                          goto out;                  if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
700                            continue;
701                    atomic_inc(&ptr->users);
702                    goto out;
703          }          }
704          list_for_each_entry(fmb, &fmb_list, list) {          ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL);
705                  if (len <= fmb->len)          allocated_len = ptr ? sizeof(*ptr) + len : 0;
706                          goto ready;          ccs_string_memory_size += allocated_len;
707          }          if (!allocated_len ||
708          cp = kzalloc(PAGE_SIZE, GFP_KERNEL);              (ccs_quota_for_string &&
709          fmb = kzalloc(sizeof(*fmb), GFP_KERNEL);               ccs_string_memory_size > ccs_quota_for_string)) {
710          if (!cp || !fmb) {                  ccs_string_memory_size -= allocated_len;
711                  kfree(cp);                  kfree(ptr);
                 kfree(fmb);  
                 printk(KERN_WARNING "ERROR: Out of memory "  
                        "for ccs_save_name().\n");  
                 if (!sbin_init_started)  
                         panic("MAC Initialization failed.\n");  
712                  ptr = NULL;                  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;                  goto out;
717          }          }
718          allocated_memory_for_savename += PAGE_SIZE;          ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
719          list_add(&fmb->list, &fmb_list);          memmove((char *) ptr->entry.name, name, len);
720          fmb->ptr = cp;          atomic_set(&ptr->users, 1);
         fmb->len = PAGE_SIZE;  
  ready:  
         ptr = ccs_alloc_element(sizeof(*ptr));  
         if (!ptr)  
                 goto out;  
         ptr->entry.name = fmb->ptr;  
         memmove(fmb->ptr, name, len);  
721          ccs_fill_path_info(&ptr->entry);          ccs_fill_path_info(&ptr->entry);
722          fmb->ptr += len;          ptr->size = allocated_len;
723          fmb->len -= len;          list_add_tail(&ptr->list, &ccs_name_list[hash % MAX_HASH]);
         list1_add_tail_mb(&ptr->list, &name_list[hash % MAX_HASH]);  
         if (fmb->len == 0) {  
                 list_del(&fmb->list);  
                 kfree(fmb);  
         }  
724   out:   out:
725          mutex_unlock(&lock);          mutex_unlock(&ccs_name_list_lock);
726            /***** EXCLUSIVE SECTION END *****/
727          return ptr ? &ptr->entry : NULL;          return ptr ? &ptr->entry : NULL;
728  }  }
729    
730  /* Structure for temporarily allocated memory. */  /**
731  struct cache_entry {   * ccs_put_name - Delete shared memory for string data.
732          struct list_head list;   *
733          void *ptr;   * @name: Pointer to "struct ccs_path_info".
734          int size;   */
735  };  void ccs_put_name(const struct ccs_path_info *name)
736    {
737  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)          struct ccs_name_entry *ptr;
738  static struct kmem_cache *ccs_cachep;          bool can_delete = false;
739  #else          if (!name)
740  static kmem_cache_t *ccs_cachep;                  return;
741  #endif          ptr = container_of(name, struct ccs_name_entry, entry);
742            /***** EXCLUSIVE SECTION START *****/
743  #ifdef CCS_MAX_RESERVED_PAGES          mutex_lock(&ccs_name_list_lock);
744  #define MAX_CCS_PAGE_BUFFER_POOL (CCS_MAX_RESERVED_PAGES)          if (atomic_dec_and_test(&ptr->users)) {
745  #else                  list_del(&ptr->list);
746  #define MAX_CCS_PAGE_BUFFER_POOL 10                  ccs_string_memory_size -= ptr->size;
747  #endif                  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  static struct ccs_page_buffer *ccs_page_buffer_pool[MAX_CCS_PAGE_BUFFER_POOL];  struct srcu_struct ccs_ss;
 static bool ccs_page_buffer_pool_in_use[MAX_CCS_PAGE_BUFFER_POOL];  
756    
757  /**  /**
758   * ccs_realpath_init - Initialize realpath related code.   * ccs_realpath_init - Initialize realpath related code.
# Line 503  static bool ccs_page_buffer_pool_in_use[ Line 762  static bool ccs_page_buffer_pool_in_use[
762  static int __init ccs_realpath_init(void)  static int __init ccs_realpath_init(void)
763  {  {
764          int i;          int i;
765            /* Constraint for ccs_get_name(). */
766          if (CCS_MAX_PATHNAME_LEN > PAGE_SIZE)          if (CCS_MAX_PATHNAME_LEN > PAGE_SIZE)
767                  panic("Bad size.");                  panic("Bad size.");
768          if (sizeof(struct path_info_with_data) > sizeof(struct ccs_page_buffer))          /* Constraint for "struct ccs_execve_entry"->tmp users. */
769            if (CCS_MAX_PATHNAME_LEN > CCS_EXEC_TMPSIZE)
770                  panic("Bad size.");                  panic("Bad size.");
771  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)          if (init_srcu_struct(&ccs_ss))
772          ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry),                  panic("Out of memory.");
                                        0, 0, NULL);  
 #else  
         ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry),  
                                        0, 0, NULL, NULL);  
 #endif  
         if (!ccs_cachep)  
                 panic("Can't create cache.\n");  
773          for (i = 0; i < MAX_HASH; i++)          for (i = 0; i < MAX_HASH; i++)
774                  INIT_LIST1_HEAD(&name_list[i]);                  INIT_LIST_HEAD(&ccs_name_list[i]);
775          INIT_LIST1_HEAD(&KERNEL_DOMAIN.acl_info_list);          INIT_LIST_HEAD(&ccs_kernel_domain.acl_info_list);
776          KERNEL_DOMAIN.domainname = ccs_save_name(ROOT_NAME);          ccs_kernel_domain.domainname = ccs_get_name(ROOT_NAME);
777          list1_add_tail_mb(&KERNEL_DOMAIN.list, &domain_list);          list_add_tail_rcu(&ccs_kernel_domain.list, &ccs_domain_list);
778          if (ccs_find_domain(ROOT_NAME) != &KERNEL_DOMAIN)          if (ccs_find_domain(ROOT_NAME) != &ccs_kernel_domain)
779                  panic("Can't register KERNEL_DOMAIN");                  panic("Can't register ccs_kernel_domain");
780          memset(ccs_page_buffer_pool, 0, sizeof(ccs_page_buffer_pool));  #ifdef CONFIG_CCSECURITY_BUILTIN_INITIALIZERS
781          for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++)          {
782                  ccs_page_buffer_pool_in_use[i] = false;                  /* 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;          return 0;
797  }  }
798    
799    #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
800  __initcall(ccs_realpath_init);  __initcall(ccs_realpath_init);
801    #else
802    core_initcall(ccs_realpath_init);
803    #endif
804    
805  /* The list for "struct cache_entry". */  unsigned int ccs_audit_log_memory_size;
806  static LIST_HEAD(cache_list);  unsigned int ccs_quota_for_audit_log;
   
 static DEFINE_SPINLOCK(cache_list_lock);  
807    
808  static unsigned int dynamic_memory_size;  unsigned int ccs_query_memory_size;
809    unsigned int ccs_quota_for_query;
810    
811  /**  /**
812   * ccs_get_memory_used_for_dynamic - Get memory used for temporal purpose.   * ccs_read_memory_counter - Check for memory usage.
813   *   *
814   * Returns memory used for temporal purpose.   * @head: Pointer to "struct ccs_io_buffer".
815     *
816     * Returns memory usage.
817   */   */
818  unsigned int ccs_get_memory_used_for_dynamic(void)  int ccs_read_memory_counter(struct ccs_io_buffer *head)
819  {  {
820          return dynamic_memory_size;          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    
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)  
863  /**  /**
864   * round2 - Rounded up to power-of-two value.   * ccs_write_memory_quota - Set memory quota.
865   *   *
866   * @size: Size in bytes.   * @head: Pointer to "struct ccs_io_buffer".
867   *   *
868   * Returns power-of-two of @size.   * Returns 0.
869   */   */
870  static int round2(size_t size)  int ccs_write_memory_quota(struct ccs_io_buffer *head)
871  {  {
872  #if PAGE_SIZE == 4096          char *data = head->write_buf;
873          size_t bsize = 32;          unsigned int size;
874  #else          if (sscanf(data, "Policy (string): %u", &size) == 1)
875          size_t bsize = 64;                  ccs_quota_for_string = size;
876  #endif          else if (sscanf(data, "Policy (non-string): %u", &size) == 1)
877          while (size > bsize) bsize <<= 1;                  ccs_quota_for_non_string = size;
878          return bsize;          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  }  }
 #endif  
884    
885  static DEFINE_SPINLOCK(ccs_page_buffer_pool_lock);  /* 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_alloc - Allocate memory for temporal purpose.   * ccs_used_by_task - Check whether the given pointer is referenced by a task.
991   *   *
992   * @size: Size in bytes.   * @domain: Pointer to "struct ccs_domain_info".
993   *   *
994   * Returns pointer to allocated memory on success, NULL otherwise.   * Returns true if @ptr is in use, false otherwise.
995   */   */
996  void *ccs_alloc(const size_t size)  static bool ccs_used_by_task(struct ccs_domain_info *domain)
997  {  {
998          int i;          bool in_use = false;
999          void *ret;          struct task_struct *p;
1000          struct cache_entry *new_entry;          /***** CRITICAL SECTION START *****/
1001          if (size != sizeof(struct ccs_page_buffer))          read_lock(&tasklist_lock);
1002                  goto normal;          for_each_process(p) {
1003          for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++) {                  if (p->ccs_domain_info != domain)
                 struct ccs_page_buffer *ptr;  
                 bool in_use;  
                 if (ccs_page_buffer_pool_in_use[i])  
                         continue;  
                 /***** CRITICAL SECTION START *****/  
                 spin_lock(&ccs_page_buffer_pool_lock);  
                 in_use = ccs_page_buffer_pool_in_use[i];  
                 if (!in_use)  
                         ccs_page_buffer_pool_in_use[i] = true;  
                 spin_unlock(&ccs_page_buffer_pool_lock);  
                 /***** CRITICAL SECTION END *****/  
                 if (in_use)  
1004                          continue;                          continue;
1005                  ptr = ccs_page_buffer_pool[i];                  in_use = true;
1006                  if (ptr)                  break;
                         goto ok;  
                 ptr = kmalloc(sizeof(struct ccs_page_buffer), GFP_KERNEL);  
                 /***** CRITICAL SECTION START *****/  
                 spin_lock(&ccs_page_buffer_pool_lock);  
                 if (ptr) {  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  
                         allocated_memory_for_pool += ksize(ptr);  
 #else  
                         allocated_memory_for_pool += round2(size);  
 #endif  
                 } else {  
                         ccs_page_buffer_pool_in_use[i] = false;  
                 }  
                 spin_unlock(&ccs_page_buffer_pool_lock);  
                 /***** CRITICAL SECTION END *****/  
                 if (!ptr)  
                         goto normal;  
                 ccs_page_buffer_pool[i] = ptr;  
                 printk(KERN_DEBUG "Allocated permanent buffer %d/%d\n",  
                        i, MAX_CCS_PAGE_BUFFER_POOL);  
  ok:  
                 memset(ptr, 0, sizeof(struct ccs_page_buffer));  
                 return ptr;  
         }  
  normal:  
         ret = kzalloc(size, GFP_KERNEL);  
         if (!ret)  
                 goto out;  
         new_entry = kmem_cache_alloc(ccs_cachep, GFP_KERNEL);  
         if (!new_entry) {  
                 kfree(ret); ret = NULL;  
                 goto out;  
1007          }          }
1008          INIT_LIST_HEAD(&new_entry->list);          read_unlock(&tasklist_lock);
         new_entry->ptr = ret;  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)  
         new_entry->size = ksize(ret);  
 #else  
         new_entry->size = round2(size);  
 #endif  
         /***** CRITICAL SECTION START *****/  
         spin_lock(&cache_list_lock);  
         list_add_tail(&new_entry->list, &cache_list);  
         dynamic_memory_size += new_entry->size;  
         spin_unlock(&cache_list_lock);  
1009          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
1010   out:          return in_use;
         return ret;  
1011  }  }
1012    
1013  /**  static size_t ccs_del_acl(struct ccs_acl_info *acl)
1014   * ccs_free - Release memory allocated by ccs_alloc().  {
1015   *          size_t size;
1016   * @p: Pointer returned by ccs_alloc(). May be NULL.          ccs_put_condition(acl->cond);
1017   *          switch (ccs_acl_type1(acl)) {
1018   * Returns nothing.          case TYPE_SINGLE_PATH_ACL:
1019   */                  {
1020  void ccs_free(const void *p)                          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;          int i;
1200          struct list_head *v;          u16 condc = ptr->condc;
1201          struct cache_entry *entry = NULL;          u16 argc = ptr->argc;
1202          if (!p)          u16 envc = ptr->envc;
1203                  return;          u16 symlinkc = ptr->symlinkc;
1204          for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++) {          unsigned long *ptr2 = (unsigned long *) (ptr + 1);
1205                  bool done;          struct ccs_argv_entry *argv = (struct ccs_argv_entry *) (ptr2 + condc);
1206                  if (p != ccs_page_buffer_pool[i])          struct ccs_envp_entry *envp = (struct ccs_envp_entry *) (argv + argc);
1207                          continue;          struct ccs_symlinkp_entry *symlinkp
1208                  /***** CRITICAL SECTION START *****/                  = (struct ccs_symlinkp_entry *) (envp + envc);
1209                  spin_lock(&ccs_page_buffer_pool_lock);          for (i = 0; i < argc; i++)
1210                  done = ccs_page_buffer_pool_in_use[i];                  ccs_put_name(argv[i].value);
1211                  if (done)          for (i = 0; i < envc; i++) {
1212                          ccs_page_buffer_pool_in_use[i] = false;                  ccs_put_name(envp[i].name);
1213                  spin_unlock(&ccs_page_buffer_pool_lock);                  ccs_put_name(envp[i].value);
                 /***** CRITICAL SECTION END *****/  
                 if (done)  
                         return;  
1214          }          }
1215          /***** CRITICAL SECTION START *****/          for (i = 0; i < symlinkc; i++)
1216          spin_lock(&cache_list_lock);                  ccs_put_name(symlinkp[i].value);
1217          list_for_each(v, &cache_list) {          return ptr->size;
1218                  entry = list_entry(v, struct cache_entry, list);  }
1219                  if (entry->ptr != p) {  
1220                          entry = NULL; continue;  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                  }                  }
                 list_del(&entry->list);  
                 dynamic_memory_size -= entry->size;  
                 break;  
1239          }          }
1240          spin_unlock(&cache_list_lock);          {
1241          /***** CRITICAL SECTION END *****/                  struct ccs_globally_usable_env_entry *ptr;
1242          if (entry) {                  list_for_each_entry_rcu(ptr, &ccs_globally_usable_env_list,
1243                  kfree(p);                                          list) {
1244                  kmem_cache_free(ccs_cachep, entry);                          if (!ptr->is_deleted)
1245          } else {                                  continue;
1246                  printk(KERN_WARNING "BUG: ccs_free() with invalid pointer.\n");                          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

Legend:
Removed from v.1052  
changed lines
  Added in v.2719

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