aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/posix_acl.c30
-rw-r--r--fs/xattr.c7
-rw-r--r--fs/xattr_acl.c90
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 */
17static 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
56void 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
64void 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}