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

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

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

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

kernel.org | git.kernel.org | LWN.net | Project Home | 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.

sflogo.php