1 // SPDX-License-Identifier: GPL-2.0
2
3 #include "fuse_i.h"
4
5 #include <linux/file.h>
6 #include <linux/fuse.h>
7 #include <linux/idr.h>
8 #include <linux/uio.h>
9
10 #define PASSTHROUGH_IOCB_MASK \
11 (IOCB_APPEND | IOCB_DSYNC | IOCB_HIPRI | IOCB_NOWAIT | IOCB_SYNC)
12
13 struct fuse_aio_req {
14 struct kiocb iocb;
15 struct kiocb *iocb_fuse;
16 };
17
fuse_file_accessed(struct file * dst_file,struct file * src_file)18 static void fuse_file_accessed(struct file *dst_file, struct file *src_file)
19 {
20 struct inode *dst_inode;
21 struct inode *src_inode;
22
23 if (dst_file->f_flags & O_NOATIME)
24 return;
25
26 dst_inode = file_inode(dst_file);
27 src_inode = file_inode(src_file);
28
29 if ((!timespec64_equal(&dst_inode->i_mtime, &src_inode->i_mtime) ||
30 !timespec64_equal(&dst_inode->i_ctime, &src_inode->i_ctime))) {
31 dst_inode->i_mtime = src_inode->i_mtime;
32 dst_inode->i_ctime = src_inode->i_ctime;
33 }
34
35 touch_atime(&dst_file->f_path);
36 }
37
fuse_copyattr(struct file * dst_file,struct file * src_file)38 void fuse_copyattr(struct file *dst_file, struct file *src_file)
39 {
40 struct inode *dst = file_inode(dst_file);
41 struct inode *src = file_inode(src_file);
42
43 dst->i_atime = src->i_atime;
44 dst->i_mtime = src->i_mtime;
45 dst->i_ctime = src->i_ctime;
46 i_size_write(dst, i_size_read(src));
47 }
48
fuse_aio_cleanup_handler(struct fuse_aio_req * aio_req)49 static void fuse_aio_cleanup_handler(struct fuse_aio_req *aio_req)
50 {
51 struct kiocb *iocb = &aio_req->iocb;
52 struct kiocb *iocb_fuse = aio_req->iocb_fuse;
53
54 if (iocb->ki_flags & IOCB_WRITE) {
55 __sb_writers_acquired(file_inode(iocb->ki_filp)->i_sb,
56 SB_FREEZE_WRITE);
57 file_end_write(iocb->ki_filp);
58 fuse_copyattr(iocb_fuse->ki_filp, iocb->ki_filp);
59 }
60
61 iocb_fuse->ki_pos = iocb->ki_pos;
62 kfree(aio_req);
63 }
64
fuse_aio_rw_complete(struct kiocb * iocb,long res)65 static void fuse_aio_rw_complete(struct kiocb *iocb, long res)
66 {
67 struct fuse_aio_req *aio_req =
68 container_of(iocb, struct fuse_aio_req, iocb);
69 struct kiocb *iocb_fuse = aio_req->iocb_fuse;
70
71 fuse_aio_cleanup_handler(aio_req);
72 iocb_fuse->ki_complete(iocb_fuse, res);
73 }
74
fuse_passthrough_read_iter(struct kiocb * iocb_fuse,struct iov_iter * iter)75 ssize_t fuse_passthrough_read_iter(struct kiocb *iocb_fuse,
76 struct iov_iter *iter)
77 {
78 ssize_t ret;
79 const struct cred *old_cred;
80 struct file *fuse_filp = iocb_fuse->ki_filp;
81 struct fuse_file *ff = fuse_filp->private_data;
82 struct file *passthrough_filp = ff->passthrough.filp;
83
84 if (!iov_iter_count(iter))
85 return 0;
86
87 old_cred = override_creds(ff->passthrough.cred);
88 if (is_sync_kiocb(iocb_fuse)) {
89 ret = vfs_iter_read(passthrough_filp, iter, &iocb_fuse->ki_pos,
90 iocb_to_rw_flags(iocb_fuse->ki_flags,
91 PASSTHROUGH_IOCB_MASK));
92 } else {
93 struct fuse_aio_req *aio_req;
94
95 aio_req = kmalloc(sizeof(struct fuse_aio_req), GFP_KERNEL);
96 if (!aio_req) {
97 ret = -ENOMEM;
98 goto out;
99 }
100
101 aio_req->iocb_fuse = iocb_fuse;
102 kiocb_clone(&aio_req->iocb, iocb_fuse, passthrough_filp);
103 aio_req->iocb.ki_complete = fuse_aio_rw_complete;
104 ret = call_read_iter(passthrough_filp, &aio_req->iocb, iter);
105 if (ret != -EIOCBQUEUED)
106 fuse_aio_cleanup_handler(aio_req);
107 }
108 out:
109 revert_creds(old_cred);
110
111 fuse_file_accessed(fuse_filp, passthrough_filp);
112
113 return ret;
114 }
115
fuse_passthrough_write_iter(struct kiocb * iocb_fuse,struct iov_iter * iter)116 ssize_t fuse_passthrough_write_iter(struct kiocb *iocb_fuse,
117 struct iov_iter *iter)
118 {
119 ssize_t ret;
120 const struct cred *old_cred;
121 struct file *fuse_filp = iocb_fuse->ki_filp;
122 struct fuse_file *ff = fuse_filp->private_data;
123 struct inode *fuse_inode = file_inode(fuse_filp);
124 struct file *passthrough_filp = ff->passthrough.filp;
125 struct inode *passthrough_inode = file_inode(passthrough_filp);
126
127 if (!iov_iter_count(iter))
128 return 0;
129
130 inode_lock(fuse_inode);
131
132 fuse_copyattr(fuse_filp, passthrough_filp);
133
134 old_cred = override_creds(ff->passthrough.cred);
135 if (is_sync_kiocb(iocb_fuse)) {
136 file_start_write(passthrough_filp);
137 ret = vfs_iter_write(passthrough_filp, iter, &iocb_fuse->ki_pos,
138 iocb_to_rw_flags(iocb_fuse->ki_flags,
139 PASSTHROUGH_IOCB_MASK));
140 file_end_write(passthrough_filp);
141 if (ret > 0)
142 fuse_copyattr(fuse_filp, passthrough_filp);
143 } else {
144 struct fuse_aio_req *aio_req;
145
146 aio_req = kmalloc(sizeof(struct fuse_aio_req), GFP_KERNEL);
147 if (!aio_req) {
148 ret = -ENOMEM;
149 goto out;
150 }
151
152 file_start_write(passthrough_filp);
153 __sb_writers_release(passthrough_inode->i_sb, SB_FREEZE_WRITE);
154
155 aio_req->iocb_fuse = iocb_fuse;
156 kiocb_clone(&aio_req->iocb, iocb_fuse, passthrough_filp);
157 aio_req->iocb.ki_complete = fuse_aio_rw_complete;
158 ret = call_write_iter(passthrough_filp, &aio_req->iocb, iter);
159 if (ret != -EIOCBQUEUED)
160 fuse_aio_cleanup_handler(aio_req);
161 }
162 out:
163 revert_creds(old_cred);
164 inode_unlock(fuse_inode);
165
166 return ret;
167 }
168
fuse_passthrough_mmap(struct file * file,struct vm_area_struct * vma)169 ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
170 {
171 int ret;
172 const struct cred *old_cred;
173 struct fuse_file *ff = file->private_data;
174 struct file *passthrough_filp = ff->passthrough.filp;
175
176 if (!passthrough_filp->f_op->mmap)
177 return -ENODEV;
178
179 if (WARN_ON(file != vma->vm_file))
180 return -EIO;
181
182 vma->vm_file = get_file(passthrough_filp);
183
184 old_cred = override_creds(ff->passthrough.cred);
185 ret = call_mmap(vma->vm_file, vma);
186 revert_creds(old_cred);
187
188 if (ret)
189 fput(passthrough_filp);
190 else
191 fput(file);
192
193 fuse_file_accessed(file, passthrough_filp);
194
195 return ret;
196 }
197
fuse_passthrough_open(struct fuse_dev * fud,u32 lower_fd)198 int fuse_passthrough_open(struct fuse_dev *fud, u32 lower_fd)
199 {
200 int res;
201 struct file *passthrough_filp;
202 struct fuse_conn *fc = fud->fc;
203 struct inode *passthrough_inode;
204 struct super_block *passthrough_sb;
205 struct fuse_passthrough *passthrough;
206
207 if (!fc->passthrough)
208 return -EPERM;
209
210 passthrough_filp = fget(lower_fd);
211 if (!passthrough_filp) {
212 pr_err("FUSE: invalid file descriptor for passthrough.\n");
213 return -EBADF;
214 }
215
216 if (!passthrough_filp->f_op->read_iter ||
217 !((passthrough_filp->f_path.mnt->mnt_flags | MNT_READONLY) ||
218 passthrough_filp->f_op->write_iter)) {
219 pr_err("FUSE: passthrough file misses file operations.\n");
220 res = -EBADF;
221 goto err_free_file;
222 }
223
224 passthrough_inode = file_inode(passthrough_filp);
225 passthrough_sb = passthrough_inode->i_sb;
226 if (passthrough_sb->s_stack_depth >= FILESYSTEM_MAX_STACK_DEPTH) {
227 pr_err("FUSE: fs stacking depth exceeded for passthrough\n");
228 res = -EINVAL;
229 goto err_free_file;
230 }
231
232 passthrough = kmalloc(sizeof(struct fuse_passthrough), GFP_KERNEL);
233 if (!passthrough) {
234 res = -ENOMEM;
235 goto err_free_file;
236 }
237
238 passthrough->filp = passthrough_filp;
239 passthrough->cred = prepare_creds();
240
241 idr_preload(GFP_KERNEL);
242 spin_lock(&fc->passthrough_req_lock);
243 res = idr_alloc(&fc->passthrough_req, passthrough, 1, 0, GFP_ATOMIC);
244 spin_unlock(&fc->passthrough_req_lock);
245 idr_preload_end();
246
247 if (res > 0)
248 return res;
249
250 fuse_passthrough_release(passthrough);
251 kfree(passthrough);
252
253 err_free_file:
254 fput(passthrough_filp);
255
256 return res;
257 }
258
fuse_passthrough_setup(struct fuse_conn * fc,struct fuse_file * ff,struct fuse_open_out * openarg)259 int fuse_passthrough_setup(struct fuse_conn *fc, struct fuse_file *ff,
260 struct fuse_open_out *openarg)
261 {
262 struct fuse_passthrough *passthrough;
263 int passthrough_fh = openarg->passthrough_fh;
264
265 if (!fc->passthrough)
266 return -EPERM;
267
268 /* Default case, passthrough is not requested */
269 if (passthrough_fh <= 0)
270 return -EINVAL;
271
272 spin_lock(&fc->passthrough_req_lock);
273 passthrough = idr_remove(&fc->passthrough_req, passthrough_fh);
274 spin_unlock(&fc->passthrough_req_lock);
275
276 if (!passthrough)
277 return -EINVAL;
278
279 ff->passthrough = *passthrough;
280 kfree(passthrough);
281
282 return 0;
283 }
284
fuse_passthrough_release(struct fuse_passthrough * passthrough)285 void fuse_passthrough_release(struct fuse_passthrough *passthrough)
286 {
287 if (passthrough->filp) {
288 fput(passthrough->filp);
289 passthrough->filp = NULL;
290 }
291 if (passthrough->cred) {
292 put_cred(passthrough->cred);
293 passthrough->cred = NULL;
294 }
295 }
296