Skip to content

Commit 52435c8

Browse files
committed
Merge tag 'ovl-update-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs updates from Miklos Szeredi: "Fixes: - Resolve mount option conflicts consistently - Sync before remount R/O - Fix file handle encoding corner cases - Fix metacopy related issues - Fix an unintialized return value - Add missing permission checks for underlying layers Optimizations: - Allow multipe whiteouts to share an inode - Optimize small writes by inheriting SB_NOSEC from upper layer - Do not call ->syncfs() multiple times for sync(2) - Do not cache negative lookups on upper layer - Make private internal mounts longterm" * tag 'ovl-update-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: (27 commits) ovl: remove unnecessary lock check ovl: make oip->index bool ovl: only pass ->ki_flags to ovl_iocb_to_rwf() ovl: make private mounts longterm ovl: get rid of redundant members in struct ovl_fs ovl: add accessor for ofs->upper_mnt ovl: initialize error in ovl_copy_xattr ovl: drop negative dentry in upper layer ovl: check permission to open real file ovl: call secutiry hook in ovl_real_ioctl() ovl: verify permissions in ovl_path_open() ovl: switch to mounter creds in readdir ovl: pass correct flags for opening real directory ovl: fix redirect traversal on metacopy dentries ovl: initialize OVL_UPPERDATA in ovl_lookup() ovl: use only uppermetacopy state in ovl_lookup() ovl: simplify setting of origin for index lookup ovl: fix out of bounds access warning in ovl_check_fb_len() ovl: return required buffer size for file handles ovl: sync dirty data when remounting to ro mode ...
2 parents 4964dd2 + 2068cf7 commit 52435c8

File tree

18 files changed

+440
-222
lines changed

18 files changed

+440
-222
lines changed

Documentation/filesystems/overlayfs.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,8 @@ pointed by REDIRECT. This should not be possible on local system as setting
365365
"trusted." xattrs will require CAP_SYS_ADMIN. But it should be possible
366366
for untrusted layers like from a pen drive.
367367

368-
Note: redirect_dir={off|nofollow|follow[*]} conflicts with metacopy=on, and
369-
results in an error.
368+
Note: redirect_dir={off|nofollow|follow[*]} and nfs_export=on mount options
369+
conflict with metacopy=on, and will result in an error.
370370

371371
[*] redirect_dir=follow only conflicts with metacopy=on if upperdir=... is
372372
given.
@@ -560,6 +560,9 @@ When the NFS export feature is enabled, all directory index entries are
560560
verified on mount time to check that upper file handles are not stale.
561561
This verification may cause significant overhead in some cases.
562562

563+
Note: the mount options index=off,nfs_export=on are conflicting and will
564+
result in an error.
565+
563566

564567
Testsuite
565568
---------

Documentation/filesystems/porting.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,3 +858,10 @@ be misspelled d_alloc_anon().
858858
[should've been added in 2016] stale comment in finish_open() nonwithstanding,
859859
failure exits in ->atomic_open() instances should *NOT* fput() the file,
860860
no matter what. Everything is handled by the caller.
861+
862+
---
863+
864+
**mandatory**
865+
866+
clone_private_mount() returns a longterm mount now, so the proper destructor of
867+
its result is kern_unmount() or kern_unmount_array().

fs/namespace.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,6 +1937,9 @@ struct vfsmount *clone_private_mount(const struct path *path)
19371937
if (IS_ERR(new_mnt))
19381938
return ERR_CAST(new_mnt);
19391939

1940+
/* Longterm mount to be removed by kern_unmount*() */
1941+
new_mnt->mnt_ns = MNT_NS_INTERNAL;
1942+
19401943
return &new_mnt->mnt;
19411944
}
19421945
EXPORT_SYMBOL_GPL(clone_private_mount);
@@ -3863,6 +3866,19 @@ void kern_unmount(struct vfsmount *mnt)
38633866
}
38643867
EXPORT_SYMBOL(kern_unmount);
38653868

3869+
void kern_unmount_array(struct vfsmount *mnt[], unsigned int num)
3870+
{
3871+
unsigned int i;
3872+
3873+
for (i = 0; i < num; i++)
3874+
if (mnt[i])
3875+
real_mount(mnt[i])->mnt_ns = NULL;
3876+
synchronize_rcu_expedited();
3877+
for (i = 0; i < num; i++)
3878+
mntput(mnt[i]);
3879+
}
3880+
EXPORT_SYMBOL(kern_unmount_array);
3881+
38663882
bool our_mnt(struct vfsmount *mnt)
38673883
{
38683884
return check_mnt(real_mount(mnt));

fs/overlayfs/copy_up.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
4747
{
4848
ssize_t list_size, size, value_size = 0;
4949
char *buf, *name, *value = NULL;
50-
int uninitialized_var(error);
50+
int error = 0;
5151
size_t slen;
5252

5353
if (!(old->d_inode->i_opflags & IOP_XATTR) ||
@@ -584,9 +584,10 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
584584
.link = c->link
585585
};
586586

587-
err = ovl_lock_rename_workdir(c->workdir, c->destdir);
588-
if (err)
589-
return err;
587+
/* workdir and destdir could be the same when copying up to indexdir */
588+
err = -EIO;
589+
if (lock_rename(c->workdir, c->destdir) != NULL)
590+
goto unlock;
590591

591592
err = ovl_prep_cu_creds(c->dentry, &cc);
592593
if (err)

fs/overlayfs/dir.c

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,35 +62,59 @@ struct dentry *ovl_lookup_temp(struct dentry *workdir)
6262
}
6363

6464
/* caller holds i_mutex on workdir */
65-
static struct dentry *ovl_whiteout(struct dentry *workdir)
65+
static struct dentry *ovl_whiteout(struct ovl_fs *ofs)
6666
{
6767
int err;
6868
struct dentry *whiteout;
69+
struct dentry *workdir = ofs->workdir;
6970
struct inode *wdir = workdir->d_inode;
7071

71-
whiteout = ovl_lookup_temp(workdir);
72-
if (IS_ERR(whiteout))
73-
return whiteout;
72+
if (!ofs->whiteout) {
73+
whiteout = ovl_lookup_temp(workdir);
74+
if (IS_ERR(whiteout))
75+
goto out;
7476

75-
err = ovl_do_whiteout(wdir, whiteout);
76-
if (err) {
77-
dput(whiteout);
78-
whiteout = ERR_PTR(err);
77+
err = ovl_do_whiteout(wdir, whiteout);
78+
if (err) {
79+
dput(whiteout);
80+
whiteout = ERR_PTR(err);
81+
goto out;
82+
}
83+
ofs->whiteout = whiteout;
7984
}
8085

86+
if (ofs->share_whiteout) {
87+
whiteout = ovl_lookup_temp(workdir);
88+
if (IS_ERR(whiteout))
89+
goto out;
90+
91+
err = ovl_do_link(ofs->whiteout, wdir, whiteout);
92+
if (!err)
93+
goto out;
94+
95+
if (err != -EMLINK) {
96+
pr_warn("Failed to link whiteout - disabling whiteout inode sharing(nlink=%u, err=%i)\n",
97+
ofs->whiteout->d_inode->i_nlink, err);
98+
ofs->share_whiteout = false;
99+
}
100+
dput(whiteout);
101+
}
102+
whiteout = ofs->whiteout;
103+
ofs->whiteout = NULL;
104+
out:
81105
return whiteout;
82106
}
83107

84108
/* Caller must hold i_mutex on both workdir and dir */
85-
int ovl_cleanup_and_whiteout(struct dentry *workdir, struct inode *dir,
109+
int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct inode *dir,
86110
struct dentry *dentry)
87111
{
88-
struct inode *wdir = workdir->d_inode;
112+
struct inode *wdir = ofs->workdir->d_inode;
89113
struct dentry *whiteout;
90114
int err;
91115
int flags = 0;
92116

93-
whiteout = ovl_whiteout(workdir);
117+
whiteout = ovl_whiteout(ofs);
94118
err = PTR_ERR(whiteout);
95119
if (IS_ERR(whiteout))
96120
return err;
@@ -262,6 +286,8 @@ static int ovl_instantiate(struct dentry *dentry, struct inode *inode,
262286
inode = ovl_get_inode(dentry->d_sb, &oip);
263287
if (IS_ERR(inode))
264288
return PTR_ERR(inode);
289+
if (inode == oip.newinode)
290+
ovl_set_flag(OVL_UPPERDATA, inode);
265291
} else {
266292
WARN_ON(ovl_inode_real(inode) != d_inode(newdentry));
267293
dput(newdentry);
@@ -715,6 +741,7 @@ static bool ovl_matches_upper(struct dentry *dentry, struct dentry *upper)
715741
static int ovl_remove_and_whiteout(struct dentry *dentry,
716742
struct list_head *list)
717743
{
744+
struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
718745
struct dentry *workdir = ovl_workdir(dentry);
719746
struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
720747
struct dentry *upper;
@@ -748,7 +775,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
748775
goto out_dput_upper;
749776
}
750777

751-
err = ovl_cleanup_and_whiteout(workdir, d_inode(upperdir), upper);
778+
err = ovl_cleanup_and_whiteout(ofs, d_inode(upperdir), upper);
752779
if (err)
753780
goto out_d_drop;
754781

fs/overlayfs/export.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ static int ovl_check_encode_origin(struct dentry *dentry)
204204
* ovl_connect_layer() will try to make origin's layer "connected" by
205205
* copying up a "connectable" ancestor.
206206
*/
207-
if (d_is_dir(dentry) && ofs->upper_mnt)
207+
if (d_is_dir(dentry) && ovl_upper_mnt(ofs))
208208
return ovl_connect_layer(dentry);
209209

210210
/* Lower file handle for indexed and non-upper dir/non-dir */
@@ -231,30 +231,26 @@ static int ovl_dentry_to_fid(struct dentry *dentry, u32 *fid, int buflen)
231231
if (IS_ERR(fh))
232232
return PTR_ERR(fh);
233233

234-
err = -EOVERFLOW;
235234
len = OVL_FH_LEN(fh);
236-
if (len > buflen)
237-
goto fail;
238-
239-
memcpy(fid, fh, len);
235+
if (len <= buflen)
236+
memcpy(fid, fh, len);
240237
err = len;
241238

242239
out:
243240
kfree(fh);
244241
return err;
245242

246243
fail:
247-
pr_warn_ratelimited("failed to encode file handle (%pd2, err=%i, buflen=%d, len=%d, type=%d)\n",
248-
dentry, err, buflen, fh ? (int)fh->fb.len : 0,
249-
fh ? fh->fb.type : 0);
244+
pr_warn_ratelimited("failed to encode file handle (%pd2, err=%i)\n",
245+
dentry, err);
250246
goto out;
251247
}
252248

253249
static int ovl_encode_fh(struct inode *inode, u32 *fid, int *max_len,
254250
struct inode *parent)
255251
{
256252
struct dentry *dentry;
257-
int bytes = *max_len << 2;
253+
int bytes, buflen = *max_len << 2;
258254

259255
/* TODO: encode connectable file handles */
260256
if (parent)
@@ -264,12 +260,14 @@ static int ovl_encode_fh(struct inode *inode, u32 *fid, int *max_len,
264260
if (WARN_ON(!dentry))
265261
return FILEID_INVALID;
266262

267-
bytes = ovl_dentry_to_fid(dentry, fid, bytes);
263+
bytes = ovl_dentry_to_fid(dentry, fid, buflen);
268264
dput(dentry);
269265
if (bytes <= 0)
270266
return FILEID_INVALID;
271267

272268
*max_len = bytes >> 2;
269+
if (bytes > buflen)
270+
return FILEID_INVALID;
273271

274272
return OVL_FILEID_V1;
275273
}
@@ -679,10 +677,10 @@ static struct dentry *ovl_upper_fh_to_d(struct super_block *sb,
679677
struct dentry *dentry;
680678
struct dentry *upper;
681679

682-
if (!ofs->upper_mnt)
680+
if (!ovl_upper_mnt(ofs))
683681
return ERR_PTR(-EACCES);
684682

685-
upper = ovl_decode_real_fh(fh, ofs->upper_mnt, true);
683+
upper = ovl_decode_real_fh(fh, ovl_upper_mnt(ofs), true);
686684
if (IS_ERR_OR_NULL(upper))
687685
return upper;
688686

fs/overlayfs/file.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/uio.h>
1111
#include <linux/uaccess.h>
1212
#include <linux/splice.h>
13+
#include <linux/security.h>
1314
#include <linux/mm.h>
1415
#include <linux/fs.h>
1516
#include "overlayfs.h"
@@ -39,10 +40,22 @@ static struct file *ovl_open_realfile(const struct file *file,
3940
struct file *realfile;
4041
const struct cred *old_cred;
4142
int flags = file->f_flags | O_NOATIME | FMODE_NONOTIFY;
43+
int acc_mode = ACC_MODE(flags);
44+
int err;
45+
46+
if (flags & O_APPEND)
47+
acc_mode |= MAY_APPEND;
4248

4349
old_cred = ovl_override_creds(inode->i_sb);
44-
realfile = open_with_fake_path(&file->f_path, flags, realinode,
45-
current_cred());
50+
err = inode_permission(realinode, MAY_OPEN | acc_mode);
51+
if (err) {
52+
realfile = ERR_PTR(err);
53+
} else if (!inode_owner_or_capable(realinode)) {
54+
realfile = ERR_PTR(-EPERM);
55+
} else {
56+
realfile = open_with_fake_path(&file->f_path, flags, realinode,
57+
current_cred());
58+
}
4659
revert_creds(old_cred);
4760

4861
pr_debug("open(%p[%pD2/%c], 0%o) -> (%p, 0%o)\n",
@@ -219,9 +232,8 @@ static void ovl_file_accessed(struct file *file)
219232
touch_atime(&file->f_path);
220233
}
221234

222-
static rwf_t ovl_iocb_to_rwf(struct kiocb *iocb)
235+
static rwf_t ovl_iocb_to_rwf(int ifl)
223236
{
224-
int ifl = iocb->ki_flags;
225237
rwf_t flags = 0;
226238

227239
if (ifl & IOCB_NOWAIT)
@@ -283,7 +295,7 @@ static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
283295
old_cred = ovl_override_creds(file_inode(file)->i_sb);
284296
if (is_sync_kiocb(iocb)) {
285297
ret = vfs_iter_read(real.file, iter, &iocb->ki_pos,
286-
ovl_iocb_to_rwf(iocb));
298+
ovl_iocb_to_rwf(iocb->ki_flags));
287299
} else {
288300
struct ovl_aio_req *aio_req;
289301

@@ -336,7 +348,7 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
336348
if (is_sync_kiocb(iocb)) {
337349
file_start_write(real.file);
338350
ret = vfs_iter_write(real.file, iter, &iocb->ki_pos,
339-
ovl_iocb_to_rwf(iocb));
351+
ovl_iocb_to_rwf(iocb->ki_flags));
340352
file_end_write(real.file);
341353
/* Update size */
342354
ovl_copyattr(ovl_inode_real(inode), inode);
@@ -520,7 +532,9 @@ static long ovl_real_ioctl(struct file *file, unsigned int cmd,
520532
return ret;
521533

522534
old_cred = ovl_override_creds(file_inode(file)->i_sb);
523-
ret = vfs_ioctl(real.file, cmd, arg);
535+
ret = security_file_ioctl(real.file, cmd, arg);
536+
if (!ret)
537+
ret = vfs_ioctl(real.file, cmd, arg);
524538
revert_creds(old_cred);
525539

526540
fdput(real);

fs/overlayfs/inode.c

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ int ovl_update_time(struct inode *inode, struct timespec64 *ts, int flags)
457457
if (flags & S_ATIME) {
458458
struct ovl_fs *ofs = inode->i_sb->s_fs_info;
459459
struct path upperpath = {
460-
.mnt = ofs->upper_mnt,
460+
.mnt = ovl_upper_mnt(ofs),
461461
.dentry = ovl_upperdentry_dereference(OVL_I(inode)),
462462
};
463463

@@ -905,7 +905,7 @@ struct inode *ovl_get_trap_inode(struct super_block *sb, struct dentry *dir)
905905
* Does overlay inode need to be hashed by lower inode?
906906
*/
907907
static bool ovl_hash_bylower(struct super_block *sb, struct dentry *upper,
908-
struct dentry *lower, struct dentry *index)
908+
struct dentry *lower, bool index)
909909
{
910910
struct ovl_fs *ofs = sb->s_fs_info;
911911

@@ -918,7 +918,7 @@ static bool ovl_hash_bylower(struct super_block *sb, struct dentry *upper,
918918
return true;
919919

920920
/* Yes, if won't be copied up */
921-
if (!ofs->upper_mnt)
921+
if (!ovl_upper_mnt(ofs))
922922
return true;
923923

924924
/* No, if lower hardlink is or will be broken on copy up */
@@ -954,7 +954,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
954954
bool bylower = ovl_hash_bylower(sb, upperdentry, lowerdentry,
955955
oip->index);
956956
int fsid = bylower ? lowerpath->layer->fsid : 0;
957-
bool is_dir, metacopy = false;
957+
bool is_dir;
958958
unsigned long ino = 0;
959959
int err = oip->newinode ? -EEXIST : -ENOMEM;
960960

@@ -1015,15 +1015,6 @@ struct inode *ovl_get_inode(struct super_block *sb,
10151015
if (oip->index)
10161016
ovl_set_flag(OVL_INDEX, inode);
10171017

1018-
if (upperdentry) {
1019-
err = ovl_check_metacopy_xattr(upperdentry);
1020-
if (err < 0)
1021-
goto out_err;
1022-
metacopy = err;
1023-
if (!metacopy)
1024-
ovl_set_flag(OVL_UPPERDATA, inode);
1025-
}
1026-
10271018
OVL_I(inode)->redirect = oip->redirect;
10281019

10291020
if (bylower)

0 commit comments

Comments
 (0)