realpath.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * security/tomoyo/realpath.c
  3. *
  4. * Copyright (C) 2005-2011 NTT DATA CORPORATION
  5. */
  6. #include <linux/types.h>
  7. #include <linux/mount.h>
  8. #include <linux/mnt_namespace.h>
  9. #include <linux/fs_struct.h>
  10. #include <linux/magic.h>
  11. #include <linux/slab.h>
  12. #include <net/sock.h>
  13. #include "common.h"
  14. #include "../../fs/internal.h"
  15. /**
  16. * tomoyo_encode2 - Encode binary string to ascii string.
  17. *
  18. * @str: String in binary format.
  19. * @str_len: Size of @str in byte.
  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_encode2(const char *str, int str_len)
  27. {
  28. int i;
  29. int len = 0;
  30. const char *p = str;
  31. char *cp;
  32. char *cp0;
  33. if (!p)
  34. return NULL;
  35. for (i = 0; i < str_len; i++) {
  36. const unsigned char c = p[i];
  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. for (i = 0; i < str_len; i++) {
  52. const unsigned char c = p[i];
  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_encode - Encode binary string to ascii string.
  69. *
  70. * @str: String in binary format.
  71. *
  72. * Returns pointer to @str in ascii format on success, NULL otherwise.
  73. *
  74. * This function uses kzalloc(), so caller must kfree() if this function
  75. * didn't return NULL.
  76. */
  77. char *tomoyo_encode(const char *str)
  78. {
  79. return str ? tomoyo_encode2(str, strlen(str)) : NULL;
  80. }
  81. /**
  82. * tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
  83. *
  84. * @path: Pointer to "struct path".
  85. * @buffer: Pointer to buffer to return value in.
  86. * @buflen: Sizeof @buffer.
  87. *
  88. * Returns the buffer on success, an error code otherwise.
  89. *
  90. * If dentry is a directory, trailing '/' is appended.
  91. */
  92. static char *tomoyo_get_absolute_path(struct path *path, char * const buffer,
  93. const int buflen)
  94. {
  95. char *pos = ERR_PTR(-ENOMEM);
  96. if (buflen >= 256) {
  97. struct path ns_root = { };
  98. /* go to whatever namespace root we are under */
  99. pos = __d_path(path, &ns_root, buffer, buflen - 1);
  100. if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
  101. struct inode *inode = path->dentry->d_inode;
  102. if (inode && S_ISDIR(inode->i_mode)) {
  103. buffer[buflen - 2] = '/';
  104. buffer[buflen - 1] = '\0';
  105. }
  106. }
  107. }
  108. return pos;
  109. }
  110. /**
  111. * tomoyo_get_dentry_path - Get the path of a dentry.
  112. *
  113. * @dentry: Pointer to "struct dentry".
  114. * @buffer: Pointer to buffer to return value in.
  115. * @buflen: Sizeof @buffer.
  116. *
  117. * Returns the buffer on success, an error code otherwise.
  118. *
  119. * If dentry is a directory, trailing '/' is appended.
  120. */
  121. static char *tomoyo_get_dentry_path(struct dentry *dentry, char * const buffer,
  122. const int buflen)
  123. {
  124. char *pos = ERR_PTR(-ENOMEM);
  125. if (buflen >= 256) {
  126. pos = dentry_path_raw(dentry, buffer, buflen - 1);
  127. if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
  128. struct inode *inode = dentry->d_inode;
  129. if (inode && S_ISDIR(inode->i_mode)) {
  130. buffer[buflen - 2] = '/';
  131. buffer[buflen - 1] = '\0';
  132. }
  133. }
  134. }
  135. return pos;
  136. }
  137. /**
  138. * tomoyo_get_local_path - Get the path of a dentry.
  139. *
  140. * @dentry: Pointer to "struct dentry".
  141. * @buffer: Pointer to buffer to return value in.
  142. * @buflen: Sizeof @buffer.
  143. *
  144. * Returns the buffer on success, an error code otherwise.
  145. */
  146. static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer,
  147. const int buflen)
  148. {
  149. struct super_block *sb = dentry->d_sb;
  150. char *pos = tomoyo_get_dentry_path(dentry, buffer, buflen);
  151. if (IS_ERR(pos))
  152. return pos;
  153. /* Convert from $PID to self if $PID is current thread. */
  154. if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
  155. char *ep;
  156. const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10);
  157. if (*ep == '/' && pid && pid ==
  158. task_tgid_nr_ns(current, sb->s_fs_info)) {
  159. pos = ep - 5;
  160. if (pos < buffer)
  161. goto out;
  162. memmove(pos, "/self", 5);
  163. }
  164. goto prepend_filesystem_name;
  165. }
  166. /* Use filesystem name for unnamed devices. */
  167. if (!MAJOR(sb->s_dev))
  168. goto prepend_filesystem_name;
  169. {
  170. struct inode *inode = sb->s_root->d_inode;
  171. /*
  172. * Use filesystem name if filesystem does not support rename()
  173. * operation.
  174. */
  175. if (inode->i_op && !inode->i_op->rename)
  176. goto prepend_filesystem_name;
  177. }
  178. /* Prepend device name. */
  179. {
  180. char name[64];
  181. int name_len;
  182. const dev_t dev = sb->s_dev;
  183. name[sizeof(name) - 1] = '\0';
  184. snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev),
  185. MINOR(dev));
  186. name_len = strlen(name);
  187. pos -= name_len;
  188. if (pos < buffer)
  189. goto out;
  190. memmove(pos, name, name_len);
  191. return pos;
  192. }
  193. /* Prepend filesystem name. */
  194. prepend_filesystem_name:
  195. {
  196. const char *name = sb->s_type->name;
  197. const int name_len = strlen(name);
  198. pos -= name_len + 1;
  199. if (pos < buffer)
  200. goto out;
  201. memmove(pos, name, name_len);
  202. pos[name_len] = ':';
  203. }
  204. return pos;
  205. out:
  206. return ERR_PTR(-ENOMEM);
  207. }
  208. /**
  209. * tomoyo_get_socket_name - Get the name of a socket.
  210. *
  211. * @path: Pointer to "struct path".
  212. * @buffer: Pointer to buffer to return value in.
  213. * @buflen: Sizeof @buffer.
  214. *
  215. * Returns the buffer.
  216. */
  217. static char *tomoyo_get_socket_name(struct path *path, char * const buffer,
  218. const int buflen)
  219. {
  220. struct inode *inode = path->dentry->d_inode;
  221. struct socket *sock = inode ? SOCKET_I(inode) : NULL;
  222. struct sock *sk = sock ? sock->sk : NULL;
  223. if (sk) {
  224. snprintf(buffer, buflen, "socket:[family=%u:type=%u:"
  225. "protocol=%u]", sk->sk_family, sk->sk_type,
  226. sk->sk_protocol);
  227. } else {
  228. snprintf(buffer, buflen, "socket:[unknown]");
  229. }
  230. return buffer;
  231. }
  232. /**
  233. * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
  234. *
  235. * @path: Pointer to "struct path".
  236. *
  237. * Returns the realpath of the given @path on success, NULL otherwise.
  238. *
  239. * If dentry is a directory, trailing '/' is appended.
  240. * Characters out of 0x20 < c < 0x7F range are converted to
  241. * \ooo style octal string.
  242. * Character \ is converted to \\ string.
  243. *
  244. * These functions use kzalloc(), so the caller must call kfree()
  245. * if these functions didn't return NULL.
  246. */
  247. char *tomoyo_realpath_from_path(struct path *path)
  248. {
  249. char *buf = NULL;
  250. char *name = NULL;
  251. unsigned int buf_len = PAGE_SIZE / 2;
  252. struct dentry *dentry = path->dentry;
  253. struct super_block *sb;
  254. if (!dentry)
  255. return NULL;
  256. sb = dentry->d_sb;
  257. while (1) {
  258. char *pos;
  259. struct inode *inode;
  260. buf_len <<= 1;
  261. kfree(buf);
  262. buf = kmalloc(buf_len, GFP_NOFS);
  263. if (!buf)
  264. break;
  265. /* To make sure that pos is '\0' terminated. */
  266. buf[buf_len - 1] = '\0';
  267. /* Get better name for socket. */
  268. if (sb->s_magic == SOCKFS_MAGIC) {
  269. pos = tomoyo_get_socket_name(path, buf, buf_len - 1);
  270. goto encode;
  271. }
  272. /* For "pipe:[\$]". */
  273. if (dentry->d_op && dentry->d_op->d_dname) {
  274. pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
  275. goto encode;
  276. }
  277. inode = sb->s_root->d_inode;
  278. /*
  279. * Get local name for filesystems without rename() operation
  280. * or dentry without vfsmount.
  281. */
  282. if (!path->mnt || (inode->i_op && !inode->i_op->rename))
  283. pos = tomoyo_get_local_path(path->dentry, buf,
  284. buf_len - 1);
  285. /* Get absolute name for the rest. */
  286. else
  287. pos = tomoyo_get_absolute_path(path, buf, buf_len - 1);
  288. encode:
  289. if (IS_ERR(pos))
  290. continue;
  291. name = tomoyo_encode(pos);
  292. break;
  293. }
  294. kfree(buf);
  295. if (!name)
  296. tomoyo_warn_oom(__func__);
  297. return name;
  298. }
  299. /**
  300. * tomoyo_realpath_nofollow - Get realpath of a pathname.
  301. *
  302. * @pathname: The pathname to solve.
  303. *
  304. * Returns the realpath of @pathname on success, NULL otherwise.
  305. */
  306. char *tomoyo_realpath_nofollow(const char *pathname)
  307. {
  308. struct path path;
  309. if (pathname && kern_path(pathname, 0, &path) == 0) {
  310. char *buf = tomoyo_realpath_from_path(&path);
  311. path_put(&path);
  312. return buf;
  313. }
  314. return NULL;
  315. }