From a0f423fd9bde3e4f7760f3afe18660d705f68b20 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 8 May 2021 17:26:03 +0800 Subject: [PATCH] SUNRPC: Close a race with transport setup and module put mainline inclusion from mainline-v5.11-rc1 commit 9bccd264611b5345d85138dc7fd55bdeb9e6942e category: bugfix bugzilla: NA CVE: NA -------------------------------- After we've looked up the transport module, we need to ensure it can't go away until we've finished running the transport setup code. conflicts: net/sunrpc/xprt.c Signed-off-by: Trond Myklebust Signed-off-by: Lu Wei Reviewed-by: Yue Haibing Signed-off-by: Yang Yingliang --- net/sunrpc/xprt.c | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 9c4235ce5789..7a0d82232438 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -149,6 +149,32 @@ xprt_class_release(const struct xprt_class *t) module_put(t->owner); } +static const struct xprt_class * +xprt_class_find_by_ident_locked(int ident) +{ + const struct xprt_class *t; + + list_for_each_entry(t, &xprt_list, list) { + if (t->ident != ident) + continue; + if (!try_module_get(t->owner)) + continue; + return t; + } + return NULL; +} + +static const struct xprt_class * +xprt_class_find_by_ident(int ident) +{ + const struct xprt_class *t; + + spin_lock(&xprt_list_lock); + t = xprt_class_find_by_ident_locked(ident); + spin_unlock(&xprt_list_lock); + return t; +} + static const struct xprt_class * xprt_class_find_by_netid_locked(const char *netid) { @@ -1468,21 +1494,17 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net) struct rpc_xprt *xprt_create_transport(struct xprt_create *args) { struct rpc_xprt *xprt; - struct xprt_class *t; + const struct xprt_class *t; - spin_lock(&xprt_list_lock); - list_for_each_entry(t, &xprt_list, list) { - if (t->ident == args->ident) { - spin_unlock(&xprt_list_lock); - goto found; - } + t = xprt_class_find_by_ident(args->ident); + if (!t) { + dprintk("RPC: transport (%d) not supported\n", args->ident); + return ERR_PTR(-EIO); } - spin_unlock(&xprt_list_lock); - dprintk("RPC: transport (%d) not supported\n", args->ident); - return ERR_PTR(-EIO); -found: xprt = t->setup(args); + xprt_class_release(t); + if (IS_ERR(xprt)) { dprintk("RPC: xprt_create_transport: failed, %ld\n", -PTR_ERR(xprt)); -- GitLab