mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-10-28 12:53:14 +01: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 <[email protected]>
Signed-off-by: Trond Myklebust <[email protected]>
This commit is contained in:
1 parent
187bfc974e
commit
d05c2007b3
3 files changed
+15
-1
No files matched your search
+13
-1
@@ -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);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user