realpath.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * security/tomoyo/realpath.c
  3. *
  4. * Pathname calculation functions for TOMOYO.
  5. *
  6. * Copyright (C) 2005-2010 NTT DATA CORPORATION
  7. */
  8. #include <linux/types.h>
  9. #include <linux/mount.h>
  10. #include <linux/mnt_namespace.h>
  11. #include <linux/fs_struct.h>
  12. #include <linux/magic.h>
  13. #include <linux/slab.h>
  14. #include <net/sock.h>
  15. #include "common.h"
  16. #include "../../fs/internal.h"
  17. /**
  18. * tomoyo_encode: Convert binary string to ascii string.
  19. *
  20. * @str: String in binary format.
  21. *
  22. * Returns pointer to @str in ascii format on success, NULL otherwise.
  23. *
  24. * This function uses kzalloc(), so caller must kfree() if this function
  25. * didn't return NULL.
  26. */
  27. char *tomoyo_encode(const char *str)
  28. {
  29. int len = 0;
  30. const char *p = str;
  31. char *cp;
  32. char *cp0;
  33. if (!p)
  34. return NULL;
  35. while (*p) {
  36. const unsigned char c = *p++;
  37. if (c == '\\')
  38. len += 2;
  39. else if (c > ' ' && c < 127)
  40. len++;
  41. else
  42. len += 4;
  43. }
  44. len++;
  45. /* Reserve space for appending "/". */
  46. cp = kzalloc(len + 10, GFP_NOFS);
  47. if (!cp)
  48. return NULL;
  49. cp0 = cp;
  50. p = str;
  51. while (*p) {
  52. const unsigned char c = *p++;
  53. if (c == '\\') {
  54. *cp++ = '\\';
  55. *cp++ = '\\';
  56. } else if (c > ' ' && c < 127) {
  57. *cp++ = c;
  58. } else {
  59. *cp++ = '\\';
  60. *cp++ = (c >> 6) + '0';
  61. *cp++ = ((c >> 3) & 7) + '0';
  62. *cp++ = (c & 7) + '0';
  63. }
  64. }
  65. return cp0;
  66. }
  67. /**
  68. * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
  69. *
  70. * @path: Pointer to "struct path".
  71. *
  72. * Returns the realpath of the given @path on success, NULL otherwise.
  73. *
  74. * If dentry is a directory, trailing '/' is appended.
  75. * Characters out of 0x20 < c < 0x7F range are converted to
  76. * \ooo style octal string.
  77. * Character \ is converted to \\ string.
  78. *
  79. * These functions use kzalloc(), so the caller must call kfree()
  80. * if these functions didn't return NULL.
  81. */
  82. char *tomoyo_realpath_from_path(struct path *path)
  83. {
  84. char *buf = NULL;
  85. char *name = NULL;
  86. unsigned int buf_len = PAGE_SIZE / 2;
  87. struct dentry *dentry = path->dentry;
  88. bool is_dir;
  89. if (!dentry)
  90. return NULL;
  91. is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode);
  92. while (1) {
  93. struct path ns_root = { .mnt = NULL, .dentry = NULL };
  94. char *pos;
  95. buf_len <<= 1;
  96. kfree(buf);
  97. buf = kmalloc(buf_len, GFP_NOFS);
  98. if (!buf)
  99. break;
  100. /* Get better name for socket. */
  101. if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
  102. struct inode *inode = dentry->d_inode;
  103. struct socket *sock = inode ? SOCKET_I(inode) : NULL;
  104. struct sock *sk = sock ? sock->sk : NULL;
  105. if (sk) {
  106. snprintf(buf, buf_len - 1, "socket:[family=%u:"
  107. "type=%u:protocol=%u]", sk->sk_family,
  108. sk->sk_type, sk->sk_protocol);
  109. } else {
  110. snprintf(buf, buf_len - 1, "socket:[unknown]");
  111. }
  112. name = tomoyo_encode(buf);
  113. break;
  114. }
  115. /* For "socket:[\$]" and "pipe:[\$]". */
  116. if (dentry->d_op && dentry->d_op->d_dname) {
  117. pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
  118. if (IS_ERR(pos))
  119. continue;
  120. name = tomoyo_encode(pos);
  121. break;
  122. }
  123. /* If we don't have a vfsmount, we can't calculate. */
  124. if (!path->mnt)
  125. break;
  126. /* go to whatever namespace root we are under */
  127. pos = __d_path(path, &ns_root, buf, buf_len);
  128. /* Prepend "/proc" prefix if using internal proc vfs mount. */
  129. if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
  130. (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
  131. pos -= 5;
  132. if (pos >= buf)
  133. memcpy(pos, "/proc", 5);
  134. else
  135. pos = ERR_PTR(-ENOMEM);
  136. }
  137. if (IS_ERR(pos))
  138. continue;
  139. name = tomoyo_encode(pos);
  140. break;
  141. }
  142. kfree(buf);
  143. if (!name)
  144. tomoyo_warn_oom(__func__);
  145. else if (is_dir && *name) {
  146. /* Append trailing '/' if dentry is a directory. */
  147. char *pos = name + strlen(name) - 1;
  148. if (*pos != '/')
  149. /*
  150. * This is OK because tomoyo_encode() reserves space
  151. * for appending "/".
  152. */
  153. *++pos = '/';
  154. }
  155. return name;
  156. }
  157. /**
  158. * tomoyo_realpath_nofollow - Get realpath of a pathname.
  159. *
  160. * @pathname: The pathname to solve.
  161. *
  162. * Returns the realpath of @pathname on success, NULL otherwise.
  163. */
  164. char *tomoyo_realpath_nofollow(const char *pathname)
  165. {
  166. struct path path;
  167. if (pathname && kern_path(pathname, 0, &path) == 0) {
  168. char *buf = tomoyo_realpath_from_path(&path);
  169. path_put(&path);
  170. return buf;
  171. }
  172. return NULL;
  173. }