realpath.c 4.2 KB

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