diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-03-26 16:24:37 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-03-28 20:12:10 -0400 |
commit | e911b8158ee1def8153849b1641b736026b036e0 (patch) | |
tree | b9c302ffd9e9580afe59b3d56b2380ea9e76204e /fs/nfs | |
parent | 494314c415e2d3b308f57c9245ae6525166c70b8 (diff) |
NFSv4: Fix a use-after-free problem in open()
If we interrupt the nfs4_wait_for_completion_rpc_task() call in
nfs4_run_open_task(), then we don't prevent the RPC call from
completing. So freeing up the opendata->f_attr.mdsthreshold
in the error path in _nfs4_do_open() leads to a use-after-free
when the XDR decoder tries to decode the mdsthreshold information
from the server.
Fixes: 82be417aa37c0 (NFSv4.1 cache mdsthreshold values on OPEN)
Tested-by: Steve Dickson <SteveD@redhat.com>
Cc: stable@vger.kernel.org # 3.5+
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 19 |
1 files changed, 10 insertions, 9 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index c866e325577f..397be39c6dc8 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -1068,6 +1068,7 @@ static void nfs4_opendata_free(struct kref *kref) | |||
1068 | dput(p->dentry); | 1068 | dput(p->dentry); |
1069 | nfs_sb_deactive(sb); | 1069 | nfs_sb_deactive(sb); |
1070 | nfs_fattr_free_names(&p->f_attr); | 1070 | nfs_fattr_free_names(&p->f_attr); |
1071 | kfree(p->f_attr.mdsthreshold); | ||
1071 | kfree(p); | 1072 | kfree(p); |
1072 | } | 1073 | } |
1073 | 1074 | ||
@@ -2304,10 +2305,12 @@ static int _nfs4_do_open(struct inode *dir, | |||
2304 | } | 2305 | } |
2305 | } | 2306 | } |
2306 | 2307 | ||
2307 | if (ctx_th && server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) { | 2308 | if (server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) { |
2308 | opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc(); | 2309 | if (!opendata->f_attr.mdsthreshold) { |
2309 | if (!opendata->f_attr.mdsthreshold) | 2310 | opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc(); |
2310 | goto err_free_label; | 2311 | if (!opendata->f_attr.mdsthreshold) |
2312 | goto err_free_label; | ||
2313 | } | ||
2311 | opendata->o_arg.open_bitmap = &nfs4_pnfs_open_bitmap[0]; | 2314 | opendata->o_arg.open_bitmap = &nfs4_pnfs_open_bitmap[0]; |
2312 | } | 2315 | } |
2313 | if (dentry->d_inode != NULL) | 2316 | if (dentry->d_inode != NULL) |
@@ -2335,11 +2338,10 @@ static int _nfs4_do_open(struct inode *dir, | |||
2335 | if (opendata->file_created) | 2338 | if (opendata->file_created) |
2336 | *opened |= FILE_CREATED; | 2339 | *opened |= FILE_CREATED; |
2337 | 2340 | ||
2338 | if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server)) | 2341 | if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server)) { |
2339 | *ctx_th = opendata->f_attr.mdsthreshold; | 2342 | *ctx_th = opendata->f_attr.mdsthreshold; |
2340 | else | 2343 | opendata->f_attr.mdsthreshold = NULL; |
2341 | kfree(opendata->f_attr.mdsthreshold); | 2344 | } |
2342 | opendata->f_attr.mdsthreshold = NULL; | ||
2343 | 2345 | ||
2344 | nfs4_label_free(olabel); | 2346 | nfs4_label_free(olabel); |
2345 | 2347 | ||
@@ -2349,7 +2351,6 @@ static int _nfs4_do_open(struct inode *dir, | |||
2349 | err_free_label: | 2351 | err_free_label: |
2350 | nfs4_label_free(olabel); | 2352 | nfs4_label_free(olabel); |
2351 | err_opendata_put: | 2353 | err_opendata_put: |
2352 | kfree(opendata->f_attr.mdsthreshold); | ||
2353 | nfs4_opendata_put(opendata); | 2354 | nfs4_opendata_put(opendata); |
2354 | err_put_state_owner: | 2355 | err_put_state_owner: |
2355 | nfs4_put_state_owner(sp); | 2356 | nfs4_put_state_owner(sp); |