lkml.org 
[lkml]   [2019]   [Aug]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.9 012/103] netfilter: nfnetlink: avoid deadlock due to synchronous request_module
    Date
    [ Upstream commit 1b0890cd60829bd51455dc5ad689ed58c4408227 ]

    Thomas and Juliana report a deadlock when running:

    (rmmod nf_conntrack_netlink/xfrm_user)

    conntrack -e NEW -E &
    modprobe -v xfrm_user

    They provided following analysis:

    conntrack -e NEW -E
    netlink_bind()
    netlink_lock_table() -> increases "nl_table_users"
    nfnetlink_bind()
    # does not unlock the table as it's locked by netlink_bind()
    __request_module()
    call_usermodehelper_exec()

    This triggers "modprobe nf_conntrack_netlink" from kernel, netlink_bind()
    won't return until modprobe process is done.

    "modprobe xfrm_user":
    xfrm_user_init()
    register_pernet_subsys()
    -> grab pernet_ops_rwsem
    ..
    netlink_table_grab()
    calls schedule() as "nl_table_users" is non-zero

    so modprobe is blocked because netlink_bind() increased
    nl_table_users while also holding pernet_ops_rwsem.

    "modprobe nf_conntrack_netlink" runs and inits nf_conntrack_netlink:
    ctnetlink_init()
    register_pernet_subsys()
    -> blocks on "pernet_ops_rwsem" thanks to xfrm_user module

    both modprobe processes wait on one another -- neither can make
    progress.

    Switch netlink_bind() to "nowait" modprobe -- this releases the netlink
    table lock, which then allows both modprobe instances to complete.

    Reported-by: Thomas Jarosch <thomas.jarosch@intra2net.com>
    Reported-by: Juliana Rodrigueiro <juliana.rodrigueiro@intra2net.com>
    Signed-off-by: Florian Westphal <fw@strlen.de>
    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    net/netfilter/nfnetlink.c | 2 +-
    1 file changed, 1 insertion(+), 1 deletion(-)

    diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
    index 2278d9ab723bf..9837a61cb3e3b 100644
    --- a/net/netfilter/nfnetlink.c
    +++ b/net/netfilter/nfnetlink.c
    @@ -490,7 +490,7 @@ static int nfnetlink_bind(struct net *net, int group)
    ss = nfnetlink_get_subsys(type << 8);
    rcu_read_unlock();
    if (!ss)
    - request_module("nfnetlink-subsys-%d", type);
    + request_module_nowait("nfnetlink-subsys-%d", type);
    return 0;
    }
    #endif
    --
    2.20.1


    \
     
     \ /
      Last update: 2019-08-22 19:56    [W:4.283 / U:0.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site