diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 955ecd4030f0..1b8721796fd4 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -43,7 +43,8 @@ static bool ovl_must_copy_xattr(const char *name)
!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN);
}
-int ovl_copy_xattr(struct super_block *sb, struct dentry *old,
+int ovl_copy_xattr(struct super_block *sb, struct user_namespace *old_user_ns,
+ struct dentry *old, struct user_namespace *new_user_ns,
struct dentry *new)
{
ssize_t list_size, size, value_size = 0;@@ -85,9 +86,9 @@ int ovl_copy_xattr(struct super_block *sb, struct dentry *old,
if (ovl_is_private_xattr(sb, name))
continue;
retry:
- size = vfs_getxattr(old, name, value, value_size);
+ size = vfs_mapped_getxattr(old_user_ns, old, name, value, value_size);
if (size == -ERANGE)
- size = vfs_getxattr(old, name, NULL, 0);
+ size = vfs_mapped_getxattr(old_user_ns, old, name, NULL, 0);
if (size < 0) {
error = size;@@ -114,7 +115,7 @@ int ovl_copy_xattr(struct super_block *sb, struct dentry *old,
error = 0;
continue; /* Discard */
}
- error = vfs_setxattr(new, name, value, size, 0);
+ error = vfs_mapped_setxattr(new_user_ns, new, name, value, size, 0);
if (error) {
if (error != -EOPNOTSUPP || ovl_must_copy_xattr(name))
break;@@ -228,17 +229,19 @@ static int ovl_copy_up_data(struct ovl_fs *ofs, struct path *old,
return error;
}
-static int ovl_set_size(struct dentry *upperdentry, struct kstat *stat)
+static int ovl_set_size(struct user_namespace *user_ns,
+ struct dentry *upperdentry, struct kstat *stat)
{
struct iattr attr = {
.ia_valid = ATTR_SIZE,
.ia_size = stat->size,
};
- return notify_change(upperdentry, &attr, NULL);
+ return notify_mapped_change(user_ns, upperdentry, &attr, NULL);
}
-static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat)
+static int ovl_set_timestamps(struct user_namespace *user_ns,
+ struct dentry *upperdentry, struct kstat *stat)
{
struct iattr attr = {
.ia_valid =@@ -247,10 +250,11 @@ static int ovl_set_timestamps(struct dentry *upperdentry, struct kstat *stat)
.ia_mtime = stat->mtime,
};
- return notify_change(upperdentry, &attr, NULL);
+ return notify_mapped_change(user_ns, upperdentry, &attr, NULL);
}
-int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat)
+int ovl_set_attr(struct user_namespace *user_ns, struct dentry *upperdentry,
+ struct kstat *stat)
{
int err = 0;
@@ -259,7 +263,7 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat)
.ia_valid = ATTR_MODE,
.ia_mode = stat->mode,
};
- err = notify_change(upperdentry, &attr, NULL);
+ err = notify_mapped_change(user_ns, upperdentry, &attr, NULL);
}
if (!err) {
struct iattr attr = {@@ -267,10 +271,10 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat)
.ia_uid = stat->uid,
.ia_gid = stat->gid,
};
- err = notify_change(upperdentry, &attr, NULL);
+ err = notify_mapped_change(user_ns, upperdentry, &attr, NULL);
}
if (!err)
- ovl_set_timestamps(upperdentry, stat);
+ ovl_set_timestamps(user_ns, upperdentry, stat);
return err;
}
@@ -356,8 +360,8 @@ int ovl_set_origin(struct dentry *dentry, struct dentry *lower,
}
/* Store file handle of @upper dir in @index dir entry */
-static int ovl_set_upper_fh(struct ovl_fs *ofs, struct dentry *upper,
- struct dentry *index)
+static int ovl_set_upper_fh(struct ovl_fs *ofs, struct user_namespace *user_ns,
+ struct dentry *upper, struct dentry *index)
{
const struct ovl_fh *fh;
int err;@@ -377,7 +381,8 @@ static int ovl_set_upper_fh(struct ovl_fs *ofs, struct dentry *upper,
*
* Caller must hold i_mutex on indexdir.
*/
-static int ovl_create_index(struct dentry *dentry, struct dentry *origin,
+static int ovl_create_index(struct user_namespace *user_ns,
+ struct dentry *dentry, struct dentry *origin,
struct dentry *upper)
{
struct dentry *indexdir = ovl_indexdir(dentry->d_sb);@@ -406,25 +411,25 @@ static int ovl_create_index(struct dentry *dentry, struct dentry *origin,
if (err)
return err;
- temp = ovl_create_temp(indexdir, OVL_CATTR(S_IFDIR | 0));
+ temp = ovl_create_temp(user_ns, indexdir, OVL_CATTR(S_IFDIR | 0));
err = PTR_ERR(temp);
if (IS_ERR(temp))
goto free_name;
- err = ovl_set_upper_fh(OVL_FS(dentry->d_sb), upper, temp);
+ err = ovl_set_upper_fh(OVL_FS(dentry->d_sb), user_ns, upper, temp);
if (err)
goto out;
- index = lookup_one_len(name.name, indexdir, name.len);
+ index = lookup_one_len_mapped(name.name, indexdir, name.len, user_ns);
if (IS_ERR(index)) {
err = PTR_ERR(index);
} else {
- err = ovl_do_rename(dir, temp, dir, index, 0);
+ err = ovl_do_rename(dir, user_ns, temp, dir, user_ns, index, 0);
dput(index);
}
out:
if (err)
- ovl_cleanup(dir, temp);
+ ovl_cleanup(user_ns, dir, temp);
dput(temp);
free_name:
kfree(name.name);@@ -441,6 +446,7 @@ struct ovl_copy_up_ctx {
struct dentry *destdir;
struct qstr destname;
struct dentry *workdir;
+ struct user_namespace *user_ns;
bool origin;
bool indexed;
bool metacopy;@@ -463,16 +469,17 @@ static int ovl_link_up(struct ovl_copy_up_ctx *c)
return err;
inode_lock_nested(udir, I_MUTEX_PARENT);
- upper = lookup_one_len(c->dentry->d_name.name, upperdir,
- c->dentry->d_name.len);
+ upper = lookup_one_len_mapped(c->dentry->d_name.name, upperdir,
+ c->dentry->d_name.len,
+ c->user_ns);
err = PTR_ERR(upper);
if (!IS_ERR(upper)) {
- err = ovl_do_link(ovl_dentry_upper(c->dentry), udir, upper);
+ err = ovl_do_link(c->user_ns, ovl_dentry_upper(c->dentry), udir, upper);
dput(upper);
if (!err) {
/* Restore timestamps on parent (best effort) */
- ovl_set_timestamps(upperdir, &c->pstat);
+ ovl_set_timestamps(c->user_ns, upperdir, &c->pstat);
ovl_dentry_set_upper_alias(c->dentry);
}
}@@ -509,7 +516,8 @@ static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp)
return err;
}
- err = ovl_copy_xattr(c->dentry->d_sb, c->lowerpath.dentry, temp);
+ err = ovl_copy_xattr(c->dentry->d_sb, mnt_user_ns(c->lowerpath.mnt),
+ c->lowerpath.dentry, c->user_ns, temp);
if (err)
return err;
@@ -535,9 +543,9 @@ static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp)
inode_lock(temp->d_inode);
if (S_ISREG(c->stat.mode))
- err = ovl_set_size(temp, &c->stat);
+ err = ovl_set_size(c->user_ns, temp, &c->stat);
if (!err)
- err = ovl_set_attr(temp, &c->stat);
+ err = ovl_set_attr(c->user_ns, temp, &c->stat);
inode_unlock(temp->d_inode);
return err;
@@ -598,7 +606,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
if (err)
goto unlock;
- temp = ovl_create_temp(c->workdir, &cattr);
+ temp = ovl_create_temp(c->user_ns, c->workdir, &cattr);
ovl_revert_cu_creds(&cc);
err = PTR_ERR(temp);
@@ -610,17 +618,18 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
goto cleanup;
if (S_ISDIR(c->stat.mode) && c->indexed) {
- err = ovl_create_index(c->dentry, c->lowerpath.dentry, temp);
+ err = ovl_create_index(c->user_ns, c->dentry, c->lowerpath.dentry, temp);
if (err)
goto cleanup;
}
- upper = lookup_one_len(c->destname.name, c->destdir, c->destname.len);
+ upper = lookup_one_len_mapped(c->destname.name, c->destdir, c->destname.len,
+ c->user_ns);
err = PTR_ERR(upper);
if (IS_ERR(upper))
goto cleanup;
- err = ovl_do_rename(wdir, temp, udir, upper, 0);
+ err = ovl_do_rename(wdir, c->user_ns, temp, udir, c->user_ns, upper, 0);
dput(upper);
if (err)
goto cleanup;@@ -637,7 +646,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
return err;
cleanup:
- ovl_cleanup(wdir, temp);
+ ovl_cleanup(c->user_ns, wdir, temp);
dput(temp);
goto unlock;
}
@@ -654,7 +663,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
if (err)
return err;
- temp = ovl_do_tmpfile(c->workdir, c->stat.mode);
+ temp = ovl_do_tmpfile(c->user_ns, c->workdir, c->stat.mode);
ovl_revert_cu_creds(&cc);
if (IS_ERR(temp))
@@ -666,10 +675,11 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
inode_lock_nested(udir, I_MUTEX_PARENT);
- upper = lookup_one_len(c->destname.name, c->destdir, c->destname.len);
+ upper = lookup_one_len_mapped(c->destname.name, c->destdir, c->destname.len,
+ c->user_ns);
err = PTR_ERR(upper);
if (!IS_ERR(upper)) {
- err = ovl_do_link(temp, udir, upper);
+ err = ovl_do_link(c->user_ns, temp, udir, upper);
dput(upper);
}
inode_unlock(udir);@@ -757,7 +767,7 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c)
/* Restore timestamps on parent (best effort) */
inode_lock(udir);
- ovl_set_timestamps(c->destdir, &c->pstat);
+ ovl_set_timestamps(c->user_ns, c->destdir, &c->pstat);
inode_unlock(udir);
ovl_dentry_set_upper_alias(c->dentry);
@@ -786,12 +796,13 @@ static bool ovl_need_meta_copy_up(struct dentry *dentry, umode_t mode,
return true;
}
-static ssize_t ovl_getxattr(struct dentry *dentry, char *name, char **value)
+static ssize_t ovl_getxattr(struct user_namespace *user_ns,
+ struct dentry *dentry, char *name, char **value)
{
ssize_t res;
char *buf;
- res = vfs_getxattr(dentry, name, NULL, 0);
+ res = vfs_mapped_getxattr(user_ns, dentry, name, NULL, 0);
if (res == -ENODATA || res == -EOPNOTSUPP)
res = 0;
@@ -800,7 +811,7 @@ static ssize_t ovl_getxattr(struct dentry *dentry, char *name, char **value)
if (!buf)
return -ENOMEM;
- res = vfs_getxattr(dentry, name, buf, res);
+ res = vfs_mapped_getxattr(user_ns, dentry, name, buf, res);
if (res < 0)
kfree(buf);
else
@@ -814,6 +825,7 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
{
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
struct path upperpath, datapath;
+ struct user_namespace *user_ns;
int err;
char *capability = NULL;
ssize_t cap_size;@@ -827,8 +839,8 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
return -EIO;
if (c->stat.size) {
- err = cap_size = ovl_getxattr(upperpath.dentry, XATTR_NAME_CAPS,
- &capability);
+ err = cap_size = ovl_getxattr(c->user_ns, upperpath.dentry,
+ XATTR_NAME_CAPS, &capability);
if (cap_size < 0)
goto out;
}@@ -841,9 +853,10 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
* Writing to upper file will clear security.capability xattr. We
* don't want that to happen for normal copy-up operation.
*/
+ user_ns = mnt_user_ns(upperpath.mnt);
if (capability) {
- err = vfs_setxattr(upperpath.dentry, XATTR_NAME_CAPS,
- capability, cap_size, 0);
+ err = vfs_mapped_setxattr(user_ns, upperpath.dentry,
+ XATTR_NAME_CAPS, capability, cap_size, 0);
if (err)
goto out_free;
}@@ -887,6 +900,7 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
ovl_path_upper(parent, &parentpath);
ctx.destdir = parentpath.dentry;
ctx.destname = dentry->d_name;
+ ctx.user_ns = mnt_user_ns(parentpath.mnt);
err = vfs_getattr(&parentpath, &ctx.pstat,
STATX_ATIME | STATX_MTIME,
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 28a075b5f5b2..23d09de00957 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -23,15 +23,16 @@ MODULE_PARM_DESC(redirect_max,
static int ovl_set_redirect(struct dentry *dentry, bool samedir);
-int ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
+int ovl_cleanup(struct user_namespace *user_ns, struct inode *wdir,
+ struct dentry *wdentry)
{
int err;
dget(wdentry);
if (d_is_dir(wdentry))
- err = ovl_do_rmdir(wdir, wdentry);
+ err = ovl_do_rmdir(user_ns, wdir, wdentry);
else
- err = ovl_do_unlink(wdir, wdentry);
+ err = ovl_do_unlink(user_ns, wdir, wdentry);
dput(wdentry);
if (err) {@@ -42,7 +43,8 @@ int ovl_cleanup(struct inode *wdir, struct dentry *wdentry)
return err;
}
-struct dentry *ovl_lookup_temp(struct dentry *workdir)
+struct dentry *ovl_lookup_temp(struct user_namespace *user_ns,
+ struct dentry *workdir)
{
struct dentry *temp;
char name[20];@@ -51,7 +53,7 @@ struct dentry *ovl_lookup_temp(struct dentry *workdir)
/* counter is allowed to wrap, since temp dentries are ephemeral */
snprintf(name, sizeof(name), "#%x", atomic_inc_return(&temp_id));
- temp = lookup_one_len(name, workdir, strlen(name));
+ temp = lookup_one_len_mapped(name, workdir, strlen(name), user_ns);
if (!IS_ERR(temp) && temp->d_inode) {
pr_err("workdir/%s already exists\n", name);
dput(temp);@@ -68,13 +70,14 @@ static struct dentry *ovl_whiteout(struct ovl_fs *ofs)
struct dentry *whiteout;
struct dentry *workdir = ofs->workdir;
struct inode *wdir = workdir->d_inode;
+ struct user_namespace *user_ns = ovl_upper_mnt_user_ns(ofs);
if (!ofs->whiteout) {
- whiteout = ovl_lookup_temp(workdir);
+ whiteout = ovl_lookup_temp(user_ns, workdir);
if (IS_ERR(whiteout))
goto out;
- err = ovl_do_whiteout(wdir, whiteout);
+ err = ovl_do_whiteout(user_ns, wdir, whiteout);
if (err) {
dput(whiteout);
whiteout = ERR_PTR(err);@@ -84,11 +87,11 @@ static struct dentry *ovl_whiteout(struct ovl_fs *ofs)
}
if (ofs->share_whiteout) {
- whiteout = ovl_lookup_temp(workdir);
+ whiteout = ovl_lookup_temp(user_ns, workdir);
if (IS_ERR(whiteout))
goto out;
- err = ovl_do_link(ofs->whiteout, wdir, whiteout);
+ err = ovl_do_link(user_ns, ofs->whiteout, wdir, whiteout);
if (!err)
goto out;
@@ -110,6 +113,7 @@ int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct inode *dir,
struct dentry *dentry)
{
struct inode *wdir = ofs->workdir->d_inode;
+ struct user_namespace *user_ns = ovl_upper_mnt_user_ns(ofs);
struct dentry *whiteout;
int err;
int flags = 0;@@ -122,28 +126,28 @@ int ovl_cleanup_and_whiteout(struct ovl_fs *ofs, struct inode *dir,
if (d_is_dir(dentry))
flags = RENAME_EXCHANGE;
- err = ovl_do_rename(wdir, whiteout, dir, dentry, flags);
+ err = ovl_do_rename(wdir, user_ns, whiteout, dir, user_ns, dentry, flags);
if (err)
goto kill_whiteout;
if (flags)
- ovl_cleanup(wdir, dentry);
+ ovl_cleanup(user_ns, wdir, dentry);
out:
dput(whiteout);
return err;
kill_whiteout:
- ovl_cleanup(wdir, whiteout);
+ ovl_cleanup(user_ns, wdir, whiteout);
goto out;
}
-static int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry,
- umode_t mode)
+static int ovl_mkdir_real(struct user_namespace *user_ns, struct inode *dir,
+ struct dentry **newdentry, umode_t mode)
{
int err;
struct dentry *d, *dentry = *newdentry;
- err = ovl_do_mkdir(dir, dentry, mode);
+ err = ovl_do_mkdir(user_ns, dir, dentry, mode);
if (err)
return err;
@@ -155,8 +159,8 @@ static int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry,
* to it unhashed and negative. If that happens, try to
* lookup a new hashed and positive dentry.
*/
- d = lookup_one_len(dentry->d_name.name, dentry->d_parent,
- dentry->d_name.len);
+ d = lookup_one_len_mapped(dentry->d_name.name, dentry->d_parent,
+ dentry->d_name.len, user_ns);
if (IS_ERR(d)) {
pr_warn("failed lookup after mkdir (%pd2, err=%i).\n",
dentry, err);@@ -168,7 +172,8 @@ static int ovl_mkdir_real(struct inode *dir, struct dentry **newdentry,
return 0;
}
-struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
+struct dentry *ovl_create_real(struct user_namespace *user_ns,
+ struct inode *dir, struct dentry *newdentry,
struct ovl_cattr *attr)
{
int err;@@ -181,28 +186,28 @@ struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
goto out;
if (attr->hardlink) {
- err = ovl_do_link(attr->hardlink, dir, newdentry);
+ err = ovl_do_link(user_ns, attr->hardlink, dir, newdentry);
} else {
switch (attr->mode & S_IFMT) {
case S_IFREG:
- err = ovl_do_create(dir, newdentry, attr->mode);
+ err = ovl_do_create(user_ns, dir, newdentry, attr->mode);
break;
case S_IFDIR:
/* mkdir is special... */
- err = ovl_mkdir_real(dir, &newdentry, attr->mode);
+ err = ovl_mkdir_real(user_ns, dir, &newdentry, attr->mode);
break;
case S_IFCHR:
case S_IFBLK:
case S_IFIFO:
case S_IFSOCK:
- err = ovl_do_mknod(dir, newdentry, attr->mode,
+ err = ovl_do_mknod(user_ns, dir, newdentry, attr->mode,
attr->rdev);
break;
case S_IFLNK:
- err = ovl_do_symlink(dir, newdentry, attr->link);
+ err = ovl_do_symlink(user_ns, dir, newdentry, attr->link);
break;
default:@@ -224,10 +229,11 @@ struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
return newdentry;
}
-struct dentry *ovl_create_temp(struct dentry *workdir, struct ovl_cattr *attr)
+struct dentry *ovl_create_temp(struct user_namespace *user_ns, struct dentry *workdir,
+ struct ovl_cattr *attr)
{
- return ovl_create_real(d_inode(workdir), ovl_lookup_temp(workdir),
- attr);
+ return ovl_create_real(user_ns, d_inode(workdir),
+ ovl_lookup_temp(user_ns, workdir), attr);
}
static int ovl_set_opaque_xerr(struct dentry *dentry, struct dentry *upper,@@ -323,16 +329,18 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
struct inode *udir = upperdir->d_inode;
struct dentry *newdentry;
+ struct user_namespace *user_ns = ovl_dentry_mnt_user_ns(dentry);
int err;
if (!attr->hardlink && !IS_POSIXACL(udir))
attr->mode &= ~current_umask();
inode_lock_nested(udir, I_MUTEX_PARENT);
- newdentry = ovl_create_real(udir,
- lookup_one_len(dentry->d_name.name,
- upperdir,
- dentry->d_name.len),
+ newdentry = ovl_create_real(user_ns, udir,
+ lookup_one_len_mapped(dentry->d_name.name,
+ upperdir,
+ dentry->d_name.len,
+ user_ns),
attr);
err = PTR_ERR(newdentry);
if (IS_ERR(newdentry))
@@ -351,7 +359,7 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
return err;
out_cleanup:
- ovl_cleanup(udir, newdentry);
+ ovl_cleanup(user_ns, udir, newdentry);
dput(newdentry);
goto out_unlock;
}
@@ -363,6 +371,7 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
struct inode *wdir = workdir->d_inode;
struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
struct inode *udir = upperdir->d_inode;
+ struct user_namespace *user_ns;
struct path upperpath;
struct dentry *upper;
struct dentry *opaquedir;
@@ -389,12 +398,13 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
if (upper->d_parent->d_inode != udir)
goto out_unlock;
- opaquedir = ovl_create_temp(workdir, OVL_CATTR(stat.mode));
+ user_ns = mnt_user_ns(upperpath.mnt);
+ opaquedir = ovl_create_temp(user_ns, workdir, OVL_CATTR(stat.mode));
err = PTR_ERR(opaquedir);
if (IS_ERR(opaquedir))
goto out_unlock;
- err = ovl_copy_xattr(dentry->d_sb, upper, opaquedir);
+ err = ovl_copy_xattr(dentry->d_sb, user_ns, upper, user_ns, opaquedir);
if (err)
goto out_cleanup;
@@ -403,17 +413,17 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
goto out_cleanup;
inode_lock(opaquedir->d_inode);
- err = ovl_set_attr(opaquedir, &stat);
+ err = ovl_set_attr(user_ns, opaquedir, &stat);
inode_unlock(opaquedir->d_inode);
if (err)
goto out_cleanup;
- err = ovl_do_rename(wdir, opaquedir, udir, upper, RENAME_EXCHANGE);
+ err = ovl_do_rename(wdir, user_ns, opaquedir, udir, user_ns, upper, RENAME_EXCHANGE);
if (err)
goto out_cleanup;
- ovl_cleanup_whiteouts(upper, list);
- ovl_cleanup(wdir, upper);
+ ovl_cleanup_whiteouts(user_ns, upper, list);
+ ovl_cleanup(user_ns, wdir, upper);
unlock_rename(workdir, upperdir);
/* dentry's upper doesn't match now, get rid of it */
@@ -422,7 +432,7 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
return opaquedir;
out_cleanup:
- ovl_cleanup(wdir, opaquedir);
+ ovl_cleanup(user_ns, wdir, opaquedir);
dput(opaquedir);
out_unlock:
unlock_rename(workdir, upperdir);
@@ -430,7 +440,8 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
return ERR_PTR(err);
}
-static int ovl_set_upper_acl(struct dentry *upperdentry, const char *name,
+static int ovl_set_upper_acl(struct user_namespace *user_ns,
+ struct dentry *upperdentry, const char *name,
const struct posix_acl *acl)
{
void *buffer;@@ -449,7 +460,7 @@ static int ovl_set_upper_acl(struct dentry *upperdentry, const char *name,
if (err < 0)
goto out_free;
- err = vfs_setxattr(upperdentry, name, buffer, size, XATTR_CREATE);
+ err = vfs_mapped_setxattr(user_ns, upperdentry, name, buffer, size, XATTR_CREATE);
out_free:
kfree(buffer);
return err;
@@ -464,6 +475,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
struct inode *udir = upperdir->d_inode;
struct dentry *upper;
struct dentry *newdentry;
+ struct user_namespace *user_ns;
int err;
struct posix_acl *acl, *default_acl;
bool hardlink = !!cattr->hardlink;
@@ -482,8 +494,9 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
if (err)
goto out;
- upper = lookup_one_len(dentry->d_name.name, upperdir,
- dentry->d_name.len);
+ user_ns = ovl_dentry_mnt_user_ns(dentry->d_parent);
+ upper = lookup_one_len_mapped(dentry->d_name.name, upperdir,
+ dentry->d_name.len, user_ns);
err = PTR_ERR(upper);
if (IS_ERR(upper))
goto out_unlock;
@@ -492,7 +505,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
if (d_is_negative(upper) || !IS_WHITEOUT(d_inode(upper)))
goto out_dput;
- newdentry = ovl_create_temp(workdir, cattr);
+ newdentry = ovl_create_temp(user_ns, workdir, cattr);
err = PTR_ERR(newdentry);
if (IS_ERR(newdentry))
goto out_dput;
@@ -508,18 +521,18 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
.ia_mode = cattr->mode,
};
inode_lock(newdentry->d_inode);
- err = notify_change(newdentry, &attr, NULL);
+ err = notify_mapped_change(user_ns, newdentry, &attr, NULL);
inode_unlock(newdentry->d_inode);
if (err)
goto out_cleanup;
}
if (!hardlink) {
- err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_ACCESS,
+ err = ovl_set_upper_acl(user_ns, newdentry, XATTR_NAME_POSIX_ACL_ACCESS,
acl);
if (err)
goto out_cleanup;
- err = ovl_set_upper_acl(newdentry, XATTR_NAME_POSIX_ACL_DEFAULT,
+ err = ovl_set_upper_acl(user_ns, newdentry, XATTR_NAME_POSIX_ACL_DEFAULT,
default_acl);
if (err)
goto out_cleanup;@@ -530,14 +543,14 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
if (err)
goto out_cleanup;
- err = ovl_do_rename(wdir, newdentry, udir, upper,
+ err = ovl_do_rename(wdir, user_ns, newdentry, udir, user_ns, upper,
RENAME_EXCHANGE);
if (err)
goto out_cleanup;
- ovl_cleanup(wdir, upper);
+ ovl_cleanup(user_ns, wdir, upper);
} else {
- err = ovl_do_rename(wdir, newdentry, udir, upper, 0);
+ err = ovl_do_rename(wdir, user_ns, newdentry, udir, user_ns, upper, 0);
if (err)
goto out_cleanup;
}@@ -556,7 +569,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
return err;
out_cleanup:
- ovl_cleanup(wdir, newdentry);
+ ovl_cleanup(user_ns, wdir, newdentry);
dput(newdentry);
goto out_dput;
}
@@ -762,8 +775,9 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
if (err)
goto out_dput;
- upper = lookup_one_len(dentry->d_name.name, upperdir,
- dentry->d_name.len);
+ upper = lookup_one_len_mapped(dentry->d_name.name, upperdir,
+ dentry->d_name.len,
+ ovl_upper_mnt_user_ns(ofs));
err = PTR_ERR(upper);
if (IS_ERR(upper))
goto out_unlock;
@@ -797,6 +811,7 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir,
{
struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent);
struct inode *dir = upperdir->d_inode;
+ struct user_namespace *user_ns = ovl_dentry_mnt_user_ns(dentry->d_parent);
struct dentry *upper;
struct dentry *opaquedir = NULL;
int err;@@ -809,8 +824,8 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir,
}
inode_lock_nested(dir, I_MUTEX_PARENT);
- upper = lookup_one_len(dentry->d_name.name, upperdir,
- dentry->d_name.len);
+ upper = lookup_one_len_mapped(dentry->d_name.name, upperdir,
+ dentry->d_name.len, user_ns);
err = PTR_ERR(upper);
if (IS_ERR(upper))
goto out_unlock;
@@ -821,9 +836,9 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir,
goto out_dput_upper;
if (is_dir)
- err = vfs_rmdir(dir, upper);
+ err = vfs_mapped_rmdir(user_ns, dir, upper);
else
- err = vfs_unlink(dir, upper, NULL);
+ err = vfs_mapped_unlink(user_ns, dir, upper, NULL);
ovl_dir_modified(dentry->d_parent, ovl_type_origin(dentry));
/*
@@ -920,7 +935,8 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
*/
upperdentry = ovl_dentry_upper(dentry);
if (upperdentry)
- ovl_copyattr(d_inode(upperdentry), d_inode(dentry));
+ ovl_copyattr(ovl_inode_real_user_ns(d_inode(dentry)),
+ d_inode(upperdentry), d_inode(dentry));
out_drop_write:
ovl_drop_write(dentry);
@@ -1078,6 +1094,7 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
struct dentry *new_upperdir;
struct dentry *olddentry;
struct dentry *newdentry;
+ struct user_namespace *old_user_ns, *new_user_ns;
struct dentry *trap;
bool old_opaque;
bool new_opaque;
@@ -1181,10 +1198,12 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
}
}
+ old_user_ns = ovl_dentry_mnt_user_ns(old->d_parent);
+ new_user_ns = ovl_dentry_mnt_user_ns(new->d_parent);
trap = lock_rename(new_upperdir, old_upperdir);
- olddentry = lookup_one_len(old->d_name.name, old_upperdir,
- old->d_name.len);
+ olddentry = lookup_one_len_mapped(old->d_name.name, old_upperdir,
+ old->d_name.len, old_user_ns);
err = PTR_ERR(olddentry);
if (IS_ERR(olddentry))
goto out_unlock;
@@ -1193,8 +1212,8 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
if (!ovl_matches_upper(old, olddentry))
goto out_dput_old;
- newdentry = lookup_one_len(new->d_name.name, new_upperdir,
- new->d_name.len);
+ newdentry = lookup_one_len_mapped(new->d_name.name, new_upperdir,
+ new->d_name.len, new_user_ns);
err = PTR_ERR(newdentry);
if (IS_ERR(newdentry))
goto out_dput_old;
@@ -1241,13 +1260,13 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
if (err)
goto out_dput;
- err = ovl_do_rename(old_upperdir->d_inode, olddentry,
- new_upperdir->d_inode, newdentry, flags);
+ err = ovl_do_rename(old_upperdir->d_inode, old_user_ns, olddentry,
+ new_upperdir->d_inode, new_user_ns, newdentry, flags);
if (err)
goto out_dput;
if (cleanup_whiteout)
- ovl_cleanup(old_upperdir->d_inode, newdentry);
+ ovl_cleanup(old_user_ns, old_upperdir->d_inode, newdentry);
if (overwrite && d_inode(new)) {
if (new_is_dir)@@ -1262,9 +1281,9 @@ static int ovl_rename(struct inode *olddir, struct dentry *old,
(d_inode(new) && ovl_type_origin(new)));
/* copy ctime: */
- ovl_copyattr(d_inode(olddentry), d_inode(old));
+ ovl_copyattr(old_user_ns, d_inode(olddentry), d_inode(old));
if (d_inode(new) && ovl_dentry_upper(new))
- ovl_copyattr(d_inode(newdentry), d_inode(new));
+ ovl_copyattr(new_user_ns, d_inode(newdentry), d_inode(new));
out_dput:
dput(newdentry);
diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
index ed35be3fafc6..15620ddc458d 100644
--- a/fs/overlayfs/export.c
+++ b/fs/overlayfs/export.c
@@ -389,7 +389,8 @@ static struct dentry *ovl_lookup_real_one(struct dentry *connected,
* pointer because we hold no lock on the real dentry.
*/
take_dentry_name_snapshot(&name, real);
- this = lookup_one_len(name.name.name, connected, name.name.len);
+ this = lookup_one_len_mapped(name.name.name, connected, name.name.len,
+ mnt_user_ns(layer->mnt));
err = PTR_ERR(this);
if (IS_ERR(this)) {
goto fail;diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c
index efccb7c1f9bc..a685c73b684a 100644
--- a/fs/overlayfs/file.c
+++ b/fs/overlayfs/file.c
@@ -40,6 +40,8 @@ static struct file *ovl_open_realfile(const struct file *file,
struct inode *realinode)
{
struct inode *inode = file_inode(file);
+ struct path realpath;
+ struct user_namespace *user_ns;
struct file *realfile;
const struct cred *old_cred;
int flags = file->f_flags | OVL_OPEN_FLAGS;@@ -49,11 +51,13 @@ static struct file *ovl_open_realfile(const struct file *file,
if (flags & O_APPEND)
acc_mode |= MAY_APPEND;
+ ovl_path_real(file_dentry(file), &realpath);
+ user_ns = mnt_user_ns(realpath.mnt);
old_cred = ovl_override_creds(inode->i_sb);
- err = inode_permission(realinode, MAY_OPEN | acc_mode);
+ err = mapped_inode_permission(user_ns, realinode, MAY_OPEN | acc_mode);
if (err) {
realfile = ERR_PTR(err);
- } else if (!inode_owner_or_capable(realinode)) {
+ } else if (!mapped_inode_owner_or_capable(user_ns, realinode)) {
realfile = ERR_PTR(-EPERM);
} else {
realfile = open_with_fake_path(&file->f_path, flags, realinode,@@ -269,7 +273,8 @@ static void ovl_aio_cleanup_handler(struct ovl_aio_req *aio_req)
__sb_writers_acquired(file_inode(iocb->ki_filp)->i_sb,
SB_FREEZE_WRITE);
file_end_write(iocb->ki_filp);
- ovl_copyattr(ovl_inode_real(inode), inode);
+ ovl_copyattr(ovl_inode_real_user_ns(inode),
+ ovl_inode_real(inode), inode);
}
orig_iocb->ki_pos = iocb->ki_pos;
@@ -345,7 +350,7 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
inode_lock(inode);
/* Update mode */
- ovl_copyattr(ovl_inode_real(inode), inode);
+ ovl_copyattr(ovl_inode_real_user_ns(inode), ovl_inode_real(inode), inode);
ret = file_remove_privs(file);
if (ret)
goto out_unlock;
@@ -364,7 +369,8 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
ovl_iocb_to_rwf(ifl));
file_end_write(real.file);
/* Update size */
- ovl_copyattr(ovl_inode_real(inode), inode);
+ ovl_copyattr(ovl_inode_real_user_ns(inode),
+ ovl_inode_real(inode), inode);
} else {
struct ovl_aio_req *aio_req;
@@ -511,7 +517,7 @@ static long ovl_fallocate(struct file *file, int mode, loff_t offset, loff_t len
revert_creds(old_cred);
/* Update size */
- ovl_copyattr(ovl_inode_real(inode), inode);
+ ovl_copyattr(ovl_inode_real_user_ns(inode), ovl_inode_real(inode), inode);
fdput(real);
@@ -582,7 +588,7 @@ static long ovl_ioctl_set_flags(struct file *file, unsigned int cmd,
struct inode *inode = file_inode(file);
unsigned int oldflags;
- if (!inode_owner_or_capable(inode))
+ if (!mapped_inode_owner_or_capable(mnt_user_ns(file->f_path.mnt), inode))
return -EACCES;
ret = mnt_want_write_file(file);
@@ -744,7 +750,8 @@ static loff_t ovl_copyfile(struct file *file_in, loff_t pos_in,
revert_creds(old_cred);
/* Update size */
- ovl_copyattr(ovl_inode_real(inode_out), inode_out);
+ ovl_copyattr(ovl_inode_real_user_ns(inode_out),
+ ovl_inode_real(inode_out), inode_out);
fdput(real_in);
fdput(real_out);
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index b584dca845ba..b6c8b904f0e7 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -9,6 +9,7 @@
#include <linux/cred.h>
#include <linux/xattr.h>
#include <linux/posix_acl.h>
+#include <linux/posix_acl_xattr.h>
#include <linux/ratelimit.h>
#include <linux/fiemap.h>
#include "overlayfs.h"
@@ -46,6 +47,7 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
err = ovl_copy_up_with_data(dentry);
if (!err) {
struct inode *winode = NULL;
+ struct user_namespace *upper_user_ns;
upperdentry = ovl_dentry_upper(dentry);
@@ -77,12 +79,20 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
*/
attr->ia_valid &= ~ATTR_OPEN;
+ upper_user_ns = ovl_upper_mnt_user_ns(OVL_FS(dentry->d_sb));
+
+ if (attr->ia_valid & ATTR_UID)
+ attr->ia_uid = kuid_from_mnt(upper_user_ns, attr->ia_uid);
+ if (attr->ia_valid & ATTR_GID)
+ attr->ia_gid = kgid_from_mnt(upper_user_ns, attr->ia_gid);
+
inode_lock(upperdentry->d_inode);
old_cred = ovl_override_creds(dentry->d_sb);
- err = notify_change(upperdentry, attr, NULL);
+ err = notify_mapped_change(upper_user_ns, upperdentry, attr, NULL);
revert_creds(old_cred);
if (!err)
- ovl_copyattr(upperdentry->d_inode, dentry->d_inode);
+ ovl_copyattr(upper_user_ns, upperdentry->d_inode,
+ dentry->d_inode);
inode_unlock(upperdentry->d_inode);
if (winode)
@@ -281,6 +291,7 @@ int ovl_permission(struct inode *inode, int mask)
{
struct inode *upperinode = ovl_inode_upper(inode);
struct inode *realinode = upperinode ?: ovl_inode_lower(inode);
+ struct user_namespace *user_ns;
const struct cred *old_cred;
int err;
@@ -290,6 +301,11 @@ int ovl_permission(struct inode *inode, int mask)
return -ECHILD;
}
+ if (upperinode)
+ user_ns = ovl_upper_mnt_user_ns(OVL_FS(inode->i_sb));
+ else
+ user_ns = OVL_I(inode)->lower_user_ns;
+
/*
* Check overlay inode with the creds of task and underlying inode
* with creds of mounter
@@ -298,6 +314,7 @@ int ovl_permission(struct inode *inode, int mask)
if (err)
return err;
+ /* Handle idmapped lower mounts. */
old_cred = ovl_override_creds(inode->i_sb);
if (!upperinode &&
!special_file(realinode->i_mode) && mask & MAY_WRITE) {@@ -305,7 +322,7 @@ int ovl_permission(struct inode *inode, int mask)
/* Make sure mounter can read file for copy up later */
mask |= MAY_READ;
}
- err = inode_permission(realinode, mask);
+ err = mapped_inode_permission(user_ns, realinode, mask);
revert_creds(old_cred);
return err;
@@ -337,16 +354,23 @@ int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
int err;
+ void *val = NULL;
struct dentry *upperdentry = ovl_i_dentry_upper(inode);
struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
+ struct user_namespace *user_ns;
const struct cred *old_cred;
err = ovl_want_write(dentry);
if (err)
goto out;
+ if (upperdentry)
+ user_ns = ovl_upper_mnt_user_ns(OVL_FS(inode->i_sb));
+ else
+ user_ns = OVL_I(inode)->lower_user_ns;
+
if (!value && !upperdentry) {
- err = vfs_getxattr(realdentry, name, NULL, 0);
+ err = vfs_mapped_getxattr(user_ns, realdentry, name, NULL, 0);
if (err < 0)
goto out_drop_write;
}@@ -360,19 +384,34 @@ int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
}
old_cred = ovl_override_creds(dentry->d_sb);
- if (value)
- err = vfs_setxattr(realdentry, name, value, size, flags);
- else {
+ if (value) {
+ val = kmalloc(size, GFP_KERNEL);
+ if (!val)
+ goto out_drop_write;
+ memcpy(val, value, size);
+
+ if ((strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
+ (strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
+ posix_acl_fix_xattr_from_user(user_ns, val, size);
+ else if (strcmp(name, XATTR_NAME_CAPS) == 0) {
+ err = cap_convert_nscap(user_ns, realdentry, &val, size);
+ if (err < 0)
+ goto out_drop_write;
+ size = err;
+ }
+ err = vfs_mapped_setxattr(user_ns, realdentry, name, val, size, flags);
+ } else {
WARN_ON(flags != XATTR_REPLACE);
- err = vfs_removexattr(realdentry, name);
+ err = vfs_mapped_removexattr(user_ns, realdentry, name);
}
revert_creds(old_cred);
/* copy c/mtime */
- ovl_copyattr(d_inode(realdentry), inode);
+ ovl_copyattr(user_ns, d_inode(realdentry), inode);
out_drop_write:
ovl_drop_write(dentry);
+ kfree(val);
out:
return err;
}@@ -382,11 +421,22 @@ int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
{
ssize_t res;
const struct cred *old_cred;
- struct dentry *realdentry =
- ovl_i_dentry_upper(inode) ?: ovl_dentry_lower(dentry);
+ struct dentry *realdentry = ovl_i_dentry_upper(inode);
+ struct user_namespace *user_ns;
+
+
+ if (realdentry) {
+ user_ns = ovl_upper_mnt_user_ns(OVL_FS(inode->i_sb));
+ } else {
+ realdentry = ovl_dentry_lower(dentry);
+ user_ns = OVL_I(inode)->lower_user_ns;
+ }
old_cred = ovl_override_creds(dentry->d_sb);
- res = vfs_getxattr(realdentry, name, value, size);
+ res = vfs_mapped_getxattr(user_ns, realdentry, name, value, size);
+ if ((strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
+ (strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
+ posix_acl_fix_xattr_to_user(user_ns, value, size);
revert_creds(old_cred);
return res;
}@@ -634,13 +684,15 @@ void ovl_inode_init(struct inode *inode, struct ovl_inode_params *oip,
if (oip->upperdentry)
OVL_I(inode)->__upperdentry = oip->upperdentry;
- if (oip->lowerpath && oip->lowerpath->dentry)
+ if (oip->lowerpath && oip->lowerpath->dentry) {
OVL_I(inode)->lower = igrab(d_inode(oip->lowerpath->dentry));
+ OVL_I(inode)->lower_user_ns = get_user_ns(mnt_user_ns(oip->lowerpath->layer->mnt));
+ }
if (oip->lowerdata)
OVL_I(inode)->lowerdata = igrab(d_inode(oip->lowerdata));
realinode = ovl_inode_real(inode);
- ovl_copyattr(realinode, inode);
+ ovl_copyattr(ovl_inode_real_user_ns(inode), realinode, inode);
ovl_copyflags(realinode, inode);
ovl_map_ino(inode, ino, fsid);
}@@ -751,8 +803,8 @@ unsigned int ovl_get_nlink(struct ovl_fs *ofs, struct dentry *lowerdentry,
if (!lowerdentry || !upperdentry || d_inode(lowerdentry)->i_nlink == 1)
return fallback;
- err = ovl_do_getxattr(ofs, upperdentry, OVL_XATTR_NLINK,
- &buf, sizeof(buf) - 1);
+ err = ovl_do_getxattr(ofs, ovl_upper_mnt_user_ns(ofs), upperdentry,
+ OVL_XATTR_NLINK, &buf, sizeof(buf) - 1);
if (err < 0)
goto fail;
@@ -956,6 +1008,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL;
struct inode *inode;
struct dentry *lowerdentry = lowerpath ? lowerpath->dentry : NULL;
+ struct user_namespace *user_ns = ovl_upper_mnt_user_ns(OVL_FS(sb));
bool bylower = ovl_hash_bylower(sb, upperdentry, lowerdentry,
oip->index);
int fsid = bylower ? lowerpath->layer->fsid : 0;
@@ -1028,8 +1081,10 @@ struct inode *ovl_get_inode(struct super_block *sb,
/* Check for non-merge dir that may have whiteouts */
if (is_dir) {
+ if (!upperdentry)
+ user_ns = mnt_user_ns(lowerpath->layer->mnt);
if (((upperdentry && lowerdentry) || oip->numlower > 1) ||
- ovl_check_origin_xattr(ofs, upperdentry ?: lowerdentry)) {
+ ovl_check_origin_xattr(ofs, user_ns, upperdentry ?: lowerdentry)) {
ovl_set_flag(OVL_WHITEOUTS, inode);
}
}diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
index a6162c4076db..4a5e9ef6524b 100644
--- a/fs/overlayfs/namei.c
+++ b/fs/overlayfs/namei.c
@@ -25,14 +25,15 @@ struct ovl_lookup_data {
bool metacopy;
};
-static int ovl_check_redirect(struct dentry *dentry, struct ovl_lookup_data *d,
+static int ovl_check_redirect(struct user_namespace *mnt_user_ns,
+ struct dentry *dentry, struct ovl_lookup_data *d,
size_t prelen, const char *post)
{
int res;
char *buf;
struct ovl_fs *ofs = OVL_FS(d->sb);
- buf = ovl_get_redirect_xattr(ofs, dentry, prelen + strlen(post));
+ buf = ovl_get_redirect_xattr(ofs, mnt_user_ns, dentry, prelen + strlen(post));
if (IS_ERR_OR_NULL(buf))
return PTR_ERR(buf);
@@ -110,8 +111,9 @@ static struct ovl_fh *ovl_get_fh(struct ovl_fs *ofs, struct dentry *dentry,
{
int res, err;
struct ovl_fh *fh = NULL;
+ struct user_namespace *user_ns = ovl_upper_mnt_user_ns(ofs);
- res = ovl_do_getxattr(ofs, dentry, ox, NULL, 0);
+ res = ovl_do_getxattr(ofs, user_ns, dentry, ox, NULL, 0);
if (res < 0) {
if (res == -ENODATA || res == -EOPNOTSUPP)
return NULL;@@ -125,7 +127,7 @@ static struct ovl_fh *ovl_get_fh(struct ovl_fs *ofs, struct dentry *dentry,
if (!fh)
return ERR_PTR(-ENOMEM);
- res = ovl_do_getxattr(ofs, dentry, ox, fh->buf, res);
+ res = ovl_do_getxattr(ofs, user_ns, dentry, ox, fh->buf, res);
if (res < 0)
goto fail;
@@ -188,16 +190,19 @@ struct dentry *ovl_decode_real_fh(struct ovl_fh *fh, struct vfsmount *mnt,
return real;
}
-static bool ovl_is_opaquedir(struct super_block *sb, struct dentry *dentry)
+static bool ovl_is_opaquedir(struct super_block *sb,
+ struct user_namespace *user_ns,
+ struct dentry *dentry)
{
- return ovl_check_dir_xattr(sb, dentry, OVL_XATTR_OPAQUE);
+ return ovl_check_dir_xattr(sb, user_ns, dentry, OVL_XATTR_OPAQUE);
}
static struct dentry *ovl_lookup_positive_unlocked(const char *name,
struct dentry *base, int len,
- bool drop_negative)
+ bool drop_negative,
+ struct user_namespace *mnt_user_ns)
{
- struct dentry *ret = lookup_one_len_unlocked(name, base, len);
+ struct dentry *ret = lookup_one_len_mapped_unlocked(name, base, len, mnt_user_ns);
if (!IS_ERR(ret) && d_flags_negative(smp_load_acquire(&ret->d_flags))) {
if (drop_negative && ret->d_lockref.count == 1) {@@ -216,13 +221,14 @@ static struct dentry *ovl_lookup_positive_unlocked(const char *name,
static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
const char *name, unsigned int namelen,
size_t prelen, const char *post,
- struct dentry **ret, bool drop_negative)
+ struct dentry **ret, bool drop_negative,
+ struct user_namespace *mnt_user_ns)
{
struct dentry *this;
int err;
bool last_element = !post[0];
- this = ovl_lookup_positive_unlocked(name, base, namelen, drop_negative);
+ this = ovl_lookup_positive_unlocked(name, base, namelen, drop_negative, mnt_user_ns);
if (IS_ERR(this)) {
err = PTR_ERR(this);
this = NULL;@@ -253,7 +259,7 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
d->stop = true;
goto put_and_out;
}
- err = ovl_check_metacopy_xattr(OVL_FS(d->sb), this);
+ err = ovl_check_metacopy_xattr(OVL_FS(d->sb), mnt_user_ns, this);
if (err < 0)
goto out_err;
@@ -273,14 +279,14 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
if (d->last)
goto out;
- if (ovl_is_opaquedir(d->sb, this)) {
+ if (ovl_is_opaquedir(d->sb, mnt_user_ns, this)) {
d->stop = true;
if (last_element)
d->opaque = true;
goto out;
}
}
- err = ovl_check_redirect(this, d, prelen, post);
+ err = ovl_check_redirect(mnt_user_ns, this, d, prelen, post);
if (err)
goto out_err;
out:@@ -298,7 +304,8 @@ static int ovl_lookup_single(struct dentry *base, struct ovl_lookup_data *d,
}
static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
- struct dentry **ret, bool drop_negative)
+ struct dentry **ret, bool drop_negative,
+ struct user_namespace *mnt_user_ns)
{
/* Counting down from the end, since the prefix can change */
size_t rem = d->name.len - 1;@@ -307,7 +314,7 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
if (d->name.name[0] != '/')
return ovl_lookup_single(base, d, d->name.name, d->name.len,
- 0, "", ret, drop_negative);
+ 0, "", ret, drop_negative, mnt_user_ns);
while (!IS_ERR_OR_NULL(base) && d_can_lookup(base)) {
const char *s = d->name.name + d->name.len - rem;@@ -321,7 +328,7 @@ static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
err = ovl_lookup_single(base, d, s, thislen,
d->name.len - rem, next, &base,
- drop_negative);
+ drop_negative, mnt_user_ns);
dput(dentry);
if (err)
return err;
@@ -666,7 +673,8 @@ struct dentry *ovl_get_index_fh(struct ovl_fs *ofs, struct ovl_fh *fh)
if (err)
return ERR_PTR(err);
- index = lookup_positive_unlocked(name.name, ofs->indexdir, name.len);
+ index = lookup_positive_mapped_unlocked(name.name, ofs->indexdir, name.len,
+ ovl_upper_mnt_user_ns(ofs));
kfree(name.name);
if (IS_ERR(index)) {
if (PTR_ERR(index) == -ENOENT)@@ -698,7 +706,8 @@ struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper,
if (err)
return ERR_PTR(err);
- index = lookup_positive_unlocked(name.name, ofs->indexdir, name.len);
+ index = lookup_positive_mapped_unlocked(name.name, ofs->indexdir, name.len,
+ ovl_upper_mnt_user_ns(ofs));
if (IS_ERR(index)) {
err = PTR_ERR(index);
if (err == -ENOENT) {@@ -798,7 +807,7 @@ static int ovl_fix_origin(struct ovl_fs *ofs, struct dentry *dentry,
{
int err;
- if (ovl_check_origin_xattr(ofs, upper))
+ if (ovl_check_origin_xattr(ofs, ovl_upper_mnt_user_ns(ofs), upper))
return 0;
err = ovl_want_write(dentry);@@ -818,6 +827,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
{
struct ovl_entry *oe;
const struct cred *old_cred;
+ struct user_namespace *user_ns;
struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
struct ovl_entry *poe = dentry->d_parent->d_fsdata;
struct ovl_entry *roe = dentry->d_sb->s_root->d_fsdata;@@ -850,7 +860,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
old_cred = ovl_override_creds(dentry->d_sb);
upperdir = ovl_dentry_upper(dentry->d_parent);
if (upperdir) {
- err = ovl_lookup_layer(upperdir, &d, &upperdentry, true);
+ user_ns = ovl_upper_mnt_user_ns(ofs);
+ err = ovl_lookup_layer(upperdir, &d, &upperdentry, true, user_ns);
if (err)
goto out;
@@ -905,7 +916,8 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
else
d.last = lower.layer->idx == roe->numlower;
- err = ovl_lookup_layer(lower.dentry, &d, &this, false);
+ user_ns = mnt_user_ns(lower.layer->mnt);
+ err = ovl_lookup_layer(lower.dentry, &d, &this, false, user_ns);
if (err)
goto out_put;
@@ -1062,14 +1074,15 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
if (upperdentry)
ovl_dentry_set_upper_alias(dentry);
else if (index) {
+ struct user_namespace *upper_user_ns = ovl_upper_mnt_user_ns(ofs);
upperdentry = dget(index);
- upperredirect = ovl_get_redirect_xattr(ofs, upperdentry, 0);
+ upperredirect = ovl_get_redirect_xattr(ofs, upper_user_ns, upperdentry, 0);
if (IS_ERR(upperredirect)) {
err = PTR_ERR(upperredirect);
upperredirect = NULL;
goto out_free_oe;
}
- err = ovl_check_metacopy_xattr(ofs, upperdentry);
+ err = ovl_check_metacopy_xattr(ofs, upper_user_ns, upperdentry);
if (err < 0)
goto out_free_oe;
uppermetacopy = err;@@ -1153,9 +1166,10 @@ bool ovl_lower_positive(struct dentry *dentry)
for (i = 0; !done && !positive && i < poe->numlower; i++) {
struct dentry *this;
struct dentry *lowerdir = poe->lowerstack[i].dentry;
+ struct user_namespace *user_ns = mnt_user_ns(poe->lowerstack[i].layer->mnt);
- this = lookup_positive_unlocked(name->name, lowerdir,
- name->len);
+ this = lookup_positive_mapped_unlocked(name->name, lowerdir,
+ name->len, user_ns);
if (IS_ERR(this)) {
switch (PTR_ERR(this)) {
case -ENOENT:diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 30ee48ddfaa2..63c257c3bfa8 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -7,6 +7,7 @@
#include <linux/kernel.h>
#include <linux/uuid.h>
#include <linux/fs.h>
+#include <linux/mount.h>
#include "ovl_entry.h"
#undef pr_fmt
@@ -119,72 +120,90 @@ static inline const char *ovl_xattr(struct ovl_fs *ofs, enum ovl_xattr ox)
return ovl_xattr_table[ox];
}
-static inline int ovl_do_rmdir(struct inode *dir, struct dentry *dentry)
+static inline struct user_namespace *ovl_upper_mnt_user_ns(struct ovl_fs *ofs)
{
- int err = vfs_rmdir(dir, dentry);
+ return mnt_user_ns(ovl_upper_mnt(ofs));
+}
+
+static inline struct user_namespace *ovl_dentry_mnt_user_ns(struct dentry *dentry)
+{
+ return mnt_user_ns(ovl_upper_mnt(OVL_FS(dentry->d_sb)));
+}
+
+static inline int ovl_do_rmdir(struct user_namespace *user_ns,
+ struct inode *dir, struct dentry *dentry)
+{
+ int err = vfs_mapped_rmdir(user_ns, dir, dentry);
pr_debug("rmdir(%pd2) = %i\n", dentry, err);
return err;
}
-static inline int ovl_do_unlink(struct inode *dir, struct dentry *dentry)
+static inline int ovl_do_unlink(struct user_namespace *user_ns,
+ struct inode *dir, struct dentry *dentry)
{
- int err = vfs_unlink(dir, dentry, NULL);
+ int err = vfs_mapped_unlink(user_ns, dir, dentry, NULL);
pr_debug("unlink(%pd2) = %i\n", dentry, err);
return err;
}
-static inline int ovl_do_link(struct dentry *old_dentry, struct inode *dir,
+static inline int ovl_do_link(struct user_namespace *user_ns,
+ struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry)
{
- int err = vfs_link(old_dentry, dir, new_dentry, NULL);
+ int err = vfs_mapped_link(old_dentry, user_ns, dir, new_dentry, NULL);
pr_debug("link(%pd2, %pd2) = %i\n", old_dentry, new_dentry, err);
return err;
}
-static inline int ovl_do_create(struct inode *dir, struct dentry *dentry,
+static inline int ovl_do_create(struct user_namespace *user_ns,
+ struct inode *dir, struct dentry *dentry,
umode_t mode)
{
- int err = vfs_create(dir, dentry, mode, true);
+ int err = vfs_mapped_create(user_ns, dir, dentry, mode, true);
pr_debug("create(%pd2, 0%o) = %i\n", dentry, mode, err);
return err;
}
-static inline int ovl_do_mkdir(struct inode *dir, struct dentry *dentry,
+static inline int ovl_do_mkdir(struct user_namespace *user_ns,
+ struct inode *dir, struct dentry *dentry,
umode_t mode)
{
- int err = vfs_mkdir(dir, dentry, mode);
+ int err = vfs_mapped_mkdir(user_ns, dir, dentry, mode);
pr_debug("mkdir(%pd2, 0%o) = %i\n", dentry, mode, err);
return err;
}
-static inline int ovl_do_mknod(struct inode *dir, struct dentry *dentry,
+static inline int ovl_do_mknod(struct user_namespace *user_ns,
+ struct inode *dir, struct dentry *dentry,
umode_t mode, dev_t dev)
{
- int err = vfs_mknod(dir, dentry, mode, dev);
+ int err = vfs_mapped_mknod(user_ns, dir, dentry, mode, dev);
pr_debug("mknod(%pd2, 0%o, 0%o) = %i\n", dentry, mode, dev, err);
return err;
}
-static inline int ovl_do_symlink(struct inode *dir, struct dentry *dentry,
+static inline int ovl_do_symlink(struct user_namespace *user_ns,
+ struct inode *dir, struct dentry *dentry,
const char *oldname)
{
- int err = vfs_symlink(dir, dentry, oldname);
+ int err = vfs_mapped_symlink(user_ns, dir, dentry, oldname);
pr_debug("symlink(\"%s\", %pd2) = %i\n", oldname, dentry, err);
return err;
}
-static inline ssize_t ovl_do_getxattr(struct ovl_fs *ofs, struct dentry *dentry,
- enum ovl_xattr ox, void *value,
- size_t size)
+static inline ssize_t ovl_do_getxattr(struct ovl_fs *ofs,
+ struct user_namespace *user_ns,
+ struct dentry *dentry, enum ovl_xattr ox,
+ void *value, size_t size)
{
const char *name = ovl_xattr(ofs, ox);
- return vfs_getxattr(dentry, name, value, size);
+ return vfs_mapped_getxattr(user_ns, dentry, name, value, size);
}
static inline int ovl_do_setxattr(struct ovl_fs *ofs, struct dentry *dentry,@@ -192,7 +211,8 @@ static inline int ovl_do_setxattr(struct ovl_fs *ofs, struct dentry *dentry,
size_t size)
{
const char *name = ovl_xattr(ofs, ox);
- int err = vfs_setxattr(dentry, name, value, size, 0);
+ struct user_namespace *user_ns = ovl_upper_mnt_user_ns(ofs);
+ int err = vfs_mapped_setxattr(user_ns, dentry, name, value, size, 0);
pr_debug("setxattr(%pd2, \"%s\", \"%*pE\", %zu, 0) = %i\n",
dentry, name, min((int)size, 48), value, size, err);
return err;@@ -202,19 +222,31 @@ static inline int ovl_do_removexattr(struct ovl_fs *ofs, struct dentry *dentry,
enum ovl_xattr ox)
{
const char *name = ovl_xattr(ofs, ox);
- int err = vfs_removexattr(dentry, name);
+ struct user_namespace *user_ns = ovl_upper_mnt_user_ns(ofs);
+ int err = vfs_mapped_removexattr(user_ns, dentry, name);
pr_debug("removexattr(%pd2, \"%s\") = %i\n", dentry, name, err);
return err;
}
-static inline int ovl_do_rename(struct inode *olddir, struct dentry *olddentry,
- struct inode *newdir, struct dentry *newdentry,
- unsigned int flags)
+static inline int ovl_do_rename(struct inode *olddir,
+ struct user_namespace *old_user_ns,
+ struct dentry *olddentry, struct inode *newdir,
+ struct user_namespace *new_user_ns,
+ struct dentry *newdentry, unsigned int flags)
{
int err;
+ struct renamedata data = {
+ .old_dir = olddir,
+ .old_dentry = olddentry,
+ .old_user_ns = old_user_ns,
+ .new_dir = newdir,
+ .new_dentry = newdentry,
+ .new_user_ns = new_user_ns,
+ .flags = flags,
+ };
pr_debug("rename(%pd2, %pd2, 0x%x)\n", olddentry, newdentry, flags);
- err = vfs_rename(olddir, olddentry, newdir, newdentry, NULL, flags);
+ err = vfs_mapped_rename(&data);
if (err) {
pr_debug("...rename(%pd2, %pd2, ...) = %i\n",
olddentry, newdentry, err);@@ -222,16 +254,18 @@ static inline int ovl_do_rename(struct inode *olddir, struct dentry *olddentry,
return err;
}
-static inline int ovl_do_whiteout(struct inode *dir, struct dentry *dentry)
+static inline int ovl_do_whiteout(struct user_namespace *user_ns,
+ struct inode *dir, struct dentry *dentry)
{
- int err = vfs_whiteout(&init_user_ns, dir, dentry);
+ int err = vfs_whiteout(user_ns, dir, dentry);
pr_debug("whiteout(%pd2) = %i\n", dentry, err);
return err;
}
-static inline struct dentry *ovl_do_tmpfile(struct dentry *dentry, umode_t mode)
+static inline struct dentry *ovl_do_tmpfile(struct user_namespace *user_ns,
+ struct dentry *dentry, umode_t mode)
{
- struct dentry *ret = vfs_tmpfile(dentry, mode, 0);
+ struct dentry *ret = vfs_mapped_tmpfile(user_ns, dentry, mode, 0);
int err = PTR_ERR_OR_ZERO(ret);
pr_debug("tmpfile(%pd2, 0%o) = %i\n", dentry, mode, err);@@ -301,9 +335,10 @@ struct file *ovl_path_open(struct path *path, int flags);
int ovl_copy_up_start(struct dentry *dentry, int flags);
void ovl_copy_up_end(struct dentry *dentry);
bool ovl_already_copied_up(struct dentry *dentry, int flags);
-bool ovl_check_origin_xattr(struct ovl_fs *ofs, struct dentry *dentry);
-bool ovl_check_dir_xattr(struct super_block *sb, struct dentry *dentry,
- enum ovl_xattr ox);
+bool ovl_check_origin_xattr(struct ovl_fs *ofs, struct user_namespace *user_ns,
+ struct dentry *dentry);
+bool ovl_check_dir_xattr(struct super_block *sb, struct user_namespace *user_ns,
+ struct dentry *dentry, enum ovl_xattr ox);
int ovl_check_setxattr(struct dentry *dentry, struct dentry *upperdentry,
enum ovl_xattr ox, const void *value, size_t size,
int xerr);
@@ -318,15 +353,17 @@ bool ovl_need_index(struct dentry *dentry);
int ovl_nlink_start(struct dentry *dentry);
void ovl_nlink_end(struct dentry *dentry);
int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir);
-int ovl_check_metacopy_xattr(struct ovl_fs *ofs, struct dentry *dentry);
+int ovl_check_metacopy_xattr(struct ovl_fs *ofs, struct user_namespace *user_ns,
+ struct dentry *dentry);
bool ovl_is_metacopy_dentry(struct dentry *dentry);
-char *ovl_get_redirect_xattr(struct ovl_fs *ofs, struct dentry *dentry,
- int padding);
+char *ovl_get_redirect_xattr(struct ovl_fs *ofs, struct user_namespace *user_ns,
+ struct dentry *dentry, int padding);
static inline bool ovl_is_impuredir(struct super_block *sb,
struct dentry *dentry)
{
- return ovl_check_dir_xattr(sb, dentry, OVL_XATTR_IMPURE);
+ return ovl_check_dir_xattr(sb, ovl_upper_mnt_user_ns(OVL_FS(sb)),
+ dentry, OVL_XATTR_IMPURE);
}
/*@@ -404,8 +441,7 @@ bool ovl_lower_positive(struct dentry *dentry);
static inline int ovl_verify_origin(struct ovl_fs *ofs, struct dentry *upper,
struct dentry *origin, bool set)
{
- return ovl_verify_set_fh(ofs, upper, OVL_XATTR_ORIGIN, origin,
- false, set);
+ return ovl_verify_set_fh(ofs, upper, OVL_XATTR_ORIGIN, origin, false, set);
}
static inline int ovl_verify_upper(struct ovl_fs *ofs, struct dentry *index,@@ -418,7 +454,8 @@ static inline int ovl_verify_upper(struct ovl_fs *ofs, struct dentry *index,
extern const struct file_operations ovl_dir_operations;
struct file *ovl_dir_real_file(const struct file *file, bool want_upper);
int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list);
-void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list);
+void ovl_cleanup_whiteouts(struct user_namespace *user_ns, struct dentry *upper,
+ struct list_head *list);
void ovl_cache_free(struct list_head *list);
void ovl_dir_cache_free(struct inode *inode);
int ovl_check_d_type_supported(struct path *realpath);
@@ -463,10 +500,11 @@ bool ovl_lookup_trap_inode(struct super_block *sb, struct dentry *dir);
struct inode *ovl_get_trap_inode(struct super_block *sb, struct dentry *dir);
struct inode *ovl_get_inode(struct super_block *sb,
struct ovl_inode_params *oip);
-static inline void ovl_copyattr(struct inode *from, struct inode *to)
+static inline void ovl_copyattr(struct user_namespace *user_ns,
+ struct inode *from, struct inode *to)
{
- to->i_uid = from->i_uid;
- to->i_gid = from->i_gid;
+ to->i_uid = i_uid_into_mnt(user_ns, from);
+ to->i_gid = i_gid_into_mnt(user_ns, from);
to->i_mode = from->i_mode;
to->i_atime = from->i_atime;
to->i_mtime = from->i_mtime;@@ -474,6 +512,17 @@ static inline void ovl_copyattr(struct inode *from, struct inode *to)
i_size_write(to, i_size_read(from));
}
+static inline struct user_namespace *ovl_inode_real_user_ns(struct inode *inode)
+{
+ struct inode *realinode;
+
+ realinode = ovl_inode_upper(inode);
+ if (realinode)
+ return ovl_upper_mnt_user_ns(OVL_FS(inode->i_sb));
+
+ return OVL_I(inode)->lower_user_ns;
+}
+
static inline void ovl_copyflags(struct inode *from, struct inode *to)
{
unsigned int mask = S_SYNC | S_IMMUTABLE | S_APPEND | S_NOATIME;@@ -494,11 +543,15 @@ struct ovl_cattr {
#define OVL_CATTR(m) (&(struct ovl_cattr) { .mode = (m) })
-struct dentry *ovl_create_real(struct inode *dir, struct dentry *newdentry,
+struct dentry *ovl_create_real(struct user_namespace *user_ns,
+ struct inode *dir, struct dentry *newdentry,
struct ovl_cattr *attr);
-int ovl_cleanup(struct inode *dir, struct dentry *dentry);
-struct dentry *ovl_lookup_temp(struct dentry *workdir);
-struct dentry *ovl_create_temp(struct dentry *workdir, struct ovl_cattr *attr);
+int ovl_cleanup(struct user_namespace *user_ns, struct inode *dir,
+ struct dentry *dentry);
+struct dentry *ovl_lookup_temp(struct user_namespace *user_ns,
+ struct dentry *workdir);
+struct dentry *ovl_create_temp(struct user_namespace *user_ns,
+ struct dentry *workdir, struct ovl_cattr *attr);
/* file.c */
extern const struct file_operations ovl_file_operations;@@ -511,9 +564,11 @@ long ovl_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
int ovl_copy_up(struct dentry *dentry);
int ovl_copy_up_with_data(struct dentry *dentry);
int ovl_maybe_copy_up(struct dentry *dentry, int flags);
-int ovl_copy_xattr(struct super_block *sb, struct dentry *old,
+int ovl_copy_xattr(struct super_block *sb, struct user_namespace *old_user_ns,
+ struct dentry *old, struct user_namespace *new_user_ns,
struct dentry *new);
-int ovl_set_attr(struct dentry *upper, struct kstat *stat);
+int ovl_set_attr(struct user_namespace *user_ns, struct dentry *upper,
+ struct kstat *stat);
struct ovl_fh *ovl_encode_real_fh(struct dentry *real, bool is_upper);
int ovl_set_origin(struct dentry *dentry, struct dentry *lower,
struct dentry *upper);
diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
index 1b5a2094df8e..c505605f27ee 100644
--- a/fs/overlayfs/ovl_entry.h
+++ b/fs/overlayfs/ovl_entry.h
@@ -126,6 +126,7 @@ struct ovl_inode {
struct inode vfs_inode;
struct dentry *__upperdentry;
struct inode *lower;
+ struct user_namespace *lower_user_ns;
/* synchronize copy up and more */
struct mutex lock;diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index 01620ebae1bd..6927e4e93d44 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -264,7 +264,8 @@ static int ovl_fill_merge(struct dir_context *ctx, const char *name,
return ovl_fill_lowest(rdd, name, namelen, offset, ino, d_type);
}
-static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd)
+static int ovl_check_whiteouts(struct user_namespace *user_ns,
+ struct dentry *dir, struct ovl_readdir_data *rdd)
{
int err;
struct ovl_cache_entry *p;@@ -278,7 +279,7 @@ static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd)
while (rdd->first_maybe_whiteout) {
p = rdd->first_maybe_whiteout;
rdd->first_maybe_whiteout = p->next_maybe_whiteout;
- dentry = lookup_one_len(p->name, dir, p->len);
+ dentry = lookup_one_len_mapped(p->name, dir, p->len, user_ns);
if (!IS_ERR(dentry)) {
p->is_whiteout = ovl_is_whiteout(dentry);
dput(dentry);@@ -312,7 +313,8 @@ static inline int ovl_dir_read(struct path *realpath,
} while (!err && rdd->count);
if (!err && rdd->first_maybe_whiteout && rdd->dentry)
- err = ovl_check_whiteouts(realpath->dentry, rdd);
+ err = ovl_check_whiteouts(mnt_user_ns(realpath->mnt),
+ realpath->dentry, rdd);
fput(realfile);
@@ -491,7 +493,7 @@ static int ovl_cache_update_ino(struct path *path, struct ovl_cache_entry *p)
goto get;
}
}
- this = lookup_one_len(p->name, dir, p->len);
+ this = lookup_one_len_mapped(p->name, dir, p->len, mnt_user_ns(path->mnt));
if (IS_ERR_OR_NULL(this) || !this->d_inode) {
if (IS_ERR(this)) {
err = PTR_ERR(this);@@ -1020,7 +1022,8 @@ int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)
return err;
}
-void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list)
+void ovl_cleanup_whiteouts(struct user_namespace *user_ns, struct dentry *upper,
+ struct list_head *list)
{
struct ovl_cache_entry *p;
@@ -1031,7 +1034,7 @@ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list)
if (WARN_ON(!p->is_whiteout || !p->is_upper))
continue;
- dentry = lookup_one_len(p->name, upper, p->len);
+ dentry = lookup_one_len_mapped(p->name, upper, p->len, user_ns);
if (IS_ERR(dentry)) {
pr_err("lookup '%s/%.*s' failed (%i)\n",
upper->d_name.name, p->len, p->name,@@ -1039,7 +1042,7 @@ void ovl_cleanup_whiteouts(struct dentry *upper, struct list_head *list)
continue;
}
if (dentry->d_inode)
- ovl_cleanup(upper->d_inode, dentry);
+ ovl_cleanup(user_ns, upper->d_inode, dentry);
dput(dentry);
}
inode_unlock(upper->d_inode);
@@ -1130,7 +1133,8 @@ static int ovl_workdir_cleanup_recurse(struct path *path, int level)
err = -EINVAL;
break;
}
- dentry = lookup_one_len(p->name, path->dentry, p->len);
+ dentry = lookup_one_len_mapped(p->name, path->dentry, p->len,
+ mnt_user_ns(path->mnt));
if (IS_ERR(dentry))
continue;
if (dentry->d_inode)
@@ -1149,12 +1153,13 @@ int ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
struct dentry *dentry, int level)
{
int err;
+ struct user_namespace *user_ns = mnt_user_ns(mnt);
if (!d_is_dir(dentry) || level > 1) {
- return ovl_cleanup(dir, dentry);
+ return ovl_cleanup(user_ns, dir, dentry);
}
- err = ovl_do_rmdir(dir, dentry);
+ err = ovl_do_rmdir(user_ns, dir, dentry);
if (err) {
struct path path = { .mnt = mnt, .dentry = dentry };
@@ -1162,7 +1167,7 @@ int ovl_workdir_cleanup(struct inode *dir, struct vfsmount *mnt,
err = ovl_workdir_cleanup_recurse(&path, level + 1);
inode_lock_nested(dir, I_MUTEX_PARENT);
if (!err)
- err = ovl_cleanup(dir, dentry);
+ err = ovl_cleanup(user_ns, dir, dentry);
}
return err;
@@ -1175,6 +1180,7 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
struct dentry *index = NULL;
struct inode *dir = indexdir->d_inode;
struct path path = { .mnt = ovl_upper_mnt(ofs), .dentry = indexdir };
+ struct user_namespace *user_ns = mnt_user_ns(path.mnt);
LIST_HEAD(list);
struct rb_root root = RB_ROOT;
struct ovl_cache_entry *p;@@ -1198,7 +1204,7 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
if (p->len == 2 && p->name[1] == '.')
continue;
}
- index = lookup_one_len(p->name, indexdir, p->len);
+ index = lookup_one_len_mapped(p->name, indexdir, p->len, user_ns);
if (IS_ERR(index)) {
err = PTR_ERR(index);
index = NULL;@@ -1216,7 +1222,7 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
goto next;
} else if (err == -ESTALE) {
/* Cleanup stale index entries */
- err = ovl_cleanup(dir, index);
+ err = ovl_cleanup(user_ns, dir, index);
} else if (err != -ENOENT) {
/*
* Abort mount to avoid corrupting the index if@@ -1232,7 +1238,7 @@ int ovl_indexdir_cleanup(struct ovl_fs *ofs)
err = ovl_cleanup_and_whiteout(ofs, dir, index);
} else {
/* Cleanup orphan index entries */
- err = ovl_cleanup(dir, index);
+ err = ovl_cleanup(user_ns, dir, index);
}
if (err)diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 290983bcfbb3..755f651587a5 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -203,6 +203,7 @@ static void ovl_destroy_inode(struct inode *inode)
dput(oi->__upperdentry);
iput(oi->lower);
+ put_user_ns(oi->lower_user_ns);
if (S_ISDIR(inode->i_mode))
ovl_dir_cache_free(inode);
else
@@ -699,13 +700,14 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs,
{
struct inode *dir = ofs->workbasedir->d_inode;
struct vfsmount *mnt = ovl_upper_mnt(ofs);
+ struct user_namespace *user_ns = mnt_user_ns(mnt);
struct dentry *work;
int err;
bool retried = false;
inode_lock_nested(dir, I_MUTEX_PARENT);
retry:
- work = lookup_one_len(name, ofs->workbasedir, strlen(name));
+ work = lookup_one_len_mapped(name, ofs->workbasedir, strlen(name), user_ns);
if (!IS_ERR(work)) {
struct iattr attr = {@@ -731,7 +733,7 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs,
goto retry;
}
- work = ovl_create_real(dir, work, OVL_CATTR(attr.ia_mode));
+ work = ovl_create_real(user_ns, dir, work, OVL_CATTR(attr.ia_mode));
err = PTR_ERR(work);
if (IS_ERR(work))
goto out_err;
@@ -749,17 +751,17 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs,
* allowed as upper are limited to "normal" ones, where checking
* for the above two errors is sufficient.
*/
- err = vfs_removexattr(work, XATTR_NAME_POSIX_ACL_DEFAULT);
+ err = vfs_mapped_removexattr(user_ns, work, XATTR_NAME_POSIX_ACL_DEFAULT);
if (err && err != -ENODATA && err != -EOPNOTSUPP)
goto out_dput;
- err = vfs_removexattr(work, XATTR_NAME_POSIX_ACL_ACCESS);
+ err = vfs_mapped_removexattr(user_ns, work, XATTR_NAME_POSIX_ACL_ACCESS);
if (err && err != -ENODATA && err != -EOPNOTSUPP)
goto out_dput;
/* Clear any inherited mode bits */
inode_lock(work->d_inode);
- err = notify_change(work, &attr, NULL);
+ err = notify_mapped_change(user_ns, work, &attr, NULL);
inode_unlock(work->d_inode);
if (err)
goto out_dput;
@@ -934,10 +936,11 @@ ovl_posix_acl_xattr_get(const struct xattr_handler *handler,
}
static int __maybe_unused
-ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
- struct dentry *dentry, struct inode *inode,
- const char *name, const void *value,
- size_t size, int flags)
+ovl_posix_acl_xattr_set_mapped(const struct xattr_handler *handler,
+ struct user_namespace *user_ns,
+ struct dentry *dentry, struct inode *inode,
+ const char *name, const void *value,
+ size_t size, int flags)
{
struct dentry *workdir = ovl_workdir(dentry);
struct inode *realinode = ovl_inode_real(inode);@@ -960,7 +963,7 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
goto out_acl_release;
}
err = -EPERM;
- if (!inode_owner_or_capable(inode))
+ if (!mapped_inode_owner_or_capable(user_ns, inode))
goto out_acl_release;
posix_acl_release(acl);
@@ -971,8 +974,8 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
*/
if (unlikely(inode->i_mode & S_ISGID) &&
handler->flags == ACL_TYPE_ACCESS &&
- !in_group_p(inode->i_gid) &&
- !capable_wrt_inode_uidgid(inode, CAP_FSETID)) {
+ !in_group_p(i_gid_into_mnt(user_ns, inode)) &&
+ !capable_wrt_mapped_inode_uidgid(user_ns, inode, CAP_FSETID)) {
struct iattr iattr = { .ia_valid = ATTR_KILL_SGID };
err = ovl_setattr(dentry, &iattr);@@ -982,7 +985,7 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
err = ovl_xattr_set(dentry, inode, handler->name, value, size, flags);
if (!err)
- ovl_copyattr(ovl_inode_real(inode), inode);
+ ovl_copyattr(ovl_inode_real_user_ns(inode), realinode, inode);
return err;
@@ -991,6 +994,16 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
return err;
}
+static int __maybe_unused
+ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
+ struct dentry *dentry, struct inode *inode,
+ const char *name, const void *value,
+ size_t size, int flags)
+{
+ return ovl_posix_acl_xattr_set_mapped(handler, &init_user_ns, dentry,
+ inode, name, value, size, flags);
+}
+
static int ovl_own_xattr_get(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode,
const char *name, void *buffer, size_t size)@@ -998,6 +1011,17 @@ static int ovl_own_xattr_get(const struct xattr_handler *handler,
return -EOPNOTSUPP;
}
+#ifdef CONFIG_IDMAP_MOUNTS
+static int ovl_own_xattr_set_mapped(const struct xattr_handler *handler,
+ struct user_namespace *user_ns,
+ struct dentry *dentry, struct inode *inode,
+ const char *name, const void *value,
+ size_t size, int flags)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
static int ovl_own_xattr_set(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode,
const char *name, const void *value,@@ -1013,6 +1037,17 @@ static int ovl_other_xattr_get(const struct xattr_handler *handler,
return ovl_xattr_get(dentry, inode, name, buffer, size);
}
+#ifdef CONFIG_IDMAP_MOUNTS
+static int ovl_other_xattr_set_mapped(const struct xattr_handler *handler,
+ struct user_namespace *user_ns,
+ struct dentry *dentry,
+ struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ return ovl_xattr_set(dentry, inode, name, value, size, flags);
+}
+#endif
+
static int ovl_other_xattr_set(const struct xattr_handler *handler,
struct dentry *dentry, struct inode *inode,
const char *name, const void *value,@@ -1027,6 +1062,9 @@ ovl_posix_acl_access_xattr_handler = {
.flags = ACL_TYPE_ACCESS,
.get = ovl_posix_acl_xattr_get,
.set = ovl_posix_acl_xattr_set,
+#ifdef CONFIG_IDMAP_MOUNTS
+ .set_mapped = ovl_posix_acl_xattr_set_mapped,
+#endif
};
static const struct xattr_handler __maybe_unused@@ -1035,18 +1073,27 @@ ovl_posix_acl_default_xattr_handler = {
.flags = ACL_TYPE_DEFAULT,
.get = ovl_posix_acl_xattr_get,
.set = ovl_posix_acl_xattr_set,
+#ifdef CONFIG_IDMAP_MOUNTS
+ .set_mapped = ovl_posix_acl_xattr_set_mapped,
+#endif
};
static const struct xattr_handler ovl_own_xattr_handler = {
.prefix = OVL_XATTR_PREFIX,
.get = ovl_own_xattr_get,
.set = ovl_own_xattr_set,
+#ifdef CONFIG_IDMAP_MOUNTS
+ .set_mapped = ovl_own_xattr_set_mapped,
+#endif
};
static const struct xattr_handler ovl_other_xattr_handler = {
.prefix = "", /* catch all */
.get = ovl_other_xattr_get,
.set = ovl_other_xattr_set,
+#ifdef CONFIG_IDMAP_MOUNTS
+ .set_mapped = ovl_other_xattr_set_mapped,
+#endif
};
static const struct xattr_handler *ovl_xattr_handlers[] = {@@ -1164,7 +1211,8 @@ static int ovl_get_upper(struct super_block *sb, struct ovl_fs *ofs,
* Returns 1 if RENAME_WHITEOUT is supported, 0 if not supported and
* negative values if error is encountered.
*/
-static int ovl_check_rename_whiteout(struct dentry *workdir)
+static int ovl_check_rename_whiteout(struct user_namespace *user_ns,
+ struct dentry *workdir)
{
struct inode *dir = d_inode(workdir);
struct dentry *temp;@@ -1175,12 +1223,12 @@ static int ovl_check_rename_whiteout(struct dentry *workdir)
inode_lock_nested(dir, I_MUTEX_PARENT);
- temp = ovl_create_temp(workdir, OVL_CATTR(S_IFREG | 0));
+ temp = ovl_create_temp(user_ns, workdir, OVL_CATTR(S_IFREG | 0));
err = PTR_ERR(temp);
if (IS_ERR(temp))
goto out_unlock;
- dest = ovl_lookup_temp(workdir);
+ dest = ovl_lookup_temp(user_ns, workdir);
err = PTR_ERR(dest);
if (IS_ERR(dest)) {
dput(temp);@@ -1189,14 +1237,14 @@ static int ovl_check_rename_whiteout(struct dentry *workdir)
/* Name is inline and stable - using snapshot as a copy helper */
take_dentry_name_snapshot(&name, temp);
- err = ovl_do_rename(dir, temp, dir, dest, RENAME_WHITEOUT);
+ err = ovl_do_rename(dir, user_ns, temp, dir, user_ns, dest, RENAME_WHITEOUT);
if (err) {
if (err == -EINVAL)
err = 0;
goto cleanup_temp;
}
- whiteout = lookup_one_len(name.name.name, workdir, name.name.len);
+ whiteout = lookup_one_len_mapped(name.name.name, workdir, name.name.len, user_ns);
err = PTR_ERR(whiteout);
if (IS_ERR(whiteout))
goto cleanup_temp;@@ -1205,11 +1253,11 @@ static int ovl_check_rename_whiteout(struct dentry *workdir)
/* Best effort cleanup of whiteout and temp file */
if (err)
- ovl_cleanup(dir, whiteout);
+ ovl_cleanup(user_ns, dir, whiteout);
dput(whiteout);
cleanup_temp:
- ovl_cleanup(dir, temp);
+ ovl_cleanup(user_ns, dir, temp);
release_dentry_name_snapshot(&name);
dput(temp);
dput(dest);
@@ -1220,16 +1268,17 @@ static int ovl_check_rename_whiteout(struct dentry *workdir)
return err;
}
-static struct dentry *ovl_lookup_or_create(struct dentry *parent,
+static struct dentry *ovl_lookup_or_create(struct user_namespace *user_ns,
+ struct dentry *parent,
const char *name, umode_t mode)
{
size_t len = strlen(name);
struct dentry *child;
inode_lock_nested(parent->d_inode, I_MUTEX_PARENT);
- child = lookup_one_len(name, parent, len);
+ child = lookup_one_len_mapped(name, parent, len, user_ns);
if (!IS_ERR(child) && !child->d_inode)
- child = ovl_create_real(parent->d_inode, child,
+ child = ovl_create_real(user_ns, parent->d_inode, child,
OVL_CATTR(mode));
inode_unlock(parent->d_inode);
dput(parent);@@ -1251,7 +1300,8 @@ static int ovl_create_volatile_dirty(struct ovl_fs *ofs)
const char *const *name = volatile_path;
for (ctr = ARRAY_SIZE(volatile_path); ctr; ctr--, name++) {
- d = ovl_lookup_or_create(d, *name, ctr > 1 ? S_IFDIR : S_IFREG);
+ d = ovl_lookup_or_create(ovl_upper_mnt_user_ns(ofs), d, *name,
+ ctr > 1 ? S_IFDIR : S_IFREG);
if (IS_ERR(d))
return PTR_ERR(d);
}@@ -1264,6 +1314,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
{
struct vfsmount *mnt = ovl_upper_mnt(ofs);
struct dentry *temp, *workdir;
+ struct user_namespace *user_ns = mnt_user_ns(mnt);
bool rename_whiteout;
bool d_type;
int fh_type;@@ -1299,7 +1350,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
pr_warn("upper fs needs to support d_type.\n");
/* Check if upper/work fs supports O_TMPFILE */
- temp = ovl_do_tmpfile(ofs->workdir, S_IFREG | 0);
+ temp = ovl_do_tmpfile(user_ns, ofs->workdir, S_IFREG | 0);
ofs->tmpfile = !IS_ERR(temp);
if (ofs->tmpfile)
dput(temp);@@ -1308,7 +1359,7 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
/* Check if upper/work fs supports RENAME_WHITEOUT */
- err = ovl_check_rename_whiteout(ofs->workdir);
+ err = ovl_check_rename_whiteout(user_ns, ofs->workdir);
if (err < 0)
goto out;
@@ -1423,6 +1474,7 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs,
{
struct vfsmount *mnt = ovl_upper_mnt(ofs);
struct dentry *indexdir;
+ struct user_namespace *user_ns = mnt_user_ns(mnt);
int err;
err = mnt_want_write(mnt);@@ -1462,7 +1514,7 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs,
* "trusted.overlay.upper" to indicate that index may have
* directory entries.
*/
- if (ovl_check_origin_xattr(ofs, ofs->indexdir)) {
+ if (ovl_check_origin_xattr(ofs, user_ns, ofs->indexdir)) {
err = ovl_verify_set_fh(ofs, ofs->indexdir,
OVL_XATTR_ORIGIN,
upperpath->dentry, true, false);diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
index 23f475627d07..efd4dd067258 100644
--- a/fs/overlayfs/util.c
+++ b/fs/overlayfs/util.c
@@ -437,7 +437,8 @@ static void ovl_dentry_version_inc(struct dentry *dentry, bool impurity)
void ovl_dir_modified(struct dentry *dentry, bool impurity)
{
/* Copy mtime/ctime */
- ovl_copyattr(d_inode(ovl_dentry_upper(dentry)), d_inode(dentry));
+ ovl_copyattr(ovl_upper_mnt_user_ns(OVL_FS(dentry->d_sb)),
+ d_inode(ovl_dentry_upper(dentry)), d_inode(dentry));
ovl_dentry_version_inc(dentry, impurity);
}@@ -460,6 +461,7 @@ bool ovl_is_whiteout(struct dentry *dentry)
struct file *ovl_path_open(struct path *path, int flags)
{
struct inode *inode = d_inode(path->dentry);
+ struct user_namespace *user_ns = mnt_user_ns(path->mnt);
int err, acc_mode;
if (flags & ~(O_ACCMODE | O_LARGEFILE))@@ -476,12 +478,12 @@ struct file *ovl_path_open(struct path *path, int flags)
BUG();
}
- err = inode_permission(inode, acc_mode | MAY_OPEN);
+ err = mapped_inode_permission(user_ns, inode, acc_mode | MAY_OPEN);
if (err)
return ERR_PTR(err);
/* O_NOATIME is an optimization, don't fail if not permitted */
- if (inode_owner_or_capable(inode))
+ if (mapped_inode_owner_or_capable(user_ns, inode))
flags |= O_NOATIME;
return dentry_open(path, flags, current_cred());
@@ -544,11 +546,12 @@ void ovl_copy_up_end(struct dentry *dentry)
ovl_inode_unlock(d_inode(dentry));
}
-bool ovl_check_origin_xattr(struct ovl_fs *ofs, struct dentry *dentry)
+bool ovl_check_origin_xattr(struct ovl_fs *ofs, struct user_namespace *user_ns,
+ struct dentry *dentry)
{
int res;
- res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_ORIGIN, NULL, 0);
+ res = ovl_do_getxattr(ofs, user_ns, dentry, OVL_XATTR_ORIGIN, NULL, 0);
/* Zero size value means "copied up but origin unknown" */
if (res >= 0)@@ -557,8 +560,8 @@ bool ovl_check_origin_xattr(struct ovl_fs *ofs, struct dentry *dentry)
return false;
}
-bool ovl_check_dir_xattr(struct super_block *sb, struct dentry *dentry,
- enum ovl_xattr ox)
+bool ovl_check_dir_xattr(struct super_block *sb, struct user_namespace *user_ns,
+ struct dentry *dentry, enum ovl_xattr ox)
{
int res;
char val;@@ -566,7 +569,7 @@ bool ovl_check_dir_xattr(struct super_block *sb, struct dentry *dentry,
if (!d_is_dir(dentry))
return false;
- res = ovl_do_getxattr(OVL_FS(sb), dentry, ox, &val, 1);
+ res = ovl_do_getxattr(OVL_FS(sb), user_ns, dentry, ox, &val, 1);
if (res == 1 && val == 'y')
return true;
@@ -723,6 +726,7 @@ static void ovl_cleanup_index(struct dentry *dentry)
struct dentry *index = NULL;
struct inode *inode;
struct qstr name = { };
+ struct user_namespace *user_ns = ovl_dentry_mnt_user_ns(upperdentry);
int err;
err = ovl_get_index_name(lowerdentry, &name);@@ -748,7 +752,7 @@ static void ovl_cleanup_index(struct dentry *dentry)
}
inode_lock_nested(dir, I_MUTEX_PARENT);
- index = lookup_one_len(name.name, indexdir, name.len);
+ index = lookup_one_len_mapped(name.name, indexdir, name.len, user_ns);
err = PTR_ERR(index);
if (IS_ERR(index)) {
index = NULL;@@ -758,7 +762,7 @@ static void ovl_cleanup_index(struct dentry *dentry)
dir, index);
} else {
/* Cleanup orphan index entries */
- err = ovl_cleanup(dir, index);
+ err = ovl_cleanup(user_ns, dir, index);
}
inode_unlock(dir);@@ -867,7 +871,8 @@ int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir)
}
/* err < 0, 0 if no metacopy xattr, 1 if metacopy xattr found */
-int ovl_check_metacopy_xattr(struct ovl_fs *ofs, struct dentry *dentry)
+int ovl_check_metacopy_xattr(struct ovl_fs *ofs, struct user_namespace *user_ns,
+ struct dentry *dentry)
{
int res;
@@ -875,7 +880,7 @@ int ovl_check_metacopy_xattr(struct ovl_fs *ofs, struct dentry *dentry)
if (!S_ISREG(d_inode(dentry)->i_mode))
return 0;
- res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_METACOPY, NULL, 0);
+ res = ovl_do_getxattr(ofs, user_ns, dentry, OVL_XATTR_METACOPY, NULL, 0);
if (res < 0) {
if (res == -ENODATA || res == -EOPNOTSUPP)
return 0;@@ -904,13 +909,14 @@ bool ovl_is_metacopy_dentry(struct dentry *dentry)
return (oe->numlower > 1);
}
-char *ovl_get_redirect_xattr(struct ovl_fs *ofs, struct dentry *dentry,
- int padding)
+char *ovl_get_redirect_xattr(struct ovl_fs *ofs,
+ struct user_namespace *mnt_user_ns,
+ struct dentry *dentry, int padding)
{
int res;
char *s, *next, *buf = NULL;
- res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_REDIRECT, NULL, 0);
+ res = ovl_do_getxattr(ofs, mnt_user_ns, dentry, OVL_XATTR_REDIRECT, NULL, 0);
if (res == -ENODATA || res == -EOPNOTSUPP)
return NULL;
if (res < 0)@@ -922,7 +928,7 @@ char *ovl_get_redirect_xattr(struct ovl_fs *ofs, struct dentry *dentry,
if (!buf)
return ERR_PTR(-ENOMEM);
- res = ovl_do_getxattr(ofs, dentry, OVL_XATTR_REDIRECT, buf, res);
+ res = ovl_do_getxattr(ofs, mnt_user_ns, dentry, OVL_XATTR_REDIRECT, buf, res);
if (res < 0)
goto fail;
if (res == 0)
--
2.29.0