diff options
Diffstat (limited to 'fs/xattr_acl.c')
-rw-r--r-- | fs/xattr_acl.c | 96 |
1 files changed, 89 insertions, 7 deletions
diff --git a/fs/xattr_acl.c b/fs/xattr_acl.c index 69d06b07b169..11efd830b5f5 100644 --- a/fs/xattr_acl.c +++ b/fs/xattr_acl.c | |||
@@ -9,13 +9,72 @@ | |||
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. |
16 | */ | 74 | */ |
17 | struct posix_acl * | 75 | struct posix_acl * |
18 | posix_acl_from_xattr(const void *value, size_t size) | 76 | posix_acl_from_xattr(struct user_namespace *user_ns, |
77 | const void *value, size_t size) | ||
19 | { | 78 | { |
20 | posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; | 79 | posix_acl_xattr_header *header = (posix_acl_xattr_header *)value; |
21 | posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; | 80 | posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; |
@@ -50,12 +109,21 @@ posix_acl_from_xattr(const void *value, size_t size) | |||
50 | case ACL_GROUP_OBJ: | 109 | case ACL_GROUP_OBJ: |
51 | case ACL_MASK: | 110 | case ACL_MASK: |
52 | case ACL_OTHER: | 111 | case ACL_OTHER: |
53 | acl_e->e_id = ACL_UNDEFINED_ID; | ||
54 | break; | 112 | break; |
55 | 113 | ||
56 | case ACL_USER: | 114 | case ACL_USER: |
115 | acl_e->e_uid = | ||
116 | make_kuid(user_ns, | ||
117 | le32_to_cpu(entry->e_id)); | ||
118 | if (!uid_valid(acl_e->e_uid)) | ||
119 | goto fail; | ||
120 | break; | ||
57 | case ACL_GROUP: | 121 | case ACL_GROUP: |
58 | acl_e->e_id = le32_to_cpu(entry->e_id); | 122 | acl_e->e_gid = |
123 | make_kgid(user_ns, | ||
124 | le32_to_cpu(entry->e_id)); | ||
125 | if (!gid_valid(acl_e->e_gid)) | ||
126 | goto fail; | ||
59 | break; | 127 | break; |
60 | 128 | ||
61 | default: | 129 | default: |
@@ -74,7 +142,8 @@ EXPORT_SYMBOL (posix_acl_from_xattr); | |||
74 | * Convert from in-memory to extended attribute representation. | 142 | * Convert from in-memory to extended attribute representation. |
75 | */ | 143 | */ |
76 | int | 144 | int |
77 | posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size) | 145 | posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl, |
146 | void *buffer, size_t size) | ||
78 | { | 147 | { |
79 | posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer; | 148 | posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer; |
80 | posix_acl_xattr_entry *ext_entry = ext_acl->a_entries; | 149 | posix_acl_xattr_entry *ext_entry = ext_acl->a_entries; |
@@ -89,9 +158,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); | 158 | ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); |
90 | 159 | ||
91 | for (n=0; n < acl->a_count; n++, ext_entry++) { | 160 | for (n=0; n < acl->a_count; n++, ext_entry++) { |
92 | ext_entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag); | 161 | 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); | 162 | 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); | 163 | ext_entry->e_perm = cpu_to_le16(acl_e->e_perm); |
164 | switch(acl_e->e_tag) { | ||
165 | case ACL_USER: | ||
166 | ext_entry->e_id = | ||
167 | cpu_to_le32(from_kuid(user_ns, acl_e->e_uid)); | ||
168 | break; | ||
169 | case ACL_GROUP: | ||
170 | ext_entry->e_id = | ||
171 | cpu_to_le32(from_kgid(user_ns, acl_e->e_gid)); | ||
172 | break; | ||
173 | default: | ||
174 | ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID); | ||
175 | break; | ||
176 | } | ||
95 | } | 177 | } |
96 | return real_size; | 178 | return real_size; |
97 | } | 179 | } |