mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
NFSv4: remove callback IDR entry on client allocation failure
nfs4_alloc_client() allocates an NFSv4.0 callback identifier before it
finishes setting up the client. If any later initialization step fails,
the error path frees the nfs_client directly with nfs_free_client(). That
bypasses nfs_put_client(), which is where the callback IDR entry is
removed during normal teardown.
A failed allocation can therefore leave cb_ident_idr pointing at a freed
nfs_client. A later NFSv4.0 callback lookup by cb_ident would find the
stale pointer and take a reference to it.
Make the callback IDR removal helper callable by the allocation failure
path, and remove the callback identifier before freeing the client.
This was found by a local static-analysis checker for publish-before-free
lifetime bugs and confirmed by manual inspection.
Fixes: f4eecd5da3 ("NFS implement v4.0 callback_ident")
Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
parent
187bfc974e
commit
d05c2007b3
|
|
@ -215,10 +215,22 @@ static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
|
|||
{
|
||||
struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
|
||||
|
||||
if (clp->cl_cb_ident)
|
||||
if (clp->cl_cb_ident) {
|
||||
idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident);
|
||||
clp->cl_cb_ident = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void nfs_cb_idr_remove(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
|
||||
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
nfs_cb_idr_remove_locked(clp);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_cb_idr_remove);
|
||||
|
||||
static void pnfs_init_server(struct nfs_server *server)
|
||||
{
|
||||
rpc_init_wait_queue(&server->roc_rpcwaitq, "pNFS ROC");
|
||||
|
|
|
|||
|
|
@ -225,6 +225,7 @@ void nfs_server_copy_userdata(struct nfs_server *, struct nfs_server *);
|
|||
|
||||
extern void nfs_put_client(struct nfs_client *);
|
||||
extern void nfs_free_client(struct nfs_client *);
|
||||
void nfs_cb_idr_remove(struct nfs_client *clp);
|
||||
extern struct nfs_client *nfs4_find_client_ident(struct net *, int);
|
||||
extern struct nfs_client *
|
||||
nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
|
||||
|
|
|
|||
|
|
@ -261,6 +261,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
|
|||
return clp;
|
||||
|
||||
error:
|
||||
nfs_cb_idr_remove(clp);
|
||||
nfs_free_client(clp);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user