lkml.org 
[lkml]   [2022]   [Apr]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.17 055/343] net: initialize init_net earlier
    Date
    From: Eric Dumazet <edumazet@google.com>

    [ Upstream commit 9c1be1935fb68b2413796cdc03d019b8cf35ab51 ]

    While testing a patch that will follow later
    ("net: add netns refcount tracker to struct nsproxy")
    I found that devtmpfs_init() was called before init_net
    was initialized.

    This is a bug, because devtmpfs_setup() calls
    ksys_unshare(CLONE_NEWNS);

    This has the effect of increasing init_net refcount,
    which will be later overwritten to 1, as part of setup_net(&init_net)

    We had too many prior patches [1] trying to work around the root cause.

    Really, make sure init_net is in BSS section, and that net_ns_init()
    is called earlier at boot time.

    Note that another patch ("vfs: add netns refcount tracker
    to struct fs_context") also will need net_ns_init() being called
    before vfs_caches_init()

    As a bonus, this patch saves around 4KB in .data section.

    [1]

    f8c46cb39079 ("netns: do not call pernet ops for not yet set up init_net namespace")
    b5082df8019a ("net: Initialise init_net.count to 1")
    734b65417b24 ("net: Statically initialize init_net.dev_base_head")

    v2: fixed a build error reported by kernel build bots (CONFIG_NET=n)

    Signed-off-by: Eric Dumazet <edumazet@google.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    include/net/net_namespace.h | 6 ++++++
    init/main.c | 2 ++
    net/core/dev.c | 3 +--
    net/core/net_namespace.c | 17 +++++------------
    4 files changed, 14 insertions(+), 14 deletions(-)

    diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
    index 5b61c462e534..374cc7b260fc 100644
    --- a/include/net/net_namespace.h
    +++ b/include/net/net_namespace.h
    @@ -513,4 +513,10 @@ static inline void fnhe_genid_bump(struct net *net)
    atomic_inc(&net->fnhe_genid);
    }

    +#ifdef CONFIG_NET
    +void net_ns_init(void);
    +#else
    +static inline void net_ns_init(void) {}
    +#endif
    +
    #endif /* __NET_NET_NAMESPACE_H */
    diff --git a/init/main.c b/init/main.c
    index 65fa2e41a9c0..ada50f5a15e4 100644
    --- a/init/main.c
    +++ b/init/main.c
    @@ -99,6 +99,7 @@
    #include <linux/kcsan.h>
    #include <linux/init_syscalls.h>
    #include <linux/stackdepot.h>
    +#include <net/net_namespace.h>

    #include <asm/io.h>
    #include <asm/bugs.h>
    @@ -1116,6 +1117,7 @@ asmlinkage __visible void __init __no_sanitize_address start_kernel(void)
    key_init();
    security_init();
    dbg_late_init();
    + net_ns_init();
    vfs_caches_init();
    pagecache_init();
    signals_init();
    diff --git a/net/core/dev.c b/net/core/dev.c
    index 1baab07820f6..91cf709c98b3 100644
    --- a/net/core/dev.c
    +++ b/net/core/dev.c
    @@ -10732,8 +10732,7 @@ static int __net_init netdev_init(struct net *net)
    BUILD_BUG_ON(GRO_HASH_BUCKETS >
    8 * sizeof_field(struct napi_struct, gro_bitmask));

    - if (net != &init_net)
    - INIT_LIST_HEAD(&net->dev_base_head);
    + INIT_LIST_HEAD(&net->dev_base_head);

    net->dev_name_head = netdev_create_hash();
    if (net->dev_name_head == NULL)
    diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
    index a5b5bb99c644..212e65add951 100644
    --- a/net/core/net_namespace.c
    +++ b/net/core/net_namespace.c
    @@ -44,13 +44,7 @@ EXPORT_SYMBOL_GPL(net_rwsem);
    static struct key_tag init_net_key_domain = { .usage = REFCOUNT_INIT(1) };
    #endif

    -struct net init_net = {
    - .ns.count = REFCOUNT_INIT(1),
    - .dev_base_head = LIST_HEAD_INIT(init_net.dev_base_head),
    -#ifdef CONFIG_KEYS
    - .key_domain = &init_net_key_domain,
    -#endif
    -};
    +struct net init_net;
    EXPORT_SYMBOL(init_net);

    static bool init_net_initialized;
    @@ -1084,7 +1078,7 @@ static void rtnl_net_notifyid(struct net *net, int cmd, int id, u32 portid,
    rtnl_set_sk_err(net, RTNLGRP_NSID, err);
    }

    -static int __init net_ns_init(void)
    +void __init net_ns_init(void)
    {
    struct net_generic *ng;

    @@ -1105,6 +1099,9 @@ static int __init net_ns_init(void)

    rcu_assign_pointer(init_net.gen, ng);

    +#ifdef CONFIG_KEYS
    + init_net.key_domain = &init_net_key_domain;
    +#endif
    down_write(&pernet_ops_rwsem);
    if (setup_net(&init_net, &init_user_ns))
    panic("Could not setup the initial network namespace");
    @@ -1119,12 +1116,8 @@ static int __init net_ns_init(void)
    RTNL_FLAG_DOIT_UNLOCKED);
    rtnl_register(PF_UNSPEC, RTM_GETNSID, rtnl_net_getid, rtnl_net_dumpid,
    RTNL_FLAG_DOIT_UNLOCKED);
    -
    - return 0;
    }

    -pure_initcall(net_ns_init);
    -
    static void free_exit_list(struct pernet_operations *ops, struct list_head *net_exit_list)
    {
    ops_pre_exit_list(ops, net_exit_list);
    --
    2.35.1


    \
     
     \ /
      Last update: 2022-04-12 10:43    [W:6.122 / U:0.020 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site