mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-11-17 01:51:00 +03:00
Support idmapped mount in user namespace
Linux 5.17 commit torvalds/linux@5dfbfe71e enables "the idmapping infrastructure to support idmapped mounts of filesystems mounted with an idmapping". Update the OpenZFS accordingly to improve the idmapped mount support. This pull request contains the following changes: - xattr setter functions are fixed to take mnt_ns argument. Without this, cp -p would fail for an idmapped mount in a user namespace. - idmap_util is enhanced/fixed for its use in a user ns context. - One test case added to test idmapped mount in a user ns. Reviewed-by: Christian Brauner <christian@brauner.io> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Youzhong Yang <yyang@mathworks.com> Closes #14097
This commit is contained in:
parent
109731cd73
commit
f224eddf92
24
config/kernel-iattr-vfsid.m4
Normal file
24
config/kernel-iattr-vfsid.m4
Normal file
@ -0,0 +1,24 @@
|
||||
dnl #
|
||||
dnl # 6.0 API change
|
||||
dnl # struct iattr has two unions for the uid and gid
|
||||
dnl #
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_IATTR_VFSID], [
|
||||
ZFS_LINUX_TEST_SRC([iattr_vfsid], [
|
||||
#include <linux/fs.h>
|
||||
], [
|
||||
struct iattr ia;
|
||||
ia.ia_vfsuid = (vfsuid_t){0};
|
||||
ia.ia_vfsgid = (vfsgid_t){0};
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([ZFS_AC_KERNEL_IATTR_VFSID], [
|
||||
AC_MSG_CHECKING([whether iattr->ia_vfsuid and iattr->ia_vfsgid exist])
|
||||
ZFS_LINUX_TEST_RESULT([iattr_vfsid], [
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_IATTR_VFSID, 1,
|
||||
[iattr->ia_vfsuid and iattr->ia_vfsgid exist])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
@ -149,6 +149,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
|
||||
ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC
|
||||
ZFS_AC_KERNEL_SRC_USER_NS_COMMON_INUM
|
||||
ZFS_AC_KERNEL_SRC_IDMAP_MNT_API
|
||||
ZFS_AC_KERNEL_SRC_IATTR_VFSID
|
||||
|
||||
AC_MSG_CHECKING([for available kernel interfaces])
|
||||
ZFS_LINUX_TEST_COMPILE_ALL([kabi])
|
||||
@ -271,6 +272,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
|
||||
ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC
|
||||
ZFS_AC_KERNEL_USER_NS_COMMON_INUM
|
||||
ZFS_AC_KERNEL_IDMAP_MNT_API
|
||||
ZFS_AC_KERNEL_IATTR_VFSID
|
||||
])
|
||||
|
||||
dnl #
|
||||
|
@ -146,7 +146,7 @@ fn(const struct xattr_handler *handler, struct user_namespace *user_ns, \
|
||||
struct dentry *dentry, struct inode *inode, const char *name, \
|
||||
const void *buffer, size_t size, int flags) \
|
||||
{ \
|
||||
return (__ ## fn(inode, name, buffer, size, flags)); \
|
||||
return (__ ## fn(user_ns, inode, name, buffer, size, flags)); \
|
||||
}
|
||||
/*
|
||||
* 4.7 API change,
|
||||
@ -160,7 +160,7 @@ fn(const struct xattr_handler *handler, struct dentry *dentry, \
|
||||
struct inode *inode, const char *name, const void *buffer, \
|
||||
size_t size, int flags) \
|
||||
{ \
|
||||
return (__ ## fn(inode, name, buffer, size, flags)); \
|
||||
return (__ ## fn(kcred->user_ns, inode, name, buffer, size, flags));\
|
||||
}
|
||||
/*
|
||||
* 4.4 API change,
|
||||
@ -174,7 +174,8 @@ static int \
|
||||
fn(const struct xattr_handler *handler, struct dentry *dentry, \
|
||||
const char *name, const void *buffer, size_t size, int flags) \
|
||||
{ \
|
||||
return (__ ## fn(dentry->d_inode, name, buffer, size, flags)); \
|
||||
return (__ ## fn(kcred->user_ns, dentry->d_inode, name, \
|
||||
buffer, size, flags)); \
|
||||
}
|
||||
/*
|
||||
* 2.6.33 API change,
|
||||
@ -187,7 +188,8 @@ static int \
|
||||
fn(struct dentry *dentry, const char *name, const void *buffer, \
|
||||
size_t size, int flags, int unused_handler_flags) \
|
||||
{ \
|
||||
return (__ ## fn(dentry->d_inode, name, buffer, size, flags)); \
|
||||
return (__ ## fn(kcred->user_ns, dentry->d_inode, name, \
|
||||
buffer, size, flags)); \
|
||||
}
|
||||
#else
|
||||
#error "Unsupported kernel"
|
||||
|
@ -26,11 +26,14 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/sched.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/vfs.h>
|
||||
|
||||
typedef struct cred cred_t;
|
||||
|
||||
extern struct task_struct init_task;
|
||||
|
||||
#define kcred ((cred_t *)(init_task.cred))
|
||||
#define CRED() ((cred_t *)current_cred())
|
||||
|
||||
@ -45,32 +48,80 @@ typedef struct cred cred_t;
|
||||
#define SGID_TO_KGID(x) (KGIDT_INIT(x))
|
||||
#define KGIDP_TO_SGIDP(x) (&(x)->val)
|
||||
|
||||
static inline uid_t zfs_uid_into_mnt(struct user_namespace *mnt_ns, uid_t uid)
|
||||
/* Check if the user ns is the initial one */
|
||||
static inline boolean_t
|
||||
zfs_is_init_userns(struct user_namespace *user_ns)
|
||||
{
|
||||
if (mnt_ns)
|
||||
return (__kuid_val(make_kuid(mnt_ns, uid)));
|
||||
#if defined(CONFIG_USER_NS)
|
||||
return (user_ns == kcred->user_ns);
|
||||
#else
|
||||
return (B_FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline struct user_namespace *zfs_i_user_ns(struct inode *inode)
|
||||
{
|
||||
#ifdef HAVE_SUPER_USER_NS
|
||||
return (inode->i_sb->s_user_ns);
|
||||
#else
|
||||
return (kcred->user_ns);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline boolean_t zfs_no_idmapping(struct user_namespace *mnt_userns,
|
||||
struct user_namespace *fs_userns)
|
||||
{
|
||||
return (zfs_is_init_userns(mnt_userns) || mnt_userns == fs_userns);
|
||||
}
|
||||
|
||||
static inline uid_t zfs_uid_to_vfsuid(struct user_namespace *mnt_userns,
|
||||
struct user_namespace *fs_userns, uid_t uid)
|
||||
{
|
||||
if (zfs_no_idmapping(mnt_userns, fs_userns))
|
||||
return (uid);
|
||||
}
|
||||
|
||||
static inline gid_t zfs_gid_into_mnt(struct user_namespace *mnt_ns, gid_t gid)
|
||||
{
|
||||
if (mnt_ns)
|
||||
return (__kgid_val(make_kgid(mnt_ns, gid)));
|
||||
return (gid);
|
||||
}
|
||||
|
||||
static inline uid_t zfs_uid_from_mnt(struct user_namespace *mnt_ns, uid_t uid)
|
||||
{
|
||||
if (mnt_ns)
|
||||
return (from_kuid(mnt_ns, KUIDT_INIT(uid)));
|
||||
if (!zfs_is_init_userns(fs_userns))
|
||||
uid = from_kuid(fs_userns, KUIDT_INIT(uid));
|
||||
if (uid == (uid_t)-1)
|
||||
return (uid);
|
||||
return (__kuid_val(make_kuid(mnt_userns, uid)));
|
||||
}
|
||||
|
||||
static inline gid_t zfs_gid_from_mnt(struct user_namespace *mnt_ns, gid_t gid)
|
||||
static inline gid_t zfs_gid_to_vfsgid(struct user_namespace *mnt_userns,
|
||||
struct user_namespace *fs_userns, gid_t gid)
|
||||
{
|
||||
if (mnt_ns)
|
||||
return (from_kgid(mnt_ns, KGIDT_INIT(gid)));
|
||||
if (zfs_no_idmapping(mnt_userns, fs_userns))
|
||||
return (gid);
|
||||
if (!zfs_is_init_userns(fs_userns))
|
||||
gid = from_kgid(fs_userns, KGIDT_INIT(gid));
|
||||
if (gid == (gid_t)-1)
|
||||
return (gid);
|
||||
return (__kgid_val(make_kgid(mnt_userns, gid)));
|
||||
}
|
||||
|
||||
static inline uid_t zfs_vfsuid_to_uid(struct user_namespace *mnt_userns,
|
||||
struct user_namespace *fs_userns, uid_t uid)
|
||||
{
|
||||
if (zfs_no_idmapping(mnt_userns, fs_userns))
|
||||
return (uid);
|
||||
uid = from_kuid(mnt_userns, KUIDT_INIT(uid));
|
||||
if (uid == (uid_t)-1)
|
||||
return (uid);
|
||||
if (zfs_is_init_userns(fs_userns))
|
||||
return (uid);
|
||||
return (__kuid_val(make_kuid(fs_userns, uid)));
|
||||
}
|
||||
|
||||
static inline gid_t zfs_vfsgid_to_gid(struct user_namespace *mnt_userns,
|
||||
struct user_namespace *fs_userns, gid_t gid)
|
||||
{
|
||||
if (zfs_no_idmapping(mnt_userns, fs_userns))
|
||||
return (gid);
|
||||
gid = from_kgid(mnt_userns, KGIDT_INIT(gid));
|
||||
if (gid == (gid_t)-1)
|
||||
return (gid);
|
||||
if (zfs_is_init_userns(fs_userns))
|
||||
return (gid);
|
||||
return (__kgid_val(make_kgid(fs_userns, gid)));
|
||||
}
|
||||
|
||||
extern void crhold(cred_t *cr);
|
||||
@ -81,5 +132,4 @@ extern gid_t crgetgid(const cred_t *cr);
|
||||
extern int crgetngroups(const cred_t *cr);
|
||||
extern gid_t *crgetgroups(const cred_t *cr);
|
||||
extern int groupmember(gid_t gid, const cred_t *cr);
|
||||
|
||||
#endif /* _SPL_CRED_H */
|
||||
|
@ -47,13 +47,14 @@ int secpolicy_vnode_create_gid(const cred_t *);
|
||||
int secpolicy_vnode_remove(const cred_t *);
|
||||
int secpolicy_vnode_setdac(const cred_t *, uid_t);
|
||||
int secpolicy_vnode_setid_retain(struct znode *, const cred_t *, boolean_t);
|
||||
int secpolicy_vnode_setids_setgids(const cred_t *, gid_t, zuserns_t *);
|
||||
int secpolicy_vnode_setids_setgids(const cred_t *, gid_t, zuserns_t *,
|
||||
zuserns_t *);
|
||||
int secpolicy_zinject(const cred_t *);
|
||||
int secpolicy_zfs(const cred_t *);
|
||||
int secpolicy_zfs_proc(const cred_t *, proc_t *);
|
||||
void secpolicy_setid_clear(vattr_t *, cred_t *);
|
||||
int secpolicy_setid_setsticky_clear(struct inode *, vattr_t *,
|
||||
const vattr_t *, cred_t *, zuserns_t *);
|
||||
const vattr_t *, cred_t *, zuserns_t *, zuserns_t *);
|
||||
int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, mode_t);
|
||||
int secpolicy_vnode_setattr(cred_t *, struct inode *, struct vattr *,
|
||||
const struct vattr *, int, int (void *, int, cred_t *), void *);
|
||||
|
@ -214,9 +214,10 @@ secpolicy_vnode_setid_retain(struct znode *zp __maybe_unused, const cred_t *cr,
|
||||
* Determine that subject can set the file setgid flag.
|
||||
*/
|
||||
int
|
||||
secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid, zuserns_t *mnt_ns)
|
||||
secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid, zuserns_t *mnt_ns,
|
||||
zuserns_t *fs_ns)
|
||||
{
|
||||
gid = zfs_gid_into_mnt(mnt_ns, gid);
|
||||
gid = zfs_gid_to_vfsgid(mnt_ns, fs_ns, gid);
|
||||
#if defined(CONFIG_USER_NS)
|
||||
if (!kgid_has_mapping(cr->user_ns, SGID_TO_KGID(gid)))
|
||||
return (EPERM);
|
||||
@ -285,9 +286,10 @@ secpolicy_setid_clear(vattr_t *vap, cred_t *cr)
|
||||
* Determine that subject can set the file setid flags.
|
||||
*/
|
||||
static int
|
||||
secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner, zuserns_t *mnt_ns)
|
||||
secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner, zuserns_t *mnt_ns,
|
||||
zuserns_t *fs_ns)
|
||||
{
|
||||
owner = zfs_uid_into_mnt(mnt_ns, owner);
|
||||
owner = zfs_uid_to_vfsuid(mnt_ns, fs_ns, owner);
|
||||
|
||||
if (crgetuid(cr) == owner)
|
||||
return (0);
|
||||
@ -313,13 +315,13 @@ secpolicy_vnode_stky_modify(const cred_t *cr)
|
||||
|
||||
int
|
||||
secpolicy_setid_setsticky_clear(struct inode *ip, vattr_t *vap,
|
||||
const vattr_t *ovap, cred_t *cr, zuserns_t *mnt_ns)
|
||||
const vattr_t *ovap, cred_t *cr, zuserns_t *mnt_ns, zuserns_t *fs_ns)
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((vap->va_mode & S_ISUID) != 0 &&
|
||||
(error = secpolicy_vnode_setid_modify(cr,
|
||||
ovap->va_uid, mnt_ns)) != 0) {
|
||||
ovap->va_uid, mnt_ns, fs_ns)) != 0) {
|
||||
return (error);
|
||||
}
|
||||
|
||||
@ -337,7 +339,8 @@ secpolicy_setid_setsticky_clear(struct inode *ip, vattr_t *vap,
|
||||
* group-id bit.
|
||||
*/
|
||||
if ((vap->va_mode & S_ISGID) != 0 &&
|
||||
secpolicy_vnode_setids_setgids(cr, ovap->va_gid, mnt_ns) != 0) {
|
||||
secpolicy_vnode_setids_setgids(cr, ovap->va_gid,
|
||||
mnt_ns, fs_ns) != 0) {
|
||||
vap->va_mode &= ~S_ISGID;
|
||||
}
|
||||
|
||||
|
@ -1889,7 +1889,8 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
|
||||
acl_ids->z_mode |= S_ISGID;
|
||||
} else {
|
||||
if ((acl_ids->z_mode & S_ISGID) &&
|
||||
secpolicy_vnode_setids_setgids(cr, gid, mnt_ns) != 0) {
|
||||
secpolicy_vnode_setids_setgids(cr, gid, mnt_ns,
|
||||
zfs_i_user_ns(ZTOI(dzp))) != 0) {
|
||||
acl_ids->z_mode &= ~S_ISGID;
|
||||
}
|
||||
}
|
||||
@ -1979,7 +1980,8 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
|
||||
if (mask == 0)
|
||||
return (SET_ERROR(ENOSYS));
|
||||
|
||||
if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr, NULL)))
|
||||
if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr,
|
||||
kcred->user_ns)))
|
||||
return (error);
|
||||
|
||||
mutex_enter(&zp->z_acl_lock);
|
||||
@ -2138,7 +2140,8 @@ zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
|
||||
if (zp->z_pflags & ZFS_IMMUTABLE)
|
||||
return (SET_ERROR(EPERM));
|
||||
|
||||
if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr, NULL)))
|
||||
if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr,
|
||||
kcred->user_ns)))
|
||||
return (error);
|
||||
|
||||
error = zfs_vsec_2_aclp(zfsvfs, ZTOI(zp)->i_mode, vsecp, cr, &fuidp,
|
||||
@ -2301,9 +2304,9 @@ zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
|
||||
uid_t fowner;
|
||||
|
||||
if (mnt_ns) {
|
||||
fowner = zfs_uid_into_mnt(mnt_ns,
|
||||
fowner = zfs_uid_to_vfsuid(mnt_ns, zfs_i_user_ns(ZTOI(zp)),
|
||||
KUID_TO_SUID(ZTOI(zp)->i_uid));
|
||||
gowner = zfs_gid_into_mnt(mnt_ns,
|
||||
gowner = zfs_gid_to_vfsgid(mnt_ns, zfs_i_user_ns(ZTOI(zp)),
|
||||
KGID_TO_SGID(ZTOI(zp)->i_gid));
|
||||
} else
|
||||
zfs_fuid_map_ids(zp, cr, &fowner, &gowner);
|
||||
@ -2417,7 +2420,8 @@ zfs_has_access(znode_t *zp, cred_t *cr)
|
||||
{
|
||||
uint32_t have = ACE_ALL_PERMS;
|
||||
|
||||
if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr, NULL) != 0) {
|
||||
if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr,
|
||||
kcred->user_ns) != 0) {
|
||||
uid_t owner;
|
||||
|
||||
owner = zfs_fuid_map_id(ZTOZSB(zp),
|
||||
@ -2610,7 +2614,8 @@ slow:
|
||||
DTRACE_PROBE(zfs__fastpath__execute__access__miss);
|
||||
if ((error = zfs_enter(ZTOZSB(zdp), FTAG)) != 0)
|
||||
return (error);
|
||||
error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr, NULL);
|
||||
error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr,
|
||||
kcred->user_ns);
|
||||
zfs_exit(ZTOZSB(zdp), FTAG);
|
||||
return (error);
|
||||
}
|
||||
@ -2662,7 +2667,8 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr,
|
||||
}
|
||||
}
|
||||
|
||||
owner = zfs_uid_into_mnt(mnt_ns, KUID_TO_SUID(ZTOI(zp)->i_uid));
|
||||
owner = zfs_uid_to_vfsuid(mnt_ns, zfs_i_user_ns(ZTOI(zp)),
|
||||
KUID_TO_SUID(ZTOI(zp)->i_uid));
|
||||
owner = zfs_fuid_map_id(ZTOZSB(zp), owner, cr, ZFS_OWNER);
|
||||
|
||||
/*
|
||||
@ -2786,7 +2792,7 @@ zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr)
|
||||
{
|
||||
int v4_mode = zfs_unix_to_v4(mode >> 6);
|
||||
|
||||
return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr, NULL));
|
||||
return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr, kcred->user_ns));
|
||||
}
|
||||
|
||||
/* See zfs_zaccess_delete() */
|
||||
|
@ -1113,11 +1113,11 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, znode_t **xzpp, cred_t *cr)
|
||||
*xzpp = NULL;
|
||||
|
||||
if ((error = zfs_zaccess(zp, ACE_WRITE_NAMED_ATTRS, 0, B_FALSE, cr,
|
||||
NULL)))
|
||||
kcred->user_ns)))
|
||||
return (error);
|
||||
|
||||
if ((error = zfs_acl_ids_create(zp, IS_XATTR, vap, cr, NULL,
|
||||
&acl_ids, NULL)) != 0)
|
||||
&acl_ids, kcred->user_ns)) != 0)
|
||||
return (error);
|
||||
if (zfs_acl_ids_overquota(zfsvfs, &acl_ids, zp->z_projid)) {
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
@ -1265,7 +1265,8 @@ zfs_sticky_remove_access(znode_t *zdp, znode_t *zp, cred_t *cr)
|
||||
cr, ZFS_OWNER);
|
||||
|
||||
if ((uid = crgetuid(cr)) == downer || uid == fowner ||
|
||||
zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr, NULL) == 0)
|
||||
zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr,
|
||||
kcred->user_ns) == 0)
|
||||
return (0);
|
||||
else
|
||||
return (secpolicy_vnode_remove(cr));
|
||||
|
@ -476,7 +476,7 @@ zfs_lookup(znode_t *zdp, char *nm, znode_t **zpp, int flags, cred_t *cr,
|
||||
*/
|
||||
|
||||
if ((error = zfs_zaccess(*zpp, ACE_EXECUTE, 0,
|
||||
B_TRUE, cr, NULL))) {
|
||||
B_TRUE, cr, kcred->user_ns))) {
|
||||
zrele(*zpp);
|
||||
*zpp = NULL;
|
||||
}
|
||||
@ -494,7 +494,8 @@ zfs_lookup(znode_t *zdp, char *nm, znode_t **zpp, int flags, cred_t *cr,
|
||||
* Check accessibility of directory.
|
||||
*/
|
||||
|
||||
if ((error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr, NULL))) {
|
||||
if ((error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr,
|
||||
kcred->user_ns))) {
|
||||
zfs_exit(zfsvfs, FTAG);
|
||||
return (error);
|
||||
}
|
||||
@ -972,7 +973,7 @@ top:
|
||||
return (error);
|
||||
}
|
||||
|
||||
if ((error = zfs_zaccess_delete(dzp, zp, cr, NULL))) {
|
||||
if ((error = zfs_zaccess_delete(dzp, zp, cr, kcred->user_ns))) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1386,7 +1387,7 @@ top:
|
||||
return (error);
|
||||
}
|
||||
|
||||
if ((error = zfs_zaccess_delete(dzp, zp, cr, NULL))) {
|
||||
if ((error = zfs_zaccess_delete(dzp, zp, cr, kcred->user_ns))) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -2024,10 +2025,10 @@ top:
|
||||
* Take ownership or chgrp to group we are a member of
|
||||
*/
|
||||
|
||||
uid = zfs_uid_into_mnt((struct user_namespace *)mnt_ns,
|
||||
vap->va_uid);
|
||||
gid = zfs_gid_into_mnt((struct user_namespace *)mnt_ns,
|
||||
vap->va_gid);
|
||||
uid = zfs_uid_to_vfsuid((struct user_namespace *)mnt_ns,
|
||||
zfs_i_user_ns(ip), vap->va_uid);
|
||||
gid = zfs_gid_to_vfsgid((struct user_namespace *)mnt_ns,
|
||||
zfs_i_user_ns(ip), vap->va_gid);
|
||||
take_owner = (mask & ATTR_UID) && (uid == crgetuid(cr));
|
||||
take_group = (mask & ATTR_GID) &&
|
||||
zfs_groupmember(zfsvfs, gid, cr);
|
||||
@ -2162,7 +2163,7 @@ top:
|
||||
if (zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr,
|
||||
mnt_ns) == 0) {
|
||||
err = secpolicy_setid_setsticky_clear(ip, vap,
|
||||
&oldva, cr, mnt_ns);
|
||||
&oldva, cr, mnt_ns, zfs_i_user_ns(ip));
|
||||
if (err)
|
||||
goto out3;
|
||||
trim_mask |= ATTR_MODE;
|
||||
@ -3506,7 +3507,8 @@ zfs_link(znode_t *tdzp, znode_t *szp, char *name, cred_t *cr,
|
||||
return (SET_ERROR(EPERM));
|
||||
}
|
||||
|
||||
if ((error = zfs_zaccess(tdzp, ACE_ADD_FILE, 0, B_FALSE, cr, NULL))) {
|
||||
if ((error = zfs_zaccess(tdzp, ACE_ADD_FILE, 0, B_FALSE, cr,
|
||||
kcred->user_ns))) {
|
||||
zfs_exit(zfsvfs, FTAG);
|
||||
return (error);
|
||||
}
|
||||
@ -4132,7 +4134,8 @@ zfs_space(znode_t *zp, int cmd, flock64_t *bfp, int flag,
|
||||
* On Linux we can get here through truncate_range() which
|
||||
* operates directly on inodes, so we need to check access rights.
|
||||
*/
|
||||
if ((error = zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr, NULL))) {
|
||||
if ((error = zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr,
|
||||
kcred->user_ns))) {
|
||||
zfs_exit(zfsvfs, FTAG);
|
||||
return (error);
|
||||
}
|
||||
|
@ -1964,7 +1964,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx)
|
||||
}
|
||||
|
||||
VERIFY(0 == zfs_acl_ids_create(rootzp, IS_ROOT_NODE, &vattr,
|
||||
cr, NULL, &acl_ids, NULL));
|
||||
cr, NULL, &acl_ids, kcred->user_ns));
|
||||
zfs_mknode(rootzp, &vattr, tx, cr, IS_ROOT_NODE, &zp, &acl_ids);
|
||||
ASSERT3P(zp, ==, rootzp);
|
||||
error = zap_add(os, moid, ZFS_ROOT_OBJ, 8, 1, &rootzp->z_id, tx);
|
||||
|
@ -374,7 +374,7 @@ zpl_snapdir_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
|
||||
#ifdef HAVE_IOPS_MKDIR_USERNS
|
||||
zpl_vap_init(vap, dip, mode | S_IFDIR, cr, user_ns);
|
||||
#else
|
||||
zpl_vap_init(vap, dip, mode | S_IFDIR, cr, NULL);
|
||||
zpl_vap_init(vap, dip, mode | S_IFDIR, cr, kcred->user_ns);
|
||||
#endif
|
||||
|
||||
error = -zfsctl_snapdir_mkdir(dip, dname(dentry), vap, &ip, cr, 0);
|
||||
|
@ -1085,7 +1085,7 @@ zpl_ioctl_setflags(struct file *filp, void __user *arg)
|
||||
|
||||
crhold(cr);
|
||||
cookie = spl_fstrans_mark();
|
||||
err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, NULL);
|
||||
err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, kcred->user_ns);
|
||||
spl_fstrans_unmark(cookie);
|
||||
crfree(cr);
|
||||
|
||||
@ -1133,7 +1133,7 @@ zpl_ioctl_setxattr(struct file *filp, void __user *arg)
|
||||
|
||||
crhold(cr);
|
||||
cookie = spl_fstrans_mark();
|
||||
err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, NULL);
|
||||
err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, kcred->user_ns);
|
||||
spl_fstrans_unmark(cookie);
|
||||
crfree(cr);
|
||||
|
||||
@ -1221,7 +1221,7 @@ zpl_ioctl_setdosflags(struct file *filp, void __user *arg)
|
||||
|
||||
crhold(cr);
|
||||
cookie = spl_fstrans_mark();
|
||||
err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, NULL);
|
||||
err = -zfs_setattr(ITOZ(ip), (vattr_t *)&xva, 0, cr, kcred->user_ns);
|
||||
spl_fstrans_unmark(cookie);
|
||||
crfree(cr);
|
||||
|
||||
|
@ -118,16 +118,16 @@ zpl_vap_init(vattr_t *vap, struct inode *dir, umode_t mode, cred_t *cr,
|
||||
vap->va_mask = ATTR_MODE;
|
||||
vap->va_mode = mode;
|
||||
|
||||
vap->va_uid = zfs_uid_from_mnt((struct user_namespace *)mnt_ns,
|
||||
crgetuid(cr));
|
||||
vap->va_uid = zfs_vfsuid_to_uid((struct user_namespace *)mnt_ns,
|
||||
zfs_i_user_ns(dir), crgetuid(cr));
|
||||
|
||||
if (dir && dir->i_mode & S_ISGID) {
|
||||
vap->va_gid = KGID_TO_SGID(dir->i_gid);
|
||||
if (S_ISDIR(mode))
|
||||
vap->va_mode |= S_ISGID;
|
||||
} else {
|
||||
vap->va_gid = zfs_gid_from_mnt((struct user_namespace *)mnt_ns,
|
||||
crgetgid(cr));
|
||||
vap->va_gid = zfs_vfsgid_to_gid((struct user_namespace *)mnt_ns,
|
||||
zfs_i_user_ns(dir), crgetgid(cr));
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,7 +145,7 @@ zpl_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool flag)
|
||||
int error;
|
||||
fstrans_cookie_t cookie;
|
||||
#ifndef HAVE_IOPS_CREATE_USERNS
|
||||
zuserns_t *user_ns = NULL;
|
||||
zuserns_t *user_ns = kcred->user_ns;
|
||||
#endif
|
||||
|
||||
crhold(cr);
|
||||
@ -192,7 +192,7 @@ zpl_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
int error;
|
||||
fstrans_cookie_t cookie;
|
||||
#ifndef HAVE_IOPS_MKNOD_USERNS
|
||||
zuserns_t *user_ns = NULL;
|
||||
zuserns_t *user_ns = kcred->user_ns;
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -247,7 +247,7 @@ zpl_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
int error;
|
||||
fstrans_cookie_t cookie;
|
||||
#ifndef HAVE_TMPFILE_USERNS
|
||||
zuserns_t *userns = NULL;
|
||||
zuserns_t *userns = kcred->user_ns;
|
||||
#endif
|
||||
|
||||
crhold(cr);
|
||||
@ -325,7 +325,7 @@ zpl_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
int error;
|
||||
fstrans_cookie_t cookie;
|
||||
#ifndef HAVE_IOPS_MKDIR_USERNS
|
||||
zuserns_t *user_ns = NULL;
|
||||
zuserns_t *user_ns = kcred->user_ns;
|
||||
#endif
|
||||
|
||||
crhold(cr);
|
||||
@ -468,8 +468,20 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia)
|
||||
vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP);
|
||||
vap->va_mask = ia->ia_valid & ATTR_IATTR_MASK;
|
||||
vap->va_mode = ia->ia_mode;
|
||||
if (ia->ia_valid & ATTR_UID)
|
||||
#ifdef HAVE_IATTR_VFSID
|
||||
vap->va_uid = zfs_vfsuid_to_uid(user_ns, zfs_i_user_ns(ip),
|
||||
__vfsuid_val(ia->ia_vfsuid));
|
||||
#else
|
||||
vap->va_uid = KUID_TO_SUID(ia->ia_uid);
|
||||
#endif
|
||||
if (ia->ia_valid & ATTR_GID)
|
||||
#ifdef HAVE_IATTR_VFSID
|
||||
vap->va_gid = zfs_vfsgid_to_gid(user_ns, zfs_i_user_ns(ip),
|
||||
__vfsgid_val(ia->ia_vfsgid));
|
||||
#else
|
||||
vap->va_gid = KGID_TO_SGID(ia->ia_gid);
|
||||
#endif
|
||||
vap->va_size = ia->ia_size;
|
||||
vap->va_atime = ia->ia_atime;
|
||||
vap->va_mtime = ia->ia_mtime;
|
||||
@ -482,7 +494,7 @@ zpl_setattr(struct dentry *dentry, struct iattr *ia)
|
||||
#ifdef HAVE_SETATTR_PREPARE_USERNS
|
||||
error = -zfs_setattr(ITOZ(ip), vap, 0, cr, user_ns);
|
||||
#else
|
||||
error = -zfs_setattr(ITOZ(ip), vap, 0, cr, NULL);
|
||||
error = -zfs_setattr(ITOZ(ip), vap, 0, cr, kcred->user_ns);
|
||||
#endif
|
||||
if (!error && (ia->ia_valid & ATTR_MODE))
|
||||
error = zpl_chmod_acl(ip);
|
||||
@ -510,7 +522,7 @@ zpl_rename2(struct inode *sdip, struct dentry *sdentry,
|
||||
int error;
|
||||
fstrans_cookie_t cookie;
|
||||
#ifndef HAVE_IOPS_RENAME_USERNS
|
||||
zuserns_t *user_ns = NULL;
|
||||
zuserns_t *user_ns = kcred->user_ns;
|
||||
#endif
|
||||
|
||||
crhold(cr);
|
||||
@ -557,7 +569,7 @@ zpl_symlink(struct inode *dir, struct dentry *dentry, const char *name)
|
||||
int error;
|
||||
fstrans_cookie_t cookie;
|
||||
#ifndef HAVE_IOPS_SYMLINK_USERNS
|
||||
zuserns_t *user_ns = NULL;
|
||||
zuserns_t *user_ns = kcred->user_ns;
|
||||
#endif
|
||||
|
||||
crhold(cr);
|
||||
|
@ -499,7 +499,7 @@ zpl_xattr_set_dir(struct inode *ip, const char *name, const void *value,
|
||||
vap->va_gid = crgetgid(cr);
|
||||
|
||||
error = -zfs_create(dxzp, (char *)name, vap, 0, 0644, &xzp,
|
||||
cr, 0, NULL, NULL);
|
||||
cr, 0, NULL, kcred->user_ns);
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
@ -738,9 +738,11 @@ __zpl_xattr_user_get(struct inode *ip, const char *name,
|
||||
ZPL_XATTR_GET_WRAPPER(zpl_xattr_user_get);
|
||||
|
||||
static int
|
||||
__zpl_xattr_user_set(struct inode *ip, const char *name,
|
||||
__zpl_xattr_user_set(struct user_namespace *user_ns,
|
||||
struct inode *ip, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
(void) user_ns;
|
||||
int error = 0;
|
||||
/* xattr_resolve_name will do this for us if this is defined */
|
||||
#ifndef HAVE_XATTR_HANDLER_NAME
|
||||
@ -846,9 +848,11 @@ __zpl_xattr_trusted_get(struct inode *ip, const char *name,
|
||||
ZPL_XATTR_GET_WRAPPER(zpl_xattr_trusted_get);
|
||||
|
||||
static int
|
||||
__zpl_xattr_trusted_set(struct inode *ip, const char *name,
|
||||
__zpl_xattr_trusted_set(struct user_namespace *user_ns,
|
||||
struct inode *ip, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
(void) user_ns;
|
||||
char *xattr_name;
|
||||
int error;
|
||||
|
||||
@ -914,9 +918,11 @@ __zpl_xattr_security_get(struct inode *ip, const char *name,
|
||||
ZPL_XATTR_GET_WRAPPER(zpl_xattr_security_get);
|
||||
|
||||
static int
|
||||
__zpl_xattr_security_set(struct inode *ip, const char *name,
|
||||
__zpl_xattr_security_set(struct user_namespace *user_ns,
|
||||
struct inode *ip, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
(void) user_ns;
|
||||
char *xattr_name;
|
||||
int error;
|
||||
/* xattr_resolve_name will do this for us if this is defined */
|
||||
@ -940,7 +946,7 @@ zpl_xattr_security_init_impl(struct inode *ip, const struct xattr *xattrs,
|
||||
int error = 0;
|
||||
|
||||
for (xattr = xattrs; xattr->name != NULL; xattr++) {
|
||||
error = __zpl_xattr_security_set(ip,
|
||||
error = __zpl_xattr_security_set(NULL, ip,
|
||||
xattr->name, xattr->value, xattr->value_len, 0);
|
||||
|
||||
if (error < 0)
|
||||
@ -1300,7 +1306,8 @@ __zpl_xattr_acl_get_default(struct inode *ip, const char *name,
|
||||
ZPL_XATTR_GET_WRAPPER(zpl_xattr_acl_get_default);
|
||||
|
||||
static int
|
||||
__zpl_xattr_acl_set_access(struct inode *ip, const char *name,
|
||||
__zpl_xattr_acl_set_access(struct user_namespace *mnt_ns,
|
||||
struct inode *ip, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
@ -1314,8 +1321,14 @@ __zpl_xattr_acl_set_access(struct inode *ip, const char *name,
|
||||
if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX)
|
||||
return (-EOPNOTSUPP);
|
||||
|
||||
#if defined(HAVE_XATTR_SET_USERNS)
|
||||
if (!zpl_inode_owner_or_capable(mnt_ns, ip))
|
||||
return (-EPERM);
|
||||
#else
|
||||
(void) mnt_ns;
|
||||
if (!zpl_inode_owner_or_capable(kcred->user_ns, ip))
|
||||
return (-EPERM);
|
||||
#endif
|
||||
|
||||
if (value) {
|
||||
acl = zpl_acl_from_xattr(value, size);
|
||||
@ -1339,7 +1352,8 @@ __zpl_xattr_acl_set_access(struct inode *ip, const char *name,
|
||||
ZPL_XATTR_SET_WRAPPER(zpl_xattr_acl_set_access);
|
||||
|
||||
static int
|
||||
__zpl_xattr_acl_set_default(struct inode *ip, const char *name,
|
||||
__zpl_xattr_acl_set_default(struct user_namespace *mnt_ns,
|
||||
struct inode *ip, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
struct posix_acl *acl;
|
||||
@ -1353,8 +1367,14 @@ __zpl_xattr_acl_set_default(struct inode *ip, const char *name,
|
||||
if (ITOZSB(ip)->z_acl_type != ZFS_ACLTYPE_POSIX)
|
||||
return (-EOPNOTSUPP);
|
||||
|
||||
#if defined(HAVE_XATTR_SET_USERNS)
|
||||
if (!zpl_inode_owner_or_capable(mnt_ns, ip))
|
||||
return (-EPERM);
|
||||
#else
|
||||
(void) mnt_ns;
|
||||
if (!zpl_inode_owner_or_capable(kcred->user_ns, ip))
|
||||
return (-EPERM);
|
||||
#endif
|
||||
|
||||
if (value) {
|
||||
acl = zpl_acl_from_xattr(value, size);
|
||||
|
@ -386,8 +386,13 @@ zfs_replay_create_acl(void *arg1, void *arg2, boolean_t byteswap)
|
||||
lr->lr_uid, lr->lr_gid);
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
error = zfs_create(dzp, name, &xva.xva_vattr,
|
||||
0, 0, &zp, kcred, vflg, &vsec, kcred->user_ns);
|
||||
#else
|
||||
error = zfs_create(dzp, name, &xva.xva_vattr,
|
||||
0, 0, &zp, kcred, vflg, &vsec, NULL);
|
||||
#endif
|
||||
break;
|
||||
case TX_MKDIR_ACL:
|
||||
aclstart = (caddr_t)(lracl + 1);
|
||||
@ -416,8 +421,13 @@ zfs_replay_create_acl(void *arg1, void *arg2, boolean_t byteswap)
|
||||
(void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt,
|
||||
lr->lr_uid, lr->lr_gid);
|
||||
}
|
||||
#if defined(__linux__)
|
||||
error = zfs_mkdir(dzp, name, &xva.xva_vattr,
|
||||
&zp, kcred, vflg, &vsec, kcred->user_ns);
|
||||
#else
|
||||
error = zfs_mkdir(dzp, name, &xva.xva_vattr,
|
||||
&zp, kcred, vflg, &vsec, NULL);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
error = SET_ERROR(ENOTSUP);
|
||||
@ -527,8 +537,13 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap)
|
||||
if (name == NULL)
|
||||
name = (char *)start;
|
||||
|
||||
#if defined(__linux__)
|
||||
error = zfs_create(dzp, name, &xva.xva_vattr,
|
||||
0, 0, &zp, kcred, vflg, NULL, kcred->user_ns);
|
||||
#else
|
||||
error = zfs_create(dzp, name, &xva.xva_vattr,
|
||||
0, 0, &zp, kcred, vflg, NULL, NULL);
|
||||
#endif
|
||||
break;
|
||||
case TX_MKDIR_ATTR:
|
||||
lrattr = (lr_attr_t *)(caddr_t)(lr + 1);
|
||||
@ -545,8 +560,14 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap)
|
||||
if (name == NULL)
|
||||
name = (char *)(lr + 1);
|
||||
|
||||
#if defined(__linux__)
|
||||
error = zfs_mkdir(dzp, name, &xva.xva_vattr,
|
||||
&zp, kcred, vflg, NULL, kcred->user_ns);
|
||||
#else
|
||||
error = zfs_mkdir(dzp, name, &xva.xva_vattr,
|
||||
&zp, kcred, vflg, NULL, NULL);
|
||||
#endif
|
||||
|
||||
break;
|
||||
case TX_MKXATTR:
|
||||
error = zfs_make_xattrdir(dzp, &xva.xva_vattr, &zp, kcred);
|
||||
@ -554,8 +575,13 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap)
|
||||
case TX_SYMLINK:
|
||||
name = (char *)(lr + 1);
|
||||
link = name + strlen(name) + 1;
|
||||
#if defined(__linux__)
|
||||
error = zfs_symlink(dzp, name, &xva.xva_vattr,
|
||||
link, &zp, kcred, vflg, kcred->user_ns);
|
||||
#else
|
||||
error = zfs_symlink(dzp, name, &xva.xva_vattr,
|
||||
link, &zp, kcred, vflg, NULL);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
error = SET_ERROR(ENOTSUP);
|
||||
@ -670,8 +696,13 @@ do_zfs_replay_rename(zfsvfs_t *zfsvfs, lr_rename_t *lr, char *sname,
|
||||
if (lr->lr_common.lrc_txtype & TX_CI)
|
||||
vflg |= FIGNORECASE;
|
||||
|
||||
#if defined(__linux__)
|
||||
error = zfs_rename(sdzp, sname, tdzp, tname, kcred, vflg, rflags,
|
||||
wo_vap, kcred->user_ns);
|
||||
#else
|
||||
error = zfs_rename(sdzp, sname, tdzp, tname, kcred, vflg, rflags,
|
||||
wo_vap, NULL);
|
||||
#endif
|
||||
|
||||
zrele(tdzp);
|
||||
zrele(sdzp);
|
||||
@ -944,7 +975,11 @@ zfs_replay_setattr(void *arg1, void *arg2, boolean_t byteswap)
|
||||
zfsvfs->z_fuid_replay = zfs_replay_fuid_domain(start, &start,
|
||||
lr->lr_uid, lr->lr_gid);
|
||||
|
||||
#if defined(__linux__)
|
||||
error = zfs_setattr(zp, vap, 0, kcred, kcred->user_ns);
|
||||
#else
|
||||
error = zfs_setattr(zp, vap, 0, kcred, NULL);
|
||||
#endif
|
||||
|
||||
zfs_fuid_info_free(zfsvfs->z_fuid_replay);
|
||||
zfsvfs->z_fuid_replay = NULL;
|
||||
|
@ -168,9 +168,19 @@ zfs_access(znode_t *zp, int mode, int flag, cred_t *cr)
|
||||
return (error);
|
||||
|
||||
if (flag & V_ACE_MASK)
|
||||
error = zfs_zaccess(zp, mode, flag, B_FALSE, cr, NULL);
|
||||
#if defined(__linux__)
|
||||
error = zfs_zaccess(zp, mode, flag, B_FALSE, cr,
|
||||
kcred->user_ns);
|
||||
#else
|
||||
error = zfs_zaccess(zp, mode, flag, B_FALSE, cr,
|
||||
NULL);
|
||||
#endif
|
||||
else
|
||||
#if defined(__linux__)
|
||||
error = zfs_zaccess_rwx(zp, mode, flag, cr, kcred->user_ns);
|
||||
#else
|
||||
error = zfs_zaccess_rwx(zp, mode, flag, cr, NULL);
|
||||
#endif
|
||||
|
||||
zfs_exit(zfsvfs, FTAG);
|
||||
return (error);
|
||||
|
@ -200,5 +200,5 @@ tags = ['functional', 'zvol', 'zvol_misc']
|
||||
|
||||
[tests/functional/idmap_mount:Linux]
|
||||
tests = ['idmap_mount_001', 'idmap_mount_002', 'idmap_mount_003',
|
||||
'idmap_mount_004']
|
||||
'idmap_mount_004', 'idmap_mount_005']
|
||||
tags = ['functional', 'idmap_mount']
|
||||
|
@ -284,6 +284,7 @@ elif sys.platform.startswith('linux'):
|
||||
'idmap_mount/idmap_mount_002': ['SKIP', idmap_reason],
|
||||
'idmap_mount/idmap_mount_003': ['SKIP', idmap_reason],
|
||||
'idmap_mount/idmap_mount_004': ['SKIP', idmap_reason],
|
||||
'idmap_mount/idmap_mount_005': ['SKIP', idmap_reason],
|
||||
})
|
||||
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <syscall.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <sys/list.h>
|
||||
|
||||
@ -458,43 +459,56 @@ userns_fd_from_idmap(list_t *head)
|
||||
{
|
||||
pid_t pid;
|
||||
int ret, fd;
|
||||
int pipe_fd[2];
|
||||
int fds[2];
|
||||
char c;
|
||||
int saved_errno = 0;
|
||||
|
||||
/* pipe for bidirectional communication */
|
||||
ret = pipe(pipe_fd);
|
||||
/* socketpair for bidirectional communication */
|
||||
ret = socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, fds);
|
||||
if (ret) {
|
||||
log_errno("pipe");
|
||||
log_errno("socketpair");
|
||||
return (-errno);
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
log_errno("fork");
|
||||
return (-errno);
|
||||
fd = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pid == 0) {
|
||||
/* child process */
|
||||
close(pipe_fd[0]);
|
||||
ret = unshare(CLONE_NEWUSER);
|
||||
if (ret == 0) {
|
||||
/* notify the parent of success */
|
||||
ret = write_buf(pipe_fd[1], "1", 1);
|
||||
ret = write_buf(fds[1], "1", 1);
|
||||
if (ret < 0)
|
||||
saved_errno = errno;
|
||||
else {
|
||||
/*
|
||||
* Until the parent has written to idmap,
|
||||
* we cannot exit, otherwise the defunct
|
||||
* process is owned by the real root, writing
|
||||
* to its idmap ends up with EPERM in the
|
||||
* context of a user ns
|
||||
*/
|
||||
ret = read_buf(fds[1], &c, 1);
|
||||
if (ret < 0)
|
||||
saved_errno = errno;
|
||||
}
|
||||
} else {
|
||||
saved_errno = errno;
|
||||
log_errno("unshare");
|
||||
ret = write_buf(pipe_fd[1], "0", 1);
|
||||
}
|
||||
ret = write_buf(fds[1], "0", 1);
|
||||
if (ret < 0)
|
||||
saved_errno = errno;
|
||||
close(pipe_fd[1]);
|
||||
}
|
||||
exit(saved_errno);
|
||||
}
|
||||
|
||||
/* parent process */
|
||||
close(pipe_fd[1]);
|
||||
ret = read_buf(pipe_fd[0], &c, 1);
|
||||
ret = read_buf(fds[0], &c, 1);
|
||||
if (ret == 1 && c == '1') {
|
||||
ret = write_pid_idmaps(pid, head);
|
||||
if (!ret) {
|
||||
@ -504,11 +518,15 @@ userns_fd_from_idmap(list_t *head)
|
||||
} else {
|
||||
fd = -ret;
|
||||
}
|
||||
/* Let child know it can exit */
|
||||
(void) write_buf(fds[0], "1", 1);
|
||||
} else {
|
||||
fd = -EBADF;
|
||||
}
|
||||
close(pipe_fd[0]);
|
||||
(void) wait_for_pid(pid);
|
||||
out:
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return (fd);
|
||||
}
|
||||
|
||||
@ -532,7 +550,8 @@ is_idmap_supported(char *path)
|
||||
};
|
||||
|
||||
/* strtok_r() won't be happy with a const string */
|
||||
char *input = strdup("b:0:1000000:1000000");
|
||||
/* To check if idmapped mount can be done in a user ns, map 0 to 0 */
|
||||
char *input = strdup("b:0:0:1");
|
||||
|
||||
if (!input) {
|
||||
errno = ENOMEM;
|
||||
|
@ -2006,4 +2006,5 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||
functional/idmap_mount/idmap_mount_001.ksh \
|
||||
functional/idmap_mount/idmap_mount_002.ksh \
|
||||
functional/idmap_mount/idmap_mount_003.ksh \
|
||||
functional/idmap_mount/idmap_mount_004.ksh
|
||||
functional/idmap_mount/idmap_mount_004.ksh \
|
||||
functional/idmap_mount/idmap_mount_005.ksh
|
||||
|
138
tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_005.ksh
Executable file
138
tests/zfs-tests/tests/functional/idmap_mount/idmap_mount_005.ksh
Executable file
@ -0,0 +1,138 @@
|
||||
#!/bin/ksh -p
|
||||
#
|
||||
# CDDL HEADER START
|
||||
#
|
||||
# The contents of this file are subject to the terms of the
|
||||
# Common Development and Distribution License (the "License").
|
||||
# You may not use this file except in compliance with the License.
|
||||
#
|
||||
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
# or https://opensource.org/licenses/CDDL-1.0.
|
||||
# See the License for the specific language governing permissions
|
||||
# and limitations under the License.
|
||||
#
|
||||
# When distributing Covered Code, include this CDDL HEADER in each
|
||||
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
# If applicable, add the following below this CDDL HEADER, with the
|
||||
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
#
|
||||
# CDDL HEADER END
|
||||
#
|
||||
|
||||
. $STF_SUITE/tests/functional/idmap_mount/idmap_mount_common.kshlib
|
||||
|
||||
#
|
||||
#
|
||||
# DESCRIPTION:
|
||||
# Test idmapped mount in a user namespace
|
||||
#
|
||||
# STRATEGY:
|
||||
# 1. Create a zoned dataset
|
||||
# 2. Create a user namespace and designate the dataset to the zone
|
||||
# 3. In the zone, mount the dataset to "idmap_test"
|
||||
# 4. In the zone, idmap mount the dataset mountpoint to "idmap_dest"
|
||||
# 5. Do some file operations in the idmapped mountpoint "idmap_dest"
|
||||
# 6. Check the owner of files/folder in the mount point "idmap_test"
|
||||
# 7. unmount the mountpoints in the zone
|
||||
# 8. Remount the dataset in global zone to "idmap_test"
|
||||
# 9. Check the owenr of filers/folder in the mountpoint "idmap_test"
|
||||
#
|
||||
|
||||
verify_runnable "global"
|
||||
|
||||
export WORKDIR=$TESTDIR/idmap_test
|
||||
export IDMAPDIR=$TESTDIR/idmap_dest
|
||||
|
||||
function cleanup
|
||||
{
|
||||
if [[ -v unshared_pid ]]; then
|
||||
zfs unzone /proc/$unshared_pid/ns/user "$TESTPOOL/userns"
|
||||
kill -TERM ${unshared_pid}
|
||||
fi
|
||||
if mountpoint $WORKDIR; then
|
||||
log_must umount $WORKDIR
|
||||
fi
|
||||
log_must rm -rf $WORKDIR
|
||||
}
|
||||
|
||||
log_onexit cleanup
|
||||
|
||||
if ! idmap_util -c $TESTDIR; then
|
||||
log_unsupported "Idmap mount not supported."
|
||||
fi
|
||||
|
||||
unshare -Urm echo test
|
||||
if [ "$?" -ne "0" ]; then
|
||||
log_unsupported "Failed to create user namespace"
|
||||
fi
|
||||
|
||||
log_must zfs create -o zoned=off -o mountpoint=$WORKDIR "$TESTPOOL/userns"
|
||||
|
||||
# "root" user and group in the user ns
|
||||
log_must chown 1000000:1000000 $WORKDIR
|
||||
log_must zfs set zoned=on "$TESTPOOL/userns"
|
||||
|
||||
log_must mkdir -p $IDMAPDIR
|
||||
|
||||
unshare -Um /usr/bin/sleep 2h &
|
||||
unshared_pid=$!
|
||||
if [ "$?" -ne "0" ]; then
|
||||
log_unsupported "Failed to create user namespace"
|
||||
fi
|
||||
# wait for userns to be ready
|
||||
sleep 1
|
||||
echo "0 1000000 1000000" > /proc/$unshared_pid/uid_map
|
||||
if [ "$?" -ne "0" ]; then
|
||||
log_unsupported "Failed to write to uid_map"
|
||||
fi
|
||||
echo "0 1000000 1000000" > /proc/$unshared_pid/gid_map
|
||||
if [ "$?" -ne "0" ]; then
|
||||
log_unsupported "Failed to write to gid_map"
|
||||
fi
|
||||
|
||||
NSENTER="nsenter -t $unshared_pid --all -S 0 -G 0"
|
||||
|
||||
log_must zfs zone /proc/$unshared_pid/ns/user "$TESTPOOL/userns"
|
||||
log_must $NSENTER zfs mount "$TESTPOOL/userns"
|
||||
log_must $NSENTER chmod 777 $WORKDIR
|
||||
|
||||
$NSENTER idmap_util -c $WORKDIR
|
||||
if [ "$?" -ne "0" ]; then
|
||||
log_unsupported "Idmapped mount not supported in a user namespace"
|
||||
fi
|
||||
|
||||
log_must $NSENTER idmap_util -m b:0:10000:100000 $WORKDIR $IDMAPDIR
|
||||
log_must $NSENTER setpriv --reuid 11000 --regid 11000 --clear-groups touch $IDMAPDIR/file
|
||||
log_must $NSENTER setpriv --reuid 11000 --regid 11000 --clear-groups mkdir $IDMAPDIR/folder
|
||||
log_must $NSENTER setpriv --reuid 11000 --regid 11000 --clear-groups ln -s file $IDMAPDIR/file-soft
|
||||
log_must $NSENTER setpriv --reuid 11000 --regid 11000 --clear-groups ln $IDMAPDIR/file $IDMAPDIR/file-hard
|
||||
|
||||
log_must $NSENTER setpriv --reuid 11000 --regid 11000 --clear-groups cp -p $IDMAPDIR/file $IDMAPDIR/folder/file-p
|
||||
log_must $NSENTER setpriv --reuid 11000 --regid 11000 --clear-groups cp $IDMAPDIR/file $IDMAPDIR/folder/file
|
||||
|
||||
log_must test "1000 1000" = "$($NSENTER stat -c '%u %g' $WORKDIR/file)"
|
||||
log_must test "1000 1000" = "$($NSENTER stat -c '%u %g' $WORKDIR/folder)"
|
||||
log_must test "1000 1000" = "$($NSENTER stat -c '%u %g' $WORKDIR/file-soft)"
|
||||
log_must test "1000 1000" = "$($NSENTER stat -c '%u %g' $WORKDIR/file-hard)"
|
||||
log_must test "1000 1000" = "$($NSENTER stat -c '%u %g' $WORKDIR/folder/file-p)"
|
||||
log_must test "1000 1000" = "$($NSENTER stat -c '%u %g' $WORKDIR/folder/file)"
|
||||
|
||||
log_must $NSENTER umount $IDMAPDIR
|
||||
log_must $NSENTER umount $WORKDIR
|
||||
|
||||
log_must zfs unzone /proc/$unshared_pid/ns/user "$TESTPOOL/userns"
|
||||
log_must kill -TERM $unshared_pid
|
||||
unset unshared_pid
|
||||
log_must zfs set zoned=off "$TESTPOOL/userns"
|
||||
log_must zfs mount "$TESTPOOL/userns"
|
||||
|
||||
log_must test "1001000 1001000" = "$(stat -c '%u %g' $WORKDIR/file)"
|
||||
log_must test "1001000 1001000" = "$(stat -c '%u %g' $WORKDIR/folder)"
|
||||
log_must test "1001000 1001000" = "$(stat -c '%u %g' $WORKDIR/file-soft)"
|
||||
log_must test "1001000 1001000" = "$(stat -c '%u %g' $WORKDIR/file-hard)"
|
||||
log_must test "1001000 1001000" = "$(stat -c '%u %g' $WORKDIR/folder/file-p)"
|
||||
log_must test "1001000 1001000" = "$(stat -c '%u %g' $WORKDIR/folder/file)"
|
||||
|
||||
log_pass "Testing idmapped mount in a user ns is successful."
|
||||
|
Loading…
Reference in New Issue
Block a user