realpath.c 7.9 KB

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