passthrough.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * FUSE passthrough to backing file.
  4. *
  5. * Copyright (c) 2023 CTERA Networks.
  6. */
  7. #include "fuse_i.h"
  8. #include <linux/file.h>
  9. #include <linux/backing-file.h>
  10. #include <linux/splice.h>
  11. static void fuse_file_accessed(struct file *file)
  12. {
  13. struct inode *inode = file_inode(file);
  14. fuse_invalidate_atime(inode);
  15. }
  16. static void fuse_passthrough_end_write(struct file *file, loff_t pos, ssize_t ret)
  17. {
  18. struct inode *inode = file_inode(file);
  19. fuse_write_update_attr(inode, pos, ret);
  20. }
  21. ssize_t fuse_passthrough_read_iter(struct kiocb *iocb, struct iov_iter *iter)
  22. {
  23. struct file *file = iocb->ki_filp;
  24. struct fuse_file *ff = file->private_data;
  25. struct file *backing_file = fuse_file_passthrough(ff);
  26. size_t count = iov_iter_count(iter);
  27. ssize_t ret;
  28. struct backing_file_ctx ctx = {
  29. .cred = ff->cred,
  30. .user_file = file,
  31. .accessed = fuse_file_accessed,
  32. };
  33. pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu\n", __func__,
  34. backing_file, iocb->ki_pos, count);
  35. if (!count)
  36. return 0;
  37. ret = backing_file_read_iter(backing_file, iter, iocb, iocb->ki_flags,
  38. &ctx);
  39. return ret;
  40. }
  41. ssize_t fuse_passthrough_write_iter(struct kiocb *iocb,
  42. struct iov_iter *iter)
  43. {
  44. struct file *file = iocb->ki_filp;
  45. struct inode *inode = file_inode(file);
  46. struct fuse_file *ff = file->private_data;
  47. struct file *backing_file = fuse_file_passthrough(ff);
  48. size_t count = iov_iter_count(iter);
  49. ssize_t ret;
  50. struct backing_file_ctx ctx = {
  51. .cred = ff->cred,
  52. .user_file = file,
  53. .end_write = fuse_passthrough_end_write,
  54. };
  55. pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu\n", __func__,
  56. backing_file, iocb->ki_pos, count);
  57. if (!count)
  58. return 0;
  59. inode_lock(inode);
  60. ret = backing_file_write_iter(backing_file, iter, iocb, iocb->ki_flags,
  61. &ctx);
  62. inode_unlock(inode);
  63. return ret;
  64. }
  65. ssize_t fuse_passthrough_splice_read(struct file *in, loff_t *ppos,
  66. struct pipe_inode_info *pipe,
  67. size_t len, unsigned int flags)
  68. {
  69. struct fuse_file *ff = in->private_data;
  70. struct file *backing_file = fuse_file_passthrough(ff);
  71. struct backing_file_ctx ctx = {
  72. .cred = ff->cred,
  73. .user_file = in,
  74. .accessed = fuse_file_accessed,
  75. };
  76. pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__,
  77. backing_file, ppos ? *ppos : 0, len, flags);
  78. return backing_file_splice_read(backing_file, ppos, pipe, len, flags,
  79. &ctx);
  80. }
  81. ssize_t fuse_passthrough_splice_write(struct pipe_inode_info *pipe,
  82. struct file *out, loff_t *ppos,
  83. size_t len, unsigned int flags)
  84. {
  85. struct fuse_file *ff = out->private_data;
  86. struct file *backing_file = fuse_file_passthrough(ff);
  87. struct inode *inode = file_inode(out);
  88. ssize_t ret;
  89. struct backing_file_ctx ctx = {
  90. .cred = ff->cred,
  91. .user_file = out,
  92. .end_write = fuse_passthrough_end_write,
  93. };
  94. pr_debug("%s: backing_file=0x%p, pos=%lld, len=%zu, flags=0x%x\n", __func__,
  95. backing_file, ppos ? *ppos : 0, len, flags);
  96. inode_lock(inode);
  97. ret = backing_file_splice_write(pipe, backing_file, ppos, len, flags,
  98. &ctx);
  99. inode_unlock(inode);
  100. return ret;
  101. }
  102. ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
  103. {
  104. struct fuse_file *ff = file->private_data;
  105. struct file *backing_file = fuse_file_passthrough(ff);
  106. struct backing_file_ctx ctx = {
  107. .cred = ff->cred,
  108. .user_file = file,
  109. .accessed = fuse_file_accessed,
  110. };
  111. pr_debug("%s: backing_file=0x%p, start=%lu, end=%lu\n", __func__,
  112. backing_file, vma->vm_start, vma->vm_end);
  113. return backing_file_mmap(backing_file, vma, &ctx);
  114. }
  115. struct fuse_backing *fuse_backing_get(struct fuse_backing *fb)
  116. {
  117. if (fb && refcount_inc_not_zero(&fb->count))
  118. return fb;
  119. return NULL;
  120. }
  121. static void fuse_backing_free(struct fuse_backing *fb)
  122. {
  123. pr_debug("%s: fb=0x%p\n", __func__, fb);
  124. if (fb->file)
  125. fput(fb->file);
  126. put_cred(fb->cred);
  127. kfree_rcu(fb, rcu);
  128. }
  129. void fuse_backing_put(struct fuse_backing *fb)
  130. {
  131. if (fb && refcount_dec_and_test(&fb->count))
  132. fuse_backing_free(fb);
  133. }
  134. void fuse_backing_files_init(struct fuse_conn *fc)
  135. {
  136. idr_init(&fc->backing_files_map);
  137. }
  138. static int fuse_backing_id_alloc(struct fuse_conn *fc, struct fuse_backing *fb)
  139. {
  140. int id;
  141. idr_preload(GFP_KERNEL);
  142. spin_lock(&fc->lock);
  143. /* FIXME: xarray might be space inefficient */
  144. id = idr_alloc_cyclic(&fc->backing_files_map, fb, 1, 0, GFP_ATOMIC);
  145. spin_unlock(&fc->lock);
  146. idr_preload_end();
  147. WARN_ON_ONCE(id == 0);
  148. return id;
  149. }
  150. static struct fuse_backing *fuse_backing_id_remove(struct fuse_conn *fc,
  151. int id)
  152. {
  153. struct fuse_backing *fb;
  154. spin_lock(&fc->lock);
  155. fb = idr_remove(&fc->backing_files_map, id);
  156. spin_unlock(&fc->lock);
  157. return fb;
  158. }
  159. static int fuse_backing_id_free(int id, void *p, void *data)
  160. {
  161. struct fuse_backing *fb = p;
  162. WARN_ON_ONCE(refcount_read(&fb->count) != 1);
  163. fuse_backing_free(fb);
  164. return 0;
  165. }
  166. void fuse_backing_files_free(struct fuse_conn *fc)
  167. {
  168. idr_for_each(&fc->backing_files_map, fuse_backing_id_free, NULL);
  169. idr_destroy(&fc->backing_files_map);
  170. }
  171. int fuse_backing_open(struct fuse_conn *fc, struct fuse_backing_map *map)
  172. {
  173. struct file *file;
  174. struct super_block *backing_sb;
  175. struct fuse_backing *fb = NULL;
  176. int res;
  177. pr_debug("%s: fd=%d flags=0x%x\n", __func__, map->fd, map->flags);
  178. /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */
  179. res = -EPERM;
  180. if (!fc->passthrough || !capable(CAP_SYS_ADMIN))
  181. goto out;
  182. res = -EINVAL;
  183. if (map->flags || map->padding)
  184. goto out;
  185. file = fget_raw(map->fd);
  186. res = -EBADF;
  187. if (!file)
  188. goto out;
  189. /* read/write/splice/mmap passthrough only relevant for regular files */
  190. res = d_is_dir(file->f_path.dentry) ? -EISDIR : -EINVAL;
  191. if (!d_is_reg(file->f_path.dentry))
  192. goto out_fput;
  193. backing_sb = file_inode(file)->i_sb;
  194. res = -ELOOP;
  195. if (backing_sb->s_stack_depth >= fc->max_stack_depth)
  196. goto out_fput;
  197. fb = kmalloc(sizeof(struct fuse_backing), GFP_KERNEL);
  198. res = -ENOMEM;
  199. if (!fb)
  200. goto out_fput;
  201. fb->file = file;
  202. fb->cred = prepare_creds();
  203. refcount_set(&fb->count, 1);
  204. res = fuse_backing_id_alloc(fc, fb);
  205. if (res < 0) {
  206. fuse_backing_free(fb);
  207. fb = NULL;
  208. }
  209. out:
  210. pr_debug("%s: fb=0x%p, ret=%i\n", __func__, fb, res);
  211. return res;
  212. out_fput:
  213. fput(file);
  214. goto out;
  215. }
  216. int fuse_backing_close(struct fuse_conn *fc, int backing_id)
  217. {
  218. struct fuse_backing *fb = NULL;
  219. int err;
  220. pr_debug("%s: backing_id=%d\n", __func__, backing_id);
  221. /* TODO: relax CAP_SYS_ADMIN once backing files are visible to lsof */
  222. err = -EPERM;
  223. if (!fc->passthrough || !capable(CAP_SYS_ADMIN))
  224. goto out;
  225. err = -EINVAL;
  226. if (backing_id <= 0)
  227. goto out;
  228. err = -ENOENT;
  229. fb = fuse_backing_id_remove(fc, backing_id);
  230. if (!fb)
  231. goto out;
  232. fuse_backing_put(fb);
  233. err = 0;
  234. out:
  235. pr_debug("%s: fb=0x%p, err=%i\n", __func__, fb, err);
  236. return err;
  237. }
  238. /*
  239. * Setup passthrough to a backing file.
  240. *
  241. * Returns an fb object with elevated refcount to be stored in fuse inode.
  242. */
  243. struct fuse_backing *fuse_passthrough_open(struct file *file,
  244. struct inode *inode,
  245. int backing_id)
  246. {
  247. struct fuse_file *ff = file->private_data;
  248. struct fuse_conn *fc = ff->fm->fc;
  249. struct fuse_backing *fb = NULL;
  250. struct file *backing_file;
  251. int err;
  252. err = -EINVAL;
  253. if (backing_id <= 0)
  254. goto out;
  255. rcu_read_lock();
  256. fb = idr_find(&fc->backing_files_map, backing_id);
  257. fb = fuse_backing_get(fb);
  258. rcu_read_unlock();
  259. err = -ENOENT;
  260. if (!fb)
  261. goto out;
  262. /* Allocate backing file per fuse file to store fuse path */
  263. backing_file = backing_file_open(&file->f_path, file->f_flags,
  264. &fb->file->f_path, fb->cred);
  265. err = PTR_ERR(backing_file);
  266. if (IS_ERR(backing_file)) {
  267. fuse_backing_put(fb);
  268. goto out;
  269. }
  270. err = 0;
  271. ff->passthrough = backing_file;
  272. ff->cred = get_cred(fb->cred);
  273. out:
  274. pr_debug("%s: backing_id=%d, fb=0x%p, backing_file=0x%p, err=%i\n", __func__,
  275. backing_id, fb, ff->passthrough, err);
  276. return err ? ERR_PTR(err) : fb;
  277. }
  278. void fuse_passthrough_release(struct fuse_file *ff, struct fuse_backing *fb)
  279. {
  280. pr_debug("%s: fb=0x%p, backing_file=0x%p\n", __func__,
  281. fb, ff->passthrough);
  282. fput(ff->passthrough);
  283. ff->passthrough = NULL;
  284. put_cred(ff->cred);
  285. ff->cred = NULL;
  286. }