Support idmapped mount

Adds support for idmapped mounts.  Supported as of Linux 5.12 this 
functionality allows user and group IDs to be remapped without changing 
their state on disk.  This can be useful for portable home directories
and a variety of container related use cases.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Ryan Moeller <ryan@iXsystems.com>
Signed-off-by: Youzhong Yang <yyang@mathworks.com>
Closes #12923
Closes #13671
This commit is contained in:
youzhongyang
2022-10-19 14:17:09 -04:00
committed by GitHub
parent eaaed26ffb
commit 2a068a1394
41 changed files with 1636 additions and 166 deletions
+17 -13
View File
@@ -1619,7 +1619,7 @@ zfs_acl_inherit(zfsvfs_t *zfsvfs, vtype_t vtype, zfs_acl_t *paclp,
*/
int
zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids)
vsecattr_t *vsecp, zfs_acl_ids_t *acl_ids, zuserns_t *mnt_ns)
{
int error;
zfsvfs_t *zfsvfs = dzp->z_zfsvfs;
@@ -1789,7 +1789,7 @@ 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)))
if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr, NULL)))
return (error);
mutex_enter(&zp->z_acl_lock);
@@ -1952,7 +1952,7 @@ 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)))
if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr, NULL)))
return (error);
error = zfs_vsec_2_aclp(zfsvfs, ZTOV(zp)->v_type, vsecp, cr, &fuidp,
@@ -2341,7 +2341,8 @@ zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr)
* can define any form of access.
*/
int
zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr,
zuserns_t *mnt_ns)
{
uint32_t working_mode;
int error;
@@ -2471,9 +2472,11 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr)
* NFSv4-style ZFS ACL format and call zfs_zaccess()
*/
int
zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr)
zfs_zaccess_rwx(znode_t *zp, mode_t mode, int flags, cred_t *cr,
zuserns_t *mnt_ns)
{
return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr));
return (zfs_zaccess(zp, zfs_unix_to_v4(mode >> 6), flags, B_FALSE, cr,
mnt_ns));
}
/*
@@ -2484,7 +2487,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));
return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr, NULL));
}
static int
@@ -2540,7 +2543,7 @@ zfs_delete_final_check(znode_t *zp, znode_t *dzp,
*
*/
int
zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr, zuserns_t *mnt_ns)
{
uint32_t dzp_working_mode = 0;
uint32_t zp_working_mode = 0;
@@ -2627,7 +2630,7 @@ zfs_zaccess_delete(znode_t *dzp, znode_t *zp, cred_t *cr)
int
zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
znode_t *tzp, cred_t *cr)
znode_t *tzp, cred_t *cr, zuserns_t *mnt_ns)
{
int add_perm;
int error;
@@ -2647,7 +2650,8 @@ zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
* to another.
*/
if (ZTOV(szp)->v_type == VDIR && ZTOV(sdzp) != ZTOV(tdzp)) {
if ((error = zfs_zaccess(szp, ACE_WRITE_DATA, 0, B_FALSE, cr)))
if ((error = zfs_zaccess(szp, ACE_WRITE_DATA, 0, B_FALSE, cr,
mnt_ns)))
return (error);
}
@@ -2657,19 +2661,19 @@ zfs_zaccess_rename(znode_t *sdzp, znode_t *szp, znode_t *tdzp,
* If that succeeds then check for add_file/add_subdir permissions
*/
if ((error = zfs_zaccess_delete(sdzp, szp, cr)))
if ((error = zfs_zaccess_delete(sdzp, szp, cr, mnt_ns)))
return (error);
/*
* If we have a tzp, see if we can delete it?
*/
if (tzp && (error = zfs_zaccess_delete(tdzp, tzp, cr)))
if (tzp && (error = zfs_zaccess_delete(tdzp, tzp, cr, mnt_ns)))
return (error);
/*
* Now check for add permissions
*/
error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr);
error = zfs_zaccess(tdzp, add_perm, 0, B_FALSE, cr, mnt_ns);
return (error);
}
+2 -2
View File
@@ -809,7 +809,7 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, znode_t **xvpp, cred_t *cr)
*xvpp = NULL;
if ((error = zfs_acl_ids_create(zp, IS_XATTR, vap, cr, NULL,
&acl_ids)) != 0)
&acl_ids, NULL)) != 0)
return (error);
if (zfs_acl_ids_overquota(zfsvfs, &acl_ids, 0)) {
zfs_acl_ids_free(&acl_ids);
@@ -955,7 +955,7 @@ zfs_sticky_remove_access(znode_t *zdp, znode_t *zp, cred_t *cr)
if ((uid = crgetuid(cr)) == downer || uid == fowner ||
(ZTOV(zp)->v_type == VREG &&
zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr) == 0))
zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr, NULL) == 0))
return (0);
else
return (secpolicy_vnode_remove(ZTOV(zp), cr));
+33 -27
View File
@@ -837,7 +837,7 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp,
/*
* Do we have permission to get into attribute directory?
*/
error = zfs_zaccess(zp, ACE_EXECUTE, 0, B_FALSE, cr);
error = zfs_zaccess(zp, ACE_EXECUTE, 0, B_FALSE, cr, NULL);
if (error) {
vrele(ZTOV(zp));
}
@@ -856,7 +856,8 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp,
cnp->cn_flags &= ~NOEXECCHECK;
} else
#endif
if ((error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr))) {
if ((error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr,
NULL))) {
zfs_exit(zfsvfs, FTAG);
return (error);
}
@@ -1036,6 +1037,7 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp,
* flag - large file flag [UNUSED].
* ct - caller context
* vsecp - ACL to be set
* mnt_ns - Unused on FreeBSD
*
* OUT: vpp - vnode of created or trunc'd entry.
*
@@ -1047,7 +1049,7 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp,
*/
int
zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode,
znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp)
znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp, zuserns_t *mnt_ns)
{
(void) excl, (void) mode, (void) flag;
znode_t *zp;
@@ -1110,7 +1112,7 @@ zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode,
* Create a new file object and update the directory
* to reference it.
*/
if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr))) {
if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr, mnt_ns))) {
goto out;
}
@@ -1126,7 +1128,7 @@ zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode,
}
if ((error = zfs_acl_ids_create(dzp, 0, vap,
cr, vsecp, &acl_ids)) != 0)
cr, vsecp, &acl_ids, NULL)) != 0)
goto out;
if (S_ISREG(vap->va_mode) || S_ISDIR(vap->va_mode))
@@ -1231,7 +1233,7 @@ zfs_remove_(vnode_t *dvp, vnode_t *vp, const char *name, cred_t *cr)
xattr_obj = 0;
xzp = NULL;
if ((error = zfs_zaccess_delete(dzp, zp, cr))) {
if ((error = zfs_zaccess_delete(dzp, zp, cr, NULL))) {
goto out;
}
@@ -1387,6 +1389,7 @@ zfs_remove(znode_t *dzp, const char *name, cred_t *cr, int flags)
* ct - caller context
* flags - case flags
* vsecp - ACL to be set
* mnt_ns - Unused on FreeBSD
*
* OUT: vpp - vnode of created directory.
*
@@ -1398,7 +1401,7 @@ zfs_remove(znode_t *dzp, const char *name, cred_t *cr, int flags)
*/
int
zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, znode_t **zpp,
cred_t *cr, int flags, vsecattr_t *vsecp)
cred_t *cr, int flags, vsecattr_t *vsecp, zuserns_t *mnt_ns)
{
(void) flags, (void) vsecp;
znode_t *zp;
@@ -1447,7 +1450,7 @@ zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, znode_t **zpp,
}
if ((error = zfs_acl_ids_create(dzp, 0, vap, cr,
NULL, &acl_ids)) != 0) {
NULL, &acl_ids, NULL)) != 0) {
zfs_exit(zfsvfs, FTAG);
return (error);
}
@@ -1468,7 +1471,8 @@ zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, znode_t **zpp,
}
ASSERT3P(zp, ==, NULL);
if ((error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr))) {
if ((error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr,
mnt_ns))) {
zfs_acl_ids_free(&acl_ids);
zfs_exit(zfsvfs, FTAG);
return (error);
@@ -1585,7 +1589,7 @@ zfs_rmdir_(vnode_t *dvp, vnode_t *vp, const char *name, cred_t *cr)
zilog = zfsvfs->z_log;
if ((error = zfs_zaccess_delete(dzp, zp, cr))) {
if ((error = zfs_zaccess_delete(dzp, zp, cr, NULL))) {
goto out;
}
@@ -1976,7 +1980,7 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
if (!(zp->z_pflags & ZFS_ACL_TRIVIAL) &&
(vap->va_uid != crgetuid(cr))) {
if ((error = zfs_zaccess(zp, ACE_READ_ATTRIBUTES, 0,
skipaclchk, cr))) {
skipaclchk, cr, NULL))) {
zfs_exit(zfsvfs, FTAG);
return (error);
}
@@ -2142,7 +2146,7 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
* flags - ATTR_UTIME set if non-default time values provided.
* - ATTR_NOACLCHECK (CIFS context only).
* cr - credentials of caller.
* ct - caller context
* mnt_ns - Unused on FreeBSD
*
* RETURN: 0 on success, error code on failure.
*
@@ -2150,7 +2154,7 @@ zfs_getattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr)
* vp - ctime updated, mtime updated if size changed.
*/
int
zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr)
zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zuserns_t *mnt_ns)
{
vnode_t *vp = ZTOV(zp);
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
@@ -2322,7 +2326,7 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr)
XVA_ISSET_REQ(xvap, XAT_CREATETIME) ||
XVA_ISSET_REQ(xvap, XAT_SYSTEM)))) {
need_policy = zfs_zaccess(zp, ACE_WRITE_ATTRIBUTES, 0,
skipaclchk, cr);
skipaclchk, cr, mnt_ns);
}
if (mask & (AT_UID|AT_GID)) {
@@ -2359,7 +2363,7 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr)
((idmask == AT_UID) && take_owner) ||
((idmask == AT_GID) && take_group)) {
if (zfs_zaccess(zp, ACE_WRITE_OWNER, 0,
skipaclchk, cr) == 0) {
skipaclchk, cr, mnt_ns) == 0) {
/*
* Remove setuid/setgid for non-privileged users
*/
@@ -2468,7 +2472,8 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr)
}
if (mask & AT_MODE) {
if (zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr) == 0) {
if (zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr,
mnt_ns) == 0) {
err = secpolicy_setid_setsticky_clear(vp, vap,
&oldva, cr);
if (err) {
@@ -3264,7 +3269,7 @@ zfs_do_rename_impl(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp,
* Note that if target and source are the same, this can be
* done in a single check.
*/
if ((error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr)))
if ((error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr, NULL)))
goto out;
if ((*svpp)->v_type == VDIR) {
@@ -3415,7 +3420,7 @@ out:
int
zfs_rename(znode_t *sdzp, const char *sname, znode_t *tdzp, const char *tname,
cred_t *cr, int flags)
cred_t *cr, int flags, zuserns_t *mnt_ns)
{
struct componentname scn, tcn;
vnode_t *sdvp, *tdvp;
@@ -3460,6 +3465,7 @@ fail:
* cr - credentials of caller.
* ct - caller context
* flags - case flags
* mnt_ns - Unused on FreeBSD
*
* RETURN: 0 on success, error code on failure.
*
@@ -3468,7 +3474,7 @@ fail:
*/
int
zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap,
const char *link, znode_t **zpp, cred_t *cr, int flags)
const char *link, znode_t **zpp, cred_t *cr, int flags, zuserns_t *mnt_ns)
{
(void) flags;
znode_t *zp;
@@ -3499,7 +3505,7 @@ zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap,
}
if ((error = zfs_acl_ids_create(dzp, 0,
vap, cr, NULL, &acl_ids)) != 0) {
vap, cr, NULL, &acl_ids, NULL)) != 0) {
zfs_exit(zfsvfs, FTAG);
return (error);
}
@@ -3514,7 +3520,7 @@ zfs_symlink(znode_t *dzp, const char *name, vattr_t *vap,
return (error);
}
if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr))) {
if ((error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr, mnt_ns))) {
zfs_acl_ids_free(&acl_ids);
zfs_exit(zfsvfs, FTAG);
return (error);
@@ -3730,7 +3736,7 @@ zfs_link(znode_t *tdzp, znode_t *szp, const char *name, cred_t *cr,
return (SET_ERROR(EPERM));
}
if ((error = zfs_zaccess(tdzp, ACE_ADD_FILE, 0, B_FALSE, cr))) {
if ((error = zfs_zaccess(tdzp, ACE_ADD_FILE, 0, B_FALSE, cr, NULL))) {
zfs_exit(zfsvfs, FTAG);
return (error);
}
@@ -3831,7 +3837,7 @@ 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))) {
if ((error = zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr, NULL))) {
zfs_exit(zfsvfs, FTAG);
return (error);
}
@@ -4607,7 +4613,7 @@ zfs_freebsd_create(struct vop_create_args *ap)
*ap->a_vpp = NULL;
rc = zfs_create(VTOZ(ap->a_dvp), cnp->cn_nameptr, vap, 0, mode,
&zp, cnp->cn_cred, 0 /* flag */, NULL /* vsecattr */);
&zp, cnp->cn_cred, 0 /* flag */, NULL /* vsecattr */, NULL);
if (rc == 0)
*ap->a_vpp = ZTOV(zp);
if (zfsvfs->z_use_namecache &&
@@ -4661,7 +4667,7 @@ zfs_freebsd_mkdir(struct vop_mkdir_args *ap)
*ap->a_vpp = NULL;
rc = zfs_mkdir(VTOZ(ap->a_dvp), ap->a_cnp->cn_nameptr, vap, &zp,
ap->a_cnp->cn_cred, 0, NULL);
ap->a_cnp->cn_cred, 0, NULL, NULL);
if (rc == 0)
*ap->a_vpp = ZTOV(zp);
@@ -4914,7 +4920,7 @@ zfs_freebsd_setattr(struct vop_setattr_args *ap)
xvap.xva_vattr.va_mask |= AT_XVATTR;
XVA_SET_REQ(&xvap, XAT_CREATETIME);
}
return (zfs_setattr(VTOZ(vp), (vattr_t *)&xvap, 0, cred));
return (zfs_setattr(VTOZ(vp), (vattr_t *)&xvap, 0, cred, NULL));
}
#ifndef _SYS_SYSPROTO_H_
@@ -4985,7 +4991,7 @@ zfs_freebsd_symlink(struct vop_symlink_args *ap)
*ap->a_vpp = NULL;
rc = zfs_symlink(VTOZ(ap->a_dvp), cnp->cn_nameptr, vap,
ap->a_target, &zp, cnp->cn_cred, 0 /* flags */);
ap->a_target, &zp, cnp->cn_cred, 0 /* flags */, NULL);
if (rc == 0) {
*ap->a_vpp = ZTOV(zp);
ASSERT_VOP_ELOCKED(ZTOV(zp), __func__);
+2 -2
View File
@@ -298,7 +298,7 @@ zfs_create_share_dir(zfsvfs_t *zfsvfs, dmu_tx_t *tx)
sharezp->z_is_sa = zfsvfs->z_use_sa;
VERIFY0(zfs_acl_ids_create(sharezp, IS_ROOT_NODE, &vattr,
kcred, NULL, &acl_ids));
kcred, NULL, &acl_ids, NULL));
zfs_mknode(sharezp, &vattr, tx, kcred, IS_ROOT_NODE, &zp, &acl_ids);
ASSERT3P(zp, ==, sharezp);
POINTER_INVALIDATE(&sharezp->z_zfsvfs);
@@ -1773,7 +1773,7 @@ zfs_create_fs(objset_t *os, cred_t *cr, nvlist_t *zplprops, dmu_tx_t *tx)
rootzp->z_zfsvfs = zfsvfs;
VERIFY0(zfs_acl_ids_create(rootzp, IS_ROOT_NODE, &vattr,
cr, NULL, &acl_ids));
cr, NULL, &acl_ids, NULL));
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);