blob: 7d2f01957e40790c60419a54e1f61b075b1ee012 [file] [log] [blame]
Miklos Szeredid1d04ef2018-07-18 15:44:41 +02001/*
2 * Copyright (C) 2017 Red Hat, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 as published by
6 * the Free Software Foundation.
7 */
8
9#include <linux/cred.h>
10#include <linux/file.h>
Miklos Szeredidab5ca82018-07-18 15:44:42 +020011#include <linux/mount.h>
Miklos Szeredid1d04ef2018-07-18 15:44:41 +020012#include <linux/xattr.h>
Miklos Szeredi16914e62018-07-18 15:44:41 +020013#include <linux/uio.h>
Miklos Szeredid1d04ef2018-07-18 15:44:41 +020014#include "overlayfs.h"
15
Vivek Goyal8c444d22018-05-11 11:49:31 -040016static char ovl_whatisit(struct inode *inode, struct inode *realinode)
17{
18 if (realinode != ovl_inode_upper(inode))
19 return 'l';
20 if (ovl_has_upperdata(inode))
21 return 'u';
22 else
23 return 'm';
24}
25
26static struct file *ovl_open_realfile(const struct file *file,
27 struct inode *realinode)
Miklos Szeredid1d04ef2018-07-18 15:44:41 +020028{
29 struct inode *inode = file_inode(file);
Miklos Szeredid1d04ef2018-07-18 15:44:41 +020030 struct file *realfile;
31 const struct cred *old_cred;
Amir Goldsteind9899032019-04-24 19:39:50 +030032 int flags = file->f_flags | O_NOATIME | FMODE_NONOTIFY;
Miklos Szeredid1d04ef2018-07-18 15:44:41 +020033
34 old_cred = ovl_override_creds(inode->i_sb);
Amir Goldsteind9899032019-04-24 19:39:50 +030035 realfile = open_with_fake_path(&file->f_path, flags, realinode,
36 current_cred());
Miklos Szeredid1d04ef2018-07-18 15:44:41 +020037 revert_creds(old_cred);
38
39 pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n",
Vivek Goyal8c444d22018-05-11 11:49:31 -040040 file, file, ovl_whatisit(inode, realinode), file->f_flags,
Miklos Szeredid1d04ef2018-07-18 15:44:41 +020041 realfile, IS_ERR(realfile) ? 0 : realfile->f_flags);
42
43 return realfile;
44}
45
Miklos Szeredi2ef66b82018-07-18 15:44:41 +020046#define OVL_SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT)
47
48static int ovl_change_flags(struct file *file, unsigned int flags)
49{
50 struct inode *inode = file_inode(file);
51 int err;
52
53 /* No atime modificaton on underlying */
Amir Goldsteind9899032019-04-24 19:39:50 +030054 flags |= O_NOATIME | FMODE_NONOTIFY;
Miklos Szeredi2ef66b82018-07-18 15:44:41 +020055
56 /* If some flag changed that cannot be changed then something's amiss */
57 if (WARN_ON((file->f_flags ^ flags) & ~OVL_SETFL_MASK))
58 return -EIO;
59
60 flags &= OVL_SETFL_MASK;
61
62 if (((flags ^ file->f_flags) & O_APPEND) && IS_APPEND(inode))
63 return -EPERM;
64
65 if (flags & O_DIRECT) {
66 if (!file->f_mapping->a_ops ||
67 !file->f_mapping->a_ops->direct_IO)
68 return -EINVAL;
69 }
70
71 if (file->f_op->check_flags) {
72 err = file->f_op->check_flags(flags);
73 if (err)
74 return err;
75 }
76
77 spin_lock(&file->f_lock);
78 file->f_flags = (file->f_flags & ~OVL_SETFL_MASK) | flags;
79 spin_unlock(&file->f_lock);
80
81 return 0;
82}
83
Vivek Goyal8c444d22018-05-11 11:49:31 -040084static int ovl_real_fdget_meta(const struct file *file, struct fd *real,
85 bool allow_meta)
Miklos Szeredi2ef66b82018-07-18 15:44:41 +020086{
87 struct inode *inode = file_inode(file);
Vivek Goyal8c444d22018-05-11 11:49:31 -040088 struct inode *realinode;
Miklos Szeredi2ef66b82018-07-18 15:44:41 +020089
90 real->flags = 0;
91 real->file = file->private_data;
92
Vivek Goyal8c444d22018-05-11 11:49:31 -040093 if (allow_meta)
94 realinode = ovl_inode_real(inode);
95 else
96 realinode = ovl_inode_realdata(inode);
97
Miklos Szeredi2ef66b82018-07-18 15:44:41 +020098 /* Has it been copied up since we'd opened it? */
Vivek Goyal8c444d22018-05-11 11:49:31 -040099 if (unlikely(file_inode(real->file) != realinode)) {
Miklos Szeredi2ef66b82018-07-18 15:44:41 +0200100 real->flags = FDPUT_FPUT;
Vivek Goyal8c444d22018-05-11 11:49:31 -0400101 real->file = ovl_open_realfile(file, realinode);
Miklos Szeredi2ef66b82018-07-18 15:44:41 +0200102
103 return PTR_ERR_OR_ZERO(real->file);
104 }
105
106 /* Did the flags change since open? */
107 if (unlikely((file->f_flags ^ real->file->f_flags) & ~O_NOATIME))
108 return ovl_change_flags(real->file, file->f_flags);
109
110 return 0;
111}
112
Vivek Goyal8c444d22018-05-11 11:49:31 -0400113static int ovl_real_fdget(const struct file *file, struct fd *real)
114{
115 return ovl_real_fdget_meta(file, real, false);
116}
117
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200118static int ovl_open(struct inode *inode, struct file *file)
119{
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200120 struct file *realfile;
121 int err;
122
Amir Goldstein34280302019-01-22 07:01:39 +0200123 err = ovl_maybe_copy_up(file_dentry(file), file->f_flags);
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200124 if (err)
125 return err;
126
127 /* No longer need these flags, so don't pass them on to underlying fs */
128 file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
129
Vivek Goyal8c444d22018-05-11 11:49:31 -0400130 realfile = ovl_open_realfile(file, ovl_inode_realdata(inode));
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200131 if (IS_ERR(realfile))
132 return PTR_ERR(realfile);
133
134 file->private_data = realfile;
135
136 return 0;
137}
138
139static int ovl_release(struct inode *inode, struct file *file)
140{
141 fput(file->private_data);
142
143 return 0;
144}
145
146static loff_t ovl_llseek(struct file *file, loff_t offset, int whence)
147{
Amir Goldstein9e46b842019-02-27 13:32:11 +0200148 struct inode *inode = file_inode(file);
149 struct fd real;
150 const struct cred *old_cred;
151 ssize_t ret;
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200152
Amir Goldstein9e46b842019-02-27 13:32:11 +0200153 /*
154 * The two special cases below do not need to involve real fs,
155 * so we can optimizing concurrent callers.
156 */
157 if (offset == 0) {
158 if (whence == SEEK_CUR)
159 return file->f_pos;
160
161 if (whence == SEEK_SET)
162 return vfs_setpos(file, 0, 0);
163 }
164
165 ret = ovl_real_fdget(file, &real);
166 if (ret)
167 return ret;
168
169 /*
170 * Overlay file f_pos is the master copy that is preserved
171 * through copy up and modified on read/write, but only real
172 * fs knows how to SEEK_HOLE/SEEK_DATA and real fs may impose
173 * limitations that are more strict than ->s_maxbytes for specific
174 * files, so we use the real file to perform seeks.
175 */
176 inode_lock(inode);
177 real.file->f_pos = file->f_pos;
178
179 old_cred = ovl_override_creds(inode->i_sb);
180 ret = vfs_llseek(real.file, offset, whence);
181 revert_creds(old_cred);
182
183 file->f_pos = real.file->f_pos;
184 inode_unlock(inode);
185
186 fdput(real);
187
188 return ret;
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200189}
190
Miklos Szeredi16914e62018-07-18 15:44:41 +0200191static void ovl_file_accessed(struct file *file)
192{
193 struct inode *inode, *upperinode;
194
195 if (file->f_flags & O_NOATIME)
196 return;
197
198 inode = file_inode(file);
199 upperinode = ovl_inode_upper(inode);
200
201 if (!upperinode)
202 return;
203
204 if ((!timespec64_equal(&inode->i_mtime, &upperinode->i_mtime) ||
205 !timespec64_equal(&inode->i_ctime, &upperinode->i_ctime))) {
206 inode->i_mtime = upperinode->i_mtime;
207 inode->i_ctime = upperinode->i_ctime;
208 }
209
210 touch_atime(&file->f_path);
211}
212
213static rwf_t ovl_iocb_to_rwf(struct kiocb *iocb)
214{
215 int ifl = iocb->ki_flags;
216 rwf_t flags = 0;
217
218 if (ifl & IOCB_NOWAIT)
219 flags |= RWF_NOWAIT;
220 if (ifl & IOCB_HIPRI)
221 flags |= RWF_HIPRI;
222 if (ifl & IOCB_DSYNC)
223 flags |= RWF_DSYNC;
224 if (ifl & IOCB_SYNC)
225 flags |= RWF_SYNC;
226
227 return flags;
228}
229
230static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
231{
232 struct file *file = iocb->ki_filp;
233 struct fd real;
234 const struct cred *old_cred;
235 ssize_t ret;
236
237 if (!iov_iter_count(iter))
238 return 0;
239
240 ret = ovl_real_fdget(file, &real);
241 if (ret)
242 return ret;
243
244 old_cred = ovl_override_creds(file_inode(file)->i_sb);
245 ret = vfs_iter_read(real.file, iter, &iocb->ki_pos,
246 ovl_iocb_to_rwf(iocb));
247 revert_creds(old_cred);
248
249 ovl_file_accessed(file);
250
251 fdput(real);
252
253 return ret;
254}
255
Miklos Szeredi2a92e072018-07-18 15:44:41 +0200256static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
257{
258 struct file *file = iocb->ki_filp;
259 struct inode *inode = file_inode(file);
260 struct fd real;
261 const struct cred *old_cred;
262 ssize_t ret;
263
264 if (!iov_iter_count(iter))
265 return 0;
266
267 inode_lock(inode);
268 /* Update mode */
269 ovl_copyattr(ovl_inode_real(inode), inode);
270 ret = file_remove_privs(file);
271 if (ret)
272 goto out_unlock;
273
274 ret = ovl_real_fdget(file, &real);
275 if (ret)
276 goto out_unlock;
277
278 old_cred = ovl_override_creds(file_inode(file)->i_sb);
Amir Goldstein898cc192018-09-18 16:34:32 +0300279 file_start_write(real.file);
Miklos Szeredi2a92e072018-07-18 15:44:41 +0200280 ret = vfs_iter_write(real.file, iter, &iocb->ki_pos,
281 ovl_iocb_to_rwf(iocb));
Amir Goldstein898cc192018-09-18 16:34:32 +0300282 file_end_write(real.file);
Miklos Szeredi2a92e072018-07-18 15:44:41 +0200283 revert_creds(old_cred);
284
285 /* Update size */
286 ovl_copyattr(ovl_inode_real(inode), inode);
287
288 fdput(real);
289
290out_unlock:
291 inode_unlock(inode);
292
293 return ret;
294}
295
Miklos Szeredide30dfd2018-07-18 15:44:42 +0200296static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
297{
298 struct fd real;
299 const struct cred *old_cred;
300 int ret;
301
Vivek Goyal8c444d22018-05-11 11:49:31 -0400302 ret = ovl_real_fdget_meta(file, &real, !datasync);
Miklos Szeredide30dfd2018-07-18 15:44:42 +0200303 if (ret)
304 return ret;
305
306 /* Don't sync lower file for fear of receiving EROFS error */
307 if (file_inode(real.file) == ovl_inode_upper(file_inode(file))) {
308 old_cred = ovl_override_creds(file_inode(file)->i_sb);
309 ret = vfs_fsync_range(real.file, start, end, datasync);
310 revert_creds(old_cred);
311 }
312
313 fdput(real);
314
315 return ret;
316}
317
Miklos Szeredi2f502832018-07-18 15:44:42 +0200318static int ovl_mmap(struct file *file, struct vm_area_struct *vma)
319{
320 struct file *realfile = file->private_data;
321 const struct cred *old_cred;
322 int ret;
323
324 if (!realfile->f_op->mmap)
325 return -ENODEV;
326
327 if (WARN_ON(file != vma->vm_file))
328 return -EIO;
329
330 vma->vm_file = get_file(realfile);
331
332 old_cred = ovl_override_creds(file_inode(file)->i_sb);
333 ret = call_mmap(vma->vm_file, vma);
334 revert_creds(old_cred);
335
336 if (ret) {
337 /* Drop reference count from new vm_file value */
338 fput(realfile);
339 } else {
340 /* Drop reference count from previous vm_file value */
341 fput(file);
342 }
343
344 ovl_file_accessed(file);
345
346 return ret;
347}
348
Miklos Szerediaab88482018-07-18 15:44:42 +0200349static long ovl_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
350{
351 struct inode *inode = file_inode(file);
352 struct fd real;
353 const struct cred *old_cred;
354 int ret;
355
356 ret = ovl_real_fdget(file, &real);
357 if (ret)
358 return ret;
359
360 old_cred = ovl_override_creds(file_inode(file)->i_sb);
361 ret = vfs_fallocate(real.file, mode, offset, len);
362 revert_creds(old_cred);
363
364 /* Update size */
365 ovl_copyattr(ovl_inode_real(inode), inode);
366
367 fdput(real);
368
369 return ret;
370}
371
Amir Goldsteinb833a362018-08-28 10:58:41 +0300372static int ovl_fadvise(struct file *file, loff_t offset, loff_t len, int advice)
373{
374 struct fd real;
375 const struct cred *old_cred;
376 int ret;
377
378 ret = ovl_real_fdget(file, &real);
379 if (ret)
380 return ret;
381
382 old_cred = ovl_override_creds(file_inode(file)->i_sb);
383 ret = vfs_fadvise(real.file, offset, len, advice);
384 revert_creds(old_cred);
385
386 fdput(real);
387
388 return ret;
389}
390
Miklos Szeredidab5ca82018-07-18 15:44:42 +0200391static long ovl_real_ioctl(struct file *file, unsigned int cmd,
392 unsigned long arg)
393{
394 struct fd real;
395 const struct cred *old_cred;
396 long ret;
397
398 ret = ovl_real_fdget(file, &real);
399 if (ret)
400 return ret;
401
402 old_cred = ovl_override_creds(file_inode(file)->i_sb);
403 ret = vfs_ioctl(real.file, cmd, arg);
404 revert_creds(old_cred);
405
406 fdput(real);
407
408 return ret;
409}
410
411static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
412{
413 long ret;
414 struct inode *inode = file_inode(file);
415
416 switch (cmd) {
417 case FS_IOC_GETFLAGS:
418 ret = ovl_real_ioctl(file, cmd, arg);
419 break;
420
421 case FS_IOC_SETFLAGS:
422 if (!inode_owner_or_capable(inode))
423 return -EACCES;
424
425 ret = mnt_want_write_file(file);
426 if (ret)
427 return ret;
428
Amir Goldstein34280302019-01-22 07:01:39 +0200429 ret = ovl_maybe_copy_up(file_dentry(file), O_WRONLY);
Miklos Szeredidab5ca82018-07-18 15:44:42 +0200430 if (!ret) {
431 ret = ovl_real_ioctl(file, cmd, arg);
432
433 inode_lock(inode);
434 ovl_copyflags(ovl_inode_real(inode), inode);
435 inode_unlock(inode);
436 }
437
438 mnt_drop_write_file(file);
439 break;
440
441 default:
442 ret = -ENOTTY;
443 }
444
445 return ret;
446}
447
448static long ovl_compat_ioctl(struct file *file, unsigned int cmd,
449 unsigned long arg)
450{
451 switch (cmd) {
452 case FS_IOC32_GETFLAGS:
453 cmd = FS_IOC_GETFLAGS;
454 break;
455
456 case FS_IOC32_SETFLAGS:
457 cmd = FS_IOC_SETFLAGS;
458 break;
459
460 default:
461 return -ENOIOCTLCMD;
462 }
463
464 return ovl_ioctl(file, cmd, arg);
465}
466
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200467enum ovl_copyop {
468 OVL_COPY,
469 OVL_CLONE,
470 OVL_DEDUPE,
471};
472
Darrick J. Wong42ec3d42018-10-30 10:41:49 +1100473static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in,
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200474 struct file *file_out, loff_t pos_out,
Darrick J. Wong42ec3d42018-10-30 10:41:49 +1100475 loff_t len, unsigned int flags, enum ovl_copyop op)
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200476{
477 struct inode *inode_out = file_inode(file_out);
478 struct fd real_in, real_out;
479 const struct cred *old_cred;
Darrick J. Wong42ec3d42018-10-30 10:41:49 +1100480 loff_t ret;
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200481
482 ret = ovl_real_fdget(file_out, &real_out);
483 if (ret)
484 return ret;
485
486 ret = ovl_real_fdget(file_in, &real_in);
487 if (ret) {
488 fdput(real_out);
489 return ret;
490 }
491
492 old_cred = ovl_override_creds(file_inode(file_out)->i_sb);
493 switch (op) {
494 case OVL_COPY:
495 ret = vfs_copy_file_range(real_in.file, pos_in,
496 real_out.file, pos_out, len, flags);
497 break;
498
499 case OVL_CLONE:
Amir Goldsteina7253562018-09-18 16:34:34 +0300500 ret = vfs_clone_file_range(real_in.file, pos_in,
Darrick J. Wong452ce652018-10-30 10:41:56 +1100501 real_out.file, pos_out, len, flags);
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200502 break;
503
504 case OVL_DEDUPE:
505 ret = vfs_dedupe_file_range_one(real_in.file, pos_in,
Darrick J. Wongdf365832018-10-30 10:42:03 +1100506 real_out.file, pos_out, len,
507 flags);
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200508 break;
509 }
510 revert_creds(old_cred);
511
512 /* Update size */
513 ovl_copyattr(ovl_inode_real(inode_out), inode_out);
514
515 fdput(real_in);
516 fdput(real_out);
517
518 return ret;
519}
520
521static ssize_t ovl_copy_file_range(struct file *file_in, loff_t pos_in,
522 struct file *file_out, loff_t pos_out,
523 size_t len, unsigned int flags)
524{
525 return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, flags,
526 OVL_COPY);
527}
528
Darrick J. Wong42ec3d42018-10-30 10:41:49 +1100529static loff_t ovl_remap_file_range(struct file *file_in, loff_t pos_in,
530 struct file *file_out, loff_t pos_out,
531 loff_t len, unsigned int remap_flags)
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200532{
Darrick J. Wong2e5dfc92018-10-30 10:41:21 +1100533 enum ovl_copyop op;
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200534
Darrick J. Wong2e5dfc92018-10-30 10:41:21 +1100535 if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
536 return -EINVAL;
537
538 if (remap_flags & REMAP_FILE_DEDUP)
539 op = OVL_DEDUPE;
540 else
541 op = OVL_CLONE;
542
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200543 /*
544 * Don't copy up because of a dedupe request, this wouldn't make sense
545 * most of the time (data would be duplicated instead of deduplicated).
546 */
Darrick J. Wong2e5dfc92018-10-30 10:41:21 +1100547 if (op == OVL_DEDUPE &&
548 (!ovl_inode_upper(file_inode(file_in)) ||
549 !ovl_inode_upper(file_inode(file_out))))
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200550 return -EPERM;
551
Darrick J. Wong452ce652018-10-30 10:41:56 +1100552 return ovl_copyfile(file_in, pos_in, file_out, pos_out, len,
553 remap_flags, op);
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200554}
555
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200556const struct file_operations ovl_file_operations = {
557 .open = ovl_open,
558 .release = ovl_release,
559 .llseek = ovl_llseek,
Miklos Szeredi16914e62018-07-18 15:44:41 +0200560 .read_iter = ovl_read_iter,
Miklos Szeredi2a92e072018-07-18 15:44:41 +0200561 .write_iter = ovl_write_iter,
Miklos Szeredide30dfd2018-07-18 15:44:42 +0200562 .fsync = ovl_fsync,
Miklos Szeredi2f502832018-07-18 15:44:42 +0200563 .mmap = ovl_mmap,
Miklos Szerediaab88482018-07-18 15:44:42 +0200564 .fallocate = ovl_fallocate,
Amir Goldsteinb833a362018-08-28 10:58:41 +0300565 .fadvise = ovl_fadvise,
Miklos Szeredidab5ca82018-07-18 15:44:42 +0200566 .unlocked_ioctl = ovl_ioctl,
567 .compat_ioctl = ovl_compat_ioctl,
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200568
569 .copy_file_range = ovl_copy_file_range,
Darrick J. Wong2e5dfc92018-10-30 10:41:21 +1100570 .remap_file_range = ovl_remap_file_range,
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200571};