Skip to content

Commit eb1fe96

Browse files
bcodding-rhgregkh
authored andcommitted
NFSv4: Fix free of uninitialized nfs4_label on referral lookup.
commit c3ed222 upstream. Send along the already-allocated fattr along with nfs4_fs_locations, and drop the memcpy of fattr. We end up growing two more allocations, but this fixes up a crash as: PID: 790 TASK: ffff88811b43c000 CPU: 0 COMMAND: "ls" #0 [ffffc90000857920] panic at ffffffff81b9bfde nxp-imx#1 [ffffc900008579c0] do_trap at ffffffff81023a9b nxp-imx#2 [ffffc90000857a10] do_error_trap at ffffffff81023b78 nxp-imx#3 [ffffc90000857a58] exc_stack_segment at ffffffff81be1f45 nxp-imx#4 [ffffc90000857a80] asm_exc_stack_segment at ffffffff81c009de nxp-imx#5 [ffffc90000857b08] nfs_lookup at ffffffffa0302322 [nfs] nxp-imx#6 [ffffc90000857b70] __lookup_slow at ffffffff813a4a5f nxp-imx#7 [ffffc90000857c60] walk_component at ffffffff813a86c4 nxp-imx#8 [ffffc90000857cb8] path_lookupat at ffffffff813a9553 nxp-imx#9 [ffffc90000857cf0] filename_lookup at ffffffff813ab86b Suggested-by: Trond Myklebust <[email protected]> Fixes: 9558a00 ("NFS: Remove the label from the nfs4_lookup_res struct") Signed-off-by: Benjamin Coddington <[email protected]> Signed-off-by: Anna Schumaker <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 4f5365f commit eb1fe96

File tree

5 files changed

+25
-14
lines changed

5 files changed

+25
-14
lines changed

fs/nfs/nfs4namespace.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,9 @@ static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client)
417417
fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
418418
if (!fs_locations)
419419
goto out_free;
420+
fs_locations->fattr = nfs_alloc_fattr();
421+
if (!fs_locations->fattr)
422+
goto out_free_2;
420423

421424
/* Get locations */
422425
dentry = ctx->clone_data.dentry;
@@ -427,14 +430,16 @@ static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client)
427430
err = nfs4_proc_fs_locations(client, d_inode(parent), &dentry->d_name, fs_locations, page);
428431
dput(parent);
429432
if (err != 0)
430-
goto out_free_2;
433+
goto out_free_3;
431434

432435
err = -ENOENT;
433436
if (fs_locations->nlocations <= 0 ||
434437
fs_locations->fs_path.ncomponents <= 0)
435-
goto out_free_2;
438+
goto out_free_3;
436439

437440
err = nfs_follow_referral(fc, fs_locations);
441+
out_free_3:
442+
kfree(fs_locations->fattr);
438443
out_free_2:
439444
kfree(fs_locations);
440445
out_free:

fs/nfs/nfs4proc.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4213,6 +4213,8 @@ static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir,
42134213
if (locations == NULL)
42144214
goto out;
42154215

4216+
locations->fattr = fattr;
4217+
42164218
status = nfs4_proc_fs_locations(client, dir, name, locations, page);
42174219
if (status != 0)
42184220
goto out;
@@ -4222,17 +4224,14 @@ static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir,
42224224
* referral. Cause us to drop into the exception handler, which
42234225
* will kick off migration recovery.
42244226
*/
4225-
if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) {
4227+
if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &fattr->fsid)) {
42264228
dprintk("%s: server did not return a different fsid for"
42274229
" a referral at %s\n", __func__, name->name);
42284230
status = -NFS4ERR_MOVED;
42294231
goto out;
42304232
}
42314233
/* Fixup attributes for the nfs_lookup() call to nfs_fhget() */
4232-
nfs_fixup_referral_attributes(&locations->fattr);
4233-
4234-
/* replace the lookup nfs_fattr with the locations nfs_fattr */
4235-
memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr));
4234+
nfs_fixup_referral_attributes(fattr);
42364235
memset(fhandle, 0, sizeof(struct nfs_fh));
42374236
out:
42384237
if (page)
@@ -7917,7 +7916,7 @@ static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
79177916
else
79187917
bitmask[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
79197918

7920-
nfs_fattr_init(&fs_locations->fattr);
7919+
nfs_fattr_init(fs_locations->fattr);
79217920
fs_locations->server = server;
79227921
fs_locations->nlocations = 0;
79237922
status = nfs4_call_sync(client, server, &msg, &args.seq_args, &res.seq_res, 0);
@@ -7982,7 +7981,7 @@ static int _nfs40_proc_get_locations(struct nfs_server *server,
79827981
unsigned long now = jiffies;
79837982
int status;
79847983

7985-
nfs_fattr_init(&locations->fattr);
7984+
nfs_fattr_init(locations->fattr);
79867985
locations->server = server;
79877986
locations->nlocations = 0;
79887987

@@ -8035,7 +8034,7 @@ static int _nfs41_proc_get_locations(struct nfs_server *server,
80358034
};
80368035
int status;
80378036

8038-
nfs_fattr_init(&locations->fattr);
8037+
nfs_fattr_init(locations->fattr);
80398038
locations->server = server;
80408039
locations->nlocations = 0;
80418040

fs/nfs/nfs4state.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2096,6 +2096,11 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred
20962096
dprintk("<-- %s: no memory\n", __func__);
20972097
goto out;
20982098
}
2099+
locations->fattr = nfs_alloc_fattr();
2100+
if (locations->fattr == NULL) {
2101+
dprintk("<-- %s: no memory\n", __func__);
2102+
goto out;
2103+
}
20992104

21002105
inode = d_inode(server->super->s_root);
21012106
result = nfs4_proc_get_locations(server, NFS_FH(inode), locations,
@@ -2110,7 +2115,7 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred
21102115
if (!locations->nlocations)
21112116
goto out;
21122117

2113-
if (!(locations->fattr.valid & NFS_ATTR_FATTR_V4_LOCATIONS)) {
2118+
if (!(locations->fattr->valid & NFS_ATTR_FATTR_V4_LOCATIONS)) {
21142119
dprintk("<-- %s: No fs_locations data, migration skipped\n",
21152120
__func__);
21162121
goto out;
@@ -2135,6 +2140,8 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred
21352140
out:
21362141
if (page != NULL)
21372142
__free_page(page);
2143+
if (locations != NULL)
2144+
kfree(locations->fattr);
21382145
kfree(locations);
21392146
if (result) {
21402147
pr_err("NFS: migration recovery failed (server %s)\n",

fs/nfs/nfs4xdr.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7028,7 +7028,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
70287028
if (res->migration) {
70297029
xdr_enter_page(xdr, PAGE_SIZE);
70307030
status = decode_getfattr_generic(xdr,
7031-
&res->fs_locations->fattr,
7031+
res->fs_locations->fattr,
70327032
NULL, res->fs_locations,
70337033
NULL, res->fs_locations->server);
70347034
if (status)
@@ -7041,7 +7041,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
70417041
goto out;
70427042
xdr_enter_page(xdr, PAGE_SIZE);
70437043
status = decode_getfattr_generic(xdr,
7044-
&res->fs_locations->fattr,
7044+
res->fs_locations->fattr,
70457045
NULL, res->fs_locations,
70467046
NULL, res->fs_locations->server);
70477047
}

include/linux/nfs_xdr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1219,7 +1219,7 @@ struct nfs4_fs_location {
12191219

12201220
#define NFS4_FS_LOCATIONS_MAXENTRIES 10
12211221
struct nfs4_fs_locations {
1222-
struct nfs_fattr fattr;
1222+
struct nfs_fattr *fattr;
12231223
const struct nfs_server *server;
12241224
struct nfs4_pathname fs_path;
12251225
int nlocations;

0 commit comments

Comments
 (0)