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

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

Version: ~ [ linux-5.6-rc1 ] ~ [ linux-5.5.2 ] ~ [ linux-5.4.17 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.102 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.170 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.213 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.213 ] ~ [ 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.81 ] ~ [ 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 = d_backing_inode(path->dentry);
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 = d_backing_inode(path->dentry);
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 (d_is_dir(dentry))
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(2, 6, 38)
347         char *pos = ERR_PTR(-ENOMEM);
348         if (buflen >= 256) {
349                 /* rename_lock is locked/unlocked by dentry_path_raw(). */
350                 pos = dentry_path_raw(dentry, buffer, buflen - 1);
351                 if (!IS_ERR(pos) && *pos == '/' && pos[1] &&
352                     d_is_dir(dentry)) {
353                         buffer[buflen - 2] = '/';
354                         buffer[buflen - 1] = '\0';
355                 }
356         }
357         return pos;
358 #else
359         char *pos = buffer + buflen - 1;
360         if (buflen < 256)
361                 return ERR_PTR(-ENOMEM);
362         *pos = '\0';
363         if (d_is_dir(dentry))
364                 *--pos = '/';
365         spin_lock(&dcache_lock);
366         while (!IS_ROOT(dentry)) {
367                 struct dentry *parent = dentry->d_parent;
368                 const char *name = dentry->d_name.name;
369                 const int len = dentry->d_name.len;
370                 pos -= len;
371                 if (pos <= buffer) {
372                         pos = ERR_PTR(-ENOMEM);
373                         break;
374                 }
375                 memmove(pos, name, len);
376                 *--pos = '/';
377                 dentry = parent;
378         }
379         spin_unlock(&dcache_lock);
380         return pos;
381 #endif
382 }
383 
384 /**
385  * ccs_get_local_path - Get the path of a dentry.
386  *
387  * @dentry: Pointer to "struct dentry".
388  * @buffer: Pointer to buffer to return value in.
389  * @buflen: Sizeof @buffer.
390  *
391  * Returns the buffer on success, an error code otherwise.
392  */
393 static char *ccs_get_local_path(struct dentry *dentry, char * const buffer,
394                                 const int buflen)
395 {
396         struct super_block *sb = dentry->d_sb;
397         char *pos = ccs_get_dentry_path(dentry, buffer, buflen);
398         if (IS_ERR(pos))
399                 return pos;
400         /* Convert from $PID to self if $PID is current thread. */
401         if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
402                 char *ep;
403                 const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10);
404 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
405                 if (*ep == '/' && pid && pid ==
406                     task_tgid_nr_ns(current, sb->s_fs_info)) {
407                         pos = ep - 5;
408                         if (pos < buffer)
409                                 goto out;
410                         memmove(pos, "/self", 5);
411                 }
412 #else
413                 if (*ep == '/' && pid == ccs_sys_getpid()) {
414                         pos = ep - 5;
415                         if (pos < buffer)
416                                 goto out;
417                         memmove(pos, "/self", 5);
418                 }
419 #endif
420                 goto prepend_filesystem_name;
421         }
422         /* Use filesystem name for unnamed devices. */
423         if (!MAJOR(sb->s_dev))
424                 goto prepend_filesystem_name;
425         {
426                 struct inode *inode = d_backing_inode(sb->s_root);
427                 /*
428                  * Use filesystem name if filesystems does not support rename()
429                  * operation.
430                  */
431 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
432                 if (inode->i_op && !inode->i_op->rename)
433                         goto prepend_filesystem_name;
434 #elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
435                 if (!inode->i_op->rename && !inode->i_op->rename2)
436                         goto prepend_filesystem_name;
437 #else
438                 if (!inode->i_op->rename)
439                         goto prepend_filesystem_name;
440 #endif
441         }
442         /* Prepend device name. */
443         {
444                 char name[64];
445                 int name_len;
446                 const dev_t dev = sb->s_dev;
447                 name[sizeof(name) - 1] = '\0';
448                 snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev),
449                          MINOR(dev));
450                 name_len = strlen(name);
451                 pos -= name_len;
452                 if (pos < buffer)
453                         goto out;
454                 memmove(pos, name, name_len);
455                 return pos;
456         }
457         /* Prepend filesystem name. */
458 prepend_filesystem_name:
459         {
460                 const char *name = sb->s_type->name;
461                 const int name_len = strlen(name);
462                 pos -= name_len + 1;
463                 if (pos < buffer)
464                         goto out;
465                 memmove(pos, name, name_len);
466                 pos[name_len] = ':';
467         }
468         return pos;
469 out:
470         return ERR_PTR(-ENOMEM);
471 }
472 
473 /**
474  * ccs_get_socket_name - Get the name of a socket.
475  *
476  * @path:   Pointer to "struct path".
477  * @buffer: Pointer to buffer to return value in.
478  * @buflen: Sizeof @buffer.
479  *
480  * Returns the buffer.
481  */
482 static char *ccs_get_socket_name(const struct path *path, char * const buffer,
483                                  const int buflen)
484 {
485         struct inode *inode = d_backing_inode(path->dentry);
486         struct socket *sock = inode ? SOCKET_I(inode) : NULL;
487         struct sock *sk = sock ? sock->sk : NULL;
488         if (sk) {
489                 snprintf(buffer, buflen, "socket:[family=%u:type=%u:"
490                          "protocol=%u]", sk->sk_family, sk->sk_type,
491                          sk->sk_protocol);
492         } else {
493                 snprintf(buffer, buflen, "socket:[unknown]");
494         }
495         return buffer;
496 }
497 
498 #define SOCKFS_MAGIC 0x534F434B
499 
500 /**
501  * ccs_realpath - Returns realpath(3) of the given pathname but ignores chroot'ed root.
502  *
503  * @path: Pointer to "struct path".
504  *
505  * Returns the realpath of the given @path on success, NULL otherwise.
506  *
507  * This function uses kzalloc(), so caller must kfree() if this function
508  * didn't return NULL.
509  */
510 char *ccs_realpath(const struct path *path)
511 {
512         char *buf = NULL;
513         char *name = NULL;
514         unsigned int buf_len = PAGE_SIZE / 2;
515         struct dentry *dentry = path->dentry;
516         struct super_block *sb;
517         if (!dentry)
518                 return NULL;
519         sb = dentry->d_sb;
520         while (1) {
521                 char *pos;
522                 struct inode *inode;
523                 buf_len <<= 1;
524                 kfree(buf);
525                 buf = kmalloc(buf_len, CCS_GFP_FLAGS);
526                 if (!buf)
527                         break;
528                 /* To make sure that pos is '\0' terminated. */
529                 buf[buf_len - 1] = '\0';
530                 /* Get better name for socket. */
531                 if (sb->s_magic == SOCKFS_MAGIC) {
532                         pos = ccs_get_socket_name(path, buf, buf_len - 1);
533                         goto encode;
534                 }
535 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
536                 /* For "pipe:[\$]". */
537                 if (dentry->d_op && dentry->d_op->d_dname) {
538                         pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
539                         goto encode;
540                 }
541 #endif
542                 inode = d_backing_inode(sb->s_root);
543                 /*
544                  * Use local name for "filesystems without rename() operation"
545                  * or "path without vfsmount" or "absolute name is unavailable"
546                  * cases.
547                  */
548 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
549                 if (!path->mnt || (inode->i_op && !inode->i_op->rename))
550                         pos = ERR_PTR(-EINVAL);
551                 else {
552                         /* Get absolute name for the rest. */
553                         ccs_realpath_lock();
554                         pos = ccs_get_absolute_path(path, buf, buf_len - 1);
555                         ccs_realpath_unlock();
556                 }
557                 if (pos == ERR_PTR(-EINVAL))
558                         pos = ccs_get_local_path(path->dentry, buf,
559                                                  buf_len - 1);
560 #elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
561                 if (!path->mnt ||
562                     (!inode->i_op->rename && !inode->i_op->rename2))
563                         pos = ccs_get_local_path(path->dentry, buf,
564                                                  buf_len - 1);
565                 else
566                         pos = ccs_get_absolute_path(path, buf, buf_len - 1);
567 #else
568                 if (!path->mnt || !inode->i_op->rename)
569                         pos = ccs_get_local_path(path->dentry, buf,
570                                                  buf_len - 1);
571                 else
572                         pos = ccs_get_absolute_path(path, buf, buf_len - 1);
573 #endif
574 encode:
575                 if (IS_ERR(pos))
576                         continue;
577                 name = ccs_encode(pos);
578                 break;
579         }
580         kfree(buf);
581         if (!name)
582                 ccs_warn_oom(__func__);
583         return name;
584 }
585 
586 /**
587  * ccs_encode2 - Encode binary string to ascii string.
588  *
589  * @str:     String in binary format.
590  * @str_len: Size of @str in byte.
591  *
592  * Returns pointer to @str in ascii format on success, NULL otherwise.
593  *
594  * This function uses kzalloc(), so caller must kfree() if this function
595  * didn't return NULL.
596  */
597 char *ccs_encode2(const char *str, int str_len)
598 {
599         int i;
600         int len = 0;
601         const char *p = str;
602         char *cp;
603         char *cp0;
604         if (!p)
605                 return NULL;
606         for (i = 0; i < str_len; i++) {
607                 const unsigned char c = p[i];
608                 if (c == '\\')
609                         len += 2;
610                 else if (c > ' ' && c < 127)
611                         len++;
612                 else
613                         len += 4;
614         }
615         len++;
616         /* Reserve space for appending "/". */
617         cp = kzalloc(len + 10, CCS_GFP_FLAGS);
618         if (!cp)
619                 return NULL;
620         cp0 = cp;
621         p = str;
622         for (i = 0; i < str_len; i++) {
623                 const unsigned char c = p[i];
624                 if (c == '\\') {
625                         *cp++ = '\\';
626                         *cp++ = '\\';
627                 } else if (c > ' ' && c < 127) {
628                         *cp++ = c;
629                 } else {
630                         *cp++ = '\\';
631                         *cp++ = (c >> 6) + '';
632                         *cp++ = ((c >> 3) & 7) + '';
633                         *cp++ = (c & 7) + '';
634                 }
635         }
636         return cp0;
637 }
638 
639 /**
640  * ccs_encode - Encode binary string to ascii string.
641  *
642  * @str: String in binary format.
643  *
644  * Returns pointer to @str in ascii format on success, NULL otherwise.
645  *
646  * This function uses kzalloc(), so caller must kfree() if this function
647  * didn't return NULL.
648  */
649 char *ccs_encode(const char *str)
650 {
651         return str ? ccs_encode2(str, strlen(str)) : NULL;
652 }
653 
654 /**
655  * ccs_const_part_length - Evaluate the initial length without a pattern in a token.
656  *
657  * @filename: The string to evaluate.
658  *
659  * Returns the initial length without a pattern in @filename.
660  */
661 static int ccs_const_part_length(const char *filename)
662 {
663         char c;
664         int len = 0;
665         if (!filename)
666                 return 0;
667         while (1) {
668                 c = *filename++;
669                 if (!c)
670                         break;
671                 if (c != '\\') {
672                         len++;
673                         continue;
674                 }
675                 c = *filename++;
676                 switch (c) {
677                 case '\\':  /* "\\" */
678                         len += 2;
679                         continue;
680                 case '':   /* "\ooo" */
681                 case '1':
682                 case '2':
683                 case '3':
684                         c = *filename++;
685                         if (c < '' || c > '7')
686                                 break;
687                         c = *filename++;
688                         if (c < '' || c > '7')
689                                 break;
690                         len += 4;
691                         continue;
692                 }
693                 break;
694         }
695         return len;
696 }
697 
698 /**
699  * ccs_fill_path_info - Fill in "struct ccs_path_info" members.
700  *
701  * @ptr: Pointer to "struct ccs_path_info" to fill in.
702  *
703  * The caller sets "struct ccs_path_info"->name.
704  */
705 void ccs_fill_path_info(struct ccs_path_info *ptr)
706 {
707         const char *name = ptr->name;
708         const int len = strlen(name);
709         ptr->total_len = len;
710         ptr->const_len = ccs_const_part_length(name);
711         ptr->is_dir = len && (name[len - 1] == '/');
712         ptr->is_patterned = (ptr->const_len < len);
713 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
714         ptr->hash = full_name_hash(NULL, name, len);
715 #else
716         ptr->hash = full_name_hash(name, len);
717 #endif
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