aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2014-03-26 16:24:37 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-03-28 20:12:10 -0400
commite911b8158ee1def8153849b1641b736026b036e0 (patch)
treeb9c302ffd9e9580afe59b3d56b2380ea9e76204e /fs/nfs
parent494314c415e2d3b308f57c9245ae6525166c70b8 (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.c19
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,
2349err_free_label: 2351err_free_label:
2350 nfs4_label_free(olabel); 2352 nfs4_label_free(olabel);
2351err_opendata_put: 2353err_opendata_put:
2352 kfree(opendata->f_attr.mdsthreshold);
2353 nfs4_opendata_put(opendata); 2354 nfs4_opendata_put(opendata);
2354err_put_state_owner: 2355err_put_state_owner:
2355 nfs4_put_state_owner(sp); 2356 nfs4_put_state_owner(sp);