Skip to content

Commit 2f6f065

Browse files
committed
userns: Convert vfs posix_acl support to use kuids and kgids
- In setxattr if we are setting a posix acl convert uids and gids from the current user namespace into the initial user namespace, before the xattrs are passed to the underlying filesystem. Untranslatable uids and gids are represented as -1 which posix_acl_from_xattr will represent as INVALID_UID or INVALID_GID. posix_acl_valid will fail if an acl from userspace has any INVALID_UID or INVALID_GID values. In net this guarantees that untranslatable posix acls will not be stored by filesystems. - In getxattr if we are reading a posix acl convert uids and gids from the initial user namespace into the current user namespace. Uids and gids that can not be tranlsated into the current user namespace will be represented as -1. - Replace e_id in struct posix_acl_entry with an anymouns union of e_uid and e_gid. For the short term retain the e_id field until all of the users are converted. - Don't set struct posix_acl.e_id in the cases where the acl type does not use e_id. Greatly reducing the use of ACL_UNDEFINED_ID. - Rework the ordering checks in posix_acl_valid so that I use kuid_t and kgid_t types throughout the code, and so that I don't need arithmetic on uid and gid types. Cc: Theodore Tso <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Andreas Dilger <[email protected]> Cc: Jan Kara <[email protected]> Cc: Al Viro <[email protected]> Signed-off-by: Eric W. Biederman <[email protected]>
1 parent d20b92a commit 2f6f065

File tree

5 files changed

+126
-21
lines changed

5 files changed

+126
-21
lines changed

fs/posix_acl.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ posix_acl_valid(const struct posix_acl *acl)
7878
{
7979
const struct posix_acl_entry *pa, *pe;
8080
int state = ACL_USER_OBJ;
81-
unsigned int id = 0; /* keep gcc happy */
81+
kuid_t prev_uid = INVALID_UID;
82+
kgid_t prev_gid = INVALID_GID;
8283
int needs_mask = 0;
8384

8485
FOREACH_ACL_ENTRY(pa, acl, pe) {
@@ -87,7 +88,6 @@ posix_acl_valid(const struct posix_acl *acl)
8788
switch (pa->e_tag) {
8889
case ACL_USER_OBJ:
8990
if (state == ACL_USER_OBJ) {
90-
id = 0;
9191
state = ACL_USER;
9292
break;
9393
}
@@ -96,16 +96,17 @@ posix_acl_valid(const struct posix_acl *acl)
9696
case ACL_USER:
9797
if (state != ACL_USER)
9898
return -EINVAL;
99-
if (pa->e_id == ACL_UNDEFINED_ID ||
100-
pa->e_id < id)
99+
if (!uid_valid(pa->e_uid))
101100
return -EINVAL;
102-
id = pa->e_id + 1;
101+
if (uid_valid(prev_uid) &&
102+
uid_lte(pa->e_uid, prev_uid))
103+
return -EINVAL;
104+
prev_uid = pa->e_uid;
103105
needs_mask = 1;
104106
break;
105107

106108
case ACL_GROUP_OBJ:
107109
if (state == ACL_USER) {
108-
id = 0;
109110
state = ACL_GROUP;
110111
break;
111112
}
@@ -114,10 +115,12 @@ posix_acl_valid(const struct posix_acl *acl)
114115
case ACL_GROUP:
115116
if (state != ACL_GROUP)
116117
return -EINVAL;
117-
if (pa->e_id == ACL_UNDEFINED_ID ||
118-
pa->e_id < id)
118+
if (!gid_valid(pa->e_gid))
119+
return -EINVAL;
120+
if (gid_valid(prev_gid) &&
121+
gid_lte(pa->e_gid, prev_gid))
119122
return -EINVAL;
120-
id = pa->e_id + 1;
123+
prev_gid = pa->e_gid;
121124
needs_mask = 1;
122125
break;
123126

@@ -195,15 +198,12 @@ posix_acl_from_mode(umode_t mode, gfp_t flags)
195198
return ERR_PTR(-ENOMEM);
196199

197200
acl->a_entries[0].e_tag = ACL_USER_OBJ;
198-
acl->a_entries[0].e_id = ACL_UNDEFINED_ID;
199201
acl->a_entries[0].e_perm = (mode & S_IRWXU) >> 6;
200202

201203
acl->a_entries[1].e_tag = ACL_GROUP_OBJ;
202-
acl->a_entries[1].e_id = ACL_UNDEFINED_ID;
203204
acl->a_entries[1].e_perm = (mode & S_IRWXG) >> 3;
204205

205206
acl->a_entries[2].e_tag = ACL_OTHER;
206-
acl->a_entries[2].e_id = ACL_UNDEFINED_ID;
207207
acl->a_entries[2].e_perm = (mode & S_IRWXO);
208208
return acl;
209209
}
@@ -224,11 +224,11 @@ posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want)
224224
switch(pa->e_tag) {
225225
case ACL_USER_OBJ:
226226
/* (May have been checked already) */
227-
if (inode->i_uid == current_fsuid())
227+
if (uid_eq(inode->i_uid, current_fsuid()))
228228
goto check_perm;
229229
break;
230230
case ACL_USER:
231-
if (pa->e_id == current_fsuid())
231+
if (uid_eq(pa->e_uid, current_fsuid()))
232232
goto mask;
233233
break;
234234
case ACL_GROUP_OBJ:
@@ -239,7 +239,7 @@ posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want)
239239
}
240240
break;
241241
case ACL_GROUP:
242-
if (in_group_p(pa->e_id)) {
242+
if (in_group_p(pa->e_gid)) {
243243
found = 1;
244244
if ((pa->e_perm & want) == want)
245245
goto mask;

fs/xattr.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/fsnotify.h>
2121
#include <linux/audit.h>
2222
#include <linux/vmalloc.h>
23+
#include <linux/posix_acl_xattr.h>
2324

2425
#include <asm/uaccess.h>
2526

@@ -347,6 +348,9 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
347348
error = -EFAULT;
348349
goto out;
349350
}
351+
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
352+
(strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
353+
posix_acl_fix_xattr_from_user(kvalue, size);
350354
}
351355

352356
error = vfs_setxattr(d, kname, kvalue, size, flags);
@@ -450,6 +454,9 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
450454

451455
error = vfs_getxattr(d, kname, kvalue, size);
452456
if (error > 0) {
457+
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
458+
(strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
459+
posix_acl_fix_xattr_to_user(kvalue, size);
453460
if (size && copy_to_user(value, kvalue, error))
454461
error = -EFAULT;
455462
} else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {

fs/xattr_acl.c

Lines changed: 85 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,65 @@
99
#include <linux/fs.h>
1010
#include <linux/posix_acl_xattr.h>
1111
#include <linux/gfp.h>
12+
#include <linux/user_namespace.h>
1213

14+
/*
15+
* Fix up the uids and gids in posix acl extended attributes in place.
16+
*/
17+
static void posix_acl_fix_xattr_userns(
18+
struct user_namespace *to, struct user_namespace *from,
19+
void *value, size_t size)
20+
{
21+
posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
22+
posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
23+
int count;
24+
kuid_t uid;
25+
kgid_t gid;
26+
27+
if (!value)
28+
return;
29+
if (size < sizeof(posix_acl_xattr_header))
30+
return;
31+
if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
32+
return;
33+
34+
count = posix_acl_xattr_count(size);
35+
if (count < 0)
36+
return;
37+
if (count == 0)
38+
return;
39+
40+
for (end = entry + count; entry != end; entry++) {
41+
switch(le16_to_cpu(entry->e_tag)) {
42+
case ACL_USER:
43+
uid = make_kuid(from, le32_to_cpu(entry->e_id));
44+
entry->e_id = cpu_to_le32(from_kuid(to, uid));
45+
break;
46+
case ACL_GROUP:
47+
gid = make_kgid(from, le32_to_cpu(entry->e_id));
48+
entry->e_id = cpu_to_le32(from_kuid(to, uid));
49+
break;
50+
default:
51+
break;
52+
}
53+
}
54+
}
55+
56+
void posix_acl_fix_xattr_from_user(void *value, size_t size)
57+
{
58+
struct user_namespace *user_ns = current_user_ns();
59+
if (user_ns == &init_user_ns)
60+
return;
61+
posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
62+
}
63+
64+
void posix_acl_fix_xattr_to_user(void *value, size_t size)
65+
{
66+
struct user_namespace *user_ns = current_user_ns();
67+
if (user_ns == &init_user_ns)
68+
return;
69+
posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
70+
}
1371

1472
/*
1573
* Convert from extended attribute to in-memory representation.
@@ -50,12 +108,21 @@ posix_acl_from_xattr(const void *value, size_t size)
50108
case ACL_GROUP_OBJ:
51109
case ACL_MASK:
52110
case ACL_OTHER:
53-
acl_e->e_id = ACL_UNDEFINED_ID;
54111
break;
55112

56113
case ACL_USER:
114+
acl_e->e_uid =
115+
make_kuid(&init_user_ns,
116+
le32_to_cpu(entry->e_id));
117+
if (!uid_valid(acl_e->e_uid))
118+
goto fail;
119+
break;
57120
case ACL_GROUP:
58-
acl_e->e_id = le32_to_cpu(entry->e_id);
121+
acl_e->e_gid =
122+
make_kgid(&init_user_ns,
123+
le32_to_cpu(entry->e_id));
124+
if (!gid_valid(acl_e->e_gid))
125+
goto fail;
59126
break;
60127

61128
default:
@@ -89,9 +156,22 @@ posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size)
89156
ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
90157

91158
for (n=0; n < acl->a_count; n++, ext_entry++) {
92-
ext_entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag);
93-
ext_entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
94-
ext_entry->e_id = cpu_to_le32(acl->a_entries[n].e_id);
159+
const struct posix_acl_entry *acl_e = &acl->a_entries[n];
160+
ext_entry->e_tag = cpu_to_le16(acl_e->e_tag);
161+
ext_entry->e_perm = cpu_to_le16(acl_e->e_perm);
162+
switch(acl_e->e_tag) {
163+
case ACL_USER:
164+
ext_entry->e_id =
165+
cpu_to_le32(from_kuid(&init_user_ns, acl_e->e_uid));
166+
break;
167+
case ACL_GROUP:
168+
ext_entry->e_id =
169+
cpu_to_le32(from_kgid(&init_user_ns, acl_e->e_gid));
170+
break;
171+
default:
172+
ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
173+
break;
174+
}
95175
}
96176
return real_size;
97177
}

include/linux/posix_acl.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,13 @@
3636
struct posix_acl_entry {
3737
short e_tag;
3838
unsigned short e_perm;
39-
unsigned int e_id;
39+
union {
40+
kuid_t e_uid;
41+
kgid_t e_gid;
42+
#ifndef CONFIG_UIDGID_STRICT_TYPE_CHECKS
43+
unsigned int e_id;
44+
#endif
45+
};
4046
};
4147

4248
struct posix_acl {

include/linux/posix_acl_xattr.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,18 @@ posix_acl_xattr_count(size_t size)
5252
return size / sizeof(posix_acl_xattr_entry);
5353
}
5454

55+
#ifdef CONFIG_FS_POSIX_ACL
56+
void posix_acl_fix_xattr_from_user(void *value, size_t size);
57+
void posix_acl_fix_xattr_to_user(void *value, size_t size);
58+
#else
59+
static inline void posix_acl_fix_xattr_from_user(void *value, size_t size)
60+
{
61+
}
62+
static inline void posix_acl_fix_xattr_to_user(void *value, size_t size)
63+
{
64+
}
65+
#endif
66+
5567
struct posix_acl *posix_acl_from_xattr(const void *value, size_t size);
5668
int posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size);
5769

0 commit comments

Comments
 (0)