Commit cc6f67bc authored by Miklos Szeredi's avatar Miklos Szeredi

ovl: mount read-only if workdir can't be created

OpenWRT folks reported that overlayfs fails to mount if upper fs is full,
because workdir can't be created.  Wordir creation can fail for various
other reasons too.

There's no reason that the mount itself should fail, overlayfs can work
fine without a workdir, as long as the overlay isn't modified.

So mount it read-only and don't allow remounting read-write.

Add a couple of WARN_ON()s for the impossible case of workdir being used
despite being read-only.

Reported-by: Bastian Bittorf <bittorf@bluebottle.com> 
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
Cc: <stable@vger.kernel.org> # v3.18+
parent d377c5eb
...@@ -299,6 +299,9 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, ...@@ -299,6 +299,9 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
struct cred *override_cred; struct cred *override_cred;
char *link = NULL; char *link = NULL;
if (WARN_ON(!workdir))
return -EROFS;
ovl_path_upper(parent, &parentpath); ovl_path_upper(parent, &parentpath);
upperdir = parentpath.dentry; upperdir = parentpath.dentry;
......
...@@ -222,6 +222,9 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry, ...@@ -222,6 +222,9 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
struct kstat stat; struct kstat stat;
int err; int err;
if (WARN_ON(!workdir))
return ERR_PTR(-EROFS);
err = ovl_lock_rename_workdir(workdir, upperdir); err = ovl_lock_rename_workdir(workdir, upperdir);
if (err) if (err)
goto out; goto out;
...@@ -322,6 +325,9 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, ...@@ -322,6 +325,9 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
struct dentry *newdentry; struct dentry *newdentry;
int err; int err;
if (WARN_ON(!workdir))
return -EROFS;
err = ovl_lock_rename_workdir(workdir, upperdir); err = ovl_lock_rename_workdir(workdir, upperdir);
if (err) if (err)
goto out; goto out;
...@@ -506,6 +512,9 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir) ...@@ -506,6 +512,9 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
struct dentry *opaquedir = NULL; struct dentry *opaquedir = NULL;
int err; int err;
if (WARN_ON(!workdir))
return -EROFS;
if (is_dir) { if (is_dir) {
if (OVL_TYPE_MERGE_OR_LOWER(ovl_path_type(dentry))) { if (OVL_TYPE_MERGE_OR_LOWER(ovl_path_type(dentry))) {
opaquedir = ovl_check_empty_and_clear(dentry); opaquedir = ovl_check_empty_and_clear(dentry);
......
...@@ -529,7 +529,7 @@ static int ovl_remount(struct super_block *sb, int *flags, char *data) ...@@ -529,7 +529,7 @@ static int ovl_remount(struct super_block *sb, int *flags, char *data)
{ {
struct ovl_fs *ufs = sb->s_fs_info; struct ovl_fs *ufs = sb->s_fs_info;
if (!(*flags & MS_RDONLY) && !ufs->upper_mnt) if (!(*flags & MS_RDONLY) && (!ufs->upper_mnt || !ufs->workdir))
return -EROFS; return -EROFS;
return 0; return 0;
...@@ -925,9 +925,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -925,9 +925,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry); ufs->workdir = ovl_workdir_create(ufs->upper_mnt, workpath.dentry);
err = PTR_ERR(ufs->workdir); err = PTR_ERR(ufs->workdir);
if (IS_ERR(ufs->workdir)) { if (IS_ERR(ufs->workdir)) {
pr_err("overlayfs: failed to create directory %s/%s\n", pr_warn("overlayfs: failed to create directory %s/%s (errno: %i); mounting read-only\n",
ufs->config.workdir, OVL_WORKDIR_NAME); ufs->config.workdir, OVL_WORKDIR_NAME, -err);
goto out_put_upper_mnt; sb->s_flags |= MS_RDONLY;
ufs->workdir = NULL;
} }
} }
...@@ -997,7 +998,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) ...@@ -997,7 +998,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
kfree(ufs->lower_mnt); kfree(ufs->lower_mnt);
out_put_workdir: out_put_workdir:
dput(ufs->workdir); dput(ufs->workdir);
out_put_upper_mnt:
mntput(ufs->upper_mnt); mntput(ufs->upper_mnt);
out_put_lowerpath: out_put_lowerpath:
for (i = 0; i < numlower; i++) for (i = 0; i < numlower; i++)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment