realpath.c 7.2 KB

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