Skip to content

Commit

Permalink
ovl: fix lookup failure on multi lower squashfs
Browse files Browse the repository at this point in the history
In the past, overlayfs required that lower fs have non null uuid in
order to support nfs export and decode copy up origin file handles.

Commit 9df085f ("ovl: relax requirement for non null uuid of
lower fs") relaxed this requirement for nfs export support, as long
as uuid (even if null) is unique among all lower fs.

However, said commit unintentionally also relaxed the non null uuid
requirement for decoding copy up origin file handles, regardless of
the unique uuid requirement.

Amend this mistake by disabling decoding of copy up origin file handle
from lower fs with a conflicting uuid.

We still encode copy up origin file handles from those fs, because
file handles like those already exist in the wild and because they
might provide useful information in the future.

There is an unhandled corner case described by Miklos this way:
- two filesystems, A and B, both have null uuid
- upper layer is on A
- lower layer 1 is also on A
- lower layer 2 is on B

In this case bad_uuid won't be set for B, because the check only
involves the list of lower fs.  Hence we'll try to decode a layer 2
origin on layer 1 and fail.

We will deal with this corner case later.

Reported-by: Colin Ian King <colin.king@canonical.com>
Tested-by: Colin Ian King <colin.king@canonical.com>
Link: https://lore.kernel.org/lkml/20191106234301.283006-1-colin.king@canonical.com/
Fixes: 9df085f ("ovl: relax requirement for non null uuid ...")
Cc: stable@vger.kernel.org # v4.20+
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
  • Loading branch information
Amir Goldstein authored and Miklos Szeredi committed Dec 10, 2019
1 parent 219d543 commit 7e63c87
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 7 deletions.
8 changes: 8 additions & 0 deletions fs/overlayfs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,14 @@ int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected,
int i;

for (i = 0; i < ofs->numlower; i++) {
/*
* If lower fs uuid is not unique among lower fs we cannot match
* fh->uuid to layer.
*/
if (ofs->lower_layers[i].fsid &&
ofs->lower_layers[i].fs->bad_uuid)
continue;

origin = ovl_decode_real_fh(fh, ofs->lower_layers[i].mnt,
connected);
if (origin)
Expand Down
2 changes: 2 additions & 0 deletions fs/overlayfs/ovl_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ struct ovl_config {
struct ovl_sb {
struct super_block *sb;
dev_t pseudo_dev;
/* Unusable (conflicting) uuid */
bool bad_uuid;
};

struct ovl_layer {
Expand Down
24 changes: 17 additions & 7 deletions fs/overlayfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -1255,17 +1255,21 @@ static bool ovl_lower_uuid_ok(struct ovl_fs *ofs, const uuid_t *uuid)
{
unsigned int i;

if (!ofs->config.nfs_export && !(ofs->config.index && ofs->upper_mnt))
if (!ofs->config.nfs_export && !ofs->upper_mnt)
return true;

for (i = 0; i < ofs->numlowerfs; i++) {
/*
* We use uuid to associate an overlay lower file handle with a
* lower layer, so we can accept lower fs with null uuid as long
* as all lower layers with null uuid are on the same fs.
* if we detect multiple lower fs with the same uuid, we
* disable lower file handle decoding on all of them.
*/
if (uuid_equal(&ofs->lower_fs[i].sb->s_uuid, uuid))
if (uuid_equal(&ofs->lower_fs[i].sb->s_uuid, uuid)) {
ofs->lower_fs[i].bad_uuid = true;
return false;
}
}
return true;
}
Expand All @@ -1277,6 +1281,7 @@ static int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path)
unsigned int i;
dev_t dev;
int err;
bool bad_uuid = false;

/* fsid 0 is reserved for upper fs even with non upper overlay */
if (ofs->upper_mnt && ofs->upper_mnt->mnt_sb == sb)
Expand All @@ -1288,11 +1293,15 @@ static int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path)
}

if (!ovl_lower_uuid_ok(ofs, &sb->s_uuid)) {
ofs->config.index = false;
ofs->config.nfs_export = false;
pr_warn("overlayfs: %s uuid detected in lower fs '%pd2', falling back to index=off,nfs_export=off.\n",
uuid_is_null(&sb->s_uuid) ? "null" : "conflicting",
path->dentry);
bad_uuid = true;
if (ofs->config.index || ofs->config.nfs_export) {
ofs->config.index = false;
ofs->config.nfs_export = false;
pr_warn("overlayfs: %s uuid detected in lower fs '%pd2', falling back to index=off,nfs_export=off.\n",
uuid_is_null(&sb->s_uuid) ? "null" :
"conflicting",
path->dentry);
}
}

err = get_anon_bdev(&dev);
Expand All @@ -1303,6 +1312,7 @@ static int ovl_get_fsid(struct ovl_fs *ofs, const struct path *path)

ofs->lower_fs[ofs->numlowerfs].sb = sb;
ofs->lower_fs[ofs->numlowerfs].pseudo_dev = dev;
ofs->lower_fs[ofs->numlowerfs].bad_uuid = bad_uuid;
ofs->numlowerfs++;

return ofs->numlowerfs;
Expand Down

0 comments on commit 7e63c87

Please sign in to comment.