Skip to content

Commit ff75ffb

Browse files
author
Youzhong Yang
committed
Support idmapped mount in user namespace
Signed-off-by: Youzhong Yang <yyang@mathworks.com>
1 parent dc56c67 commit ff75ffb

File tree

14 files changed

+315
-66
lines changed

14 files changed

+315
-66
lines changed

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

Lines changed: 4 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(NULL, inode, name, buffer, size, flags)); \
164164
}
165165
/*
166166
* 4.4 API change,
@@ -174,7 +174,7 @@ 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(NULL, dentry->d_inode, name, buffer, size, flags));\
178178
}
179179
/*
180180
* 2.6.33 API change,
@@ -187,7 +187,7 @@ static int \
187187
fn(struct dentry *dentry, const char *name, const void *buffer, \
188188
size_t size, int flags, int unused_handler_flags) \
189189
{ \
190-
return (__ ## fn(dentry->d_inode, name, buffer, size, flags)); \
190+
return (__ ## fn(NULL, dentry->d_inode, name, buffer, size, flags));\
191191
}
192192
#else
193193
#error "Unsupported kernel"

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

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,32 +45,73 @@ typedef struct cred cred_t;
4545
#define SGID_TO_KGID(x) (KGIDT_INIT(x))
4646
#define KGIDP_TO_SGIDP(x) (&(x)->val)
4747

48-
static inline uid_t zfs_uid_into_mnt(struct user_namespace *mnt_ns, uid_t uid)
48+
extern boolean_t zfs_is_init_userns(struct user_namespace *ns);
49+
extern struct user_namespace *zfs_get_init_userns(void);
50+
51+
static inline struct user_namespace *zfs_i_user_ns(struct inode *inode)
52+
{
53+
#ifdef HAVE_SUPER_USER_NS
54+
return (inode->i_sb->s_user_ns);
55+
#else
56+
return (NULL);
57+
#endif
58+
}
59+
60+
static inline boolean_t zfs_no_idmapping(struct user_namespace *mnt_userns,
61+
struct user_namespace *fs_userns)
4962
{
50-
if (mnt_ns)
51-
return (__kuid_val(make_kuid(mnt_ns, uid)));
52-
return (uid);
63+
return (!mnt_userns || !fs_userns ||
64+
zfs_is_init_userns(mnt_userns) || mnt_userns == fs_userns);
5365
}
5466

55-
static inline gid_t zfs_gid_into_mnt(struct user_namespace *mnt_ns, gid_t gid)
67+
static inline uid_t zfs_uid_to_vfsuid(struct user_namespace *mnt_userns,
68+
struct user_namespace *fs_userns, uid_t uid)
5669
{
57-
if (mnt_ns)
58-
return (__kgid_val(make_kgid(mnt_ns, gid)));
59-
return (gid);
70+
if (zfs_no_idmapping(mnt_userns, fs_userns))
71+
return (uid);
72+
if (!zfs_is_init_userns(fs_userns))
73+
uid = from_kuid(fs_userns, KUIDT_INIT(uid));
74+
if (uid == (uid_t)-1)
75+
return (uid);
76+
return (__kuid_val(make_kuid(mnt_userns, uid)));
6077
}
6178

62-
static inline uid_t zfs_uid_from_mnt(struct user_namespace *mnt_ns, uid_t uid)
79+
static inline gid_t zfs_gid_to_vfsgid(struct user_namespace *mnt_userns,
80+
struct user_namespace *fs_userns, gid_t gid)
6381
{
64-
if (mnt_ns)
65-
return (from_kuid(mnt_ns, KUIDT_INIT(uid)));
66-
return (uid);
82+
if (zfs_no_idmapping(mnt_userns, fs_userns))
83+
return (gid);
84+
if (!zfs_is_init_userns(fs_userns))
85+
gid = from_kgid(fs_userns, KGIDT_INIT(gid));
86+
if (gid == (gid_t)-1)
87+
return (gid);
88+
return (__kgid_val(make_kgid(mnt_userns, gid)));
6789
}
6890

69-
static inline gid_t zfs_gid_from_mnt(struct user_namespace *mnt_ns, gid_t gid)
91+
static inline uid_t zfs_vfsuid_to_uid(struct user_namespace *mnt_userns,
92+
struct user_namespace *fs_userns, uid_t uid)
7093
{
71-
if (mnt_ns)
72-
return (from_kgid(mnt_ns, KGIDT_INIT(gid)));
73-
return (gid);
94+
if (zfs_no_idmapping(mnt_userns, fs_userns))
95+
return (uid);
96+
uid = from_kuid(mnt_userns, KUIDT_INIT(uid));
97+
if (uid == (uid_t)-1)
98+
return (uid);
99+
if (zfs_is_init_userns(fs_userns))
100+
return (uid);
101+
return (__kuid_val(make_kuid(fs_userns, uid)));
102+
}
103+
104+
static inline gid_t zfs_vfsgid_to_gid(struct user_namespace *mnt_userns,
105+
struct user_namespace *fs_userns, gid_t gid)
106+
{
107+
if (zfs_no_idmapping(mnt_userns, fs_userns))
108+
return (gid);
109+
gid = from_kgid(mnt_userns, KGIDT_INIT(gid));
110+
if (gid == (gid_t)-1)
111+
return (gid);
112+
if (zfs_is_init_userns(fs_userns))
113+
return (gid);
114+
return (__kgid_val(make_kgid(fs_userns, gid)));
74115
}
75116

76117
extern void crhold(cred_t *cr);
@@ -81,5 +122,4 @@ extern gid_t crgetgid(const cred_t *cr);
81122
extern int crgetngroups(const cred_t *cr);
82123
extern gid_t *crgetgroups(const cred_t *cr);
83124
extern int groupmember(gid_t gid, const cred_t *cr);
84-
85125
#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/spl/spl-cred.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,30 @@ crgetgid(const cred_t *cr)
145145
return (KGID_TO_SGID(cr->fsgid));
146146
}
147147

148+
/* Check if the user ns is the initial one */
149+
boolean_t
150+
zfs_is_init_userns(struct user_namespace *user_ns)
151+
{
152+
#if defined(CONFIG_USER_NS)
153+
return (user_ns == &init_user_ns);
154+
#else
155+
return (B_FALSE);
156+
#endif
157+
}
158+
159+
/* Return the initial user ns */
160+
struct user_namespace *
161+
zfs_get_init_userns(void)
162+
{
163+
#if defined(CONFIG_USER_NS)
164+
return (&init_user_ns);
165+
#else
166+
return (NULL);
167+
#endif
168+
}
169+
170+
EXPORT_SYMBOL(zfs_is_init_userns);
171+
EXPORT_SYMBOL(zfs_get_init_userns);
148172
EXPORT_SYMBOL(crhold);
149173
EXPORT_SYMBOL(crfree);
150174
EXPORT_SYMBOL(crgetuid);

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: 6 additions & 4 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
}
@@ -2301,9 +2302,9 @@ zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode,
23012302
uid_t fowner;
23022303

23032304
if (mnt_ns) {
2304-
fowner = zfs_uid_into_mnt(mnt_ns,
2305+
fowner = zfs_uid_to_vfsuid(mnt_ns, zfs_i_user_ns(ZTOI(zp)),
23052306
KUID_TO_SUID(ZTOI(zp)->i_uid));
2306-
gowner = zfs_gid_into_mnt(mnt_ns,
2307+
gowner = zfs_gid_to_vfsgid(mnt_ns, zfs_i_user_ns(ZTOI(zp)),
23072308
KGID_TO_SGID(ZTOI(zp)->i_gid));
23082309
} else
23092310
zfs_fuid_map_ids(zp, cr, &fowner, &gowner);
@@ -2662,7 +2663,8 @@ zfs_zaccess(znode_t *zp, int mode, int flags, boolean_t skipaclchk, cred_t *cr,
26622663
}
26632664
}
26642665

2665-
owner = zfs_uid_into_mnt(mnt_ns, KUID_TO_SUID(ZTOI(zp)->i_uid));
2666+
owner = zfs_uid_to_vfsuid(mnt_ns, zfs_i_user_ns(ZTOI(zp)),
2667+
KUID_TO_SUID(ZTOI(zp)->i_uid));
26662668
owner = zfs_fuid_map_id(ZTOZSB(zp), owner, cr, ZFS_OWNER);
26672669

26682670
/*

module/os/linux/zfs/zfs_vnops_os.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2024,10 +2024,10 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zuserns_t *mnt_ns)
20242024
* Take ownership or chgrp to group we are a member of
20252025
*/
20262026

2027-
uid = zfs_uid_into_mnt((struct user_namespace *)mnt_ns,
2028-
vap->va_uid);
2029-
gid = zfs_gid_into_mnt((struct user_namespace *)mnt_ns,
2030-
vap->va_gid);
2027+
uid = zfs_uid_to_vfsuid((struct user_namespace *)mnt_ns,
2028+
zfs_i_user_ns(ip), vap->va_uid);
2029+
gid = zfs_gid_to_vfsgid((struct user_namespace *)mnt_ns,
2030+
zfs_i_user_ns(ip), vap->va_gid);
20312031
take_owner = (mask & ATTR_UID) && (uid == crgetuid(cr));
20322032
take_group = (mask & ATTR_GID) &&
20332033
zfs_groupmember(zfsvfs, gid, cr);
@@ -2162,7 +2162,7 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr, zuserns_t *mnt_ns)
21622162
if (zfs_zaccess(zp, ACE_WRITE_ACL, 0, skipaclchk, cr,
21632163
mnt_ns) == 0) {
21642164
err = secpolicy_setid_setsticky_clear(ip, vap,
2165-
&oldva, cr, mnt_ns);
2165+
&oldva, cr, mnt_ns, zfs_i_user_ns(ip));
21662166
if (err)
21672167
goto out3;
21682168
trim_mask |= ATTR_MODE;

module/os/linux/zfs/zpl_inode.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,16 +118,16 @@ zpl_vap_init(vattr_t *vap, struct inode *dir, umode_t mode, cred_t *cr,
118118
vap->va_mask = ATTR_MODE;
119119
vap->va_mode = mode;
120120

121-
vap->va_uid = zfs_uid_from_mnt((struct user_namespace *)mnt_ns,
122-
crgetuid(cr));
121+
vap->va_uid = zfs_vfsuid_to_uid((struct user_namespace *)mnt_ns,
122+
zfs_i_user_ns(dir), crgetuid(cr));
123123

124124
if (dir && dir->i_mode & S_ISGID) {
125125
vap->va_gid = KGID_TO_SGID(dir->i_gid);
126126
if (S_ISDIR(mode))
127127
vap->va_mode |= S_ISGID;
128128
} else {
129-
vap->va_gid = zfs_gid_from_mnt((struct user_namespace *)mnt_ns,
130-
crgetgid(cr));
129+
vap->va_gid = zfs_vfsgid_to_gid((struct user_namespace *)mnt_ns,
130+
zfs_i_user_ns(dir), crgetgid(cr));
131131
}
132132
}
133133

0 commit comments

Comments
 (0)