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:
youzhongyang
2022-11-08 13:28:56 -05:00
committed by GitHub
parent 109731cd73
commit f224eddf92
21 changed files with 424 additions and 96 deletions
+67 -17
View File
@@ -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)));
return (uid);
#if defined(CONFIG_USER_NS)
return (user_ns == kcred->user_ns);
#else
return (B_FALSE);
#endif
}
static inline gid_t zfs_gid_into_mnt(struct user_namespace *mnt_ns, gid_t gid)
static inline struct user_namespace *zfs_i_user_ns(struct inode *inode)
{
if (mnt_ns)
return (__kgid_val(make_kgid(mnt_ns, gid)));
return (gid);
#ifdef HAVE_SUPER_USER_NS
return (inode->i_sb->s_user_ns);
#else
return (kcred->user_ns);
#endif
}
static inline uid_t zfs_uid_from_mnt(struct user_namespace *mnt_ns, uid_t uid)
static inline boolean_t zfs_no_idmapping(struct user_namespace *mnt_userns,
struct user_namespace *fs_userns)
{
if (mnt_ns)
return (from_kuid(mnt_ns, KUIDT_INIT(uid)));
return (uid);
return (zfs_is_init_userns(mnt_userns) || mnt_userns == fs_userns);
}
static inline gid_t zfs_gid_from_mnt(struct user_namespace *mnt_ns, gid_t gid)
static inline uid_t zfs_uid_to_vfsuid(struct user_namespace *mnt_userns,
struct user_namespace *fs_userns, uid_t uid)
{
if (mnt_ns)
return (from_kgid(mnt_ns, KGIDT_INIT(gid)));
return (gid);
if (zfs_no_idmapping(mnt_userns, fs_userns))
return (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_to_vfsgid(struct user_namespace *mnt_userns,
struct user_namespace *fs_userns, gid_t 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 */