realpath.c 7.9 KB

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