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

Subversion リポジトリの参照

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

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

revision 1031 by kumaneko, Tue Mar 11 04:38:56 2008 UTC revision 1052 by kumaneko, Mon Mar 24 03:50:04 2008 UTC
# Line 5  Line 5 
5   *   *
6   * Copyright (C) 2005-2008  NTT DATA CORPORATION   * Copyright (C) 2005-2008  NTT DATA CORPORATION
7   *   *
8   * Version: 1.6.0-pre   2008/03/11   * Version: 1.6.0-pre   2008/03/24
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 21  Line 21 
21  #include <asm/uaccess.h>  #include <asm/uaccess.h>
22  #include <asm/atomic.h>  #include <asm/atomic.h>
23  #include <linux/version.h>  #include <linux/version.h>
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 lookup_flags = LOOKUP_FOLLOW;
# Line 32  static const int lookup_flags = LOOKUP_F Line 32  static const int lookup_flags = LOOKUP_F
32  #include <linux/proc_fs.h>  #include <linux/proc_fs.h>
33  #include <linux/ccs_common.h>  #include <linux/ccs_common.h>
34    
35  /***** realpath handler *****/  /**
36     * get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
37  /*   *
38   * GetAbsolutePath - return the path of a dentry but ignores chroot'ed root.   * @dentry: Pointer to "struct dentry".
39   * @dentry: dentry to report   * @vfsmnt: Pointer to "struct vfsmount".
40   * @vfsmnt: vfsmnt to which the dentry belongs   * @buffer: Pointer to buffer to return value in.
41   * @buffer: buffer to return value in   * @buflen: Sizeof @buffer.
42   * @buflen: buffer length   *
43     * Returns 0 on success, -ENOMEM otherwise.
44   *   *
45   * Caller holds the dcache_lock.   * Caller holds the dcache_lock and vfsmount_lock .
46   * Based on __d_path() in fs/dcache.c   * Based on __d_path() in fs/dcache.c
47   *   *
48   * If dentry is a directory, trailing '/' is appended.   * If dentry is a directory, trailing '/' is appended.
49   * Characters other than ' ' < c < 127 are converted to \ooo style octal string.   * Characters out of 0x20 < c < 0x7F range are converted to
50     * \ooo style octal string.
51   * Character \ is converted to \\ string.   * Character \ is converted to \\ string.
52   */   */
53  static int GetAbsolutePath(struct dentry *dentry, struct vfsmount *vfsmnt, char *buffer, int buflen)  static int get_absolute_path(struct dentry *dentry, struct vfsmount *vfsmnt,
54                                 char *buffer, int buflen)
55  {  {
56            /***** CRITICAL SECTION START *****/
57          char *start = buffer;          char *start = buffer;
58          char *end = buffer + buflen;          char *end = buffer + buflen;
59          bool is_dir = (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode));          bool is_dir = (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode));
60    
61          if (buflen < 256) goto out;          if (buflen < 256)
62                    goto out;
63    
64          *--end = '\0';          *--end = '\0';
65          buflen--;          buflen--;
# Line 64  static int GetAbsolutePath(struct dentry Line 69  static int GetAbsolutePath(struct dentry
69    
70                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
71                          /* Global root? */                          /* Global root? */
72  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)                          if (vfsmnt->mnt_parent == vfsmnt)
                         spin_lock(&vfsmount_lock);  
 #endif  
                         if (vfsmnt->mnt_parent == vfsmnt) {  
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)  
                                 spin_unlock(&vfsmount_lock);  
 #endif  
73                                  break;                                  break;
                         }  
74                          dentry = vfsmnt->mnt_mountpoint;                          dentry = vfsmnt->mnt_mountpoint;
75                          vfsmnt = vfsmnt->mnt_parent;                          vfsmnt = vfsmnt->mnt_parent;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)  
                         spin_unlock(&vfsmount_lock);  
 #endif  
76                          continue;                          continue;
77                  }                  }
78                  if (is_dir) {                  if (is_dir) {
79                          is_dir = false; *--end = '/'; buflen--;                          is_dir = false;
80                            *--end = '/';
81                            buflen--;
82                  }                  }
83                  parent = dentry->d_parent;                  parent = dentry->d_parent;
84                  {                  {
# Line 89  static int GetAbsolutePath(struct dentry Line 86  static int GetAbsolutePath(struct dentry
86                          const char *cp = sp + dentry->d_name.len - 1;                          const char *cp = sp + dentry->d_name.len - 1;
87                          unsigned char c;                          unsigned char c;
88    
89                          /* Exception: Use /proc/self/ rather than /proc/\$/ for current process. */                          /*
90                          if (IS_ROOT(parent) && *sp > '0' && *sp <= '9' && parent->d_sb && parent->d_sb->s_magic == PROC_SUPER_MAGIC) {                           * Exception: Use /proc/self/ rather than
91                             * /proc/\$/ for current process.
92                             */
93                            if (IS_ROOT(parent) && *sp > '0' && *sp <= '9' &&
94                                parent->d_sb &&
95                                parent->d_sb->s_magic == PROC_SUPER_MAGIC) {
96                                  char *ep;                                  char *ep;
97                                  const pid_t pid = (pid_t) simple_strtoul(sp, &ep, 10);                                  const pid_t pid
98  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)                                          = (pid_t) simple_strtoul(sp, &ep, 10);
99                                  if (!*ep && pid == current->tgid) { sp = "self"; cp = sp + 3; }  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
100                                    if (!*ep && pid == current->tgid) {
101                                            sp = "self";
102                                            cp = sp + 3;
103                                    }
104  #else  #else
105                                  if (!*ep && pid == current->pid) { sp = "self"; cp = sp + 3; }                                  if (!*ep && pid == current->pid) {
106                                            sp = "self";
107                                            cp = sp + 3;
108                                    }
109  #endif  #endif
110                          }                          }
111    
112                          while (sp <= cp) {                          while (sp <= cp) {
113                                  c = * (unsigned char *) cp;                                  c = *(unsigned char *) cp;
114                                  if (c == '\\') {                                  if (c == '\\') {
115                                          buflen -= 2;                                          buflen -= 2;
116                                          if (buflen < 0) goto out;                                          if (buflen < 0)
117                                                    goto out;
118                                          *--end = '\\';                                          *--end = '\\';
119                                          *--end = '\\';                                          *--end = '\\';
120                                  } else if (c > ' ' && c < 127) {                                  } else if (c > ' ' && c < 127) {
121                                          if (--buflen < 0) goto out;                                          if (--buflen < 0)
122                                                    goto out;
123                                          *--end = (char) c;                                          *--end = (char) c;
124                                  } else {                                  } else {
125                                          buflen -= 4;                                          buflen -= 4;
126                                          if (buflen < 0) goto out;                                          if (buflen < 0)
127                                                    goto out;
128                                          *--end = (c & 7) + '0';                                          *--end = (c & 7) + '0';
129                                          *--end = ((c >> 3) & 7) + '0';                                          *--end = ((c >> 3) & 7) + '0';
130                                          *--end = (c >> 6) + '0';                                          *--end = (c >> 6) + '0';
# Line 120  static int GetAbsolutePath(struct dentry Line 132  static int GetAbsolutePath(struct dentry
132                                  }                                  }
133                                  cp--;                                  cp--;
134                          }                          }
135                          if (--buflen < 0) goto out;                          if (--buflen < 0)
136                                    goto out;
137                          *--end = '/';                          *--end = '/';
138                  }                  }
139                  dentry = parent;                  dentry = parent;
140          }          }
141          if (*end == '/') { buflen++; end++; }          if (*end == '/') {
142                    buflen++;
143                    end++;
144            }
145          {          {
146                  const char *sp = dentry->d_name.name;                  const char *sp = dentry->d_name.name;
147                  const char *cp = sp + dentry->d_name.len - 1;                  const char *cp = sp + dentry->d_name.len - 1;
148                  unsigned char c;                  unsigned char c;
149                  while (sp <= cp) {                  while (sp <= cp) {
150                          c = * (unsigned char *) cp;                          c = *(unsigned char *) cp;
151                          if (c == '\\') {                          if (c == '\\') {
152                                  buflen -= 2;                                  buflen -= 2;
153                                  if (buflen < 0) goto out;                                  if (buflen < 0)
154                                            goto out;
155                                  *--end = '\\';                                  *--end = '\\';
156                                  *--end = '\\';                                  *--end = '\\';
157                          } else if (c > ' ' && c < 127) {                          } else if (c > ' ' && c < 127) {
158                                  if (--buflen < 0) goto out;                                  if (--buflen < 0)
159                                            goto out;
160                                  *--end = (char) c;                                  *--end = (char) c;
161                          } else {                          } else {
162                                  buflen -= 4;                                  buflen -= 4;
163                                  if (buflen < 0) goto out;                                  if (buflen < 0)
164                                            goto out;
165                                  *--end = (c & 7) + '0';                                  *--end = (c & 7) + '0';
166                                  *--end = ((c >> 3) & 7) + '0';                                  *--end = ((c >> 3) & 7) + '0';
167                                  *--end = (c >> 6) + '0';                                  *--end = (c >> 6) + '0';
# Line 156  static int GetAbsolutePath(struct dentry Line 175  static int GetAbsolutePath(struct dentry
175          return 0;          return 0;
176   out:   out:
177          return -ENOMEM;          return -ENOMEM;
178            /***** CRITICAL SECTION END *****/
179  }  }
180    
181  /* Returns realpath(3) of the given dentry but ignores chroot'ed root. */  /**
182  int realpath_from_dentry2(struct dentry *dentry, struct vfsmount *mnt, char *newname, int newname_len)   * ccs_realpath_from_dentry2 - Returns realpath(3) of the given dentry
183     *                             but ignores chroot'ed root.
184     *
185     * @dentry:      Pointer to "struct dentry".
186     * @mnt:         Pointer to "struct vfsmount".
187     * @newname:     Pointer to buffer to return value in.
188     * @newname_len: Size of @newname .
189     *
190     * Returns 0 on success, negative value otherwise.
191     */
192    int ccs_realpath_from_dentry2(struct dentry *dentry, struct vfsmount *mnt,
193                                  char *newname, int newname_len)
194  {  {
195          int error;          int error;
196          struct dentry *d_dentry;          struct dentry *d_dentry;
197          struct vfsmount *d_mnt;          struct vfsmount *d_mnt;
198          if (!dentry || !mnt || !newname || newname_len <= 0) return -EINVAL;          if (!dentry || !mnt || !newname || newname_len <= 0)
199                    return -EINVAL;
200          d_dentry = dget(dentry);          d_dentry = dget(dentry);
201          d_mnt = mntget(mnt);          d_mnt = mntget(mnt);
202          /***** CRITICAL SECTION START *****/          /***** CRITICAL SECTION START *****/
203          spin_lock(&dcache_lock);          spin_lock(&dcache_lock);
204          error = GetAbsolutePath(d_dentry, d_mnt, newname, newname_len);  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
205            spin_lock(&vfsmount_lock);
206    #endif
207            error = get_absolute_path(d_dentry, d_mnt, newname, newname_len);
208    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
209            spin_unlock(&vfsmount_lock);
210    #endif
211          spin_unlock(&dcache_lock);          spin_unlock(&dcache_lock);
212          /***** CRITICAL SECTION END *****/          /***** CRITICAL SECTION END *****/
213          dput(d_dentry);          dput(d_dentry);
# Line 177  int realpath_from_dentry2(struct dentry Line 215  int realpath_from_dentry2(struct dentry
215          return error;          return error;
216  }  }
217    
218  /* Returns realpath(3) of the given pathname but ignores chroot'ed root. */  /**
219  /* These functions use ccs_alloc(), so caller must ccs_free() if these functions didn't return NULL. */   * ccs_realpath_from_dentry - Returns realpath(3) of the given pathname
220  char *realpath_from_dentry(struct dentry *dentry, struct vfsmount *mnt)   *                            but ignores chroot'ed root.
221     *
222     * @dentry: Pointer to "struct dentry".
223     * @mnt:    Pointer to "struct vfsmount".
224     *
225     * Returns the realpath of the given @dentry and @mnt on success,
226     * NULL otherwise.
227     *
228     * These functions use ccs_alloc(), so caller must ccs_free()
229     * if these functions didn't return NULL.
230     */
231    char *ccs_realpath_from_dentry(struct dentry *dentry, struct vfsmount *mnt)
232  {  {
233          char *buf = ccs_alloc(sizeof(struct ccs_page_buffer));          char *buf = ccs_alloc(sizeof(struct ccs_page_buffer));
234          if (buf && realpath_from_dentry2(dentry, mnt, buf, CCS_MAX_PATHNAME_LEN - 1) == 0) return buf;          if (buf && ccs_realpath_from_dentry2(dentry, mnt, buf,
235                                                 CCS_MAX_PATHNAME_LEN - 1) == 0)
236                    return buf;
237          ccs_free(buf);          ccs_free(buf);
238          return NULL;          return NULL;
239  }  }
240    
241  char *realpath(const char *pathname)  /**
242     * ccs_realpath - Get realpath of a pathname.
243     *
244     * @pathname: The pathname to solve.
245     *
246     * Returns the realpath of @pathname on success, NULL otherwise.
247     */
248    char *ccs_realpath(const char *pathname)
249  {  {
250          struct nameidata nd;          struct nameidata nd;
251          if (pathname && path_lookup(pathname, lookup_flags, &nd) == 0) {          if (pathname && path_lookup(pathname, lookup_flags, &nd) == 0) {
252  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
253                  char *buf = realpath_from_dentry(nd.path.dentry, nd.path.mnt);                  char *buf = ccs_realpath_from_dentry(nd.path.dentry,
254                                                         nd.path.mnt);
255                  path_put(&nd.path);                  path_put(&nd.path);
256  #else  #else
257                  char *buf = realpath_from_dentry(nd.dentry, nd.mnt);                  char *buf = ccs_realpath_from_dentry(nd.dentry, nd.mnt);
258                  path_release(&nd);                  path_release(&nd);
259  #endif  #endif
260                  return buf;                  return buf;
# Line 203  char *realpath(const char *pathname) Line 262  char *realpath(const char *pathname)
262          return NULL;          return NULL;
263  }  }
264    
265  char *realpath_nofollow(const char *pathname)  /**
266     * ccs_realpath_nofollow - Get realpath of a pathname.
267     *
268     * @pathname: The pathname to solve.
269     *
270     * Returns the realpath of @pathname on success, NULL otherwise.
271     */
272    char *ccs_realpath_nofollow(const char *pathname)
273  {  {
274          struct nameidata nd;          struct nameidata nd;
275          if (pathname && path_lookup(pathname, lookup_flags ^ LOOKUP_FOLLOW, &nd) == 0) {          if (pathname && path_lookup(pathname, lookup_flags ^ LOOKUP_FOLLOW,
276  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)                                      &nd) == 0) {
277                  char *buf = realpath_from_dentry(nd.path.dentry, nd.path.mnt);  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
278                    char *buf = ccs_realpath_from_dentry(nd.path.dentry,
279                                                         nd.path.mnt);
280                  path_put(&nd.path);                  path_put(&nd.path);
281  #else  #else
282                  char *buf = realpath_from_dentry(nd.dentry, nd.mnt);                  char *buf = ccs_realpath_from_dentry(nd.dentry, nd.mnt);
283                  path_release(&nd);                  path_release(&nd);
284  #endif  #endif
285                  return buf;                  return buf;
# Line 219  char *realpath_nofollow(const char *path Line 287  char *realpath_nofollow(const char *path
287          return NULL;          return NULL;
288  }  }
289    
290  /***** Private memory allocator. *****/  /**
291     * round_up - Round up an integer so that the returned pointers are
292  /*   *            appropriately aligned.
293   * Round up an integer so that the returned pointers are appropriately aligned.   *
294   * FIXME: Are there more requirements that is needed for assigning value atomically?   * @size: Size in bytes.
295   */   *
296  static inline unsigned int ROUNDUP(const unsigned int size) {   * Returns rounded value of @size.
297          if (sizeof(void *) >= sizeof(long)) {   *
298                  return ((size + sizeof(void *) - 1) / sizeof(void *)) * sizeof(void *);   * FIXME: Are there more requirements that is needed for assigning value
299          } else {   * atomically?
300                  return ((size + sizeof(long) - 1) / sizeof(long)) * sizeof(long);   */
301          }  static inline unsigned int round_up(const unsigned int size)
302    {
303            if (sizeof(void *) >= sizeof(long))
304                    return ((size + sizeof(void *) - 1)
305                            / sizeof(void *)) * sizeof(void *);
306            else
307                    return ((size + sizeof(long) - 1)
308                            / sizeof(long)) * sizeof(long);
309  }  }
310    
311  static unsigned int allocated_memory_for_elements = 0;  static unsigned int allocated_memory_for_elements;
312    
313  unsigned int GetMemoryUsedForElements(void)  /**
314     * ccs_get_memory_used_for_elements - Get memory used for keeping
315     *                                    ACL structures.
316     *
317     * Returns memory used for keeping ACL structures.
318     */
319    unsigned int ccs_get_memory_used_for_elements(void)
320  {  {
321          return allocated_memory_for_elements;          return allocated_memory_for_elements;
322  }  }
323    
324  /* Allocate memory for structures. The RAM is chunked, so NEVER try to kfree() the returned pointer. */  /**
325  void *alloc_element(const unsigned int size)   * ccs_alloc_element - Allocate permanent memory for structures.
326     *
327     * @size: Size in bytes.
328     *
329     * Returns pointer to allocated memory on success, NULL otherwise.
330     *
331     * The RAM is chunked, so NEVER try to kfree() the returned pointer.
332     */
333    void *ccs_alloc_element(const unsigned int size)
334  {  {
335          static DEFINE_MUTEX(lock);          static DEFINE_MUTEX(lock);
336          static char *buf = NULL;          static char *buf;
337          static unsigned int buf_used_len = PAGE_SIZE;          static unsigned int buf_used_len = PAGE_SIZE;
338          char *ptr = NULL;          char *ptr = NULL;
339          const unsigned int word_aligned_size = ROUNDUP(size);          const unsigned int word_aligned_size = round_up(size);
340          if (word_aligned_size > PAGE_SIZE) return NULL;          if (word_aligned_size > PAGE_SIZE)
341                    return NULL;
342          mutex_lock(&lock);          mutex_lock(&lock);
343          if (buf_used_len + word_aligned_size > PAGE_SIZE) {          if (buf_used_len + word_aligned_size > PAGE_SIZE) {
344                  if ((ptr = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) {                  ptr = kzalloc(PAGE_SIZE, GFP_KERNEL);
345                          printk("ERROR: Out of memory for alloc_element().\n");                  if (!ptr) {
346                          if (!sbin_init_started) panic("MAC Initialization failed.\n");                          printk(KERN_WARNING "ERROR: Out of memory "
347                                   "for ccs_alloc_element().\n");
348                            if (!sbin_init_started)
349                                    panic("MAC Initialization failed.\n");
350                  } else {                  } else {
351                          buf = ptr;                          buf = ptr;
352                          allocated_memory_for_elements += PAGE_SIZE;                          allocated_memory_for_elements += PAGE_SIZE;
# Line 265  void *alloc_element(const unsigned int s Line 358  void *alloc_element(const unsigned int s
358                  ptr = buf + buf_used_len;                  ptr = buf + buf_used_len;
359                  buf_used_len += word_aligned_size;                  buf_used_len += word_aligned_size;
360                  for (i = 0; i < word_aligned_size; i++) {                  for (i = 0; i < word_aligned_size; i++) {
361                          if (ptr[i]) {                          if (!ptr[i])
362                                  printk(KERN_ERR "WARNING: Reserved memory was tainted! The system might go wrong.\n");                                  continue;
363                                  ptr[i] = '\0';                          printk(KERN_ERR "WARNING: Reserved memory was tainted! "
364                          }                                 "The system might go wrong.\n");
365                            ptr[i] = '\0';
366                  }                  }
367          }          }
368          mutex_unlock(&lock);          mutex_unlock(&lock);
369          return ptr;          return ptr;
370  }  }
371    
372  /***** Shared memory allocator. *****/  static unsigned int allocated_memory_for_savename;
373    static unsigned int allocated_memory_for_pool;
374    
 static unsigned int allocated_memory_for_savename = 0;  
 static unsigned int allocated_memory_for_pool = 0;  
375    
376  unsigned int GetMemoryUsedForSaveName(void)  /**
377     * ccs_get_memory_used_for_save_name - Get memory used for keeping
378     *                                     string data.
379     *
380     * Returns memory used for keeping string data.
381     */
382    unsigned int ccs_get_memory_used_for_save_name(void)
383  {  {
384          return allocated_memory_for_savename + allocated_memory_for_pool;          return allocated_memory_for_savename + allocated_memory_for_pool;
385  }  }
386    
387  #define MAX_HASH 256  #define MAX_HASH 256
388    
389    /* Structure for string data. */
390  struct name_entry {  struct name_entry {
391          struct list1_head list;          struct list1_head list;
392          struct path_info entry;          struct path_info entry;
393  };  };
394    
395    /* Structure for available memory region. */
396  struct free_memory_block_list {  struct free_memory_block_list {
397          struct list_head list;          struct list_head list;
398          char *ptr;                           /* Pointer to a free area.               */          char *ptr;             /* Pointer to a free area. */
399          int len;                             /* Length of the area.                   */          int len;               /* Length of the area.     */
400  };  };
401    
402  static struct list1_head name_list[MAX_HASH]; /* The list of names. */  /* The list for "struct name_entry". */
403    static struct list1_head name_list[MAX_HASH];
404    
405  /* Keep the given name on the RAM. The RAM is shared, so NEVER try to modify or kfree() the returned name. */  /**
406  const struct path_info *SaveName(const char *name)   * ccs_save_name - Allocate permanent memory for string data.
407     *
408     * @name: The string to store into the permernent memory.
409     *
410     * Returns pointer to "struct path_info" on success, NULL otherwise.
411     *
412     * The RAM is shared, so NEVER try to modify or kfree() the returned name.
413     */
414    const struct path_info *ccs_save_name(const char *name)
415  {  {
416          static LIST_HEAD(fmb_list);          static LIST_HEAD(fmb_list);
417          static DEFINE_MUTEX(lock);          static DEFINE_MUTEX(lock);
# Line 310  const struct path_info *SaveName(const c Line 420  const struct path_info *SaveName(const c
420          struct free_memory_block_list *fmb;          struct free_memory_block_list *fmb;
421          int len;          int len;
422          char *cp;          char *cp;
423          if (!name) return NULL;          if (!name)
424                    return NULL;
425          len = strlen(name) + 1;          len = strlen(name) + 1;
426          if (len > CCS_MAX_PATHNAME_LEN) {          if (len > CCS_MAX_PATHNAME_LEN) {
427                  printk("ERROR: Name too long for SaveName().\n");                  printk(KERN_WARNING "ERROR: Name too long "
428                           "for ccs_save_name().\n");
429                  return NULL;                  return NULL;
430          }          }
431          hash = full_name_hash((const unsigned char *) name, len - 1);          hash = full_name_hash((const unsigned char *) name, len - 1);
432          mutex_lock(&lock);          mutex_lock(&lock);
433          list1_for_each_entry(ptr, &name_list[hash % MAX_HASH], list) {          list1_for_each_entry(ptr, &name_list[hash % MAX_HASH], list) {
434                  if (hash == ptr->entry.hash && strcmp(name, ptr->entry.name) == 0) goto out;                  if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name))
435                            goto out;
436          }          }
437          list_for_each_entry(fmb, &fmb_list, list) {          list_for_each_entry(fmb, &fmb_list, list) {
438                  if (len <= fmb->len) goto ready;                  if (len <= fmb->len)
439                            goto ready;
440          }          }
441          cp = kzalloc(PAGE_SIZE, GFP_KERNEL);          cp = kzalloc(PAGE_SIZE, GFP_KERNEL);
442          fmb = kzalloc(sizeof(*fmb), GFP_KERNEL);          fmb = kzalloc(sizeof(*fmb), GFP_KERNEL);
443          if (!cp || !fmb) {          if (!cp || !fmb) {
444                  kfree(cp);                  kfree(cp);
445                  kfree(fmb);                  kfree(fmb);
446                  printk("ERROR: Out of memory for SaveName().\n");                  printk(KERN_WARNING "ERROR: Out of memory "
447                  if (!sbin_init_started) panic("MAC Initialization failed.\n");                         "for ccs_save_name().\n");
448                    if (!sbin_init_started)
449                            panic("MAC Initialization failed.\n");
450                  ptr = NULL;                  ptr = NULL;
451                  goto out;                  goto out;
452          }          }
# Line 339  const struct path_info *SaveName(const c Line 455  const struct path_info *SaveName(const c
455          fmb->ptr = cp;          fmb->ptr = cp;
456          fmb->len = PAGE_SIZE;          fmb->len = PAGE_SIZE;
457   ready:   ready:
458          ptr = alloc_element(sizeof(*ptr));          ptr = ccs_alloc_element(sizeof(*ptr));
459          if (!ptr) goto out;          if (!ptr)
460                    goto out;
461          ptr->entry.name = fmb->ptr;          ptr->entry.name = fmb->ptr;
462          memmove(fmb->ptr, name, len);          memmove(fmb->ptr, name, len);
463          fill_path_info(&ptr->entry);          ccs_fill_path_info(&ptr->entry);
464          fmb->ptr += len;          fmb->ptr += len;
465          fmb->len -= len;          fmb->len -= len;
466          list1_add_tail_mb(&ptr->list, &name_list[hash % MAX_HASH]);          list1_add_tail_mb(&ptr->list, &name_list[hash % MAX_HASH]);
# Line 356  const struct path_info *SaveName(const c Line 473  const struct path_info *SaveName(const c
473          return ptr ? &ptr->entry : NULL;          return ptr ? &ptr->entry : NULL;
474  }  }
475    
476  /***** Dynamic memory allocator. *****/  /* Structure for temporarily allocated memory. */
   
477  struct cache_entry {  struct cache_entry {
478          struct list_head list;          struct list_head list;
479          void *ptr;          void *ptr;
480          int size;          int size;
481  };  };
482    
483  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
484  static struct kmem_cache *ccs_cachep = NULL;  static struct kmem_cache *ccs_cachep;
485  #else  #else
486  static kmem_cache_t *ccs_cachep = NULL;  static kmem_cache_t *ccs_cachep;
487  #endif  #endif
488    
489  #ifdef CCS_MAX_RESERVED_PAGES  #ifdef CCS_MAX_RESERVED_PAGES
# Line 379  static kmem_cache_t *ccs_cachep = NULL; Line 495  static kmem_cache_t *ccs_cachep = NULL;
495  static struct ccs_page_buffer *ccs_page_buffer_pool[MAX_CCS_PAGE_BUFFER_POOL];  static struct ccs_page_buffer *ccs_page_buffer_pool[MAX_CCS_PAGE_BUFFER_POOL];
496  static bool ccs_page_buffer_pool_in_use[MAX_CCS_PAGE_BUFFER_POOL];  static bool ccs_page_buffer_pool_in_use[MAX_CCS_PAGE_BUFFER_POOL];
497    
498  void __init realpath_Init(void)  /**
499     * ccs_realpath_init - Initialize realpath related code.
500     *
501     * Returns 0.
502     */
503    static int __init ccs_realpath_init(void)
504  {  {
505          int i;          int i;
506          if (CCS_MAX_PATHNAME_LEN > PAGE_SIZE) panic("Bad size.");          if (CCS_MAX_PATHNAME_LEN > PAGE_SIZE)
507          if (sizeof(struct path_info_with_data) > sizeof(struct ccs_page_buffer)) panic("Bad size.");                  panic("Bad size.");
508  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)          if (sizeof(struct path_info_with_data) > sizeof(struct ccs_page_buffer))
509          ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry), 0, 0, NULL);                  panic("Bad size.");
510    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
511            ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry),
512                                           0, 0, NULL);
513  #else  #else
514          ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry), 0, 0, NULL, NULL);          ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry),
515                                           0, 0, NULL, NULL);
516  #endif  #endif
517          if (!ccs_cachep) panic("Can't create cache.\n");          if (!ccs_cachep)
518          for (i = 0; i < MAX_HASH; i++) {                  panic("Can't create cache.\n");
519            for (i = 0; i < MAX_HASH; i++)
520                  INIT_LIST1_HEAD(&name_list[i]);                  INIT_LIST1_HEAD(&name_list[i]);
         }  
521          INIT_LIST1_HEAD(&KERNEL_DOMAIN.acl_info_list);          INIT_LIST1_HEAD(&KERNEL_DOMAIN.acl_info_list);
522          KERNEL_DOMAIN.domainname = SaveName(ROOT_NAME);          KERNEL_DOMAIN.domainname = ccs_save_name(ROOT_NAME);
523          list1_add_tail_mb(&KERNEL_DOMAIN.list, &domain_list);          list1_add_tail_mb(&KERNEL_DOMAIN.list, &domain_list);
524          if (FindDomain(ROOT_NAME) != &KERNEL_DOMAIN) panic("Can't register KERNEL_DOMAIN");          if (ccs_find_domain(ROOT_NAME) != &KERNEL_DOMAIN)
525                    panic("Can't register KERNEL_DOMAIN");
526          memset(ccs_page_buffer_pool, 0, sizeof(ccs_page_buffer_pool));          memset(ccs_page_buffer_pool, 0, sizeof(ccs_page_buffer_pool));
527          for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++) ccs_page_buffer_pool_in_use[i] = false;          for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++)
528                    ccs_page_buffer_pool_in_use[i] = false;
529            return 0;
530  }  }
531    
532    __initcall(ccs_realpath_init);
533    
534    /* The list for "struct cache_entry". */
535  static LIST_HEAD(cache_list);  static LIST_HEAD(cache_list);
 static spinlock_t cache_list_lock = SPIN_LOCK_UNLOCKED;  
 static unsigned int dynamic_memory_size = 0;  
536    
537  unsigned int GetMemoryUsedForDynamic(void)  static DEFINE_SPINLOCK(cache_list_lock);
538    
539    static unsigned int dynamic_memory_size;
540    
541    /**
542     * ccs_get_memory_used_for_dynamic - Get memory used for temporal purpose.
543     *
544     * Returns memory used for temporal purpose.
545     */
546    unsigned int ccs_get_memory_used_for_dynamic(void)
547  {  {
548          return dynamic_memory_size;          return dynamic_memory_size;
549  }  }
550    
551  #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)  #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
552    /**
553     * round2 - Rounded up to power-of-two value.
554     *
555     * @size: Size in bytes.
556     *
557     * Returns power-of-two of @size.
558     */
559  static int round2(size_t size)  static int round2(size_t size)
560  {  {
561  #if PAGE_SIZE == 4096  #if PAGE_SIZE == 4096
# Line 423  static int round2(size_t size) Line 568  static int round2(size_t size)
568  }  }
569  #endif  #endif
570    
571  static spinlock_t ccs_page_buffer_pool_lock = SPIN_LOCK_UNLOCKED;  static DEFINE_SPINLOCK(ccs_page_buffer_pool_lock);
572    
573    /**
574     * ccs_alloc - Allocate memory for temporal purpose.
575     *
576     * @size: Size in bytes.
577     *
578     * Returns pointer to allocated memory on success, NULL otherwise.
579     */
580  void *ccs_alloc(const size_t size)  void *ccs_alloc(const size_t size)
581  {  {
582          int i;          int i;
583          void *ret;          void *ret;
584          struct cache_entry *new_entry;          struct cache_entry *new_entry;
585          if (size != sizeof(struct ccs_page_buffer)) goto normal;          if (size != sizeof(struct ccs_page_buffer))
586                    goto normal;
587          for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++) {          for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++) {
588                  struct ccs_page_buffer *ptr;                  struct ccs_page_buffer *ptr;
589                  if (ccs_page_buffer_pool_in_use[i]) continue;                  bool in_use;
590                  spin_lock(&ccs_page_buffer_pool_lock);                  if (ccs_page_buffer_pool_in_use[i])
                 if (ccs_page_buffer_pool_in_use[i]) {  
                         spin_unlock(&ccs_page_buffer_pool_lock);  
591                          continue;                          continue;
592                  }                  /***** CRITICAL SECTION START *****/
593                  ccs_page_buffer_pool_in_use[i] = true;                  spin_lock(&ccs_page_buffer_pool_lock);
594                    in_use = ccs_page_buffer_pool_in_use[i];
595                    if (!in_use)
596                            ccs_page_buffer_pool_in_use[i] = true;
597                  spin_unlock(&ccs_page_buffer_pool_lock);                  spin_unlock(&ccs_page_buffer_pool_lock);
598                    /***** CRITICAL SECTION END *****/
599                    if (in_use)
600                            continue;
601                  ptr = ccs_page_buffer_pool[i];                  ptr = ccs_page_buffer_pool[i];
602                  if (!ptr) {                  if (ptr)
603                          ptr = kmalloc(sizeof(struct ccs_page_buffer), GFP_KERNEL);                          goto ok;
604                          spin_lock(&ccs_page_buffer_pool_lock);                  ptr = kmalloc(sizeof(struct ccs_page_buffer), GFP_KERNEL);
605                          if (ptr) {                  /***** CRITICAL SECTION START *****/
606  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)                  spin_lock(&ccs_page_buffer_pool_lock);
607                                  allocated_memory_for_pool += ksize(ptr);                  if (ptr) {
608    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
609                            allocated_memory_for_pool += ksize(ptr);
610  #else  #else
611                                  allocated_memory_for_pool += round2(sizeof(struct ccs_page_buffer));                          allocated_memory_for_pool += round2(size);
612  #endif  #endif
613                          } else {                  } else {
614                                  ccs_page_buffer_pool_in_use[i] = false;                          ccs_page_buffer_pool_in_use[i] = false;
                         }  
                         spin_unlock(&ccs_page_buffer_pool_lock);  
                         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);  
615                  }                  }
616                    spin_unlock(&ccs_page_buffer_pool_lock);
617                    /***** CRITICAL SECTION END *****/
618                    if (!ptr)
619                            goto normal;
620                    ccs_page_buffer_pool[i] = ptr;
621                    printk(KERN_DEBUG "Allocated permanent buffer %d/%d\n",
622                           i, MAX_CCS_PAGE_BUFFER_POOL);
623     ok:
624                  memset(ptr, 0, sizeof(struct ccs_page_buffer));                  memset(ptr, 0, sizeof(struct ccs_page_buffer));
625                  return ptr;                  return ptr;
626          }          }
627   normal:   normal:
628          ret = kzalloc(size, GFP_KERNEL);          ret = kzalloc(size, GFP_KERNEL);
629          if (!ret) goto out;          if (!ret)
630                    goto out;
631          new_entry = kmem_cache_alloc(ccs_cachep, GFP_KERNEL);          new_entry = kmem_cache_alloc(ccs_cachep, GFP_KERNEL);
632          if (!new_entry) {          if (!new_entry) {
633                  kfree(ret); ret = NULL;                  kfree(ret); ret = NULL;
# Line 472  void *ccs_alloc(const size_t size) Line 635  void *ccs_alloc(const size_t size)
635          }          }
636          INIT_LIST_HEAD(&new_entry->list);          INIT_LIST_HEAD(&new_entry->list);
637          new_entry->ptr = ret;          new_entry->ptr = ret;
638  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
639          new_entry->size = ksize(ret);          new_entry->size = ksize(ret);
640  #else  #else
641          new_entry->size = round2(size);          new_entry->size = round2(size);
642  #endif  #endif
643            /***** CRITICAL SECTION START *****/
644          spin_lock(&cache_list_lock);          spin_lock(&cache_list_lock);
645          list_add_tail(&new_entry->list, &cache_list);          list_add_tail(&new_entry->list, &cache_list);
646          dynamic_memory_size += new_entry->size;          dynamic_memory_size += new_entry->size;
647          spin_unlock(&cache_list_lock);          spin_unlock(&cache_list_lock);
648            /***** CRITICAL SECTION END *****/
649   out:   out:
650          return ret;          return ret;
651  }  }
652    
653    /**
654     * ccs_free - Release memory allocated by ccs_alloc().
655     *
656     * @p: Pointer returned by ccs_alloc(). May be NULL.
657     *
658     * Returns nothing.
659     */
660  void ccs_free(const void *p)  void ccs_free(const void *p)
661  {  {
662          int i;          int i;
663          struct list_head *v;          struct list_head *v;
664          struct cache_entry *entry = NULL;          struct cache_entry *entry = NULL;
665          if (!p) return;          if (!p)
666                    return;
667          for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++) {          for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++) {
668                  bool done;                  bool done;
669                  if (p != ccs_page_buffer_pool[i]) continue;                  if (p != ccs_page_buffer_pool[i])
670                            continue;
671                    /***** CRITICAL SECTION START *****/
672                  spin_lock(&ccs_page_buffer_pool_lock);                  spin_lock(&ccs_page_buffer_pool_lock);
673                  done = ccs_page_buffer_pool_in_use[i];                  done = ccs_page_buffer_pool_in_use[i];
674                  if (done) ccs_page_buffer_pool_in_use[i] = false;                  if (done)
675                            ccs_page_buffer_pool_in_use[i] = false;
676                  spin_unlock(&ccs_page_buffer_pool_lock);                  spin_unlock(&ccs_page_buffer_pool_lock);
677                  if (done) return;                  /***** CRITICAL SECTION END *****/
678                    if (done)
679                            return;
680          }          }
681            /***** CRITICAL SECTION START *****/
682          spin_lock(&cache_list_lock);          spin_lock(&cache_list_lock);
683          list_for_each(v, &cache_list) {          list_for_each(v, &cache_list) {
684                  entry = list_entry(v, struct cache_entry, list);                  entry = list_entry(v, struct cache_entry, list);
# Line 511  void ccs_free(const void *p) Line 690  void ccs_free(const void *p)
690                  break;                  break;
691          }          }
692          spin_unlock(&cache_list_lock);          spin_unlock(&cache_list_lock);
693            /***** CRITICAL SECTION END *****/
694          if (entry) {          if (entry) {
695                  kfree(p);                  kfree(p);
696                  kmem_cache_free(ccs_cachep, entry);                  kmem_cache_free(ccs_cachep, entry);
697          } else {          } else {
698                  printk("BUG: ccs_free() with invalid pointer.\n");                  printk(KERN_WARNING "BUG: ccs_free() with invalid pointer.\n");
699          }          }
700  }  }

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

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