.. | .. |
---|
4 | 4 | * All Rights Reserved. |
---|
5 | 5 | */ |
---|
6 | 6 | #include "xfs.h" |
---|
| 7 | +#include "xfs_shared.h" |
---|
7 | 8 | #include "xfs_format.h" |
---|
8 | 9 | #include "xfs_log_format.h" |
---|
9 | 10 | #include "xfs_trans_resv.h" |
---|
10 | 11 | #include "xfs_mount.h" |
---|
11 | 12 | #include "xfs_inode.h" |
---|
12 | | -#include "xfs_acl.h" |
---|
13 | 13 | #include "xfs_attr.h" |
---|
14 | 14 | #include "xfs_trace.h" |
---|
15 | | -#include <linux/slab.h> |
---|
16 | | -#include <linux/xattr.h> |
---|
17 | | -#include <linux/posix_acl_xattr.h> |
---|
| 15 | +#include "xfs_error.h" |
---|
| 16 | +#include "xfs_acl.h" |
---|
| 17 | +#include "xfs_da_format.h" |
---|
| 18 | +#include "xfs_da_btree.h" |
---|
18 | 19 | |
---|
| 20 | +#include <linux/posix_acl_xattr.h> |
---|
19 | 21 | |
---|
20 | 22 | /* |
---|
21 | 23 | * Locking scheme: |
---|
.. | .. |
---|
25 | 27 | |
---|
26 | 28 | STATIC struct posix_acl * |
---|
27 | 29 | xfs_acl_from_disk( |
---|
| 30 | + struct xfs_mount *mp, |
---|
28 | 31 | const struct xfs_acl *aclp, |
---|
29 | 32 | int len, |
---|
30 | 33 | int max_entries) |
---|
.. | .. |
---|
34 | 37 | const struct xfs_acl_entry *ace; |
---|
35 | 38 | unsigned int count, i; |
---|
36 | 39 | |
---|
37 | | - if (len < sizeof(*aclp)) |
---|
| 40 | + if (len < sizeof(*aclp)) { |
---|
| 41 | + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, aclp, |
---|
| 42 | + len); |
---|
38 | 43 | return ERR_PTR(-EFSCORRUPTED); |
---|
| 44 | + } |
---|
| 45 | + |
---|
39 | 46 | count = be32_to_cpu(aclp->acl_cnt); |
---|
40 | | - if (count > max_entries || XFS_ACL_SIZE(count) != len) |
---|
| 47 | + if (count > max_entries || XFS_ACL_SIZE(count) != len) { |
---|
| 48 | + XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, aclp, |
---|
| 49 | + len); |
---|
41 | 50 | return ERR_PTR(-EFSCORRUPTED); |
---|
| 51 | + } |
---|
42 | 52 | |
---|
43 | 53 | acl = posix_acl_alloc(count, GFP_KERNEL); |
---|
44 | 54 | if (!acl) |
---|
.. | .. |
---|
59 | 69 | |
---|
60 | 70 | switch (acl_e->e_tag) { |
---|
61 | 71 | case ACL_USER: |
---|
62 | | - acl_e->e_uid = xfs_uid_to_kuid(be32_to_cpu(ace->ae_id)); |
---|
| 72 | + acl_e->e_uid = make_kuid(&init_user_ns, |
---|
| 73 | + be32_to_cpu(ace->ae_id)); |
---|
63 | 74 | break; |
---|
64 | 75 | case ACL_GROUP: |
---|
65 | | - acl_e->e_gid = xfs_gid_to_kgid(be32_to_cpu(ace->ae_id)); |
---|
| 76 | + acl_e->e_gid = make_kgid(&init_user_ns, |
---|
| 77 | + be32_to_cpu(ace->ae_id)); |
---|
66 | 78 | break; |
---|
67 | 79 | case ACL_USER_OBJ: |
---|
68 | 80 | case ACL_GROUP_OBJ: |
---|
.. | .. |
---|
95 | 107 | ace->ae_tag = cpu_to_be32(acl_e->e_tag); |
---|
96 | 108 | switch (acl_e->e_tag) { |
---|
97 | 109 | case ACL_USER: |
---|
98 | | - ace->ae_id = cpu_to_be32(xfs_kuid_to_uid(acl_e->e_uid)); |
---|
| 110 | + ace->ae_id = cpu_to_be32( |
---|
| 111 | + from_kuid(&init_user_ns, acl_e->e_uid)); |
---|
99 | 112 | break; |
---|
100 | 113 | case ACL_GROUP: |
---|
101 | | - ace->ae_id = cpu_to_be32(xfs_kgid_to_gid(acl_e->e_gid)); |
---|
| 114 | + ace->ae_id = cpu_to_be32( |
---|
| 115 | + from_kgid(&init_user_ns, acl_e->e_gid)); |
---|
102 | 116 | break; |
---|
103 | 117 | default: |
---|
104 | 118 | ace->ae_id = cpu_to_be32(ACL_UNDEFINED_ID); |
---|
.. | .. |
---|
112 | 126 | struct posix_acl * |
---|
113 | 127 | xfs_get_acl(struct inode *inode, int type) |
---|
114 | 128 | { |
---|
115 | | - struct xfs_inode *ip = XFS_I(inode); |
---|
116 | | - struct posix_acl *acl = NULL; |
---|
117 | | - struct xfs_acl *xfs_acl; |
---|
118 | | - unsigned char *ea_name; |
---|
119 | | - int error; |
---|
120 | | - int len; |
---|
| 129 | + struct xfs_inode *ip = XFS_I(inode); |
---|
| 130 | + struct xfs_mount *mp = ip->i_mount; |
---|
| 131 | + struct posix_acl *acl = NULL; |
---|
| 132 | + struct xfs_da_args args = { |
---|
| 133 | + .dp = ip, |
---|
| 134 | + .attr_filter = XFS_ATTR_ROOT, |
---|
| 135 | + .valuelen = XFS_ACL_MAX_SIZE(mp), |
---|
| 136 | + }; |
---|
| 137 | + int error; |
---|
121 | 138 | |
---|
122 | 139 | trace_xfs_get_acl(ip); |
---|
123 | 140 | |
---|
124 | 141 | switch (type) { |
---|
125 | 142 | case ACL_TYPE_ACCESS: |
---|
126 | | - ea_name = SGI_ACL_FILE; |
---|
| 143 | + args.name = SGI_ACL_FILE; |
---|
127 | 144 | break; |
---|
128 | 145 | case ACL_TYPE_DEFAULT: |
---|
129 | | - ea_name = SGI_ACL_DEFAULT; |
---|
| 146 | + args.name = SGI_ACL_DEFAULT; |
---|
130 | 147 | break; |
---|
131 | 148 | default: |
---|
132 | 149 | BUG(); |
---|
133 | 150 | } |
---|
| 151 | + args.namelen = strlen(args.name); |
---|
134 | 152 | |
---|
135 | 153 | /* |
---|
136 | | - * If we have a cached ACLs value just return it, not need to |
---|
137 | | - * go out to the disk. |
---|
| 154 | + * If the attribute doesn't exist make sure we have a negative cache |
---|
| 155 | + * entry, for any other error assume it is transient. |
---|
138 | 156 | */ |
---|
139 | | - len = XFS_ACL_MAX_SIZE(ip->i_mount); |
---|
140 | | - xfs_acl = kmem_zalloc_large(len, KM_SLEEP); |
---|
141 | | - if (!xfs_acl) |
---|
142 | | - return ERR_PTR(-ENOMEM); |
---|
143 | | - |
---|
144 | | - error = xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl, |
---|
145 | | - &len, ATTR_ROOT); |
---|
146 | | - if (error) { |
---|
147 | | - /* |
---|
148 | | - * If the attribute doesn't exist make sure we have a negative |
---|
149 | | - * cache entry, for any other error assume it is transient. |
---|
150 | | - */ |
---|
151 | | - if (error != -ENOATTR) |
---|
152 | | - acl = ERR_PTR(error); |
---|
153 | | - } else { |
---|
154 | | - acl = xfs_acl_from_disk(xfs_acl, len, |
---|
155 | | - XFS_ACL_MAX_ENTRIES(ip->i_mount)); |
---|
| 157 | + error = xfs_attr_get(&args); |
---|
| 158 | + if (!error) { |
---|
| 159 | + acl = xfs_acl_from_disk(mp, args.value, args.valuelen, |
---|
| 160 | + XFS_ACL_MAX_ENTRIES(mp)); |
---|
| 161 | + } else if (error != -ENOATTR) { |
---|
| 162 | + acl = ERR_PTR(error); |
---|
156 | 163 | } |
---|
157 | | - kmem_free(xfs_acl); |
---|
| 164 | + |
---|
| 165 | + kmem_free(args.value); |
---|
158 | 166 | return acl; |
---|
159 | 167 | } |
---|
160 | 168 | |
---|
161 | 169 | int |
---|
162 | 170 | __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) |
---|
163 | 171 | { |
---|
164 | | - struct xfs_inode *ip = XFS_I(inode); |
---|
165 | | - unsigned char *ea_name; |
---|
166 | | - int error; |
---|
| 172 | + struct xfs_inode *ip = XFS_I(inode); |
---|
| 173 | + struct xfs_da_args args = { |
---|
| 174 | + .dp = ip, |
---|
| 175 | + .attr_filter = XFS_ATTR_ROOT, |
---|
| 176 | + }; |
---|
| 177 | + int error; |
---|
167 | 178 | |
---|
168 | 179 | switch (type) { |
---|
169 | 180 | case ACL_TYPE_ACCESS: |
---|
170 | | - ea_name = SGI_ACL_FILE; |
---|
| 181 | + args.name = SGI_ACL_FILE; |
---|
171 | 182 | break; |
---|
172 | 183 | case ACL_TYPE_DEFAULT: |
---|
173 | 184 | if (!S_ISDIR(inode->i_mode)) |
---|
174 | 185 | return acl ? -EACCES : 0; |
---|
175 | | - ea_name = SGI_ACL_DEFAULT; |
---|
| 186 | + args.name = SGI_ACL_DEFAULT; |
---|
176 | 187 | break; |
---|
177 | 188 | default: |
---|
178 | 189 | return -EINVAL; |
---|
179 | 190 | } |
---|
| 191 | + args.namelen = strlen(args.name); |
---|
180 | 192 | |
---|
181 | 193 | if (acl) { |
---|
182 | | - struct xfs_acl *xfs_acl; |
---|
183 | | - int len = XFS_ACL_MAX_SIZE(ip->i_mount); |
---|
184 | | - |
---|
185 | | - xfs_acl = kmem_zalloc_large(len, KM_SLEEP); |
---|
186 | | - if (!xfs_acl) |
---|
| 194 | + args.valuelen = XFS_ACL_SIZE(acl->a_count); |
---|
| 195 | + args.value = kvzalloc(args.valuelen, GFP_KERNEL); |
---|
| 196 | + if (!args.value) |
---|
187 | 197 | return -ENOMEM; |
---|
188 | | - |
---|
189 | | - xfs_acl_to_disk(xfs_acl, acl); |
---|
190 | | - |
---|
191 | | - /* subtract away the unused acl entries */ |
---|
192 | | - len -= sizeof(struct xfs_acl_entry) * |
---|
193 | | - (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count); |
---|
194 | | - |
---|
195 | | - error = xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl, |
---|
196 | | - len, ATTR_ROOT); |
---|
197 | | - |
---|
198 | | - kmem_free(xfs_acl); |
---|
199 | | - } else { |
---|
200 | | - /* |
---|
201 | | - * A NULL ACL argument means we want to remove the ACL. |
---|
202 | | - */ |
---|
203 | | - error = xfs_attr_remove(ip, ea_name, ATTR_ROOT); |
---|
204 | | - |
---|
205 | | - /* |
---|
206 | | - * If the attribute didn't exist to start with that's fine. |
---|
207 | | - */ |
---|
208 | | - if (error == -ENOATTR) |
---|
209 | | - error = 0; |
---|
| 198 | + xfs_acl_to_disk(args.value, acl); |
---|
210 | 199 | } |
---|
211 | 200 | |
---|
| 201 | + error = xfs_attr_set(&args); |
---|
| 202 | + kmem_free(args.value); |
---|
| 203 | + |
---|
| 204 | + /* |
---|
| 205 | + * If the attribute didn't exist to start with that's fine. |
---|
| 206 | + */ |
---|
| 207 | + if (!acl && error == -ENOATTR) |
---|
| 208 | + error = 0; |
---|
212 | 209 | if (!error) |
---|
213 | 210 | set_cached_acl(inode, type, acl); |
---|
214 | 211 | return error; |
---|
.. | .. |
---|
268 | 265 | |
---|
269 | 266 | return error; |
---|
270 | 267 | } |
---|
| 268 | + |
---|
| 269 | +/* |
---|
| 270 | + * Invalidate any cached ACLs if the user has bypassed the ACL interface. |
---|
| 271 | + * We don't validate the content whatsoever so it is caller responsibility to |
---|
| 272 | + * provide data in valid format and ensure i_mode is consistent. |
---|
| 273 | + */ |
---|
| 274 | +void |
---|
| 275 | +xfs_forget_acl( |
---|
| 276 | + struct inode *inode, |
---|
| 277 | + const char *name) |
---|
| 278 | +{ |
---|
| 279 | + if (!strcmp(name, SGI_ACL_FILE)) |
---|
| 280 | + forget_cached_acl(inode, ACL_TYPE_ACCESS); |
---|
| 281 | + else if (!strcmp(name, SGI_ACL_DEFAULT)) |
---|
| 282 | + forget_cached_acl(inode, ACL_TYPE_DEFAULT); |
---|
| 283 | +} |
---|