~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/security/ccsecurity/realpath.c

Version: ~ [ linux-5.5-rc1 ] ~ [ linux-5.4.2 ] ~ [ linux-5.3.15 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.88 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.158 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.206 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.206 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.78 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * security/ccsecurity/realpath.c
  3  *
  4  * Copyright (C) 2005-2012  NTT DATA CORPORATION
  5  *
  6  * Version: 1.8.5   2015/11/11
  7  */
  8 
  9 #include "internal.h"
 10 
 11 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36) && LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)
 12 #include <linux/nsproxy.h>
 13 #include <linux/mnt_namespace.h>
 14 #endif
 15 
 16 /***** SECTION1: Constants definition *****/
 17 
 18 #define SOCKFS_MAGIC 0x534F434B
 19 
 20 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
 21 #define s_fs_info u.generic_sbp
 22 #endif
 23 
 24 /***** SECTION2: Structure definition *****/
 25 
 26 /***** SECTION3: Prototype definition section *****/
 27 
 28 char *ccs_encode(const char *str);
 29 char *ccs_encode2(const char *str, int str_len);
 30 char *ccs_realpath(const struct path *path);
 31 const char *ccs_get_exe(void);
 32 void ccs_fill_path_info(struct ccs_path_info *ptr);
 33 
 34 static char *ccs_get_absolute_path(const struct path *path,
 35                                    char * const buffer, const int buflen);
 36 static char *ccs_get_dentry_path(struct dentry *dentry, char * const buffer,
 37                                  const int buflen);
 38 static char *ccs_get_local_path(struct dentry *dentry, char * const buffer,
 39                                 const int buflen);
 40 static char *ccs_get_socket_name(const struct path *path, char * const buffer,
 41                                  const int buflen);
 42 static int ccs_const_part_length(const char *filename);
 43 
 44 /***** SECTION4: Standalone functions section *****/
 45 
 46 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
 47 
 48 /**
 49  * SOCKET_I - Get "struct socket".
 50  *
 51  * @inode: Pointer to "struct inode".
 52  *
 53  * Returns pointer to "struct socket".
 54  *
 55  * This is for compatibility with older kernels.
 56  */
 57 static inline struct socket *SOCKET_I(struct inode *inode)
 58 {
 59         return inode->i_sock ? &inode->u.socket_i : NULL;
 60 }
 61 
 62 #endif
 63 
 64 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
 65 
 66 /**
 67  * ccs_realpath_lock - Take locks for __d_path().
 68  *
 69  * Returns nothing.
 70  */
 71 static inline void ccs_realpath_lock(void)
 72 {
 73         /* dcache_lock is locked by __d_path(). */
 74         /* vfsmount_lock is locked by __d_path(). */
 75 }
 76 
 77 /**
 78  * ccs_realpath_unlock - Release locks for __d_path().
 79  *
 80  * Returns nothing.
 81  */
 82 static inline void ccs_realpath_unlock(void)
 83 {
 84         /* vfsmount_lock is unlocked by __d_path(). */
 85         /* dcache_lock is unlocked by __d_path(). */
 86 }
 87 
 88 #elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 36)
 89 
 90 /**
 91  * ccs_realpath_lock - Take locks for __d_path().
 92  *
 93  * Returns nothing.
 94  */
 95 static inline void ccs_realpath_lock(void)
 96 {
 97         spin_lock(&dcache_lock);
 98         /* vfsmount_lock is locked by __d_path(). */
 99 }
100 
101 /**
102  * ccs_realpath_unlock - Release locks for __d_path().
103  *
104  * Returns nothing.
105  */
106 static inline void ccs_realpath_unlock(void)
107 {
108         /* vfsmount_lock is unlocked by __d_path(). */
109         spin_unlock(&dcache_lock);
110 }
111 
112 #elif defined(D_PATH_DISCONNECT) && !defined(CONFIG_SUSE_KERNEL)
113 
114 /**
115  * ccs_realpath_lock - Take locks for __d_path().
116  *
117  * Returns nothing.
118  *
119  * Original unambiguous-__d_path.diff in patches.apparmor.tar.bz2 inversed the
120  * order of holding dcache_lock and vfsmount_lock. That patch was applied on
121  * (at least) SUSE 11.1 and Ubuntu 8.10 and Ubuntu 9.04 kernels.
122  *
123  * However, that patch was updated to use original order and the updated patch
124  * is applied to (as far as I know) only SUSE kernels.
125  *
126  * Therefore, I need to use original order for SUSE 11.1 kernels and inversed
127  * order for other kernels. I detect it by checking D_PATH_DISCONNECT and
128  * CONFIG_SUSE_KERNEL. I don't know whether other distributions are using the
129  * updated patch or not. If you got deadlock, check fs/dcache.c for locking
130  * order, and add " && 0" to this "#elif " block if fs/dcache.c uses original
131  * order.
132  */
133 static inline void ccs_realpath_lock(void)
134 {
135         spin_lock(ccsecurity_exports.vfsmount_lock);
136         spin_lock(&dcache_lock);
137 }
138 
139 /**
140  * ccs_realpath_unlock - Release locks for __d_path().
141  *
142  * Returns nothing.
143  */
144 static inline void ccs_realpath_unlock(void)
145 {
146         spin_unlock(&dcache_lock);
147         spin_unlock(ccsecurity_exports.vfsmount_lock);
148 }
149 
150 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
151 
152 /**
153  * ccs_realpath_lock - Take locks for __d_path().
154  *
155  * Returns nothing.
156  */
157 static inline void ccs_realpath_lock(void)
158 {
159         spin_lock(&dcache_lock);
160         spin_lock(ccsecurity_exports.vfsmount_lock);
161 }
162 
163 /**
164  * ccs_realpath_unlock - Release locks for __d_path().
165  *
166  * Returns nothing.
167  */
168 static inline void ccs_realpath_unlock(void)
169 {
170         spin_unlock(ccsecurity_exports.vfsmount_lock);
171         spin_unlock(&dcache_lock);
172 }
173 
174 #else
175 
176 /**
177  * ccs_realpath_lock - Take locks for __d_path().
178  *
179  * Returns nothing.
180  */
181 static inline void ccs_realpath_lock(void)
182 {
183         spin_lock(&dcache_lock);
184 }
185 
186 /**
187  * ccs_realpath_unlock - Release locks for __d_path().
188  *
189  * Returns nothing.
190  */
191 static inline void ccs_realpath_unlock(void)
192 {
193         spin_unlock(&dcache_lock);
194 }
195 
196 #endif
197 
198 /***** SECTION5: Variables definition section *****/
199 
200 /***** SECTION6: Dependent functions section *****/
201 
202 /**
203  * ccs_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
204  *
205  * @path:   Pointer to "struct path".
206  * @buffer: Pointer to buffer to return value in.
207  * @buflen: Sizeof @buffer.
208  *
209  * Returns the buffer on success, an error code otherwise.
210  *
211  * Caller holds the dcache_lock and vfsmount_lock.
212  * Based on __d_path() in fs/dcache.c
213  *
214  * If dentry is a directory, trailing '/' is appended.
215  */
216 static char *ccs_get_absolute_path(const struct path *path,
217                                    char * const buffer, const int buflen)
218 {
219 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
220         char *pos = ERR_PTR(-ENOMEM);
221         if (buflen >= 256) {
222                 pos = ccsecurity_exports.d_absolute_path(path, buffer,
223                                                          buflen - 1);
224                 if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
225                         struct inode *inode = path->dentry->d_inode;
226                         if (inode && S_ISDIR(inode->i_mode)) {
227                                 buffer[buflen - 2] = '/';
228                                 buffer[buflen - 1] = '\0';
229                         }
230                 }
231         }
232         return pos;
233 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
234         /*
235          * __d_path() will start returning NULL by backporting commit 02125a82
236          * "fix apparmor dereferencing potentially freed dentry, sanitize
237          * __d_path() API".
238          *
239          * Unfortunately, __d_path() after applying that commit always returns
240          * NULL when root is empty. d_absolute_path() is provided for TOMOYO
241          * 2.x and AppArmor but TOMOYO 1.x does not use it, for TOMOYO 1.x
242          * might be built as a loadable kernel module and there is no warrantee
243          * that TOMOYO 1.x is recompiled after applying that commit. Also,
244          * I don't want to search /proc/kallsyms for d_absolute_path() because
245          * I want to keep TOMOYO 1.x architecture independent. Thus, supply
246          * non empty root like AppArmor's d_namespace_path() did.
247          */
248         char *pos = ERR_PTR(-ENOMEM);
249         if (buflen >= 256) {
250                 static bool ccs_no_empty;
251                 if (!ccs_no_empty) {
252                         struct path root = { };
253                         pos = ccsecurity_exports.__d_path(path, &root, buffer,
254                                                           buflen - 1);
255                 } else {
256                         pos = NULL;
257                 }
258                 if (!pos) {
259                         struct task_struct *task = current;
260                         struct path root;
261                         struct path tmp;
262                         spin_lock(&task->fs->lock);
263                         root.mnt = task->nsproxy->mnt_ns->root;
264                         root.dentry = root.mnt->mnt_root;
265                         path_get(&root);
266                         spin_unlock(&task->fs->lock);
267                         tmp = root;
268                         pos = ccsecurity_exports.__d_path(path, &tmp, buffer,
269                                                           buflen - 1);
270                         path_put(&root);
271                         if (!pos)
272                                 return ERR_PTR(-EINVAL);
273                         /* Remember if __d_path() needs non empty root. */
274                         ccs_no_empty = true;
275                 }
276                 if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
277                         struct inode *inode = path->dentry->d_inode;
278                         if (inode && S_ISDIR(inode->i_mode)) {
279                                 buffer[buflen - 2] = '/';
280                                 buffer[buflen - 1] = '\0';
281                         }
282                 }
283         }
284         return pos;
285 #else
286         char *pos = buffer + buflen - 1;
287         struct dentry *dentry = path->dentry;
288         struct vfsmount *vfsmnt = path->mnt;
289         const char *name;
290         int len;
291 
292         if (buflen < 256)
293                 goto out;
294 
295         *pos = '\0';
296         if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
297                 *--pos = '/';
298         for (;;) {
299                 struct dentry *parent;
300                 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
301                         if (vfsmnt->mnt_parent == vfsmnt)
302                                 break;
303                         dentry = vfsmnt->mnt_mountpoint;
304                         vfsmnt = vfsmnt->mnt_parent;
305                         continue;
306                 }
307                 parent = dentry->d_parent;
308                 name = dentry->d_name.name;
309                 len = dentry->d_name.len;
310                 pos -= len;
311                 if (pos <= buffer)
312                         goto out;
313                 memmove(pos, name, len);
314                 *--pos = '/';
315                 dentry = parent;
316         }
317         if (*pos == '/')
318                 pos++;
319         len = dentry->d_name.len;
320         pos -= len;
321         if (pos < buffer)
322                 goto out;
323         memmove(pos, dentry->d_name.name, len);
324         return pos;
325 out:
326         return ERR_PTR(-ENOMEM);
327 #endif
328 }
329 
330 /**
331  * ccs_get_dentry_path - Get the path of a dentry.
332  *
333  * @dentry: Pointer to "struct dentry".
334  * @buffer: Pointer to buffer to return value in.
335  * @buflen: Sizeof @buffer.
336  *
337  * Returns the buffer on success, an error code otherwise.
338  *
339  * Based on dentry_path() in fs/dcache.c
340  *
341  * If dentry is a directory, trailing '/' is appended.
342  */
343 static char *ccs_get_dentry_path(struct dentry *dentry, char * const buffer,
344                                  const int buflen)
345 {
346 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
347         char *pos = ERR_PTR(-ENOMEM);
348         if (buflen >= 256) {
349                 pos = dentry_path_raw(dentry, buffer, buflen - 1);
350                 if (!IS_ERR(pos) && *pos == '/' && pos[1] &&
351                     d_is_dir(dentry)) {
352                         buffer[buflen - 2] = '/';
353                         buffer[buflen - 1] = '\0';
354                 }
355         }
356         return pos;
357 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
358         char *pos = ERR_PTR(-ENOMEM);
359         if (buflen >= 256) {
360                 /* rename_lock is locked/unlocked by dentry_path_raw(). */
361                 pos = dentry_path_raw(dentry, buffer, buflen - 1);
362                 if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
363                         struct inode *inode = dentry->d_inode;
364                         if (inode && S_ISDIR(inode->i_mode)) {
365                                 buffer[buflen - 2] = '/';
366                                 buffer[buflen - 1] = '\0';
367                         }
368                 }
369         }
370         return pos;
371 #else
372         char *pos = buffer + buflen - 1;
373         if (buflen < 256)
374                 return ERR_PTR(-ENOMEM);
375         *pos = '\0';
376         if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
377                 *--pos = '/';
378         spin_lock(&dcache_lock);
379         while (!IS_ROOT(dentry)) {
380                 struct dentry *parent = dentry->d_parent;
381                 const char *name = dentry->d_name.name;
382                 const int len = dentry->d_name.len;
383                 pos -= len;
384                 if (pos <= buffer) {
385                         pos = ERR_PTR(-ENOMEM);
386                         break;
387                 }
388                 memmove(pos, name, len);
389                 *--pos = '/';
390                 dentry = parent;
391         }
392         spin_unlock(&dcache_lock);
393         return pos;
394 #endif
395 }
396 
397 /**
398  * ccs_get_local_path - Get the path of a dentry.
399  *
400  * @dentry: Pointer to "struct dentry".
401  * @buffer: Pointer to buffer to return value in.
402  * @buflen: Sizeof @buffer.
403  *
404  * Returns the buffer on success, an error code otherwise.
405  */
406 static char *ccs_get_local_path(struct dentry *dentry, char * const buffer,
407                                 const int buflen)
408 {
409         struct super_block *sb = dentry->d_sb;
410         char *pos = ccs_get_dentry_path(dentry, buffer, buflen);
411         if (IS_ERR(pos))
412                 return pos;
413         /* Convert from $PID to self if $PID is current thread. */
414         if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
415                 char *ep;
416                 const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10);
417 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
418                 if (*ep == '/' && pid && pid ==
419                     task_tgid_nr_ns(current, sb->s_fs_info)) {
420                         pos = ep - 5;
421                         if (pos < buffer)
422                                 goto out;
423                         memmove(pos, "/self", 5);
424                 }
425 #else
426                 if (*ep == '/' && pid == ccs_sys_getpid()) {
427                         pos = ep - 5;
428                         if (pos < buffer)
429                                 goto out;
430                         memmove(pos, "/self", 5);
431                 }
432 #endif
433                 goto prepend_filesystem_name;
434         }
435         /* Use filesystem name for unnamed devices. */
436         if (!MAJOR(sb->s_dev))
437                 goto prepend_filesystem_name;
438         {
439                 struct inode *inode = sb->s_root->d_inode;
440                 /*
441                  * Use filesystem name if filesystems does not support rename()
442                  * operation.
443                  */
444 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
445                 if (inode->i_op && !inode->i_op->rename)
446                         goto prepend_filesystem_name;
447 #else
448                 if (!inode->i_op->rename && !inode->i_op->rename2)
449                         goto prepend_filesystem_name;
450 #endif
451         }
452         /* Prepend device name. */
453         {
454                 char name[64];
455                 int name_len;
456                 const dev_t dev = sb->s_dev;
457                 name[sizeof(name) - 1] = '\0';
458                 snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev),
459                          MINOR(dev));
460                 name_len = strlen(name);
461                 pos -= name_len;
462                 if (pos < buffer)
463                         goto out;
464                 memmove(pos, name, name_len);
465                 return pos;
466         }
467         /* Prepend filesystem name. */
468 prepend_filesystem_name:
469         {
470                 const char *name = sb->s_type->name;
471                 const int name_len = strlen(name);
472                 pos -= name_len + 1;
473                 if (pos < buffer)
474                         goto out;
475                 memmove(pos, name, name_len);
476                 pos[name_len] = ':';
477         }
478         return pos;
479 out:
480         return ERR_PTR(-ENOMEM);
481 }
482 
483 /**
484  * ccs_get_socket_name - Get the name of a socket.
485  *
486  * @path:   Pointer to "struct path".
487  * @buffer: Pointer to buffer to return value in.
488  * @buflen: Sizeof @buffer.
489  *
490  * Returns the buffer.
491  */
492 static char *ccs_get_socket_name(const struct path *path, char * const buffer,
493                                  const int buflen)
494 {
495         struct inode *inode = path->dentry->d_inode;
496         struct socket *sock = inode ? SOCKET_I(inode) : NULL;
497         struct sock *sk = sock ? sock->sk : NULL;
498         if (sk) {
499                 snprintf(buffer, buflen, "socket:[family=%u:type=%u:"
500                          "protocol=%u]", sk->sk_family, sk->sk_type,
501                          sk->sk_protocol);
502         } else {
503                 snprintf(buffer, buflen, "socket:[unknown]");
504         }
505         return buffer;
506 }
507 
508 #define SOCKFS_MAGIC 0x534F434B
509 
510 /**
511  * ccs_realpath - Returns realpath(3) of the given pathname but ignores chroot'ed root.
512  *
513  * @path: Pointer to "struct path".
514  *
515  * Returns the realpath of the given @path on success, NULL otherwise.
516  *
517  * This function uses kzalloc(), so caller must kfree() if this function
518  * didn't return NULL.
519  */
520 char *ccs_realpath(const struct path *path)
521 {
522         char *buf = NULL;
523         char *name = NULL;
524         unsigned int buf_len = PAGE_SIZE / 2;
525         struct dentry *dentry = path->dentry;
526         struct super_block *sb;
527         if (!dentry)
528                 return NULL;
529         sb = dentry->d_sb;
530         while (1) {
531                 char *pos;
532                 struct inode *inode;
533                 buf_len <<= 1;
534                 kfree(buf);
535                 buf = kmalloc(buf_len, CCS_GFP_FLAGS);
536                 if (!buf)
537                         break;
538                 /* To make sure that pos is '\0' terminated. */
539                 buf[buf_len - 1] = '\0';
540                 /* Get better name for socket. */
541                 if (sb->s_magic == SOCKFS_MAGIC) {
542                         pos = ccs_get_socket_name(path, buf, buf_len - 1);
543                         goto encode;
544                 }
545 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
546                 /* For "pipe:[\$]". */
547                 if (dentry->d_op && dentry->d_op->d_dname) {
548                         pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
549                         goto encode;
550                 }
551 #endif
552                 inode = sb->s_root->d_inode;
553                 /*
554                  * Use local name for "filesystems without rename() operation"
555                  * or "path without vfsmount" or "absolute name is unavailable"
556                  * cases.
557                  */
558 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
559                 if (!path->mnt || (inode->i_op && !inode->i_op->rename))
560                         pos = ERR_PTR(-EINVAL);
561                 else {
562                         /* Get absolute name for the rest. */
563                         ccs_realpath_lock();
564                         pos = ccs_get_absolute_path(path, buf, buf_len - 1);
565                         ccs_realpath_unlock();
566                 }
567                 if (pos == ERR_PTR(-EINVAL))
568                         pos = ccs_get_local_path(path->dentry, buf,
569                                                  buf_len - 1);
570 #else
571                 if (!path->mnt ||
572                     (!inode->i_op->rename && !inode->i_op->rename2))
573                         pos = ccs_get_local_path(path->dentry, buf,
574                                                  buf_len - 1);
575                 else
576                         pos = ccs_get_absolute_path(path, buf, buf_len - 1);
577 #endif
578 encode:
579                 if (IS_ERR(pos))
580                         continue;
581                 name = ccs_encode(pos);
582                 break;
583         }
584         kfree(buf);
585         if (!name)
586                 ccs_warn_oom(__func__);
587         return name;
588 }
589 
590 /**
591  * ccs_encode2 - Encode binary string to ascii string.
592  *
593  * @str:     String in binary format.
594  * @str_len: Size of @str in byte.
595  *
596  * Returns pointer to @str in ascii format on success, NULL otherwise.
597  *
598  * This function uses kzalloc(), so caller must kfree() if this function
599  * didn't return NULL.
600  */
601 char *ccs_encode2(const char *str, int str_len)
602 {
603         int i;
604         int len = 0;
605         const char *p = str;
606         char *cp;
607         char *cp0;
608         if (!p)
609                 return NULL;
610         for (i = 0; i < str_len; i++) {
611                 const unsigned char c = p[i];
612                 if (c == '\\')
613                         len += 2;
614                 else if (c > ' ' && c < 127)
615                         len++;
616                 else
617                         len += 4;
618         }
619         len++;
620         /* Reserve space for appending "/". */
621         cp = kzalloc(len + 10, CCS_GFP_FLAGS);
622         if (!cp)
623                 return NULL;
624         cp0 = cp;
625         p = str;
626         for (i = 0; i < str_len; i++) {
627                 const unsigned char c = p[i];
628                 if (c == '\\') {
629                         *cp++ = '\\';
630                         *cp++ = '\\';
631                 } else if (c > ' ' && c < 127) {
632                         *cp++ = c;
633                 } else {
634                         *cp++ = '\\';
635                         *cp++ = (c >> 6) + '';
636                         *cp++ = ((c >> 3) & 7) + '';
637                         *cp++ = (c & 7) + '';
638                 }
639         }
640         return cp0;
641 }
642 
643 /**
644  * ccs_encode - Encode binary string to ascii string.
645  *
646  * @str: String in binary format.
647  *
648  * Returns pointer to @str in ascii format on success, NULL otherwise.
649  *
650  * This function uses kzalloc(), so caller must kfree() if this function
651  * didn't return NULL.
652  */
653 char *ccs_encode(const char *str)
654 {
655         return str ? ccs_encode2(str, strlen(str)) : NULL;
656 }
657 
658 /**
659  * ccs_const_part_length - Evaluate the initial length without a pattern in a token.
660  *
661  * @filename: The string to evaluate.
662  *
663  * Returns the initial length without a pattern in @filename.
664  */
665 static int ccs_const_part_length(const char *filename)
666 {
667         char c;
668         int len = 0;
669         if (!filename)
670                 return 0;
671         while (1) {
672                 c = *filename++;
673                 if (!c)
674                         break;
675                 if (c != '\\') {
676                         len++;
677                         continue;
678                 }
679                 c = *filename++;
680                 switch (c) {
681                 case '\\':  /* "\\" */
682                         len += 2;
683                         continue;
684                 case '':   /* "\ooo" */
685                 case '1':
686                 case '2':
687                 case '3':
688                         c = *filename++;
689                         if (c < '' || c > '7')
690                                 break;
691                         c = *filename++;
692                         if (c < '' || c > '7')
693                                 break;
694                         len += 4;
695                         continue;
696                 }
697                 break;
698         }
699         return len;
700 }
701 
702 /**
703  * ccs_fill_path_info - Fill in "struct ccs_path_info" members.
704  *
705  * @ptr: Pointer to "struct ccs_path_info" to fill in.
706  *
707  * The caller sets "struct ccs_path_info"->name.
708  */
709 void ccs_fill_path_info(struct ccs_path_info *ptr)
710 {
711         const char *name = ptr->name;
712         const int len = strlen(name);
713         ptr->total_len = len;
714         ptr->const_len = ccs_const_part_length(name);
715         ptr->is_dir = len && (name[len - 1] == '/');
716         ptr->is_patterned = (ptr->const_len < len);
717         ptr->hash = full_name_hash(name, len);
718 }
719 
720 /**
721  * ccs_get_exe - Get ccs_realpath() of current process.
722  *
723  * Returns the ccs_realpath() of current process on success, NULL otherwise.
724  *
725  * This function uses kzalloc(), so the caller must kfree()
726  * if this function didn't return NULL.
727  */
728 const char *ccs_get_exe(void)
729 {
730         struct mm_struct *mm = current->mm;
731 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
732         struct vm_area_struct *vma;
733 #endif
734 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
735         struct path path;
736 #endif
737         struct file *exe_file = NULL;
738         const char *cp;
739         if (!mm)
740                 return NULL;
741         down_read(&mm->mmap_sem);
742 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
743         /* Not using get_mm_exe_file() as it is not exported. */
744         exe_file = mm->exe_file;
745 #else
746         for (vma = mm->mmap; vma; vma = vma->vm_next) {
747                 if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
748                         exe_file = vma->vm_file;
749                         break;
750                 }
751         }
752 #endif
753         if (exe_file)
754                 get_file(exe_file);
755         up_read(&mm->mmap_sem);
756         if (!exe_file)
757                 return NULL;
758 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
759         cp = ccs_realpath(&exe_file->f_path);
760 #else
761         path.mnt = exe_file->f_vfsmnt;
762         path.dentry = exe_file->f_dentry;
763         cp = ccs_realpath(&path);
764 #endif
765         fput(exe_file);
766         return cp;
767 }
768 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp