diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/posix_acl.c | 30 | ||||
-rw-r--r-- | fs/xattr.c | 7 | ||||
-rw-r--r-- | fs/xattr_acl.c | 90 |
3 files changed, 107 insertions, 20 deletions
diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 5e325a42e33..8bd2135b7f8 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c | |||
@@ -78,7 +78,8 @@ posix_acl_valid(const struct posix_acl *acl) | |||
78 | { | 78 | { |
79 | const struct posix_acl_entry *pa, *pe; | 79 | const struct posix_acl_entry *pa, *pe; |
80 | int state = ACL_USER_OBJ; | 80 | 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; | ||
82 | int needs_mask = 0; | 83 | int needs_mask = 0; |
83 | 84 | ||
84 | FOREACH_ACL_ENTRY(pa, acl, pe) { | 85 | FOREACH_ACL_ENTRY(pa, acl, pe) { |
@@ -87,7 +88,6 @@ posix_acl_valid(const struct posix_acl *acl) | |||
87 | switch (pa->e_tag) { | 88 | switch (pa->e_tag) { |
88 | case ACL_USER_OBJ: | 89 | case ACL_USER_OBJ: |
89 | if (state == ACL_USER_OBJ) { | 90 | if (state == ACL_USER_OBJ) { |
90 | id = 0; | ||
91 | state = ACL_USER; | 91 | state = ACL_USER; |
92 | break; | 92 | break; |
93 | } | 93 | } |
@@ -96,16 +96,17 @@ posix_acl_valid(const struct posix_acl *acl) | |||
96 | case ACL_USER: | 96 | case ACL_USER: |
97 | if (state != ACL_USER) | 97 | if (state != ACL_USER) |
98 | return -EINVAL; | 98 | return -EINVAL; |
99 | if (pa->e_id == ACL_UNDEFINED_ID || | 99 | if (!uid_valid(pa->e_uid)) |
100 | pa->e_id < id) | ||
101 | return -EINVAL; | 100 | 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; | ||
103 | needs_mask = 1; | 105 | needs_mask = 1; |
104 | break; | 106 | break; |
105 | 107 | ||
106 | case ACL_GROUP_OBJ: | 108 | case ACL_GROUP_OBJ: |
107 | if (state == ACL_USER) { | 109 | if (state == ACL_USER) { |
108 | id = 0; | ||
109 | state = ACL_GROUP; | 110 | state = ACL_GROUP; |
110 | break; | 111 | break; |
111 | } | 112 | } |
@@ -114,10 +115,12 @@ posix_acl_valid(const struct posix_acl *acl) | |||
114 | case ACL_GROUP: | 115 | case ACL_GROUP: |
115 | if (state != ACL_GROUP) | 116 | if (state != ACL_GROUP) |
116 | return -EINVAL; | 117 | return -EINVAL; |
117 | if (pa->e_id == ACL_UNDEFINED_ID || | 118 | if (!gid_valid(pa->e_gid)) |
118 | pa->e_id < id) | 119 | return -EINVAL; |
120 | if (gid_valid(prev_gid) && | ||
121 | gid_lte(pa->e_gid, prev_gid)) | ||
119 | return -EINVAL; | 122 | return -EINVAL; |
120 | id = pa->e_id + 1; | 123 | prev_gid = pa->e_gid; |
121 | needs_mask = 1; | 124 | needs_mask = 1; |
122 | break; | 125 | break; |
123 | 126 | ||
@@ -195,15 +198,12 @@ posix_acl_from_mode(umode_t mode, gfp_t flags) | |||
195 | return ERR_PTR(-ENOMEM); | 198 | return ERR_PTR(-ENOMEM); |
196 | 199 | ||
197 | acl->a_entries[0].e_tag = ACL_USER_OBJ; | 200 | acl->a_entries[0].e_tag = ACL_USER_OBJ; |
198 | acl->a_entries[0].e_id = ACL_UNDEFINED_ID; | ||
199 | acl->a_entries[0].e_perm = (mode & S_IRWXU) >> 6; | 201 | acl->a_entries[0].e_perm = (mode & S_IRWXU) >> 6; |
200 | 202 | ||
201 | acl->a_entries[1].e_tag = ACL_GROUP_OBJ; | 203 | acl->a_entries[1].e_tag = ACL_GROUP_OBJ; |
202 | acl->a_entries[1].e_id = ACL_UNDEFINED_ID; | ||
203 | acl->a_entries[1].e_perm = (mode & S_IRWXG) >> 3; | 204 | acl->a_entries[1].e_perm = (mode & S_IRWXG) >> 3; |
204 | 205 | ||
205 | acl->a_entries[2].e_tag = ACL_OTHER; | 206 | acl->a_entries[2].e_tag = ACL_OTHER; |
206 | acl->a_entries[2].e_id = ACL_UNDEFINED_ID; | ||
207 | acl->a_entries[2].e_perm = (mode & S_IRWXO); | 207 | acl->a_entries[2].e_perm = (mode & S_IRWXO); |
208 | return acl; | 208 | return acl; |
209 | } | 209 | } |
@@ -224,11 +224,11 @@ posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want) | |||
224 | switch(pa->e_tag) { | 224 | switch(pa->e_tag) { |
225 | case ACL_USER_OBJ: | 225 | case ACL_USER_OBJ: |
226 | /* (May have been checked already) */ | 226 | /* (May have been checked already) */ |
227 | if (inode->i_uid == current_fsuid()) | 227 | if (uid_eq(inode->i_uid, current_fsuid())) |
228 | goto check_perm; | 228 | goto check_perm; |
229 | break; | 229 | break; |
230 | case ACL_USER: | 230 | case ACL_USER: |
231 | if (pa->e_id == current_fsuid()) | 231 | if (uid_eq(pa->e_uid, current_fsuid())) |
232 | goto mask; | 232 | goto mask; |
233 | break; | 233 | break; |
234 | case ACL_GROUP_OBJ: | 234 | case ACL_GROUP_OBJ: |
@@ -239,7 +239,7 @@ posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want) | |||
239 | } | 239 | } |
240 | break; | 240 | break; |
241 | case ACL_GROUP: | 241 | case ACL_GROUP: |
242 | if (in_group_p(pa->e_id)) { | 242 | if (in_group_p(pa->e_gid)) { |
243 | found = 1; | 243 | found = 1; |
244 | if ((pa->e_perm & want) == want) | 244 | if ((pa->e_perm & want) == want) |
245 | goto mask; | 245 | goto mask; |
diff --git a/fs/xattr.c b/fs/xattr.c index 4d45b7189e7..c111745c2da 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/fsnotify.h> | 20 | #include <linux/fsnotify.h> |
21 | #include <linux/audit.h> | 21 | #include <linux/audit.h> |
22 | #include <linux/vmalloc.h> | 22 | #include <linux/vmalloc.h> |
23 | #include <linux/posix_acl_xattr.h> | ||
23 | 24 | ||
24 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
25 | 26 | ||
@@ -347,6 +348,9 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value, | |||
347 | error = -EFAULT; | 348 | error = -EFAULT; |
348 | goto out; | 349 | goto out; |
349 | } | 350 | } |
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); | ||
350 | } | 354 | } |
351 | 355 | ||
352 | error = vfs_setxattr(d, kname, kvalue, size, flags); | 356 | error = vfs_setxattr(d, kname, kvalue, size, flags); |
@@ -450,6 +454,9 @@ getxattr(struct dentry *d, const char __user *name, void __user *value, | |||
450 | 454 | ||
451 | error = vfs_getxattr(d, kname, kvalue, size); | 455 | error = vfs_getxattr(d, kname, kvalue, size); |
452 | if (error > 0) { | 456 | 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); | ||
453 | if (size && copy_to_user(value, kvalue, error)) | 460 | if (size && copy_to_user(value, kvalue, error)) |
454 | error = -EFAULT; | 461 | error = -EFAULT; |
455 | } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) { | 462 | } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) { |
diff --git a/fs/xattr_acl.c b/fs/xattr_acl.c index 69d06b07b16..bf472ca1b34 100644 --- a/fs/xattr_acl.c +++ b/fs/xattr_acl.c | |||
@@ -9,7 +9,65 @@ | |||
9 | #include <linux/fs.h> | 9 | #include <linux/fs.h> |
10 | #include <linux/posix_acl_xattr.h> | 10 | #include <linux/posix_acl_xattr.h> |
11 | #include <linux/gfp.h> | 11 | #include <linux/gfp.h> |
12 | #include <linux/user_namespace.h> | ||
12 | 13 | ||
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 | } | ||
13 | 71 | ||
14 | /* | 72 | /* |
15 | * Convert from extended attribute to in-memory representation. | 73 | * Convert from extended attribute to in-memory representation. |
@@ -50,12 +108,21 @@ posix_acl_from_xattr(const void *value, size_t size) | |||
50 | case ACL_GROUP_OBJ: | 108 | case ACL_GROUP_OBJ: |
51 | case ACL_MASK: | 109 | case ACL_MASK: |
52 | case ACL_OTHER: | 110 | case ACL_OTHER: |
53 | acl_e->e_id = ACL_UNDEFINED_ID; | ||
54 | break; | 111 | break; |
55 | 112 | ||
56 | case ACL_USER: | 113 | 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; | ||
57 | case ACL_GROUP: | 120 | 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; | ||
59 | break; | 126 | break; |
60 | 127 | ||
61 | default: | 128 | default: |
@@ -89,9 +156,22 @@ posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size) | |||
89 | ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); | 156 | ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); |
90 | 157 | ||
91 | for (n=0; n < acl->a_count; n++, ext_entry++) { | 158 | for (n=0; n < acl->a_count; n++, ext_entry++) { |
92 | ext_entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); | 159 | const struct posix_acl_entry *acl_e = &acl->a_entries[n]; |
93 | ext_entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm); | 160 | ext_entry->e_tag = cpu_to_le16(acl_e->e_tag); |
94 | ext_entry->e_id = cpu_to_le32(acl->a_entries[n].e_id); | 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 | } | ||
95 | } | 175 | } |
96 | return real_size; | 176 | return real_size; |
97 | } | 177 | } |