Skip to content

Commit 77f77ae

Browse files
youzhongyangandrewc12
authored andcommitted
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 <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Youzhong Yang <[email protected]> Closes openzfs#14097
1 parent 101f063 commit 77f77ae

File tree

21 files changed

+424
-96
lines changed

21 files changed

+424
-96
lines changed

config/kernel-iattr-vfsid.m4

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
dnl #
2+
dnl # 6.0 API change
3+
dnl # struct iattr has two unions for the uid and gid
4+
dnl #
5+
AC_DEFUN([ZFS_AC_KERNEL_SRC_IATTR_VFSID], [
6+
ZFS_LINUX_TEST_SRC([iattr_vfsid], [
7+
#include <linux/fs.h>
8+
], [
9+
struct iattr ia;
10+
ia.ia_vfsuid = (vfsuid_t){0};
11+
ia.ia_vfsgid = (vfsgid_t){0};
12+
])
13+
])
14+
15+
AC_DEFUN([ZFS_AC_KERNEL_IATTR_VFSID], [
16+
AC_MSG_CHECKING([whether iattr->ia_vfsuid and iattr->ia_vfsgid exist])
17+
ZFS_LINUX_TEST_RESULT([iattr_vfsid], [
18+
AC_MSG_RESULT(yes)
19+
AC_DEFINE(HAVE_IATTR_VFSID, 1,
20+
[iattr->ia_vfsuid and iattr->ia_vfsgid exist])
21+
],[
22+
AC_MSG_RESULT(no)
23+
])
24+
])

config/kernel.m4

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
149149
ZFS_AC_KERNEL_SRC___COPY_FROM_USER_INATOMIC
150150
ZFS_AC_KERNEL_SRC_USER_NS_COMMON_INUM
151151
ZFS_AC_KERNEL_SRC_IDMAP_MNT_API
152+
ZFS_AC_KERNEL_SRC_IATTR_VFSID
152153
153154
AC_MSG_CHECKING([for available kernel interfaces])
154155
ZFS_LINUX_TEST_COMPILE_ALL([kabi])
@@ -271,6 +272,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
271272
ZFS_AC_KERNEL___COPY_FROM_USER_INATOMIC
272273
ZFS_AC_KERNEL_USER_NS_COMMON_INUM
273274
ZFS_AC_KERNEL_IDMAP_MNT_API
275+
ZFS_AC_KERNEL_IATTR_VFSID
274276
])
275277

276278
dnl #

include/os/linux/kernel/linux/xattr_compat.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ fn(const struct xattr_handler *handler, struct user_namespace *user_ns, \
146146
struct dentry *dentry, struct inode *inode, const char *name, \
147147
const void *buffer, size_t size, int flags) \
148148
{ \
149-
return (__ ## fn(inode, name, buffer, size, flags)); \
149+
return (__ ## fn(user_ns, inode, name, buffer, size, flags)); \
150150
}
151151
/*
152152
* 4.7 API change,
@@ -160,7 +160,7 @@ fn(const struct xattr_handler *handler, struct dentry *dentry, \
160160
struct inode *inode, const char *name, const void *buffer, \
161161
size_t size, int flags) \
162162
{ \
163-
return (__ ## fn(inode, name, buffer, size, flags)); \
163+
return (__ ## fn(kcred->user_ns, inode, name, buffer, size, flags));\
164164
}
165165
/*
166166
* 4.4 API change,
@@ -174,7 +174,8 @@ static int \
174174
fn(const struct xattr_handler *handler, struct dentry *dentry, \
175175
const char *name, const void *buffer, size_t size, int flags) \
176176
{ \
177-
return (__ ## fn(dentry->d_inode, name, buffer, size, flags)); \
177+
return (__ ## fn(kcred->user_ns, dentry->d_inode, name, \
178+
buffer, size, flags)); \
178179
}
179180
/*
180181
* 2.6.33 API change,
@@ -187,7 +188,8 @@ static int \
187188
fn(struct dentry *dentry, const char *name, const void *buffer, \
188189
size_t size, int flags, int unused_handler_flags) \
189190
{ \
190-
return (__ ## fn(dentry->d_inode, name, buffer, size, flags)); \
191+
return (__ ## fn(kcred->user_ns, dentry->d_inode, name, \
192+
buffer, size, flags)); \
191193
}
192194
#else
193195
#error "Unsupported kernel"

include/os/linux/spl/sys/cred.h

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@
2626

2727
#include <linux/module.h>
2828
#include <linux/cred.h>
29+
#include <linux/sched.h>
2930
#include <sys/types.h>
3031
#include <sys/vfs.h>
3132

3233
typedef struct cred cred_t;
3334

35+
extern struct task_struct init_task;
36+
3437
#define kcred ((cred_t *)(init_task.cred))
3538
#define CRED() ((cred_t *)current_cred())
3639

@@ -45,32 +48,80 @@ typedef struct cred cred_t;
4548
#define SGID_TO_KGID(x) (KGIDT_INIT(x))
4649
#define KGIDP_TO_SGIDP(x) (&(x)->val)
4750

48-
static inline uid_t zfs_uid_into_mnt(struct user_namespace *mnt_ns, uid_t uid)
51+
/* Check if the user ns is the initial one */
52+
static inline boolean_t
53+
zfs_is_init_userns(struct user_namespace *user_ns)
4954
{
50-
if (mnt_ns)
51-
return (__kuid_val(make_kuid(mnt_ns, uid)));
52-
return (uid);
55+
#if defined(CONFIG_USER_NS)
56+
return (user_ns == kcred->user_ns);
57+
#else
58+
return (B_FALSE);
59+
#endif
5360
}
5461

55-
static inline gid_t zfs_gid_into_mnt(struct user_namespace *mnt_ns, gid_t gid)
62+
static inline struct user_namespace *zfs_i_user_ns(struct inode *inode)
5663
{
57-
if (mnt_ns)
58-
return (__kgid_val(make_kgid(mnt_ns, gid)));
59-
return (gid);
64+
#ifdef HAVE_SUPER_USER_NS
65+
return (inode->i_sb->s_user_ns);
66+
#else
67+
return (kcred->user_ns);
68+
#endif
6069
}
6170

62-
static inline uid_t zfs_uid_from_mnt(struct user_namespace *mnt_ns, uid_t uid)
71+
static inline boolean_t zfs_no_idmapping(struct user_namespace *mnt_userns,
72+
struct user_namespace *fs_userns)
6373
{
64-
if (mnt_ns)
65-
return (from_kuid(mnt_ns, KUIDT_INIT(uid)));
66-
return (uid);
74+
return (zfs_is_init_userns(mnt_userns) || mnt_userns == fs_userns);
6775
}
6876

69-
static inline gid_t zfs_gid_from_mnt(struct user_namespace *mnt_ns, gid_t gid)
77+
static inline uid_t zfs_uid_to_vfsuid(struct user_namespace *mnt_userns,
78+
struct user_namespace *fs_userns, uid_t uid)
7079
{
71-
if (mnt_ns)
72-
return (from_kgid(mnt_ns, KGIDT_INIT(gid)));
73-
return (gid);
80+
if (zfs_no_idmapping(mnt_userns, fs_userns))
81+
return (uid);
82+
if (!zfs_is_init_userns(fs_userns))
83+
uid = from_kuid(fs_userns, KUIDT_INIT(uid));
84+
if (uid == (uid_t)-1)
85+
return (uid);
86+
return (__kuid_val(make_kuid(mnt_userns, uid)));
87+
}
88+
89+
static inline gid_t zfs_gid_to_vfsgid(struct user_namespace *mnt_userns,
90+
struct user_namespace *fs_userns, gid_t gid)
91+
{
92+
if (zfs_no_idmapping(mnt_userns, fs_userns))
93+
return (gid);
94+
if (!zfs_is_init_userns(fs_userns))
95+
gid = from_kgid(fs_userns, KGIDT_INIT(gid));
96+
if (gid == (gid_t)-1)
97+
return (gid);
98+
return (__kgid_val(make_kgid(mnt_userns, gid)));
99+
}
100+
101+
static inline uid_t zfs_vfsuid_to_uid(struct user_namespace *mnt_userns,
102+
struct user_namespace *fs_userns, uid_t uid)
103+
{
104+
if (zfs_no_idmapping(mnt_userns, fs_userns))
105+
return (uid);
106+
uid = from_kuid(mnt_userns, KUIDT_INIT(uid));
107+
if (uid == (uid_t)-1)
108+
return (uid);
109+
if (zfs_is_init_userns(fs_userns))
110+
return (uid);
111+
return (__kuid_val(make_kuid(fs_userns, uid)));
112+
}
113+
114+
static inline gid_t zfs_vfsgid_to_gid(struct user_namespace *mnt_userns,
115+
struct user_namespace *fs_userns, gid_t gid)
116+
{
117+
if (zfs_no_idmapping(mnt_userns, fs_userns))
118+
return (gid);
119+
gid = from_kgid(mnt_userns, KGIDT_INIT(gid));
120+
if (gid == (gid_t)-1)
121+
return (gid);
122+
if (zfs_is_init_userns(fs_userns))
123+
return (gid);
124+
return (__kgid_val(make_kgid(fs_userns, gid)));
74125
}
75126

76127
extern void crhold(cred_t *cr);
@@ -81,5 +132,4 @@ extern gid_t crgetgid(const cred_t *cr);
81132
extern int crgetngroups(const cred_t *cr);
82133
extern gid_t *crgetgroups(const cred_t *cr);
83134
extern int groupmember(gid_t gid, const cred_t *cr);
84-
85135
#endif /* _SPL_CRED_H */

include/os/linux/zfs/sys/policy.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,14 @@ int secpolicy_vnode_create_gid(const cred_t *);
4747
int secpolicy_vnode_remove(const cred_t *);
4848
int secpolicy_vnode_setdac(const cred_t *, uid_t);
4949
int secpolicy_vnode_setid_retain(struct znode *, const cred_t *, boolean_t);
50-
int secpolicy_vnode_setids_setgids(const cred_t *, gid_t, zuserns_t *);
50+
int secpolicy_vnode_setids_setgids(const cred_t *, gid_t, zuserns_t *,
51+
zuserns_t *);
5152
int secpolicy_zinject(const cred_t *);
5253
int secpolicy_zfs(const cred_t *);
5354
int secpolicy_zfs_proc(const cred_t *, proc_t *);
5455
void secpolicy_setid_clear(vattr_t *, cred_t *);
5556
int secpolicy_setid_setsticky_clear(struct inode *, vattr_t *,
56-
const vattr_t *, cred_t *, zuserns_t *);
57+
const vattr_t *, cred_t *, zuserns_t *, zuserns_t *);
5758
int secpolicy_xvattr(xvattr_t *, uid_t, cred_t *, mode_t);
5859
int secpolicy_vnode_setattr(cred_t *, struct inode *, struct vattr *,
5960
const struct vattr *, int, int (void *, int, cred_t *), void *);

module/os/linux/zfs/policy.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,10 @@ secpolicy_vnode_setid_retain(struct znode *zp __maybe_unused, const cred_t *cr,
214214
* Determine that subject can set the file setgid flag.
215215
*/
216216
int
217-
secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid, zuserns_t *mnt_ns)
217+
secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid, zuserns_t *mnt_ns,
218+
zuserns_t *fs_ns)
218219
{
219-
gid = zfs_gid_into_mnt(mnt_ns, gid);
220+
gid = zfs_gid_to_vfsgid(mnt_ns, fs_ns, gid);
220221
#if defined(CONFIG_USER_NS)
221222
if (!kgid_has_mapping(cr->user_ns, SGID_TO_KGID(gid)))
222223
return (EPERM);
@@ -285,9 +286,10 @@ secpolicy_setid_clear(vattr_t *vap, cred_t *cr)
285286
* Determine that subject can set the file setid flags.
286287
*/
287288
static int
288-
secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner, zuserns_t *mnt_ns)
289+
secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner, zuserns_t *mnt_ns,
290+
zuserns_t *fs_ns)
289291
{
290-
owner = zfs_uid_into_mnt(mnt_ns, owner);
292+
owner = zfs_uid_to_vfsuid(mnt_ns, fs_ns, owner);
291293

292294
if (crgetuid(cr) == owner)
293295
return (0);
@@ -313,13 +315,13 @@ secpolicy_vnode_stky_modify(const cred_t *cr)
313315

314316
int
315317
secpolicy_setid_setsticky_clear(struct inode *ip, vattr_t *vap,
316-
const vattr_t *ovap, cred_t *cr, zuserns_t *mnt_ns)
318+
const vattr_t *ovap, cred_t *cr, zuserns_t *mnt_ns, zuserns_t *fs_ns)
317319
{
318320
int error;
319321

320322
if ((vap->va_mode & S_ISUID) != 0 &&
321323
(error = secpolicy_vnode_setid_modify(cr,
322-
ovap->va_uid, mnt_ns)) != 0) {
324+
ovap->va_uid, mnt_ns, fs_ns)) != 0) {
323325
return (error);
324326
}
325327

@@ -337,7 +339,8 @@ secpolicy_setid_setsticky_clear(struct inode *ip, vattr_t *vap,
337339
* group-id bit.
338340
*/
339341
if ((vap->va_mode & S_ISGID) != 0 &&
340-
secpolicy_vnode_setids_setgids(cr, ovap->va_gid, mnt_ns) != 0) {
342+
secpolicy_vnode_setids_setgids(cr, ovap->va_gid,
343+
mnt_ns, fs_ns) != 0) {
341344
vap->va_mode &= ~S_ISGID;
342345
}
343346

module/os/linux/zfs/zfs_acl.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1889,7 +1889,8 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr,
18891889
acl_ids->z_mode |= S_ISGID;
18901890
} else {
18911891
if ((acl_ids->z_mode & S_ISGID) &&
1892-
secpolicy_vnode_setids_setgids(cr, gid, mnt_ns) != 0) {
1892+
secpolicy_vnode_setids_setgids(cr, gid, mnt_ns,
1893+
zfs_i_user_ns(ZTOI(dzp))) != 0) {
18931894
acl_ids->z_mode &= ~S_ISGID;
18941895
}
18951896
}
@@ -1979,7 +1980,8 @@ zfs_getacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
19791980
if (mask == 0)
19801981
return (SET_ERROR(ENOSYS));
19811982

1982-
if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr, NULL)))
1983+
if ((error = zfs_zaccess(zp, ACE_READ_ACL, 0, skipaclchk, cr,
1984+
kcred->user_ns)))
19831985
return (error);
19841986

19851987
mutex_enter(&zp->z_acl_lock);
@@ -2138,7 +2140,8 @@ zfs_setacl(znode_t *zp, vsecattr_t *vsecp, boolean_t skipaclchk, cred_t *cr)
21382140
if (zp->z_pflags & ZFS_IMMUTABLE)
21392141
return (SET_ERROR(EPERM));
21402142

2141-
if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr, NULL)))
2143+
if ((error = zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr,
2144+
kcred->user_ns)))
21422145
return (error);
21432146

21442147
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,
23012304
uid_t fowner;
23022305

23032306
if (mnt_ns) {
2304-
fowner = zfs_uid_into_mnt(mnt_ns,
2307+
fowner = zfs_uid_to_vfsuid(mnt_ns, zfs_i_user_ns(ZTOI(zp)),
23052308
KUID_TO_SUID(ZTOI(zp)->i_uid));
2306-
gowner = zfs_gid_into_mnt(mnt_ns,
2309+
gowner = zfs_gid_to_vfsgid(mnt_ns, zfs_i_user_ns(ZTOI(zp)),
23072310
KGID_TO_SGID(ZTOI(zp)->i_gid));
23082311
} else
23092312
zfs_fuid_map_ids(zp, cr, &fowner, &gowner);
@@ -2417,7 +2420,8 @@ zfs_has_access(znode_t *zp, cred_t *cr)
24172420
{
24182421
uint32_t have = ACE_ALL_PERMS;
24192422

2420-
if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr, NULL) != 0) {
2423+
if (zfs_zaccess_aces_check(zp, &have, B_TRUE, cr,
2424+
kcred->user_ns) != 0) {
24212425
uid_t owner;
24222426

24232427
owner = zfs_fuid_map_id(ZTOZSB(zp),
@@ -2610,7 +2614,8 @@ zfs_fastaccesschk_execute(znode_t *zdp, cred_t *cr)
26102614
DTRACE_PROBE(zfs__fastpath__execute__access__miss);
26112615
if ((error = zfs_enter(ZTOZSB(zdp), FTAG)) != 0)
26122616
return (error);
2613-
error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr, NULL);
2617+
error = zfs_zaccess(zdp, ACE_EXECUTE, 0, B_FALSE, cr,
2618+
kcred->user_ns);
26142619
zfs_exit(ZTOZSB(zdp), FTAG);
26152620
return (error);
26162621
}
@@ -2662,7 +2667,8 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr,
26622667
}
26632668
}
26642669

2665-
owner = zfs_uid_into_mnt(mnt_ns, KUID_TO_SUID(ZTOI(zp)->i_uid));
2670+
owner = zfs_uid_to_vfsuid(mnt_ns, zfs_i_user_ns(ZTOI(zp)),
2671+
KUID_TO_SUID(ZTOI(zp)->i_uid));
26662672
owner = zfs_fuid_map_id(ZTOZSB(zp), owner, cr, ZFS_OWNER);
26672673

26682674
/*
@@ -2786,7 +2792,7 @@ zfs_zaccess_unix(znode_t *zp, mode_t mode, cred_t *cr)
27862792
{
27872793
int v4_mode = zfs_unix_to_v4(mode >> 6);
27882794

2789-
return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr, NULL));
2795+
return (zfs_zaccess(zp, v4_mode, 0, B_FALSE, cr, kcred->user_ns));
27902796
}
27912797

27922798
/* See zfs_zaccess_delete() */

module/os/linux/zfs/zfs_dir.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,11 +1113,11 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, znode_t **xzpp, cred_t *cr)
11131113
*xzpp = NULL;
11141114

11151115
if ((error = zfs_zaccess(zp, ACE_WRITE_NAMED_ATTRS, 0, B_FALSE, cr,
1116-
NULL)))
1116+
kcred->user_ns)))
11171117
return (error);
11181118

11191119
if ((error = zfs_acl_ids_create(zp, IS_XATTR, vap, cr, NULL,
1120-
&acl_ids, NULL)) != 0)
1120+
&acl_ids, kcred->user_ns)) != 0)
11211121
return (error);
11221122
if (zfs_acl_ids_overquota(zfsvfs, &acl_ids, zp->z_projid)) {
11231123
zfs_acl_ids_free(&acl_ids);
@@ -1265,7 +1265,8 @@ zfs_sticky_remove_access(znode_t *zdp, znode_t *zp, cred_t *cr)
12651265
cr, ZFS_OWNER);
12661266

12671267
if ((uid = crgetuid(cr)) == downer || uid == fowner ||
1268-
zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr, NULL) == 0)
1268+
zfs_zaccess(zp, ACE_WRITE_DATA, 0, B_FALSE, cr,
1269+
kcred->user_ns) == 0)
12691270
return (0);
12701271
else
12711272
return (secpolicy_vnode_remove(cr));

0 commit comments

Comments
 (0)