if (IS_ERR(dentry))
return PTR_ERR(dentry);
- err = vfs_mkdir(&init_user_ns, d_inode(path.dentry), dentry, mode);
+ err = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode);
if (!err)
/* mark as kernel-created inode */
d_inode(dentry)->i_private = &thread;
if (IS_ERR(dentry))
return PTR_ERR(dentry);
- err = vfs_mknod(&init_user_ns, d_inode(path.dentry), dentry, mode,
+ err = vfs_mknod(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode,
dev->devt);
if (!err) {
struct iattr newattrs;
newattrs.ia_gid = gid;
newattrs.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID;
inode_lock(d_inode(dentry));
- notify_change(&init_user_ns, dentry, &newattrs, NULL);
+ notify_change(&nop_mnt_idmap, dentry, &newattrs, NULL);
inode_unlock(d_inode(dentry));
/* mark as kernel-created inode */
return PTR_ERR(dentry);
if (d_really_is_positive(dentry)) {
if (d_inode(dentry)->i_private == &thread)
- err = vfs_rmdir(&init_user_ns, d_inode(parent.dentry),
+ err = vfs_rmdir(&nop_mnt_idmap, d_inode(parent.dentry),
dentry);
else
err = -EPERM;
newattrs.ia_valid =
ATTR_UID|ATTR_GID|ATTR_MODE;
inode_lock(d_inode(dentry));
- notify_change(&init_user_ns, dentry, &newattrs, NULL);
+ notify_change(&nop_mnt_idmap, dentry, &newattrs, NULL);
inode_unlock(d_inode(dentry));
- err = vfs_unlink(&init_user_ns, d_inode(parent.dentry),
+ err = vfs_unlink(&nop_mnt_idmap, d_inode(parent.dentry),
dentry, NULL);
if (!err || err == -ENOENT)
deleted = 1;
/**
* notify_change - modify attributes of a filesytem object
- * @mnt_userns: user namespace of the mount the inode was found from
+ * @idmap: idmap of the mount the inode was found from
* @dentry: object affected
* @attr: new attributes
* @delegated_inode: returns inode, if the inode is delegated
* the file open for write, as there can be no conflicting delegation in
* that case.
*
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then
- * take care to map the inode according to @mnt_userns before checking
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then
+ * take care to map the inode according to @idmap before checking
* permissions. On non-idmapped mounts or if permission checking is to be
- * performed on the raw inode simply passs init_user_ns.
+ * performed on the raw inode simply pass @nop_mnt_idmap.
*/
-int notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
+int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr, struct inode **delegated_inode)
{
+ struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
struct inode *inode = dentry->d_inode;
umode_t mode = inode->i_mode;
int error;
newattrs.ia_size = oi_size & PAGE_MASK;
ret = cachefiles_inject_remove_error();
if (ret == 0)
- ret = notify_change(&init_user_ns, file->f_path.dentry,
+ ret = notify_change(&nop_mnt_idmap, file->f_path.dentry,
&newattrs, NULL);
if (ret < 0)
goto truncate_failed;
newattrs.ia_size = ni_size;
ret = cachefiles_inject_write_error();
if (ret == 0)
- ret = notify_change(&init_user_ns, file->f_path.dentry,
+ ret = notify_change(&nop_mnt_idmap, file->f_path.dentry,
&newattrs, NULL);
truncate_failed:
goto mkdir_error;
ret = cachefiles_inject_write_error();
if (ret == 0)
- ret = vfs_mkdir(&init_user_ns, d_inode(dir), subdir, 0700);
+ ret = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), subdir, 0700);
if (ret < 0) {
trace_cachefiles_vfs_error(NULL, d_inode(dir), ret,
cachefiles_trace_mkdir_error);
ret = cachefiles_inject_remove_error();
if (ret == 0) {
- ret = vfs_unlink(&init_user_ns, d_backing_inode(dir), dentry, NULL);
+ ret = vfs_unlink(&nop_mnt_idmap, d_backing_inode(dir), dentry, NULL);
if (ret == -EIO)
cachefiles_io_error(cache, "Unlink failed");
}
cachefiles_io_error(cache, "Rename security error %d", ret);
} else {
struct renamedata rd = {
- .old_mnt_userns = &init_user_ns,
+ .old_mnt_idmap = &nop_mnt_idmap,
.old_dir = d_inode(dir),
.old_dentry = rep,
- .new_mnt_userns = &init_user_ns,
+ .new_mnt_idmap = &nop_mnt_idmap,
.new_dir = d_inode(cache->graveyard),
.new_dentry = grave,
};
ret = cachefiles_inject_write_error();
if (ret == 0) {
- file = vfs_tmpfile_open(&init_user_ns, &parentpath, S_IFREG,
+ file = vfs_tmpfile_open(&nop_mnt_idmap, &parentpath, S_IFREG,
O_RDWR | O_LARGEFILE | O_DIRECT,
cache->cache_cred);
ret = PTR_ERR_OR_ZERO(file);
ret = cachefiles_inject_read_error();
if (ret == 0)
- ret = vfs_link(object->file->f_path.dentry, &init_user_ns,
+ ret = vfs_link(object->file->f_path.dentry, &nop_mnt_idmap,
d_inode(fan), dentry, NULL);
if (ret < 0) {
trace_cachefiles_vfs_error(object, d_inode(fan), ret,
goto close_fail;
}
} else {
+ struct mnt_idmap *idmap;
struct user_namespace *mnt_userns;
struct inode *inode;
int open_flags = O_CREAT | O_RDWR | O_NOFOLLOW |
* a process dumps core while its cwd is e.g. on a vfat
* filesystem.
*/
- mnt_userns = file_mnt_user_ns(cprm.file);
+ idmap = file_mnt_idmap(cprm.file);
+ mnt_userns = mnt_idmap_owner(idmap);
if (!vfsuid_eq_kuid(i_uid_into_vfsuid(mnt_userns, inode),
current_fsuid())) {
pr_info_ratelimited("Core dump to %s aborted: cannot preserve file owner\n",
}
if (!(cprm.file->f_mode & FMODE_CAN_WRITE))
goto close_fail;
- if (do_truncate(mnt_userns, cprm.file->f_path.dentry,
+ if (do_truncate(idmap, cprm.file->f_path.dentry,
0, 0, cprm.file))
goto close_fail;
}
if (d_unhashed(lower_dentry))
rc = -EINVAL;
else
- rc = vfs_unlink(&init_user_ns, lower_dir, lower_dentry,
+ rc = vfs_unlink(&nop_mnt_idmap, lower_dir, lower_dentry,
NULL);
}
if (rc) {
rc = lock_parent(ecryptfs_dentry, &lower_dentry, &lower_dir);
if (!rc)
- rc = vfs_create(&init_user_ns, lower_dir,
+ rc = vfs_create(&nop_mnt_idmap, lower_dir,
lower_dentry, mode, true);
if (rc) {
printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
inode = __ecryptfs_get_inode(d_inode(lower_dentry),
directory_inode->i_sb);
if (IS_ERR(inode)) {
- vfs_unlink(&init_user_ns, lower_dir, lower_dentry, NULL);
+ vfs_unlink(&nop_mnt_idmap, lower_dir, lower_dentry, NULL);
goto out_lock;
}
fsstack_copy_attr_times(directory_inode, lower_dir);
lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
rc = lock_parent(new_dentry, &lower_new_dentry, &lower_dir);
if (!rc)
- rc = vfs_link(lower_old_dentry, &init_user_ns, lower_dir,
+ rc = vfs_link(lower_old_dentry, &nop_mnt_idmap, lower_dir,
lower_new_dentry, NULL);
if (rc || d_really_is_negative(lower_new_dentry))
goto out_lock;
strlen(symname));
if (rc)
goto out_lock;
- rc = vfs_symlink(&init_user_ns, lower_dir, lower_dentry,
+ rc = vfs_symlink(&nop_mnt_idmap, lower_dir, lower_dentry,
encoded_symname);
kfree(encoded_symname);
if (rc || d_really_is_negative(lower_dentry))
rc = lock_parent(dentry, &lower_dentry, &lower_dir);
if (!rc)
- rc = vfs_mkdir(&init_user_ns, lower_dir,
+ rc = vfs_mkdir(&nop_mnt_idmap, lower_dir,
lower_dentry, mode);
if (rc || d_really_is_negative(lower_dentry))
goto out;
if (d_unhashed(lower_dentry))
rc = -EINVAL;
else
- rc = vfs_rmdir(&init_user_ns, lower_dir, lower_dentry);
+ rc = vfs_rmdir(&nop_mnt_idmap, lower_dir, lower_dentry);
}
if (!rc) {
clear_nlink(d_inode(dentry));
rc = lock_parent(dentry, &lower_dentry, &lower_dir);
if (!rc)
- rc = vfs_mknod(&init_user_ns, lower_dir,
+ rc = vfs_mknod(&nop_mnt_idmap, lower_dir,
lower_dentry, mode, dev);
if (rc || d_really_is_negative(lower_dentry))
goto out;
goto out_lock;
}
- rd.old_mnt_userns = &init_user_ns;
+ rd.old_mnt_idmap = &nop_mnt_idmap;
rd.old_dir = d_inode(lower_old_dir_dentry);
rd.old_dentry = lower_old_dentry;
- rd.new_mnt_userns = &init_user_ns;
+ rd.new_mnt_idmap = &nop_mnt_idmap;
rd.new_dir = d_inode(lower_new_dir_dentry);
rd.new_dentry = lower_new_dentry;
rc = vfs_rename(&rd);
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
inode_lock(d_inode(lower_dentry));
- rc = notify_change(&init_user_ns, lower_dentry,
+ rc = notify_change(&nop_mnt_idmap, lower_dentry,
&lower_ia, NULL);
inode_unlock(d_inode(lower_dentry));
}
lower_ia.ia_valid &= ~ATTR_MODE;
inode_lock(d_inode(lower_dentry));
- rc = notify_change(&init_user_ns, lower_dentry, &lower_ia, NULL);
+ rc = notify_change(&nop_mnt_idmap, lower_dentry, &lower_ia, NULL);
inode_unlock(d_inode(lower_dentry));
out:
fsstack_copy_attr_all(inode, lower_inode);
mode &= ~current_umask();
error = security_path_mknod(&path, dentry, mode, dev);
if (!error)
- error = vfs_mknod(mnt_user_ns(path.mnt), path.dentry->d_inode,
+ error = vfs_mknod(mnt_idmap(path.mnt), path.dentry->d_inode,
dentry, mode, new_decode_dev(dev));
done_path_create(&path, dentry);
return error;
{
struct dentry *new_dentry;
struct path old_path, new_path;
+ struct mnt_idmap *idmap;
struct user_namespace *mnt_userns;
int error;
error = -EXDEV;
if (old_path.mnt != new_path.mnt)
goto out_dput;
- mnt_userns = mnt_user_ns(new_path.mnt);
+ idmap = mnt_idmap(new_path.mnt);
+ mnt_userns = mnt_idmap_owner(idmap);
error = may_linkat(mnt_userns, &old_path);
if (unlikely(error))
goto out_dput;
error = security_path_link(old_path.dentry, &new_path, new_dentry);
if (error)
goto out_dput;
- error = vfs_link(old_path.dentry, mnt_userns, new_path.dentry->d_inode,
+ error = vfs_link(old_path.dentry, idmap, new_path.dentry->d_inode,
new_dentry, NULL);
out_dput:
done_path_create(&new_path, new_dentry);
return PTR_ERR(dentry);
error = security_path_symlink(&path, dentry, oldname);
if (!error)
- error = vfs_symlink(mnt_user_ns(path.mnt), path.dentry->d_inode,
+ error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode,
dentry, oldname);
done_path_create(&path, dentry);
return error;
mode &= ~current_umask();
error = security_path_mkdir(&path, dentry, mode);
if (!error)
- error = vfs_mkdir(mnt_user_ns(path.mnt), path.dentry->d_inode,
+ error = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode,
dentry, mode);
done_path_create(&path, dentry);
return error;
return mask;
}
-static int __remove_privs(struct user_namespace *mnt_userns,
+static int __remove_privs(struct mnt_idmap *idmap,
struct dentry *dentry, int kill)
{
struct iattr newattrs;
* Note we call this on write, so notify_change will not
* encounter any conflicting delegations:
*/
- return notify_change(mnt_userns, dentry, &newattrs, NULL);
+ return notify_change(idmap, dentry, &newattrs, NULL);
}
static int __file_remove_privs(struct file *file, unsigned int flags)
if (flags & IOCB_NOWAIT)
return -EAGAIN;
- error = __remove_privs(file_mnt_user_ns(file), dentry, kill);
+ error = __remove_privs(file_mnt_idmap(file), dentry, kill);
}
if (!error)
struct iattr attrs;
struct file *filp;
struct inode *inode;
+ struct mnt_idmap *idmap;
struct user_namespace *user_ns;
int rc = 0;
attrs.ia_valid = 0;
filp = fp->filp;
inode = file_inode(filp);
- user_ns = file_mnt_user_ns(filp);
+ idmap = file_mnt_idmap(filp);
+ user_ns = mnt_idmap_owner(idmap);
if (file_info->CreationTime)
fp->create_time = le64_to_cpu(file_info->CreationTime);
inode_lock(inode);
inode->i_ctime = attrs.ia_ctime;
attrs.ia_valid &= ~ATTR_CTIME;
- rc = notify_change(user_ns, dentry, &attrs, NULL);
+ rc = notify_change(idmap, dentry, &attrs, NULL);
inode_unlock(inode);
}
return rc;
int rc;
struct smb_fattr fattr = {{0}};
struct inode *inode = d_inode(path->dentry);
- struct user_namespace *user_ns = mnt_user_ns(path->mnt);
+ struct mnt_idmap *idmap = mnt_idmap(path->mnt);
+ struct user_namespace *user_ns = mnt_idmap_owner(idmap);
struct iattr newattrs;
fattr.cf_uid = INVALID_UID;
}
inode_lock(inode);
- rc = notify_change(user_ns, path->dentry, &newattrs, NULL);
+ rc = notify_change(idmap, path->dentry, &newattrs, NULL);
inode_unlock(inode);
if (rc)
goto out;
}
mode |= S_IFREG;
- err = vfs_create(mnt_user_ns(path.mnt), d_inode(path.dentry),
+ err = vfs_create(mnt_idmap(path.mnt), d_inode(path.dentry),
dentry, mode, true);
if (!err) {
ksmbd_vfs_inherit_owner(work, d_inode(path.dentry),
*/
int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode)
{
+ struct mnt_idmap *idmap;
struct user_namespace *user_ns;
struct path path;
struct dentry *dentry;
return err;
}
- user_ns = mnt_user_ns(path.mnt);
+ idmap = mnt_idmap(path.mnt);
+ user_ns = mnt_idmap_owner(idmap);
mode |= S_IFDIR;
- err = vfs_mkdir(user_ns, d_inode(path.dentry), dentry, mode);
+ err = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode);
if (err) {
goto out;
} else if (d_unhashed(dentry)) {
*/
int ksmbd_vfs_remove_file(struct ksmbd_work *work, char *name)
{
+ struct mnt_idmap *idmap;
struct user_namespace *user_ns;
struct path path;
struct dentry *parent;
return err;
}
- user_ns = mnt_user_ns(path.mnt);
+ idmap = mnt_idmap(path.mnt);
+ user_ns = mnt_idmap_owner(idmap);
parent = dget_parent(path.dentry);
err = ksmbd_vfs_lock_parent(user_ns, parent, path.dentry);
if (err) {
}
if (S_ISDIR(d_inode(path.dentry)->i_mode)) {
- err = vfs_rmdir(user_ns, d_inode(parent), path.dentry);
+ err = vfs_rmdir(idmap, d_inode(parent), path.dentry);
if (err && err != -ENOTEMPTY)
ksmbd_debug(VFS, "%s: rmdir failed, err %d\n", name,
err);
} else {
- err = vfs_unlink(user_ns, d_inode(parent), path.dentry, NULL);
+ err = vfs_unlink(idmap, d_inode(parent), path.dentry, NULL);
if (err)
ksmbd_debug(VFS, "%s: unlink failed, err %d\n", name,
err);
goto out3;
}
- err = vfs_link(oldpath.dentry, mnt_user_ns(newpath.mnt),
+ err = vfs_link(oldpath.dentry, mnt_idmap(newpath.mnt),
d_inode(newpath.dentry),
dentry, NULL);
if (err)
}
static int __ksmbd_vfs_rename(struct ksmbd_work *work,
- struct user_namespace *src_user_ns,
+ struct mnt_idmap *src_idmap,
struct dentry *src_dent_parent,
struct dentry *src_dent,
- struct user_namespace *dst_user_ns,
+ struct mnt_idmap *dst_idmap,
struct dentry *dst_dent_parent,
struct dentry *trap_dent,
char *dst_name)
if (ksmbd_override_fsids(work))
return -ENOMEM;
- dst_dent = lookup_one(dst_user_ns, dst_name, dst_dent_parent,
- strlen(dst_name));
+ dst_dent = lookup_one(mnt_idmap_owner(dst_idmap), dst_name,
+ dst_dent_parent, strlen(dst_name));
err = PTR_ERR(dst_dent);
if (IS_ERR(dst_dent)) {
pr_err("lookup failed %s [%d]\n", dst_name, err);
err = -ENOTEMPTY;
if (dst_dent != trap_dent && !d_really_is_positive(dst_dent)) {
struct renamedata rd = {
- .old_mnt_userns = src_user_ns,
+ .old_mnt_idmap = src_idmap,
.old_dir = d_inode(src_dent_parent),
.old_dentry = src_dent,
- .new_mnt_userns = dst_user_ns,
+ .new_mnt_idmap = dst_idmap,
.new_dir = d_inode(dst_dent_parent),
.new_dentry = dst_dent,
};
int ksmbd_vfs_fp_rename(struct ksmbd_work *work, struct ksmbd_file *fp,
char *newname)
{
+ struct mnt_idmap *idmap;
struct user_namespace *user_ns;
struct path dst_path;
struct dentry *src_dent_parent, *dst_dent_parent;
trap_dent = lock_rename(src_dent_parent, dst_dent_parent);
dget(src_dent);
dget(dst_dent_parent);
- user_ns = file_mnt_user_ns(fp->filp);
+ idmap = file_mnt_idmap(fp->filp);
+ user_ns = mnt_idmap_owner(idmap);
src_child = lookup_one(user_ns, src_dent->d_name.name, src_dent_parent,
src_dent->d_name.len);
if (IS_ERR(src_child)) {
dput(src_child);
err = __ksmbd_vfs_rename(work,
- user_ns,
+ idmap,
src_dent_parent,
src_dent,
- mnt_user_ns(dst_path.mnt),
+ mnt_idmap(dst_path.mnt),
dst_dent_parent,
trap_dent,
dst_name);
return vfs_removexattr(user_ns, dentry, attr_name);
}
-int ksmbd_vfs_unlink(struct user_namespace *user_ns,
+int ksmbd_vfs_unlink(struct mnt_idmap *idmap,
struct dentry *dir, struct dentry *dentry)
{
int err = 0;
+ struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
- err = ksmbd_vfs_lock_parent(user_ns, dir, dentry);
+ err = ksmbd_vfs_lock_parent(mnt_userns, dir, dentry);
if (err)
return err;
dget(dentry);
if (S_ISDIR(d_inode(dentry)->i_mode))
- err = vfs_rmdir(user_ns, d_inode(dir), dentry);
+ err = vfs_rmdir(idmap, d_inode(dir), dentry);
else
- err = vfs_unlink(user_ns, d_inode(dir), dentry, NULL);
+ err = vfs_unlink(idmap, d_inode(dir), dentry, NULL);
dput(dentry);
inode_unlock(d_inode(dir));
int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length,
struct file_allocated_range_buffer *ranges,
unsigned int in_count, unsigned int *out_count);
-int ksmbd_vfs_unlink(struct user_namespace *user_ns,
- struct dentry *dir, struct dentry *dentry);
+int ksmbd_vfs_unlink(struct mnt_idmap *idmap, struct dentry *dir,
+ struct dentry *dentry);
void *ksmbd_vfs_init_kstat(char **p, struct ksmbd_kstat *ksmbd_kstat);
int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work,
struct user_namespace *user_ns,
dir = dentry->d_parent;
ci->m_flags &= ~(S_DEL_ON_CLS | S_DEL_PENDING);
write_unlock(&ci->m_lock);
- ksmbd_vfs_unlink(file_mnt_user_ns(filp), dir, dentry);
+ ksmbd_vfs_unlink(file_mnt_idmap(filp), dir, dentry);
write_lock(&ci->m_lock);
}
write_unlock(&ci->m_lock);
/**
* vfs_create - create new file
- * @mnt_userns: user namespace of the mount the inode was found from
+ * @idmap: idmap of the mount the inode was found from
* @dir: inode of @dentry
* @dentry: pointer to dentry of the base directory
* @mode: mode of the new file
*
* Create a new file.
*
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
* On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
*/
-int vfs_create(struct user_namespace *mnt_userns, struct inode *dir,
+int vfs_create(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode, bool want_excl)
{
- int error = may_create(mnt_userns, dir, dentry);
+ struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
+ int error;
+
+ error = may_create(mnt_userns, dir, dentry);
if (error)
return error;
return 0;
}
-static int handle_truncate(struct user_namespace *mnt_userns, struct file *filp)
+static int handle_truncate(struct mnt_idmap *idmap, struct file *filp)
{
const struct path *path = &filp->f_path;
struct inode *inode = path->dentry->d_inode;
error = security_file_truncate(filp);
if (!error) {
- error = do_truncate(mnt_userns, path->dentry, 0,
+ error = do_truncate(idmap, path->dentry, 0,
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
filp);
}
static int do_open(struct nameidata *nd,
struct file *file, const struct open_flags *op)
{
+ struct mnt_idmap *idmap;
struct user_namespace *mnt_userns;
int open_flag = op->open_flag;
bool do_truncate;
}
if (!(file->f_mode & FMODE_CREATED))
audit_inode(nd->name, nd->path.dentry, 0);
- mnt_userns = mnt_user_ns(nd->path.mnt);
+ idmap = mnt_idmap(nd->path.mnt);
+ mnt_userns = mnt_idmap_owner(idmap);
if (open_flag & O_CREAT) {
if ((open_flag & O_EXCL) && !(file->f_mode & FMODE_CREATED))
return -EEXIST;
if (!error)
error = ima_file_check(file, op->acc_mode);
if (!error && do_truncate)
- error = handle_truncate(mnt_userns, file);
+ error = handle_truncate(idmap, file);
if (unlikely(error > 0)) {
WARN_ON(1);
error = -EINVAL;
/**
* vfs_tmpfile - create tmpfile
- * @mnt_userns: user namespace of the mount the inode was found from
+ * @idmap: idmap of the mount the inode was found from
* @dentry: pointer to dentry of the base directory
* @mode: mode of the new tmpfile
* @open_flag: flags
*
* Create a temporary file.
*
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
* On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
*/
-static int vfs_tmpfile(struct user_namespace *mnt_userns,
+static int vfs_tmpfile(struct mnt_idmap *idmap,
const struct path *parentpath,
struct file *file, umode_t mode)
{
+ struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
struct dentry *child;
struct inode *dir = d_inode(parentpath->dentry);
struct inode *inode;
/**
* vfs_tmpfile_open - open a tmpfile for kernel internal use
- * @mnt_userns: user namespace of the mount the inode was found from
+ * @idmap: idmap of the mount the inode was found from
* @parentpath: path of the base directory
* @mode: mode of the new tmpfile
* @open_flag: flags
* hence this is only for kernel internal use, and must not be installed into
* file tables or such.
*/
-struct file *vfs_tmpfile_open(struct user_namespace *mnt_userns,
+struct file *vfs_tmpfile_open(struct mnt_idmap *idmap,
const struct path *parentpath,
umode_t mode, int open_flag, const struct cred *cred)
{
file = alloc_empty_file_noaccount(open_flag, cred);
if (!IS_ERR(file)) {
- error = vfs_tmpfile(mnt_userns, parentpath, file, mode);
+ error = vfs_tmpfile(idmap, parentpath, file, mode);
if (error) {
fput(file);
file = ERR_PTR(error);
const struct open_flags *op,
struct file *file)
{
- struct user_namespace *mnt_userns;
struct path path;
int error = path_lookupat(nd, flags | LOOKUP_DIRECTORY, &path);
error = mnt_want_write(path.mnt);
if (unlikely(error))
goto out;
- mnt_userns = mnt_user_ns(path.mnt);
- error = vfs_tmpfile(mnt_userns, &path, file, op->mode);
+ error = vfs_tmpfile(mnt_idmap(path.mnt), &path, file, op->mode);
if (error)
goto out2;
audit_inode(nd->name, file->f_path.dentry, 0);
/**
* vfs_mknod - create device node or file
- * @mnt_userns: user namespace of the mount the inode was found from
+ * @idmap: idmap of the mount the inode was found from
* @dir: inode of @dentry
* @dentry: pointer to dentry of the base directory
* @mode: mode of the new device node or file
*
* Create a device node or file.
*
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
* On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
*/
-int vfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
+int vfs_mknod(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode, dev_t dev)
{
+ struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
bool is_whiteout = S_ISCHR(mode) && dev == WHITEOUT_DEV;
int error = may_create(mnt_userns, dir, dentry);
static int do_mknodat(int dfd, struct filename *name, umode_t mode,
unsigned int dev)
{
+ struct mnt_idmap *idmap;
struct user_namespace *mnt_userns;
struct dentry *dentry;
struct path path;
if (error)
goto out2;
- mnt_userns = mnt_user_ns(path.mnt);
+ idmap = mnt_idmap(path.mnt);
+ mnt_userns = mnt_idmap_owner(idmap);
switch (mode & S_IFMT) {
case 0: case S_IFREG:
- error = vfs_create(mnt_userns, path.dentry->d_inode,
+ error = vfs_create(idmap, path.dentry->d_inode,
dentry, mode, true);
if (!error)
ima_post_path_mknod(mnt_userns, dentry);
break;
case S_IFCHR: case S_IFBLK:
- error = vfs_mknod(mnt_userns, path.dentry->d_inode,
+ error = vfs_mknod(idmap, path.dentry->d_inode,
dentry, mode, new_decode_dev(dev));
break;
case S_IFIFO: case S_IFSOCK:
- error = vfs_mknod(mnt_userns, path.dentry->d_inode,
+ error = vfs_mknod(idmap, path.dentry->d_inode,
dentry, mode, 0);
break;
}
/**
* vfs_mkdir - create directory
- * @mnt_userns: user namespace of the mount the inode was found from
+ * @idmap: idmap of the mount the inode was found from
* @dir: inode of @dentry
* @dentry: pointer to dentry of the base directory
* @mode: mode of the new directory
*
* Create a directory.
*
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
* On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
*/
-int vfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
+int vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, umode_t mode)
{
- int error = may_create(mnt_userns, dir, dentry);
+ struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
+ int error;
unsigned max_links = dir->i_sb->s_max_links;
+ error = may_create(mnt_userns, dir, dentry);
if (error)
return error;
error = security_path_mkdir(&path, dentry,
mode_strip_umask(path.dentry->d_inode, mode));
if (!error) {
- struct user_namespace *mnt_userns;
- mnt_userns = mnt_user_ns(path.mnt);
- error = vfs_mkdir(mnt_userns, path.dentry->d_inode, dentry,
- mode);
+ error = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode,
+ dentry, mode);
}
done_path_create(&path, dentry);
if (retry_estale(error, lookup_flags)) {
/**
* vfs_rmdir - remove directory
- * @mnt_userns: user namespace of the mount the inode was found from
+ * @idmap: idmap of the mount the inode was found from
* @dir: inode of @dentry
* @dentry: pointer to dentry of the base directory
*
* Remove a directory.
*
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
* On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
*/
-int vfs_rmdir(struct user_namespace *mnt_userns, struct inode *dir,
+int vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry)
{
+ struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
int error = may_delete(mnt_userns, dir, dentry, 1);
if (error)
int do_rmdir(int dfd, struct filename *name)
{
- struct user_namespace *mnt_userns;
int error;
struct dentry *dentry;
struct path path;
error = security_path_rmdir(&path, dentry);
if (error)
goto exit4;
- mnt_userns = mnt_user_ns(path.mnt);
- error = vfs_rmdir(mnt_userns, path.dentry->d_inode, dentry);
+ error = vfs_rmdir(mnt_idmap(path.mnt), path.dentry->d_inode, dentry);
exit4:
dput(dentry);
exit3:
/**
* vfs_unlink - unlink a filesystem object
- * @mnt_userns: user namespace of the mount the inode was found from
+ * @idmap: idmap of the mount the inode was found from
* @dir: parent directory
* @dentry: victim
* @delegated_inode: returns victim inode, if the inode is delegated.
* be appropriate for callers that expect the underlying filesystem not
* to be NFS exported.
*
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
* On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
*/
-int vfs_unlink(struct user_namespace *mnt_userns, struct inode *dir,
+int vfs_unlink(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, struct inode **delegated_inode)
{
+ struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
struct inode *target = dentry->d_inode;
int error = may_delete(mnt_userns, dir, dentry, 0);
dentry = __lookup_hash(&last, path.dentry, lookup_flags);
error = PTR_ERR(dentry);
if (!IS_ERR(dentry)) {
- struct user_namespace *mnt_userns;
/* Why not before? Because we want correct error value */
if (last.name[last.len])
error = security_path_unlink(&path, dentry);
if (error)
goto exit3;
- mnt_userns = mnt_user_ns(path.mnt);
- error = vfs_unlink(mnt_userns, path.dentry->d_inode, dentry,
- &delegated_inode);
+ error = vfs_unlink(mnt_idmap(path.mnt), path.dentry->d_inode,
+ dentry, &delegated_inode);
exit3:
dput(dentry);
}
/**
* vfs_symlink - create symlink
- * @mnt_userns: user namespace of the mount the inode was found from
+ * @idmap: idmap of the mount the inode was found from
* @dir: inode of @dentry
* @dentry: pointer to dentry of the base directory
* @oldname: name of the file to link to
*
* Create a symlink.
*
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
* On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
*/
-int vfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
+int vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,
struct dentry *dentry, const char *oldname)
{
+ struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
int error = may_create(mnt_userns, dir, dentry);
if (error)
goto out_putnames;
error = security_path_symlink(&path, dentry, from->name);
- if (!error) {
- struct user_namespace *mnt_userns;
-
- mnt_userns = mnt_user_ns(path.mnt);
- error = vfs_symlink(mnt_userns, path.dentry->d_inode, dentry,
- from->name);
- }
+ if (!error)
+ error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode,
+ dentry, from->name);
done_path_create(&path, dentry);
if (retry_estale(error, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
/**
* vfs_link - create a new link
* @old_dentry: object to be linked
- * @mnt_userns: the user namespace of the mount
+ * @idmap: idmap of the mount
* @dir: new parent
* @new_dentry: where to create the new link
* @delegated_inode: returns inode needing a delegation break
* be appropriate for callers that expect the underlying filesystem not
* to be NFS exported.
*
- * If the inode has been found through an idmapped mount the user namespace of
- * the vfsmount must be passed through @mnt_userns. This function will then take
- * care to map the inode according to @mnt_userns before checking permissions.
+ * If the inode has been found through an idmapped mount the idmap of
+ * the vfsmount must be passed through @idmap. This function will then take
+ * care to map the inode according to @idmap before checking permissions.
* On non-idmapped mounts or if permission checking is to be performed on the
- * raw inode simply passs init_user_ns.
+ * raw inode simply passs @nop_mnt_idmap.
*/
-int vfs_link(struct dentry *old_dentry, struct user_namespace *mnt_userns,
+int vfs_link(struct dentry *old_dentry, struct mnt_idmap *idmap,
struct inode *dir, struct dentry *new_dentry,
struct inode **delegated_inode)
{
+ struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
struct inode *inode = old_dentry->d_inode;
unsigned max_links = dir->i_sb->s_max_links;
int error;
int do_linkat(int olddfd, struct filename *old, int newdfd,
struct filename *new, int flags)
{
+ struct mnt_idmap *idmap;
struct user_namespace *mnt_userns;
struct dentry *new_dentry;
struct path old_path, new_path;
error = -EXDEV;
if (old_path.mnt != new_path.mnt)
goto out_dput;
- mnt_userns = mnt_user_ns(new_path.mnt);
+ idmap = mnt_idmap(new_path.mnt);
+ mnt_userns = mnt_idmap_owner(idmap);
error = may_linkat(mnt_userns, &old_path);
if (unlikely(error))
goto out_dput;
error = security_path_link(old_path.dentry, &new_path, new_dentry);
if (error)
goto out_dput;
- error = vfs_link(old_path.dentry, mnt_userns, new_path.dentry->d_inode,
+ error = vfs_link(old_path.dentry, idmap, new_path.dentry->d_inode,
new_dentry, &delegated_inode);
out_dput:
done_path_create(&new_path, new_dentry);
bool new_is_dir = false;
unsigned max_links = new_dir->i_sb->s_max_links;
struct name_snapshot old_name;
+ struct user_namespace *old_mnt_userns = mnt_idmap_owner(rd->old_mnt_idmap),
+ *new_mnt_userns = mnt_idmap_owner(rd->new_mnt_idmap);
if (source == target)
return 0;
- error = may_delete(rd->old_mnt_userns, old_dir, old_dentry, is_dir);
+ error = may_delete(old_mnt_userns, old_dir, old_dentry, is_dir);
if (error)
return error;
if (!target) {
- error = may_create(rd->new_mnt_userns, new_dir, new_dentry);
+ error = may_create(new_mnt_userns, new_dir, new_dentry);
} else {
new_is_dir = d_is_dir(new_dentry);
if (!(flags & RENAME_EXCHANGE))
- error = may_delete(rd->new_mnt_userns, new_dir,
+ error = may_delete(new_mnt_userns, new_dir,
new_dentry, is_dir);
else
- error = may_delete(rd->new_mnt_userns, new_dir,
+ error = may_delete(new_mnt_userns, new_dir,
new_dentry, new_is_dir);
}
if (error)
*/
if (new_dir != old_dir) {
if (is_dir) {
- error = inode_permission(rd->old_mnt_userns, source,
+ error = inode_permission(old_mnt_userns, source,
MAY_WRITE);
if (error)
return error;
}
if ((flags & RENAME_EXCHANGE) && new_is_dir) {
- error = inode_permission(rd->new_mnt_userns, target,
+ error = inode_permission(new_mnt_userns, target,
MAY_WRITE);
if (error)
return error;
if (error)
goto out;
}
- error = old_dir->i_op->rename(rd->new_mnt_userns, old_dir, old_dentry,
+ error = old_dir->i_op->rename(new_mnt_userns, old_dir, old_dentry,
new_dir, new_dentry, flags);
if (error)
goto out;
rd.old_dir = old_path.dentry->d_inode;
rd.old_dentry = old_dentry;
- rd.old_mnt_userns = mnt_user_ns(old_path.mnt);
+ rd.old_mnt_idmap = mnt_idmap(old_path.mnt);
rd.new_dir = new_path.dentry->d_inode;
rd.new_dentry = new_dentry;
- rd.new_mnt_userns = mnt_user_ns(new_path.mnt);
+ rd.new_mnt_idmap = mnt_idmap(new_path.mnt);
rd.delegated_inode = &delegated_inode;
rd.flags = flags;
error = vfs_rename(&rd);
iap->ia_mode &= ~current_umask();
fh_fill_pre_attrs(fhp);
- host_err = vfs_create(&init_user_ns, inode, child, iap->ia_mode, true);
+ host_err = vfs_create(&nop_mnt_idmap, inode, child, iap->ia_mode, true);
if (host_err < 0) {
status = nfserrno(host_err);
goto out;
* as well be forgiving and just succeed silently.
*/
goto out_put;
- status = vfs_mkdir(&init_user_ns, d_inode(dir), dentry, S_IRWXU);
+ status = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), dentry, S_IRWXU);
out_put:
dput(dentry);
out_unlock:
status = -ENOENT;
if (d_really_is_negative(dentry))
goto out;
- status = vfs_rmdir(&init_user_ns, d_inode(dir), dentry);
+ status = vfs_rmdir(&nop_mnt_idmap, d_inode(dir), dentry);
out:
dput(dentry);
out_unlock:
if (nfs4_has_reclaimed_state(name, nn))
goto out_free;
- status = vfs_rmdir(&init_user_ns, d_inode(parent), child);
+ status = vfs_rmdir(&nop_mnt_idmap, d_inode(parent), child);
if (status)
printk("failed to remove client recovery directory %pd\n",
child);
if (iap->ia_size < 0)
return -EFBIG;
- host_err = notify_change(&init_user_ns, dentry, &size_attr, NULL);
+ host_err = notify_change(&nop_mnt_idmap, dentry, &size_attr, NULL);
if (host_err)
return host_err;
iap->ia_valid &= ~ATTR_SIZE;
return 0;
iap->ia_valid |= ATTR_CTIME;
- return notify_change(&init_user_ns, dentry, iap, NULL);
+ return notify_change(&nop_mnt_idmap, dentry, iap, NULL);
}
/**
err = 0;
switch (type) {
case S_IFREG:
- host_err = vfs_create(&init_user_ns, dirp, dchild, iap->ia_mode, true);
+ host_err = vfs_create(&nop_mnt_idmap, dirp, dchild,
+ iap->ia_mode, true);
if (!host_err)
nfsd_check_ignore_resizing(iap);
break;
case S_IFDIR:
- host_err = vfs_mkdir(&init_user_ns, dirp, dchild, iap->ia_mode);
+ host_err = vfs_mkdir(&nop_mnt_idmap, dirp, dchild, iap->ia_mode);
if (!host_err && unlikely(d_unhashed(dchild))) {
struct dentry *d;
d = lookup_one_len(dchild->d_name.name,
case S_IFBLK:
case S_IFIFO:
case S_IFSOCK:
- host_err = vfs_mknod(&init_user_ns, dirp, dchild,
+ host_err = vfs_mknod(&nop_mnt_idmap, dirp, dchild,
iap->ia_mode, rdev);
break;
default:
goto out_drop_write;
}
fh_fill_pre_attrs(fhp);
- host_err = vfs_symlink(&init_user_ns, d_inode(dentry), dnew, path);
+ host_err = vfs_symlink(&nop_mnt_idmap, d_inode(dentry), dnew, path);
err = nfserrno(host_err);
cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
if (!err)
if (d_really_is_negative(dold))
goto out_dput;
fh_fill_pre_attrs(ffhp);
- host_err = vfs_link(dold, &init_user_ns, dirp, dnew, NULL);
+ host_err = vfs_link(dold, &nop_mnt_idmap, dirp, dnew, NULL);
fh_fill_post_attrs(ffhp);
inode_unlock(dirp);
if (!host_err) {
goto out_dput_old;
} else {
struct renamedata rd = {
- .old_mnt_userns = &init_user_ns,
+ .old_mnt_idmap = &nop_mnt_idmap,
.old_dir = fdir,
.old_dentry = odentry,
- .new_mnt_userns = &init_user_ns,
+ .new_mnt_idmap = &nop_mnt_idmap,
.new_dir = tdir,
.new_dentry = ndentry,
};
nfsd_close_cached_files(rdentry);
for (retries = 1;;) {
- host_err = vfs_unlink(&init_user_ns, dirp, rdentry, NULL);
+ host_err = vfs_unlink(&nop_mnt_idmap, dirp, rdentry, NULL);
if (host_err != -EAGAIN || !retries--)
break;
if (!nfsd_wait_for_delegreturn(rqstp, rinode))
break;
}
} else {
- host_err = vfs_rmdir(&init_user_ns, dirp, rdentry);
+ host_err = vfs_rmdir(&nop_mnt_idmap, dirp, rdentry);
}
fh_fill_post_attrs(fhp);
#include "internal.h"
-int do_truncate(struct user_namespace *mnt_userns, struct dentry *dentry,
+int do_truncate(struct mnt_idmap *idmap, struct dentry *dentry,
loff_t length, unsigned int time_attrs, struct file *filp)
{
+ struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
int ret;
struct iattr newattrs;
inode_lock(dentry->d_inode);
/* Note any delegations or leases have already been broken: */
- ret = notify_change(mnt_userns, dentry, &newattrs, NULL);
+ ret = notify_change(idmap, dentry, &newattrs, NULL);
inode_unlock(dentry->d_inode);
return ret;
}
long vfs_truncate(const struct path *path, loff_t length)
{
+ struct mnt_idmap *idmap;
struct user_namespace *mnt_userns;
struct inode *inode;
long error;
if (error)
goto out;
- mnt_userns = mnt_user_ns(path->mnt);
+ idmap = mnt_idmap(path->mnt);
+ mnt_userns = mnt_idmap_owner(idmap);
error = inode_permission(mnt_userns, inode, MAY_WRITE);
if (error)
goto mnt_drop_write_and_out;
error = security_path_truncate(path);
if (!error)
- error = do_truncate(mnt_userns, path->dentry, length, 0, NULL);
+ error = do_truncate(idmap, path->dentry, length, 0, NULL);
put_write_and_out:
put_write_access(inode);
sb_start_write(inode->i_sb);
error = security_file_truncate(f.file);
if (!error)
- error = do_truncate(file_mnt_user_ns(f.file), dentry, length,
+ error = do_truncate(file_mnt_idmap(f.file), dentry, length,
ATTR_MTIME | ATTR_CTIME, f.file);
sb_end_write(inode->i_sb);
out_putf:
goto out_unlock;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
- error = notify_change(mnt_user_ns(path->mnt), path->dentry,
+ error = notify_change(mnt_idmap(path->mnt), path->dentry,
&newattrs, &delegated_inode);
out_unlock:
inode_unlock(inode);
int chown_common(const struct path *path, uid_t user, gid_t group)
{
+ struct mnt_idmap *idmap;
struct user_namespace *mnt_userns, *fs_userns;
struct inode *inode = path->dentry->d_inode;
struct inode *delegated_inode = NULL;
uid = make_kuid(current_user_ns(), user);
gid = make_kgid(current_user_ns(), group);
- mnt_userns = mnt_user_ns(path->mnt);
+ idmap = mnt_idmap(path->mnt);
+ mnt_userns = mnt_idmap_owner(idmap);
fs_userns = i_user_ns(inode);
retry_deleg:
from_vfsuid(mnt_userns, fs_userns, newattrs.ia_vfsuid),
from_vfsgid(mnt_userns, fs_userns, newattrs.ia_vfsgid));
if (!error)
- error = notify_change(mnt_userns, path->dentry, &newattrs,
+ error = notify_change(idmap, path->dentry, &newattrs,
&delegated_inode);
inode_unlock(inode);
if (delegated_inode) {
if (IS_ERR(f))
return f;
- error = vfs_create(mnt_user_ns(path->mnt),
+ error = vfs_create(mnt_idmap(path->mnt),
d_inode(path->dentry->d_parent),
path->dentry, mode, true);
if (!error)
struct dentry *upperdentry,
struct iattr *attr)
{
- return notify_change(ovl_upper_mnt_userns(ofs), upperdentry, attr, NULL);
+ return notify_change(ovl_upper_mnt_idmap(ofs), upperdentry, attr, NULL);
}
static inline int ovl_do_rmdir(struct ovl_fs *ofs,
struct inode *dir, struct dentry *dentry)
{
- int err = vfs_rmdir(ovl_upper_mnt_userns(ofs), dir, dentry);
+ int err = vfs_rmdir(ovl_upper_mnt_idmap(ofs), dir, dentry);
pr_debug("rmdir(%pd2) = %i\n", dentry, err);
return err;
static inline int ovl_do_unlink(struct ovl_fs *ofs, struct inode *dir,
struct dentry *dentry)
{
- int err = vfs_unlink(ovl_upper_mnt_userns(ofs), dir, dentry, NULL);
+ int err = vfs_unlink(ovl_upper_mnt_idmap(ofs), dir, dentry, NULL);
pr_debug("unlink(%pd2) = %i\n", dentry, err);
return err;
static inline int ovl_do_link(struct ovl_fs *ofs, struct dentry *old_dentry,
struct inode *dir, struct dentry *new_dentry)
{
- int err = vfs_link(old_dentry, ovl_upper_mnt_userns(ofs), dir, new_dentry, NULL);
+ int err = vfs_link(old_dentry, ovl_upper_mnt_idmap(ofs), dir,
+ new_dentry, NULL);
pr_debug("link(%pd2, %pd2) = %i\n", old_dentry, new_dentry, err);
return err;
struct inode *dir, struct dentry *dentry,
umode_t mode)
{
- int err = vfs_create(ovl_upper_mnt_userns(ofs), dir, dentry, mode, true);
+ int err = vfs_create(ovl_upper_mnt_idmap(ofs), dir, dentry, mode, true);
pr_debug("create(%pd2, 0%o) = %i\n", dentry, mode, err);
return err;
struct inode *dir, struct dentry *dentry,
umode_t mode)
{
- int err = vfs_mkdir(ovl_upper_mnt_userns(ofs), dir, dentry, mode);
+ int err = vfs_mkdir(ovl_upper_mnt_idmap(ofs), dir, dentry, mode);
pr_debug("mkdir(%pd2, 0%o) = %i\n", dentry, mode, err);
return err;
}
struct inode *dir, struct dentry *dentry,
umode_t mode, dev_t dev)
{
- int err = vfs_mknod(ovl_upper_mnt_userns(ofs), dir, dentry, mode, dev);
+ int err = vfs_mknod(ovl_upper_mnt_idmap(ofs), dir, dentry, mode, dev);
pr_debug("mknod(%pd2, 0%o, 0%o) = %i\n", dentry, mode, dev, err);
return err;
struct inode *dir, struct dentry *dentry,
const char *oldname)
{
- int err = vfs_symlink(ovl_upper_mnt_userns(ofs), dir, dentry, oldname);
+ int err = vfs_symlink(ovl_upper_mnt_idmap(ofs), dir, dentry, oldname);
pr_debug("symlink(\"%s\", %pd2) = %i\n", oldname, dentry, err);
return err;
{
int err;
struct renamedata rd = {
- .old_mnt_userns = ovl_upper_mnt_userns(ofs),
+ .old_mnt_idmap = ovl_upper_mnt_idmap(ofs),
.old_dir = olddir,
.old_dentry = olddentry,
- .new_mnt_userns = ovl_upper_mnt_userns(ofs),
+ .new_mnt_idmap = ovl_upper_mnt_idmap(ofs),
.new_dir = newdir,
.new_dentry = newdentry,
.flags = flags,
static inline int ovl_do_whiteout(struct ovl_fs *ofs,
struct inode *dir, struct dentry *dentry)
{
- int err = vfs_whiteout(ovl_upper_mnt_userns(ofs), dir, dentry);
+ int err = vfs_whiteout(ovl_upper_mnt_idmap(ofs), dir, dentry);
pr_debug("whiteout(%pd2) = %i\n", dentry, err);
return err;
}
struct dentry *dentry, umode_t mode)
{
struct path path = { .mnt = ovl_upper_mnt(ofs), .dentry = dentry };
- struct file *file = vfs_tmpfile_open(ovl_upper_mnt_userns(ofs), &path, mode,
+ struct file *file = vfs_tmpfile_open(ovl_upper_mnt_idmap(ofs), &path, mode,
O_LARGEFILE | O_WRONLY, current_cred());
int err = PTR_ERR_OR_ZERO(file);
return mnt_user_ns(ovl_upper_mnt(ofs));
}
+static inline struct mnt_idmap *ovl_upper_mnt_idmap(struct ovl_fs *ofs)
+{
+ return mnt_idmap(ovl_upper_mnt(ofs));
+}
+
static inline struct ovl_fs *OVL_FS(struct super_block *sb)
{
return (struct ovl_fs *)sb->s_fs_info;
}
retry_deleg:
inode_lock(inode);
- error = notify_change(mnt_user_ns(path->mnt), path->dentry, &newattrs,
+ error = notify_change(mnt_idmap(path->mnt), path->dentry, &newattrs,
&delegated_inode);
inode_unlock(inode);
if (delegated_inode) {
/*
* VFS helper functions..
*/
-int vfs_create(struct user_namespace *, struct inode *,
+int vfs_create(struct mnt_idmap *, struct inode *,
struct dentry *, umode_t, bool);
-int vfs_mkdir(struct user_namespace *, struct inode *,
+int vfs_mkdir(struct mnt_idmap *, struct inode *,
struct dentry *, umode_t);
-int vfs_mknod(struct user_namespace *, struct inode *, struct dentry *,
+int vfs_mknod(struct mnt_idmap *, struct inode *, struct dentry *,
umode_t, dev_t);
-int vfs_symlink(struct user_namespace *, struct inode *,
+int vfs_symlink(struct mnt_idmap *, struct inode *,
struct dentry *, const char *);
-int vfs_link(struct dentry *, struct user_namespace *, struct inode *,
+int vfs_link(struct dentry *, struct mnt_idmap *, struct inode *,
struct dentry *, struct inode **);
-int vfs_rmdir(struct user_namespace *, struct inode *, struct dentry *);
-int vfs_unlink(struct user_namespace *, struct inode *, struct dentry *,
+int vfs_rmdir(struct mnt_idmap *, struct inode *, struct dentry *);
+int vfs_unlink(struct mnt_idmap *, struct inode *, struct dentry *,
struct inode **);
/**
* struct renamedata - contains all information required for renaming
- * @old_mnt_userns: old user namespace of the mount the inode was found from
+ * @old_mnt_idmap: idmap of the old mount the inode was found from
* @old_dir: parent of source
* @old_dentry: source
- * @new_mnt_userns: new user namespace of the mount the inode was found from
+ * @new_mnt_idmap: idmap of the new mount the inode was found from
* @new_dir: parent of destination
* @new_dentry: destination
* @delegated_inode: returns an inode needing a delegation break
* @flags: rename flags
*/
struct renamedata {
- struct user_namespace *old_mnt_userns;
+ struct mnt_idmap *old_mnt_idmap;
struct inode *old_dir;
struct dentry *old_dentry;
- struct user_namespace *new_mnt_userns;
+ struct mnt_idmap *new_mnt_idmap;
struct inode *new_dir;
struct dentry *new_dentry;
struct inode **delegated_inode;
int vfs_rename(struct renamedata *);
-static inline int vfs_whiteout(struct user_namespace *mnt_userns,
+static inline int vfs_whiteout(struct mnt_idmap *idmap,
struct inode *dir, struct dentry *dentry)
{
- return vfs_mknod(mnt_userns, dir, dentry, S_IFCHR | WHITEOUT_MODE,
+ return vfs_mknod(idmap, dir, dentry, S_IFCHR | WHITEOUT_MODE,
WHITEOUT_DEV);
}
-struct file *vfs_tmpfile_open(struct user_namespace *mnt_userns,
+struct file *vfs_tmpfile_open(struct mnt_idmap *idmap,
const struct path *parentpath,
umode_t mode, int open_flag, const struct cred *cred);
}
extern long vfs_truncate(const struct path *, loff_t);
-int do_truncate(struct user_namespace *, struct dentry *, loff_t start,
+int do_truncate(struct mnt_idmap *, struct dentry *, loff_t start,
unsigned int time_attrs, struct file *filp);
extern int vfs_fallocate(struct file *file, int mode, loff_t offset,
loff_t len);
}
#endif
-int notify_change(struct user_namespace *, struct dentry *,
+int notify_change(struct mnt_idmap *, struct dentry *,
struct iattr *, struct inode **);
int inode_permission(struct user_namespace *, struct inode *, int);
int generic_permission(struct user_namespace *, struct inode *, int);
err = -ENOENT;
} else {
ihold(inode);
- err = vfs_unlink(&init_user_ns, d_inode(dentry->d_parent),
+ err = vfs_unlink(&nop_mnt_idmap, d_inode(dentry->d_parent),
dentry, NULL);
}
dput(dentry);
unsigned int new_hash, old_hash = sk->sk_hash;
struct unix_sock *u = unix_sk(sk);
struct net *net = sock_net(sk);
- struct user_namespace *ns; // barf...
+ struct mnt_idmap *idmap;
struct unix_address *addr;
struct dentry *dentry;
struct path parent;
/*
* All right, let's create it.
*/
- ns = mnt_user_ns(parent.mnt);
+ idmap = mnt_idmap(parent.mnt);
err = security_path_mknod(&parent, dentry, mode, 0);
if (!err)
- err = vfs_mknod(ns, d_inode(parent.dentry), dentry, mode, 0);
+ err = vfs_mknod(idmap, d_inode(parent.dentry), dentry, mode, 0);
if (err)
goto out_path;
err = mutex_lock_interruptible(&u->bindlock);
err = -EINVAL;
out_unlink:
/* failed after successful mknod? unlink what we'd created... */
- vfs_unlink(ns, d_inode(parent.dentry), dentry, NULL);
+ vfs_unlink(idmap, d_inode(parent.dentry), dentry, NULL);
out_path:
done_path_create(&parent, dentry);
out:
SEC("kprobe/vfs_link")
int BPF_KPROBE(kprobe__vfs_link,
- struct dentry* old_dentry, struct user_namespace *mnt_userns,
+ struct dentry* old_dentry, struct mnt_idmap *idmap,
struct inode* dir, struct dentry* new_dentry,
struct inode** delegated_inode)
{