diff options
author | David Howells <dhowells@redhat.com> | 2019-05-12 03:31:23 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-05-15 12:35:53 -0400 |
commit | 773e0c40253443e0ce5491cb0e414b62f7cc45ed (patch) | |
tree | 48752e7b9ff1ec36c9baeadc7e4f11ebf16addf7 /fs/afs | |
parent | cc1dd5c85cb70ebe09ccf1cc34f29af65442a10f (diff) |
afs: Fix afs_xattr_get_yfs() to not try freeing an error value
afs_xattr_get_yfs() tries to free yacl, which may hold an error value (say
if yfs_fs_fetch_opaque_acl() failed and returned an error).
Fix this by allocating yacl up front (since it's a fixed-length struct,
unlike afs_acl) and passing it in to the RPC function. This also allows
the flags to be placed in the object rather than passing them through to
the RPC function.
Fixes: ae46578b963f ("afs: Get YFS ACLs and information through xattrs")
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'fs/afs')
-rw-r--r-- | fs/afs/internal.h | 2 | ||||
-rw-r--r-- | fs/afs/xattr.c | 86 | ||||
-rw-r--r-- | fs/afs/yfsclient.c | 29 |
3 files changed, 53 insertions, 64 deletions
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index b3cd6e8ad59d..74ee0f8ef8dd 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -1382,7 +1382,7 @@ struct yfs_acl { | |||
1382 | }; | 1382 | }; |
1383 | 1383 | ||
1384 | extern void yfs_free_opaque_acl(struct yfs_acl *); | 1384 | extern void yfs_free_opaque_acl(struct yfs_acl *); |
1385 | extern struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *, unsigned int); | 1385 | extern struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *, struct yfs_acl *); |
1386 | extern int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *, const struct afs_acl *); | 1386 | extern int yfs_fs_store_opaque_acl2(struct afs_fs_cursor *, const struct afs_acl *); |
1387 | 1387 | ||
1388 | /* | 1388 | /* |
diff --git a/fs/afs/xattr.c b/fs/afs/xattr.c index b6c44e75b361..d12bcda911e1 100644 --- a/fs/afs/xattr.c +++ b/fs/afs/xattr.c | |||
@@ -148,9 +148,8 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler, | |||
148 | struct afs_vnode *vnode = AFS_FS_I(inode); | 148 | struct afs_vnode *vnode = AFS_FS_I(inode); |
149 | struct yfs_acl *yacl = NULL; | 149 | struct yfs_acl *yacl = NULL; |
150 | struct key *key; | 150 | struct key *key; |
151 | unsigned int flags = 0; | ||
152 | char buf[16], *data; | 151 | char buf[16], *data; |
153 | int which = 0, dsize, ret; | 152 | int which = 0, dsize, ret = -ENOMEM; |
154 | 153 | ||
155 | if (strcmp(name, "acl") == 0) | 154 | if (strcmp(name, "acl") == 0) |
156 | which = 0; | 155 | which = 0; |
@@ -163,20 +162,26 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler, | |||
163 | else | 162 | else |
164 | return -EOPNOTSUPP; | 163 | return -EOPNOTSUPP; |
165 | 164 | ||
165 | yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL); | ||
166 | if (!yacl) | ||
167 | goto error; | ||
168 | |||
166 | if (which == 0) | 169 | if (which == 0) |
167 | flags |= YFS_ACL_WANT_ACL; | 170 | yacl->flags |= YFS_ACL_WANT_ACL; |
168 | else if (which == 3) | 171 | else if (which == 3) |
169 | flags |= YFS_ACL_WANT_VOL_ACL; | 172 | yacl->flags |= YFS_ACL_WANT_VOL_ACL; |
170 | 173 | ||
171 | key = afs_request_key(vnode->volume->cell); | 174 | key = afs_request_key(vnode->volume->cell); |
172 | if (IS_ERR(key)) | 175 | if (IS_ERR(key)) { |
173 | return PTR_ERR(key); | 176 | ret = PTR_ERR(key); |
177 | goto error_yacl; | ||
178 | } | ||
174 | 179 | ||
175 | ret = -ERESTARTSYS; | 180 | ret = -ERESTARTSYS; |
176 | if (afs_begin_vnode_operation(&fc, vnode, key)) { | 181 | if (afs_begin_vnode_operation(&fc, vnode, key)) { |
177 | while (afs_select_fileserver(&fc)) { | 182 | while (afs_select_fileserver(&fc)) { |
178 | fc.cb_break = afs_calc_vnode_cb_break(vnode); | 183 | fc.cb_break = afs_calc_vnode_cb_break(vnode); |
179 | yacl = yfs_fs_fetch_opaque_acl(&fc, flags); | 184 | yfs_fs_fetch_opaque_acl(&fc, yacl); |
180 | } | 185 | } |
181 | 186 | ||
182 | afs_check_for_remote_deletion(&fc, fc.vnode); | 187 | afs_check_for_remote_deletion(&fc, fc.vnode); |
@@ -184,44 +189,45 @@ static int afs_xattr_get_yfs(const struct xattr_handler *handler, | |||
184 | ret = afs_end_vnode_operation(&fc); | 189 | ret = afs_end_vnode_operation(&fc); |
185 | } | 190 | } |
186 | 191 | ||
187 | if (ret == 0) { | 192 | if (ret < 0) |
188 | switch (which) { | 193 | goto error_key; |
189 | case 0: | 194 | |
190 | data = yacl->acl->data; | 195 | switch (which) { |
191 | dsize = yacl->acl->size; | 196 | case 0: |
192 | break; | 197 | data = yacl->acl->data; |
193 | case 1: | 198 | dsize = yacl->acl->size; |
194 | data = buf; | 199 | break; |
195 | dsize = snprintf(buf, sizeof(buf), "%u", | 200 | case 1: |
196 | yacl->inherit_flag); | 201 | data = buf; |
197 | break; | 202 | dsize = snprintf(buf, sizeof(buf), "%u", yacl->inherit_flag); |
198 | case 2: | 203 | break; |
199 | data = buf; | 204 | case 2: |
200 | dsize = snprintf(buf, sizeof(buf), "%u", | 205 | data = buf; |
201 | yacl->num_cleaned); | 206 | dsize = snprintf(buf, sizeof(buf), "%u", yacl->num_cleaned); |
202 | break; | 207 | break; |
203 | case 3: | 208 | case 3: |
204 | data = yacl->vol_acl->data; | 209 | data = yacl->vol_acl->data; |
205 | dsize = yacl->vol_acl->size; | 210 | dsize = yacl->vol_acl->size; |
206 | break; | 211 | break; |
207 | default: | 212 | default: |
208 | ret = -EOPNOTSUPP; | 213 | ret = -EOPNOTSUPP; |
209 | goto out; | 214 | goto error_key; |
210 | } | 215 | } |
211 | 216 | ||
212 | ret = dsize; | 217 | ret = dsize; |
213 | if (size > 0) { | 218 | if (size > 0) { |
214 | if (dsize > size) { | 219 | if (dsize > size) { |
215 | ret = -ERANGE; | 220 | ret = -ERANGE; |
216 | goto out; | 221 | goto error_key; |
217 | } | ||
218 | memcpy(buffer, data, dsize); | ||
219 | } | 222 | } |
223 | memcpy(buffer, data, dsize); | ||
220 | } | 224 | } |
221 | 225 | ||
222 | out: | 226 | error_key: |
223 | yfs_free_opaque_acl(yacl); | ||
224 | key_put(key); | 227 | key_put(key); |
228 | error_yacl: | ||
229 | yfs_free_opaque_acl(yacl); | ||
230 | error: | ||
225 | return ret; | 231 | return ret; |
226 | } | 232 | } |
227 | 233 | ||
diff --git a/fs/afs/yfsclient.c b/fs/afs/yfsclient.c index 6cf7d161baa1..d3e9e3fe0b58 100644 --- a/fs/afs/yfsclient.c +++ b/fs/afs/yfsclient.c | |||
@@ -2333,12 +2333,6 @@ void yfs_free_opaque_acl(struct yfs_acl *yacl) | |||
2333 | } | 2333 | } |
2334 | } | 2334 | } |
2335 | 2335 | ||
2336 | static void yfs_destroy_fs_fetch_opaque_acl(struct afs_call *call) | ||
2337 | { | ||
2338 | yfs_free_opaque_acl(call->reply[0]); | ||
2339 | afs_flat_call_destructor(call); | ||
2340 | } | ||
2341 | |||
2342 | /* | 2336 | /* |
2343 | * YFS.FetchOpaqueACL operation type | 2337 | * YFS.FetchOpaqueACL operation type |
2344 | */ | 2338 | */ |
@@ -2346,18 +2340,17 @@ static const struct afs_call_type yfs_RXYFSFetchOpaqueACL = { | |||
2346 | .name = "YFS.FetchOpaqueACL", | 2340 | .name = "YFS.FetchOpaqueACL", |
2347 | .op = yfs_FS_FetchOpaqueACL, | 2341 | .op = yfs_FS_FetchOpaqueACL, |
2348 | .deliver = yfs_deliver_fs_fetch_opaque_acl, | 2342 | .deliver = yfs_deliver_fs_fetch_opaque_acl, |
2349 | .destructor = yfs_destroy_fs_fetch_opaque_acl, | 2343 | .destructor = afs_flat_call_destructor, |
2350 | }; | 2344 | }; |
2351 | 2345 | ||
2352 | /* | 2346 | /* |
2353 | * Fetch the YFS advanced ACLs for a file. | 2347 | * Fetch the YFS advanced ACLs for a file. |
2354 | */ | 2348 | */ |
2355 | struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *fc, | 2349 | struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *fc, |
2356 | unsigned int flags) | 2350 | struct yfs_acl *yacl) |
2357 | { | 2351 | { |
2358 | struct afs_vnode *vnode = fc->vnode; | 2352 | struct afs_vnode *vnode = fc->vnode; |
2359 | struct afs_call *call; | 2353 | struct afs_call *call; |
2360 | struct yfs_acl *yacl; | ||
2361 | struct afs_net *net = afs_v2net(vnode); | 2354 | struct afs_net *net = afs_v2net(vnode); |
2362 | __be32 *bp; | 2355 | __be32 *bp; |
2363 | 2356 | ||
@@ -2370,19 +2363,15 @@ struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *fc, | |||
2370 | sizeof(__be32) * 2 + | 2363 | sizeof(__be32) * 2 + |
2371 | sizeof(struct yfs_xdr_YFSFetchStatus) + | 2364 | sizeof(struct yfs_xdr_YFSFetchStatus) + |
2372 | sizeof(struct yfs_xdr_YFSVolSync)); | 2365 | sizeof(struct yfs_xdr_YFSVolSync)); |
2373 | if (!call) | 2366 | if (!call) { |
2374 | goto nomem; | 2367 | fc->ac.error = -ENOMEM; |
2375 | 2368 | return ERR_PTR(-ENOMEM); | |
2376 | yacl = kzalloc(sizeof(struct yfs_acl), GFP_KERNEL); | 2369 | } |
2377 | if (!yacl) | ||
2378 | goto nomem_call; | ||
2379 | 2370 | ||
2380 | yacl->flags = flags; | ||
2381 | call->key = fc->key; | 2371 | call->key = fc->key; |
2382 | call->reply[0] = yacl; | 2372 | call->reply[0] = yacl; |
2383 | call->reply[1] = vnode; | 2373 | call->reply[1] = vnode; |
2384 | call->reply[2] = NULL; /* volsync */ | 2374 | call->reply[2] = NULL; /* volsync */ |
2385 | call->ret_reply0 = true; | ||
2386 | 2375 | ||
2387 | /* marshall the parameters */ | 2376 | /* marshall the parameters */ |
2388 | bp = call->request; | 2377 | bp = call->request; |
@@ -2396,12 +2385,6 @@ struct yfs_acl *yfs_fs_fetch_opaque_acl(struct afs_fs_cursor *fc, | |||
2396 | trace_afs_make_fs_call(call, &vnode->fid); | 2385 | trace_afs_make_fs_call(call, &vnode->fid); |
2397 | afs_make_call(&fc->ac, call, GFP_KERNEL); | 2386 | afs_make_call(&fc->ac, call, GFP_KERNEL); |
2398 | return (struct yfs_acl *)afs_wait_for_call_to_complete(call, &fc->ac); | 2387 | return (struct yfs_acl *)afs_wait_for_call_to_complete(call, &fc->ac); |
2399 | |||
2400 | nomem_call: | ||
2401 | afs_put_call(call); | ||
2402 | nomem: | ||
2403 | fc->ac.error = -ENOMEM; | ||
2404 | return ERR_PTR(-ENOMEM); | ||
2405 | } | 2388 | } |
2406 | 2389 | ||
2407 | /* | 2390 | /* |