blob: ddfd93f13cc5f4a7e3948c137252f58bd1e9a370 [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;
32
33 old_cred = ovl_override_creds(inode->i_sb);
34 realfile = open_with_fake_path(&file->f_path, file->f_flags | O_NOATIME,
35 realinode, current_cred());
36 revert_creds(old_cred);
37
38 pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n",
Vivek Goyal8c444d22018-05-11 11:49:31 -040039 file, file, ovl_whatisit(inode, realinode), file->f_flags,
Miklos Szeredid1d04ef2018-07-18 15:44:41 +020040 realfile, IS_ERR(realfile) ? 0 : realfile->f_flags);
41
42 return realfile;
43}
44
Miklos Szeredi2ef66b82018-07-18 15:44:41 +020045#define OVL_SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT)
46
47static int ovl_change_flags(struct file *file, unsigned int flags)
48{
49 struct inode *inode = file_inode(file);
50 int err;
51
52 /* No atime modificaton on underlying */
53 flags |= O_NOATIME;
54
55 /* If some flag changed that cannot be changed then something's amiss */
56 if (WARN_ON((file->f_flags ^ flags) & ~OVL_SETFL_MASK))
57 return -EIO;
58
59 flags &= OVL_SETFL_MASK;
60
61 if (((flags ^ file->f_flags) & O_APPEND) && IS_APPEND(inode))
62 return -EPERM;
63
64 if (flags & O_DIRECT) {
65 if (!file->f_mapping->a_ops ||
66 !file->f_mapping->a_ops->direct_IO)
67 return -EINVAL;
68 }
69
70 if (file->f_op->check_flags) {
71 err = file->f_op->check_flags(flags);
72 if (err)
73 return err;
74 }
75
76 spin_lock(&file->f_lock);
77 file->f_flags = (file->f_flags & ~OVL_SETFL_MASK) | flags;
78 spin_unlock(&file->f_lock);
79
80 return 0;
81}
82
Vivek Goyal8c444d22018-05-11 11:49:31 -040083static int ovl_real_fdget_meta(const struct file *file, struct fd *real,
84 bool allow_meta)
Miklos Szeredi2ef66b82018-07-18 15:44:41 +020085{
86 struct inode *inode = file_inode(file);
Vivek Goyal8c444d22018-05-11 11:49:31 -040087 struct inode *realinode;
Miklos Szeredi2ef66b82018-07-18 15:44:41 +020088
89 real->flags = 0;
90 real->file = file->private_data;
91
Vivek Goyal8c444d22018-05-11 11:49:31 -040092 if (allow_meta)
93 realinode = ovl_inode_real(inode);
94 else
95 realinode = ovl_inode_realdata(inode);
96
Miklos Szeredi2ef66b82018-07-18 15:44:41 +020097 /* Has it been copied up since we'd opened it? */
Vivek Goyal8c444d22018-05-11 11:49:31 -040098 if (unlikely(file_inode(real->file) != realinode)) {
Miklos Szeredi2ef66b82018-07-18 15:44:41 +020099 real->flags = FDPUT_FPUT;
Vivek Goyal8c444d22018-05-11 11:49:31 -0400100 real->file = ovl_open_realfile(file, realinode);
Miklos Szeredi2ef66b82018-07-18 15:44:41 +0200101
102 return PTR_ERR_OR_ZERO(real->file);
103 }
104
105 /* Did the flags change since open? */
106 if (unlikely((file->f_flags ^ real->file->f_flags) & ~O_NOATIME))
107 return ovl_change_flags(real->file, file->f_flags);
108
109 return 0;
110}
111
Vivek Goyal8c444d22018-05-11 11:49:31 -0400112static int ovl_real_fdget(const struct file *file, struct fd *real)
113{
114 return ovl_real_fdget_meta(file, real, false);
115}
116
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200117static int ovl_open(struct inode *inode, struct file *file)
118{
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200119 struct file *realfile;
120 int err;
121
Amir Goldstein34280302019-01-22 07:01:39 +0200122 err = ovl_maybe_copy_up(file_dentry(file), file->f_flags);
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200123 if (err)
124 return err;
125
126 /* No longer need these flags, so don't pass them on to underlying fs */
127 file->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
128
Vivek Goyal8c444d22018-05-11 11:49:31 -0400129 realfile = ovl_open_realfile(file, ovl_inode_realdata(inode));
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200130 if (IS_ERR(realfile))
131 return PTR_ERR(realfile);
132
133 file->private_data = realfile;
134
135 return 0;
136}
137
138static int ovl_release(struct inode *inode, struct file *file)
139{
140 fput(file->private_data);
141
142 return 0;
143}
144
145static loff_t ovl_llseek(struct file *file, loff_t offset, int whence)
146{
Amir Goldstein9e46b842019-02-27 13:32:11 +0200147 struct inode *inode = file_inode(file);
148 struct fd real;
149 const struct cred *old_cred;
150 ssize_t ret;
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200151
Amir Goldstein9e46b842019-02-27 13:32:11 +0200152 /*
153 * The two special cases below do not need to involve real fs,
154 * so we can optimizing concurrent callers.
155 */
156 if (offset == 0) {
157 if (whence == SEEK_CUR)
158 return file->f_pos;
159
160 if (whence == SEEK_SET)
161 return vfs_setpos(file, 0, 0);
162 }
163
164 ret = ovl_real_fdget(file, &real);
165 if (ret)
166 return ret;
167
168 /*
169 * Overlay file f_pos is the master copy that is preserved
170 * through copy up and modified on read/write, but only real
171 * fs knows how to SEEK_HOLE/SEEK_DATA and real fs may impose
172 * limitations that are more strict than ->s_maxbytes for specific
173 * files, so we use the real file to perform seeks.
174 */
175 inode_lock(inode);
176 real.file->f_pos = file->f_pos;
177
178 old_cred = ovl_override_creds(inode->i_sb);
179 ret = vfs_llseek(real.file, offset, whence);
180 revert_creds(old_cred);
181
182 file->f_pos = real.file->f_pos;
183 inode_unlock(inode);
184
185 fdput(real);
186
187 return ret;
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200188}
189
Miklos Szeredi16914e62018-07-18 15:44:41 +0200190static void ovl_file_accessed(struct file *file)
191{
192 struct inode *inode, *upperinode;
193
194 if (file->f_flags & O_NOATIME)
195 return;
196
197 inode = file_inode(file);
198 upperinode = ovl_inode_upper(inode);
199
200 if (!upperinode)
201 return;
202
203 if ((!timespec64_equal(&inode->i_mtime, &upperinode->i_mtime) ||
204 !timespec64_equal(&inode->i_ctime, &upperinode->i_ctime))) {
205 inode->i_mtime = upperinode->i_mtime;
206 inode->i_ctime = upperinode->i_ctime;
207 }
208
209 touch_atime(&file->f_path);
210}
211
212static rwf_t ovl_iocb_to_rwf(struct kiocb *iocb)
213{
214 int ifl = iocb->ki_flags;
215 rwf_t flags = 0;
216
217 if (ifl & IOCB_NOWAIT)
218 flags |= RWF_NOWAIT;
219 if (ifl & IOCB_HIPRI)
220 flags |= RWF_HIPRI;
221 if (ifl & IOCB_DSYNC)
222 flags |= RWF_DSYNC;
223 if (ifl & IOCB_SYNC)
224 flags |= RWF_SYNC;
225
226 return flags;
227}
228
229static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
230{
231 struct file *file = iocb->ki_filp;
232 struct fd real;
233 const struct cred *old_cred;
234 ssize_t ret;
235
236 if (!iov_iter_count(iter))
237 return 0;
238
239 ret = ovl_real_fdget(file, &real);
240 if (ret)
241 return ret;
242
243 old_cred = ovl_override_creds(file_inode(file)->i_sb);
244 ret = vfs_iter_read(real.file, iter, &iocb->ki_pos,
245 ovl_iocb_to_rwf(iocb));
246 revert_creds(old_cred);
247
248 ovl_file_accessed(file);
249
250 fdput(real);
251
252 return ret;
253}
254
Miklos Szeredi2a92e072018-07-18 15:44:41 +0200255static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
256{
257 struct file *file = iocb->ki_filp;
258 struct inode *inode = file_inode(file);
259 struct fd real;
260 const struct cred *old_cred;
261 ssize_t ret;
262
263 if (!iov_iter_count(iter))
264 return 0;
265
266 inode_lock(inode);
267 /* Update mode */
268 ovl_copyattr(ovl_inode_real(inode), inode);
269 ret = file_remove_privs(file);
270 if (ret)
271 goto out_unlock;
272
273 ret = ovl_real_fdget(file, &real);
274 if (ret)
275 goto out_unlock;
276
277 old_cred = ovl_override_creds(file_inode(file)->i_sb);
Amir Goldstein898cc192018-09-18 16:34:32 +0300278 file_start_write(real.file);
Miklos Szeredi2a92e072018-07-18 15:44:41 +0200279 ret = vfs_iter_write(real.file, iter, &iocb->ki_pos,
280 ovl_iocb_to_rwf(iocb));
Amir Goldstein898cc192018-09-18 16:34:32 +0300281 file_end_write(real.file);
Miklos Szeredi2a92e072018-07-18 15:44:41 +0200282 revert_creds(old_cred);
283
284 /* Update size */
285 ovl_copyattr(ovl_inode_real(inode), inode);
286
287 fdput(real);
288
289out_unlock:
290 inode_unlock(inode);
291
292 return ret;
293}
294
Miklos Szeredide30dfd2018-07-18 15:44:42 +0200295static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync)
296{
297 struct fd real;
298 const struct cred *old_cred;
299 int ret;
300
Vivek Goyal8c444d22018-05-11 11:49:31 -0400301 ret = ovl_real_fdget_meta(file, &real, !datasync);
Miklos Szeredide30dfd2018-07-18 15:44:42 +0200302 if (ret)
303 return ret;
304
305 /* Don't sync lower file for fear of receiving EROFS error */
306 if (file_inode(real.file) == ovl_inode_upper(file_inode(file))) {
307 old_cred = ovl_override_creds(file_inode(file)->i_sb);
308 ret = vfs_fsync_range(real.file, start, end, datasync);
309 revert_creds(old_cred);
310 }
311
312 fdput(real);
313
314 return ret;
315}
316
Miklos Szeredi2f502832018-07-18 15:44:42 +0200317static int ovl_mmap(struct file *file, struct vm_area_struct *vma)
318{
319 struct file *realfile = file->private_data;
320 const struct cred *old_cred;
321 int ret;
322
323 if (!realfile->f_op->mmap)
324 return -ENODEV;
325
326 if (WARN_ON(file != vma->vm_file))
327 return -EIO;
328
329 vma->vm_file = get_file(realfile);
330
331 old_cred = ovl_override_creds(file_inode(file)->i_sb);
332 ret = call_mmap(vma->vm_file, vma);
333 revert_creds(old_cred);
334
335 if (ret) {
336 /* Drop reference count from new vm_file value */
337 fput(realfile);
338 } else {
339 /* Drop reference count from previous vm_file value */
340 fput(file);
341 }
342
343 ovl_file_accessed(file);
344
345 return ret;
346}
347
Miklos Szerediaab88482018-07-18 15:44:42 +0200348static long ovl_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
349{
350 struct inode *inode = file_inode(file);
351 struct fd real;
352 const struct cred *old_cred;
353 int ret;
354
355 ret = ovl_real_fdget(file, &real);
356 if (ret)
357 return ret;
358
359 old_cred = ovl_override_creds(file_inode(file)->i_sb);
360 ret = vfs_fallocate(real.file, mode, offset, len);
361 revert_creds(old_cred);
362
363 /* Update size */
364 ovl_copyattr(ovl_inode_real(inode), inode);
365
366 fdput(real);
367
368 return ret;
369}
370
Amir Goldsteinb833a362018-08-28 10:58:41 +0300371static int ovl_fadvise(struct file *file, loff_t offset, loff_t len, int advice)
372{
373 struct fd real;
374 const struct cred *old_cred;
375 int ret;
376
377 ret = ovl_real_fdget(file, &real);
378 if (ret)
379 return ret;
380
381 old_cred = ovl_override_creds(file_inode(file)->i_sb);
382 ret = vfs_fadvise(real.file, offset, len, advice);
383 revert_creds(old_cred);
384
385 fdput(real);
386
387 return ret;
388}
389
Miklos Szeredidab5ca82018-07-18 15:44:42 +0200390static long ovl_real_ioctl(struct file *file, unsigned int cmd,
391 unsigned long arg)
392{
393 struct fd real;
394 const struct cred *old_cred;
395 long ret;
396
397 ret = ovl_real_fdget(file, &real);
398 if (ret)
399 return ret;
400
401 old_cred = ovl_override_creds(file_inode(file)->i_sb);
402 ret = vfs_ioctl(real.file, cmd, arg);
403 revert_creds(old_cred);
404
405 fdput(real);
406
407 return ret;
408}
409
410static long ovl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
411{
412 long ret;
413 struct inode *inode = file_inode(file);
414
415 switch (cmd) {
416 case FS_IOC_GETFLAGS:
417 ret = ovl_real_ioctl(file, cmd, arg);
418 break;
419
420 case FS_IOC_SETFLAGS:
421 if (!inode_owner_or_capable(inode))
422 return -EACCES;
423
424 ret = mnt_want_write_file(file);
425 if (ret)
426 return ret;
427
Amir Goldstein34280302019-01-22 07:01:39 +0200428 ret = ovl_maybe_copy_up(file_dentry(file), O_WRONLY);
Miklos Szeredidab5ca82018-07-18 15:44:42 +0200429 if (!ret) {
430 ret = ovl_real_ioctl(file, cmd, arg);
431
432 inode_lock(inode);
433 ovl_copyflags(ovl_inode_real(inode), inode);
434 inode_unlock(inode);
435 }
436
437 mnt_drop_write_file(file);
438 break;
439
440 default:
441 ret = -ENOTTY;
442 }
443
444 return ret;
445}
446
447static long ovl_compat_ioctl(struct file *file, unsigned int cmd,
448 unsigned long arg)
449{
450 switch (cmd) {
451 case FS_IOC32_GETFLAGS:
452 cmd = FS_IOC_GETFLAGS;
453 break;
454
455 case FS_IOC32_SETFLAGS:
456 cmd = FS_IOC_SETFLAGS;
457 break;
458
459 default:
460 return -ENOIOCTLCMD;
461 }
462
463 return ovl_ioctl(file, cmd, arg);
464}
465
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200466enum ovl_copyop {
467 OVL_COPY,
468 OVL_CLONE,
469 OVL_DEDUPE,
470};
471
Darrick J. Wong42ec3d42018-10-30 10:41:49 +1100472static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in,
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200473 struct file *file_out, loff_t pos_out,
Darrick J. Wong42ec3d42018-10-30 10:41:49 +1100474 loff_t len, unsigned int flags, enum ovl_copyop op)
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200475{
476 struct inode *inode_out = file_inode(file_out);
477 struct fd real_in, real_out;
478 const struct cred *old_cred;
Darrick J. Wong42ec3d42018-10-30 10:41:49 +1100479 loff_t ret;
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200480
481 ret = ovl_real_fdget(file_out, &real_out);
482 if (ret)
483 return ret;
484
485 ret = ovl_real_fdget(file_in, &real_in);
486 if (ret) {
487 fdput(real_out);
488 return ret;
489 }
490
491 old_cred = ovl_override_creds(file_inode(file_out)->i_sb);
492 switch (op) {
493 case OVL_COPY:
494 ret = vfs_copy_file_range(real_in.file, pos_in,
495 real_out.file, pos_out, len, flags);
496 break;
497
498 case OVL_CLONE:
Amir Goldsteina7253562018-09-18 16:34:34 +0300499 ret = vfs_clone_file_range(real_in.file, pos_in,
Darrick J. Wong452ce652018-10-30 10:41:56 +1100500 real_out.file, pos_out, len, flags);
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200501 break;
502
503 case OVL_DEDUPE:
504 ret = vfs_dedupe_file_range_one(real_in.file, pos_in,
Darrick J. Wongdf365832018-10-30 10:42:03 +1100505 real_out.file, pos_out, len,
506 flags);
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200507 break;
508 }
509 revert_creds(old_cred);
510
511 /* Update size */
512 ovl_copyattr(ovl_inode_real(inode_out), inode_out);
513
514 fdput(real_in);
515 fdput(real_out);
516
517 return ret;
518}
519
520static ssize_t ovl_copy_file_range(struct file *file_in, loff_t pos_in,
521 struct file *file_out, loff_t pos_out,
522 size_t len, unsigned int flags)
523{
524 return ovl_copyfile(file_in, pos_in, file_out, pos_out, len, flags,
525 OVL_COPY);
526}
527
Darrick J. Wong42ec3d42018-10-30 10:41:49 +1100528static loff_t ovl_remap_file_range(struct file *file_in, loff_t pos_in,
529 struct file *file_out, loff_t pos_out,
530 loff_t len, unsigned int remap_flags)
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200531{
Darrick J. Wong2e5dfc92018-10-30 10:41:21 +1100532 enum ovl_copyop op;
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200533
Darrick J. Wong2e5dfc92018-10-30 10:41:21 +1100534 if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY))
535 return -EINVAL;
536
537 if (remap_flags & REMAP_FILE_DEDUP)
538 op = OVL_DEDUPE;
539 else
540 op = OVL_CLONE;
541
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200542 /*
543 * Don't copy up because of a dedupe request, this wouldn't make sense
544 * most of the time (data would be duplicated instead of deduplicated).
545 */
Darrick J. Wong2e5dfc92018-10-30 10:41:21 +1100546 if (op == OVL_DEDUPE &&
547 (!ovl_inode_upper(file_inode(file_in)) ||
548 !ovl_inode_upper(file_inode(file_out))))
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200549 return -EPERM;
550
Darrick J. Wong452ce652018-10-30 10:41:56 +1100551 return ovl_copyfile(file_in, pos_in, file_out, pos_out, len,
552 remap_flags, op);
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200553}
554
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200555const struct file_operations ovl_file_operations = {
556 .open = ovl_open,
557 .release = ovl_release,
558 .llseek = ovl_llseek,
Miklos Szeredi16914e62018-07-18 15:44:41 +0200559 .read_iter = ovl_read_iter,
Miklos Szeredi2a92e072018-07-18 15:44:41 +0200560 .write_iter = ovl_write_iter,
Miklos Szeredide30dfd2018-07-18 15:44:42 +0200561 .fsync = ovl_fsync,
Miklos Szeredi2f502832018-07-18 15:44:42 +0200562 .mmap = ovl_mmap,
Miklos Szerediaab88482018-07-18 15:44:42 +0200563 .fallocate = ovl_fallocate,
Amir Goldsteinb833a362018-08-28 10:58:41 +0300564 .fadvise = ovl_fadvise,
Miklos Szeredidab5ca82018-07-18 15:44:42 +0200565 .unlocked_ioctl = ovl_ioctl,
566 .compat_ioctl = ovl_compat_ioctl,
Miklos Szeredi8ede2052018-07-18 15:44:42 +0200567
568 .copy_file_range = ovl_copy_file_range,
Darrick J. Wong2e5dfc92018-10-30 10:41:21 +1100569 .remap_file_range = ovl_remap_file_range,
Miklos Szeredid1d04ef2018-07-18 15:44:41 +0200570};