Skip to content

Commit

Permalink
Support idmapped mount
Browse files Browse the repository at this point in the history
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
  • Loading branch information
youzhongyang authored Oct 19, 2022
1 parent eaaed26 commit 2a068a1
Show file tree
Hide file tree
Showing 41 changed files with 1,636 additions and 166 deletions.
25 changes: 25 additions & 0 deletions config/kernel-idmap_mnt_api.m4
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
dnl #
dnl # 5.12 API
dnl #
dnl # Check if APIs for idmapped mount are available
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_IDMAP_MNT_API], [
ZFS_LINUX_TEST_SRC([idmap_mnt_api], [
#include <linux/fs.h>
],[
int fs_flags = 0;
fs_flags |= FS_ALLOW_IDMAP;
])
])

AC_DEFUN([ZFS_AC_KERNEL_IDMAP_MNT_API], [
AC_MSG_CHECKING([whether APIs for idmapped mount are present])
ZFS_LINUX_TEST_RESULT([idmap_mnt_api], [
AC_MSG_RESULT([yes])
AC_DEFINE(HAVE_IDMAP_MNT_API, 1,
[APIs for idmapped mount are present])
],[
AC_MSG_RESULT([no])
])
])

2 changes: 2 additions & 0 deletions config/kernel.m4
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
ZFS_AC_KERNEL_SRC_ZERO_PAGE
ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC
ZFS_AC_KERNEL_SRC_USER_NS_COMMON_INUM
ZFS_AC_KERNEL_SRC_IDMAP_MNT_API
AC_MSG_CHECKING([for available kernel interfaces])
ZFS_LINUX_TEST_COMPILE_ALL([kabi])
Expand Down Expand Up @@ -267,6 +268,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
ZFS_AC_KERNEL_ZERO_PAGE
ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC
ZFS_AC_KERNEL_USER_NS_COMMON_INUM
ZFS_AC_KERNEL_IDMAP_MNT_API
])

dnl #
Expand Down
2 changes: 2 additions & 0 deletions include/os/freebsd/spl/sys/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,7 @@ typedef u_longlong_t len_t;

typedef longlong_t diskaddr_t;

typedef void zuserns_t;

#include <sys/debug.h>
#endif /* !_OPENSOLARIS_SYS_TYPES_H_ */
12 changes: 7 additions & 5 deletions include/os/freebsd/zfs/sys/zfs_vnops_os.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,22 @@ int dmu_read_pages(objset_t *os, uint64_t object, vm_page_t *ma, int count,
int *rbehind, int *rahead, int last_size);
extern int zfs_remove(znode_t *dzp, const char *name, cred_t *cr, int flags);
extern int zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap,
znode_t **zpp, cred_t *cr, int flags, vsecattr_t *vsecp);
znode_t **zpp, cred_t *cr, int flags, vsecattr_t *vsecp, zuserns_t *mnt_ns);
extern int zfs_rmdir(znode_t *dzp, const char *name, znode_t *cwd,
cred_t *cr, int flags);
extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr);
extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr,
zuserns_t *mnt_ns);
extern int zfs_rename(znode_t *sdzp, const char *snm, znode_t *tdzp,
const char *tnm, cred_t *cr, int flags);
const char *tnm, cred_t *cr, int flags, zuserns_t *mnt_ns);
extern 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);
extern int zfs_link(znode_t *tdzp, znode_t *sp,
const char *name, cred_t *cr, int flags);
extern int zfs_space(znode_t *zp, int cmd, struct flock *bfp, int flag,
offset_t offset, cred_t *cr);
extern 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);
int mode, znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp,
zuserns_t *mnt_ns);
extern int zfs_setsecattr(znode_t *zp, vsecattr_t *vsecp, int flag,
cred_t *cr);
extern int zfs_write_simple(znode_t *zp, const void *data, size_t len,
Expand Down
28 changes: 28 additions & 0 deletions include/os/linux/spl/sys/cred.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,34 @@ 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)
{
if (mnt_ns)
return (__kuid_val(make_kuid(mnt_ns, uid)));
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)));
return (uid);
}

static inline gid_t zfs_gid_from_mnt(struct user_namespace *mnt_ns, gid_t gid)
{
if (mnt_ns)
return (from_kgid(mnt_ns, KGIDT_INIT(gid)));
return (gid);
}

extern void crhold(cred_t *cr);
extern void crfree(cred_t *cr);
extern uid_t crgetuid(const cred_t *cr);
Expand Down
3 changes: 3 additions & 0 deletions include/os/linux/spl/sys/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,7 @@ typedef ulong_t pgcnt_t;
typedef int major_t;
typedef int minor_t;

struct user_namespace;
typedef struct user_namespace zuserns_t;

#endif /* _SPL_TYPES_H */
4 changes: 2 additions & 2 deletions include/os/linux/zfs/sys/policy.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ 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);
int secpolicy_vnode_setids_setgids(const cred_t *, gid_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 *);
const vattr_t *, cred_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 *);
Expand Down
15 changes: 9 additions & 6 deletions include/os/linux/zfs/sys/zfs_vnops_os.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,25 @@ extern int zfs_write_simple(znode_t *zp, const void *data, size_t len,
extern int zfs_lookup(znode_t *dzp, char *nm, znode_t **zpp, int flags,
cred_t *cr, int *direntflags, pathname_t *realpnp);
extern int zfs_create(znode_t *dzp, char *name, vattr_t *vap, int excl,
int mode, znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp);
int mode, znode_t **zpp, cred_t *cr, int flag, vsecattr_t *vsecp,
zuserns_t *mnt_ns);
extern int zfs_tmpfile(struct inode *dip, vattr_t *vapzfs, int excl,
int mode, struct inode **ipp, cred_t *cr, int flag, vsecattr_t *vsecp);
int mode, struct inode **ipp, cred_t *cr, int flag, vsecattr_t *vsecp,
zuserns_t *mnt_ns);
extern int zfs_remove(znode_t *dzp, char *name, cred_t *cr, int flags);
extern int zfs_mkdir(znode_t *dzp, char *dirname, vattr_t *vap,
znode_t **zpp, cred_t *cr, int flags, vsecattr_t *vsecp);
znode_t **zpp, cred_t *cr, int flags, vsecattr_t *vsecp, zuserns_t *mnt_ns);
extern int zfs_rmdir(znode_t *dzp, char *name, znode_t *cwd,
cred_t *cr, int flags);
extern int zfs_readdir(struct inode *ip, zpl_dir_context_t *ctx, cred_t *cr);
extern int zfs_getattr_fast(struct user_namespace *, struct inode *ip,
struct kstat *sp);
extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr);
extern int zfs_setattr(znode_t *zp, vattr_t *vap, int flag, cred_t *cr,
zuserns_t *mnt_ns);
extern int zfs_rename(znode_t *sdzp, char *snm, znode_t *tdzp,
char *tnm, cred_t *cr, int flags);
char *tnm, cred_t *cr, int flags, zuserns_t *mnt_ns);
extern int zfs_symlink(znode_t *dzp, char *name, vattr_t *vap,
char *link, znode_t **zpp, cred_t *cr, int flags);
char *link, znode_t **zpp, cred_t *cr, int flags, zuserns_t *mnt_ns);
extern int zfs_readlink(struct inode *ip, zfs_uio_t *uio, cred_t *cr);
extern int zfs_link(znode_t *tdzp, znode_t *szp,
char *name, cred_t *cr, int flags);
Expand Down
2 changes: 1 addition & 1 deletion include/os/linux/zfs/sys/zpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

/* zpl_inode.c */
extern void zpl_vap_init(vattr_t *vap, struct inode *dir,
umode_t mode, cred_t *cr);
umode_t mode, cred_t *cr, zuserns_t *mnt_ns);

extern const struct inode_operations zpl_inode_operations;
extern const struct inode_operations zpl_dir_inode_operations;
Expand Down
11 changes: 6 additions & 5 deletions include/sys/zfs_acl.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ struct zfsvfs;

#ifdef _KERNEL
int zfs_acl_ids_create(struct znode *, int, vattr_t *,
cred_t *, vsecattr_t *, zfs_acl_ids_t *);
cred_t *, vsecattr_t *, zfs_acl_ids_t *, zuserns_t *);
void zfs_acl_ids_free(zfs_acl_ids_t *);
boolean_t zfs_acl_ids_overquota(struct zfsvfs *, zfs_acl_ids_t *, uint64_t);
int zfs_getacl(struct znode *, vsecattr_t *, boolean_t, cred_t *);
Expand All @@ -215,15 +215,16 @@ void zfs_acl_rele(void *);
void zfs_oldace_byteswap(ace_t *, int);
void zfs_ace_byteswap(void *, size_t, boolean_t);
extern boolean_t zfs_has_access(struct znode *zp, cred_t *cr);
extern int zfs_zaccess(struct znode *, int, int, boolean_t, cred_t *);
extern int zfs_zaccess(struct znode *, int, int, boolean_t, cred_t *,
zuserns_t *);
int zfs_fastaccesschk_execute(struct znode *, cred_t *);
extern int zfs_zaccess_rwx(struct znode *, mode_t, int, cred_t *);
extern int zfs_zaccess_rwx(struct znode *, mode_t, int, cred_t *, zuserns_t *);
extern int zfs_zaccess_unix(struct znode *, mode_t, cred_t *);
extern int zfs_acl_access(struct znode *, int, cred_t *);
int zfs_acl_chmod_setattr(struct znode *, zfs_acl_t **, uint64_t);
int zfs_zaccess_delete(struct znode *, struct znode *, cred_t *);
int zfs_zaccess_delete(struct znode *, struct znode *, cred_t *, zuserns_t *);
int zfs_zaccess_rename(struct znode *, struct znode *,
struct znode *, struct znode *, cred_t *cr);
struct znode *, struct znode *, cred_t *cr, zuserns_t *mnt_ns);
void zfs_acl_free(zfs_acl_t *);
int zfs_vsec_2_aclp(struct zfsvfs *, umode_t, vsecattr_t *, cred_t *,
struct zfs_fuid_info **, zfs_acl_t **);
Expand Down
30 changes: 17 additions & 13 deletions module/os/freebsd/zfs/zfs_acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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));
}

/*
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
}

Expand All @@ -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);
}
4 changes: 2 additions & 2 deletions module/os/freebsd/zfs/zfs_dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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));
Expand Down
Loading

0 comments on commit 2a068a1

Please sign in to comment.