Commit c3ed2227 authored by Benjamin Coddington's avatar Benjamin Coddington Committed by Anna Schumaker

NFSv4: Fix free of uninitialized nfs4_label on referral lookup.

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
 #1 [ffffc900008579c0] do_trap at ffffffff81023a9b
 #2 [ffffc90000857a10] do_error_trap at ffffffff81023b78
 #3 [ffffc90000857a58] exc_stack_segment at ffffffff81be1f45
 #4 [ffffc90000857a80] asm_exc_stack_segment at ffffffff81c009de
 #5 [ffffc90000857b08] nfs_lookup at ffffffffa0302322 [nfs]
 #6 [ffffc90000857b70] __lookup_slow at ffffffff813a4a5f
 #7 [ffffc90000857c60] walk_component at ffffffff813a86c4
 #8 [ffffc90000857cb8] path_lookupat at ffffffff813a9553
 #9 [ffffc90000857cf0] filename_lookup at ffffffff813ab86b
Suggested-by: default avatarTrond Myklebust <trondmy@hammerspace.com>
Fixes: 9558a007 ("NFS: Remove the label from the nfs4_lookup_res struct")
Signed-off-by: default avatarBenjamin Coddington <bcodding@redhat.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 9c4a5c75
...@@ -417,6 +417,9 @@ static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client) ...@@ -417,6 +417,9 @@ static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client)
fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL); fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
if (!fs_locations) if (!fs_locations)
goto out_free; goto out_free;
fs_locations->fattr = nfs_alloc_fattr();
if (!fs_locations->fattr)
goto out_free_2;
/* Get locations */ /* Get locations */
dentry = ctx->clone_data.dentry; dentry = ctx->clone_data.dentry;
...@@ -427,14 +430,16 @@ static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client) ...@@ -427,14 +430,16 @@ static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client)
err = nfs4_proc_fs_locations(client, d_inode(parent), &dentry->d_name, fs_locations, page); err = nfs4_proc_fs_locations(client, d_inode(parent), &dentry->d_name, fs_locations, page);
dput(parent); dput(parent);
if (err != 0) if (err != 0)
goto out_free_2; goto out_free_3;
err = -ENOENT; err = -ENOENT;
if (fs_locations->nlocations <= 0 || if (fs_locations->nlocations <= 0 ||
fs_locations->fs_path.ncomponents <= 0) fs_locations->fs_path.ncomponents <= 0)
goto out_free_2; goto out_free_3;
err = nfs_follow_referral(fc, fs_locations); err = nfs_follow_referral(fc, fs_locations);
out_free_3:
kfree(fs_locations->fattr);
out_free_2: out_free_2:
kfree(fs_locations); kfree(fs_locations);
out_free: out_free:
......
...@@ -4247,6 +4247,8 @@ static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir, ...@@ -4247,6 +4247,8 @@ static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir,
if (locations == NULL) if (locations == NULL)
goto out; goto out;
locations->fattr = fattr;
status = nfs4_proc_fs_locations(client, dir, name, locations, page); status = nfs4_proc_fs_locations(client, dir, name, locations, page);
if (status != 0) if (status != 0)
goto out; goto out;
...@@ -4256,17 +4258,14 @@ static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir, ...@@ -4256,17 +4258,14 @@ static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir,
* referral. Cause us to drop into the exception handler, which * referral. Cause us to drop into the exception handler, which
* will kick off migration recovery. * will kick off migration recovery.
*/ */
if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) { if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &fattr->fsid)) {
dprintk("%s: server did not return a different fsid for" dprintk("%s: server did not return a different fsid for"
" a referral at %s\n", __func__, name->name); " a referral at %s\n", __func__, name->name);
status = -NFS4ERR_MOVED; status = -NFS4ERR_MOVED;
goto out; goto out;
} }
/* Fixup attributes for the nfs_lookup() call to nfs_fhget() */ /* Fixup attributes for the nfs_lookup() call to nfs_fhget() */
nfs_fixup_referral_attributes(&locations->fattr); nfs_fixup_referral_attributes(fattr);
/* replace the lookup nfs_fattr with the locations nfs_fattr */
memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr));
memset(fhandle, 0, sizeof(struct nfs_fh)); memset(fhandle, 0, sizeof(struct nfs_fh));
out: out:
if (page) if (page)
...@@ -7979,7 +7978,7 @@ static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir, ...@@ -7979,7 +7978,7 @@ static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
else else
bitmask[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID; bitmask[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
nfs_fattr_init(&fs_locations->fattr); nfs_fattr_init(fs_locations->fattr);
fs_locations->server = server; fs_locations->server = server;
fs_locations->nlocations = 0; fs_locations->nlocations = 0;
status = nfs4_call_sync(client, server, &msg, &args.seq_args, &res.seq_res, 0); status = nfs4_call_sync(client, server, &msg, &args.seq_args, &res.seq_res, 0);
...@@ -8044,7 +8043,7 @@ static int _nfs40_proc_get_locations(struct nfs_server *server, ...@@ -8044,7 +8043,7 @@ static int _nfs40_proc_get_locations(struct nfs_server *server,
unsigned long now = jiffies; unsigned long now = jiffies;
int status; int status;
nfs_fattr_init(&locations->fattr); nfs_fattr_init(locations->fattr);
locations->server = server; locations->server = server;
locations->nlocations = 0; locations->nlocations = 0;
...@@ -8109,7 +8108,7 @@ static int _nfs41_proc_get_locations(struct nfs_server *server, ...@@ -8109,7 +8108,7 @@ static int _nfs41_proc_get_locations(struct nfs_server *server,
}; };
int status; int status;
nfs_fattr_init(&locations->fattr); nfs_fattr_init(locations->fattr);
locations->server = server; locations->server = server;
locations->nlocations = 0; locations->nlocations = 0;
......
...@@ -2116,6 +2116,11 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred ...@@ -2116,6 +2116,11 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred
dprintk("<-- %s: no memory\n", __func__); dprintk("<-- %s: no memory\n", __func__);
goto out; goto out;
} }
locations->fattr = nfs_alloc_fattr();
if (locations->fattr == NULL) {
dprintk("<-- %s: no memory\n", __func__);
goto out;
}
inode = d_inode(server->super->s_root); inode = d_inode(server->super->s_root);
result = nfs4_proc_get_locations(server, NFS_FH(inode), locations, result = nfs4_proc_get_locations(server, NFS_FH(inode), locations,
...@@ -2130,7 +2135,7 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred ...@@ -2130,7 +2135,7 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred
if (!locations->nlocations) if (!locations->nlocations)
goto out; goto out;
if (!(locations->fattr.valid & NFS_ATTR_FATTR_V4_LOCATIONS)) { if (!(locations->fattr->valid & NFS_ATTR_FATTR_V4_LOCATIONS)) {
dprintk("<-- %s: No fs_locations data, migration skipped\n", dprintk("<-- %s: No fs_locations data, migration skipped\n",
__func__); __func__);
goto out; goto out;
...@@ -2155,6 +2160,8 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred ...@@ -2155,6 +2160,8 @@ static int nfs4_try_migration(struct nfs_server *server, const struct cred *cred
out: out:
if (page != NULL) if (page != NULL)
__free_page(page); __free_page(page);
if (locations != NULL)
kfree(locations->fattr);
kfree(locations); kfree(locations);
if (result) { if (result) {
pr_err("NFS: migration recovery failed (server %s)\n", pr_err("NFS: migration recovery failed (server %s)\n",
......
...@@ -7080,7 +7080,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, ...@@ -7080,7 +7080,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
if (res->migration) { if (res->migration) {
xdr_enter_page(xdr, PAGE_SIZE); xdr_enter_page(xdr, PAGE_SIZE);
status = decode_getfattr_generic(xdr, status = decode_getfattr_generic(xdr,
&res->fs_locations->fattr, res->fs_locations->fattr,
NULL, res->fs_locations, NULL, res->fs_locations,
res->fs_locations->server); res->fs_locations->server);
if (status) if (status)
...@@ -7093,7 +7093,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, ...@@ -7093,7 +7093,7 @@ static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req,
goto out; goto out;
xdr_enter_page(xdr, PAGE_SIZE); xdr_enter_page(xdr, PAGE_SIZE);
status = decode_getfattr_generic(xdr, status = decode_getfattr_generic(xdr,
&res->fs_locations->fattr, res->fs_locations->fattr,
NULL, res->fs_locations, NULL, res->fs_locations,
res->fs_locations->server); res->fs_locations->server);
} }
......
...@@ -1222,7 +1222,7 @@ struct nfs4_fs_location { ...@@ -1222,7 +1222,7 @@ struct nfs4_fs_location {
#define NFS4_FS_LOCATIONS_MAXENTRIES 10 #define NFS4_FS_LOCATIONS_MAXENTRIES 10
struct nfs4_fs_locations { struct nfs4_fs_locations {
struct nfs_fattr fattr; struct nfs_fattr *fattr;
const struct nfs_server *server; const struct nfs_server *server;
struct nfs4_pathname fs_path; struct nfs4_pathname fs_path;
int nlocations; int nlocations;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment