Add duplication helpers in the cases where the ctl_table array elements
are modified after duplication. Helpers return a ctl_table as const
pointer allowing the const qualification of the static global ctl_table
array.

Signed-off-by: Joel Granados <[email protected]>
---
 net/core/sysctl_net_core.c        | 38 +++++++++++++++++----------
 net/ipv4/sysctl_net_ipv4.c        | 54 +++++++++++++++++++++++----------------
 net/ipv4/xfrm4_policy.c           | 22 ++++++++++++----
 net/ipv6/xfrm6_policy.c           | 22 ++++++++++++----
 net/netfilter/nf_hooks_lwtunnel.c |  4 +--
 net/smc/smc_sysctl.c              | 26 ++++++++++++++-----
 net/unix/sysctl_net_unix.c        | 21 +++++++++++----
 net/vmw_vsock/af_vsock.c          | 25 +++++++++++++-----
 8 files changed, 146 insertions(+), 66 deletions(-)

diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 
b508618bfc12393ba926ebf5a2dd4ea73ef03ee8..eb35da3556f4aa00cecd4582ab94e339d2518506
 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -678,7 +678,7 @@ static struct ctl_table net_core_table[] = {
        },
 };
 
-static struct ctl_table netns_core_table[] = {
+static const struct ctl_table netns_core_table[] = {
 #if IS_ENABLED(CONFIG_RPS)
        {
                .procname       = "rps_default_mask",
@@ -787,26 +787,38 @@ static int __init 
fb_tunnels_only_for_init_net_sysctl_setup(char *str)
 }
 __setup("fb_tunnels=", fb_tunnels_only_for_init_net_sysctl_setup);
 
-static __net_init int sysctl_core_net_init(struct net *net)
+static const struct ctl_table *netns_core_table_dup(struct net *net)
 {
        size_t table_size = ARRAY_SIZE(netns_core_table);
        struct ctl_table *tbl;
+       int i;
+
+       tbl = kmemdup(netns_core_table, sizeof(netns_core_table), GFP_KERNEL);
+       if (!tbl)
+               return NULL;
+
+       for (i = 0; i < table_size; ++i) {
+               if (tbl[i].data == &sysctl_wmem_max)
+                       break;
+
+               tbl[i].data += (char *)net - (char *)&init_net;
+       }
+       for (; i < table_size; ++i)
+               tbl[i].mode &= ~0222;
+
+       return tbl;
+}
+
+static __net_init int sysctl_core_net_init(struct net *net)
+{
+       size_t table_size = ARRAY_SIZE(netns_core_table);
+       const struct ctl_table *tbl;
 
        tbl = netns_core_table;
        if (!net_eq(net, &init_net)) {
-               int i;
-               tbl = kmemdup(tbl, sizeof(netns_core_table), GFP_KERNEL);
+               tbl = netns_core_table_dup(net);
                if (tbl == NULL)
                        goto err_dup;
-
-               for (i = 0; i < table_size; ++i) {
-                       if (tbl[i].data == &sysctl_wmem_max)
-                               break;
-
-                       tbl[i].data += (char *)net - (char *)&init_net;
-               }
-               for (; i < table_size; ++i)
-                       tbl[i].mode &= ~0222;
        }
 
        net->core.sysctl_hdr = register_net_sysctl_sz(net, "net/core", tbl, 
table_size);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 
ca1180dba1dea9ce72028ba49b7f953da343336b..2f0363bca2a88d68276670cfce6fb04398f82bc5
 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -624,7 +624,7 @@ static struct ctl_table ipv4_table[] = {
        },
 };
 
-static struct ctl_table ipv4_net_table[] = {
+static const struct ctl_table ipv4_net_table[] = {
        {
                .procname       = "tcp_max_tw_buckets",
                .data           = 
&init_net.ipv4.tcp_death_row.sysctl_max_tw_buckets,
@@ -1654,35 +1654,45 @@ static struct ctl_table ipv4_net_table[] = {
        },
 };
 
-static __net_init int ipv4_sysctl_init_net(struct net *net)
+static const struct ctl_table *ipv4_net_table_dup(struct net *net)
 {
        size_t table_size = ARRAY_SIZE(ipv4_net_table);
        struct ctl_table *table;
+       int i;
+
+       table = kmemdup(ipv4_net_table, sizeof(ipv4_net_table), GFP_KERNEL);
+       if (!table)
+               return NULL;
+
+       for (i = 0; i < table_size; i++) {
+               if (table[i].data) {
+                       /* Update the variables to point into
+                        * the current struct net
+                        */
+                       table[i].data += (void *)net - (void *)&init_net;
+               } else {
+                       /* Entries without data pointer are global;
+                        * Make them read-only in non-init_net ns
+                        */
+                       table[i].mode &= ~0222;
+               }
+               if (table[i].extra2 >= (void *)&init_net.ipv4 &&
+                   table[i].extra2 < (void *)(&init_net.ipv4 + 1))
+                       table[i].extra2 += (void *)net - (void *)&init_net;
+       }
+       return table;
+}
+
+static __net_init int ipv4_sysctl_init_net(struct net *net)
+{
+       size_t table_size = ARRAY_SIZE(ipv4_net_table);
+       const struct ctl_table *table;
 
        table = ipv4_net_table;
        if (!net_eq(net, &init_net)) {
-               int i;
-
-               table = kmemdup(table, sizeof(ipv4_net_table), GFP_KERNEL);
+               table = ipv4_net_table_dup(net);
                if (!table)
                        goto err_alloc;
-
-               for (i = 0; i < table_size; i++) {
-                       if (table[i].data) {
-                               /* Update the variables to point into
-                                * the current struct net
-                                */
-                               table[i].data += (void *)net - (void 
*)&init_net;
-                       } else {
-                               /* Entries without data pointer are global;
-                                * Make them read-only in non-init_net ns
-                                */
-                               table[i].mode &= ~0222;
-                       }
-                       if (table[i].extra2 >= (void *)&init_net.ipv4 &&
-                           table[i].extra2 < (void *)(&init_net.ipv4 + 1))
-                               table[i].extra2 += (void *)net - (void 
*)&init_net;
-               }
        }
 
        net->ipv4.ipv4_hdr = register_net_sysctl_sz(net, "net/ipv4", table,
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 
58faf1ddd2b151e4569bb6351029718dac37521b..ab7a01029d490416d36482f7a3189f83d6670f42
 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -141,7 +141,7 @@ static const struct xfrm_policy_afinfo xfrm4_policy_afinfo 
= {
 };
 
 #ifdef CONFIG_SYSCTL
-static struct ctl_table xfrm4_policy_table[] = {
+static const struct ctl_table xfrm4_policy_table[] = {
        {
                .procname       = "xfrm4_gc_thresh",
                .data           = &init_net.xfrm.xfrm4_dst_ops.gc_thresh,
@@ -151,18 +151,30 @@ static struct ctl_table xfrm4_policy_table[] = {
        },
 };
 
-static __net_init int xfrm4_net_sysctl_init(struct net *net)
+static const struct ctl_table *xfrm4_policy_table_dup(struct net *net)
 {
        struct ctl_table *table;
+
+       table = kmemdup(xfrm4_policy_table, sizeof(xfrm4_policy_table),
+                       GFP_KERNEL);
+       if (!table)
+               return NULL;
+
+       table[0].data = &net->xfrm.xfrm4_dst_ops.gc_thresh;
+
+       return table;
+}
+
+static __net_init int xfrm4_net_sysctl_init(struct net *net)
+{
+       const struct ctl_table *table;
        struct ctl_table_header *hdr;
 
        table = xfrm4_policy_table;
        if (!net_eq(net, &init_net)) {
-               table = kmemdup(table, sizeof(xfrm4_policy_table), GFP_KERNEL);
+               table = xfrm4_policy_table_dup(net);
                if (!table)
                        goto err_alloc;
-
-               table[0].data = &net->xfrm.xfrm4_dst_ops.gc_thresh;
        }
 
        hdr = register_net_sysctl_sz(net, "net/ipv4", table,
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 
125ea9a5b8a082052380b7fd7ed7123f5247d7cc..1e0385b62cde3f6d23382f92bbad5d7fdd09f1ef
 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -186,7 +186,7 @@ static void xfrm6_policy_fini(void)
 }
 
 #ifdef CONFIG_SYSCTL
-static struct ctl_table xfrm6_policy_table[] = {
+static const struct ctl_table xfrm6_policy_table[] = {
        {
                .procname       = "xfrm6_gc_thresh",
                .data           = &init_net.xfrm.xfrm6_dst_ops.gc_thresh,
@@ -196,18 +196,30 @@ static struct ctl_table xfrm6_policy_table[] = {
        },
 };
 
-static int __net_init xfrm6_net_sysctl_init(struct net *net)
+static const struct ctl_table *xfrm6_policy_table_dup(struct net *net)
 {
        struct ctl_table *table;
+
+       table = kmemdup(xfrm6_policy_table, sizeof(xfrm6_policy_table),
+                       GFP_KERNEL);
+       if (!table)
+               return NULL;
+
+       table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh;
+
+       return table;
+}
+
+static int __net_init xfrm6_net_sysctl_init(struct net *net)
+{
+       const struct ctl_table *table;
        struct ctl_table_header *hdr;
 
        table = xfrm6_policy_table;
        if (!net_eq(net, &init_net)) {
-               table = kmemdup(table, sizeof(xfrm6_policy_table), GFP_KERNEL);
+               table = xfrm6_policy_table_dup(net);
                if (!table)
                        goto err_alloc;
-
-               table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh;
        }
 
        hdr = register_net_sysctl_sz(net, "net/ipv6", table,
diff --git a/net/netfilter/nf_hooks_lwtunnel.c 
b/net/netfilter/nf_hooks_lwtunnel.c
index 
2d890dd04ff89041e6aec3741f24cdd7bc47d1fe..4e1eef1ba0f1559ca35f024723af551c6c9e7d35
 100644
--- a/net/netfilter/nf_hooks_lwtunnel.c
+++ b/net/netfilter/nf_hooks_lwtunnel.c
@@ -54,7 +54,7 @@ int nf_hooks_lwtunnel_sysctl_handler(const struct ctl_table 
*table, int write,
 }
 EXPORT_SYMBOL_GPL(nf_hooks_lwtunnel_sysctl_handler);
 
-static struct ctl_table nf_lwtunnel_sysctl_table[] = {
+static const struct ctl_table nf_lwtunnel_sysctl_table[] = {
        {
                .procname       = "nf_hooks_lwtunnel",
                .data           = NULL,
@@ -66,8 +66,8 @@ static struct ctl_table nf_lwtunnel_sysctl_table[] = {
 
 static int __net_init nf_lwtunnel_net_init(struct net *net)
 {
+       const struct ctl_table *table;
        struct ctl_table_header *hdr;
-       struct ctl_table *table;
 
        table = nf_lwtunnel_sysctl_table;
        if (!net_eq(net, &init_net)) {
diff --git a/net/smc/smc_sysctl.c b/net/smc/smc_sysctl.c
index 
b1efed5462435b1a6f2f59584a4cf47f5f6e1981..09dad48337f6164f5765fa793412bdebf47e61ca
 100644
--- a/net/smc/smc_sysctl.c
+++ b/net/smc/smc_sysctl.c
@@ -97,7 +97,7 @@ static int proc_smc_hs_ctrl(const struct ctl_table *ctl, int 
write,
 }
 #endif /* CONFIG_SMC_HS_CTRL_BPF */
 
-static struct ctl_table smc_table[] = {
+static const struct ctl_table smc_table[] = {
        {
                .procname       = "autocorking_size",
                .data           = &init_net.smc.sysctl_autocorking_size,
@@ -195,14 +195,29 @@ static struct ctl_table smc_table[] = {
 #endif /* CONFIG_SMC_HS_CTRL_BPF */
 };
 
-int __net_init smc_sysctl_net_init(struct net *net)
+static const struct ctl_table *smc_table_dup(struct net *net)
 {
        size_t table_size = ARRAY_SIZE(smc_table);
        struct ctl_table *table;
+       int i;
+
+       table = kmemdup(smc_table, sizeof(smc_table), GFP_KERNEL);
+       if (!table)
+               return NULL;
+
+       for (i = 0; i < table_size; i++)
+               table[i].data += (void *)net - (void *)&init_net;
+
+       return table;
+}
+
+int __net_init smc_sysctl_net_init(struct net *net)
+{
+       size_t table_size = ARRAY_SIZE(smc_table);
+       const struct ctl_table *table;
 
        table = smc_table;
        if (!net_eq(net, &init_net)) {
-               int i;
 #if IS_ENABLED(CONFIG_SMC_HS_CTRL_BPF)
                struct smc_hs_ctrl *ctrl;
 
@@ -214,12 +229,9 @@ int __net_init smc_sysctl_net_init(struct net *net)
                rcu_read_unlock();
 #endif /* CONFIG_SMC_HS_CTRL_BPF */
 
-               table = kmemdup(table, sizeof(smc_table), GFP_KERNEL);
+               table = smc_table_dup(net);
                if (!table)
                        goto err_alloc;
-
-               for (i = 0; i < table_size; i++)
-                       table[i].data += (void *)net - (void *)&init_net;
        }
 
        net->smc.smc_hdr = register_net_sysctl_sz(net, "net/smc", table,
diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c
index 
e02ed6e3955c06b60cf4afb02656df8956f075ba..47660d5726bbd7d812762f4feffa9a0a42499d7d
 100644
--- a/net/unix/sysctl_net_unix.c
+++ b/net/unix/sysctl_net_unix.c
@@ -13,7 +13,7 @@
 
 #include "af_unix.h"
 
-static struct ctl_table unix_table[] = {
+static const struct ctl_table unix_table[] = {
        {
                .procname       = "max_dgram_qlen",
                .data           = &init_net.unx.sysctl_max_dgram_qlen,
@@ -23,18 +23,29 @@ static struct ctl_table unix_table[] = {
        },
 };
 
-int __net_init unix_sysctl_register(struct net *net)
+static const struct ctl_table *unix_table_dup(struct net *net)
 {
        struct ctl_table *table;
 
+       table = kmemdup(unix_table, sizeof(unix_table), GFP_KERNEL);
+       if (!table)
+               return NULL;
+
+       table[0].data = &net->unx.sysctl_max_dgram_qlen;
+
+       return table;
+}
+
+int __net_init unix_sysctl_register(struct net *net)
+{
+       const struct ctl_table *table;
+
        if (net_eq(net, &init_net)) {
                table = unix_table;
        } else {
-               table = kmemdup(unix_table, sizeof(unix_table), GFP_KERNEL);
+               table = unix_table_dup(net);
                if (!table)
                        goto err_alloc;
-
-               table[0].data = &net->unx.sysctl_max_dgram_qlen;
        }
 
        net->unx.ctl = register_net_sysctl_sz(net, "net/unix", table,
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
index 
622dbd0467994428f1a590f559b78d8c17f6ba60..caebef73ea58d2b6043ca3fe3b6872f92fbe9fa6
 100644
--- a/net/vmw_vsock/af_vsock.c
+++ b/net/vmw_vsock/af_vsock.c
@@ -2899,7 +2899,7 @@ static int vsock_net_child_mode_string(const struct 
ctl_table *table, int write,
        return 0;
 }
 
-static struct ctl_table vsock_table[] = {
+static const struct ctl_table vsock_table[] = {
        {
                .procname       = "ns_mode",
                .data           = &init_net.vsock.mode,
@@ -2925,20 +2925,31 @@ static struct ctl_table vsock_table[] = {
        },
 };
 
-static int __net_init vsock_sysctl_register(struct net *net)
+static const struct ctl_table *vsock_table_dup(struct net *net)
 {
        struct ctl_table *table;
 
+       table = kmemdup(vsock_table, sizeof(vsock_table), GFP_KERNEL);
+       if (!table)
+               return NULL;
+
+       table[0].data = &net->vsock.mode;
+       table[1].data = &net->vsock.child_ns_mode;
+       table[2].data = &net->vsock.g2h_fallback;
+
+       return table;
+}
+
+static int __net_init vsock_sysctl_register(struct net *net)
+{
+       const struct ctl_table *table;
+
        if (net_eq(net, &init_net)) {
                table = vsock_table;
        } else {
-               table = kmemdup(vsock_table, sizeof(vsock_table), GFP_KERNEL);
+               table = vsock_table_dup(net);
                if (!table)
                        goto err_alloc;
-
-               table[0].data = &net->vsock.mode;
-               table[1].data = &net->vsock.child_ns_mode;
-               table[2].data = &net->vsock.g2h_fallback;
        }
 
        net->vsock.sysctl_hdr = register_net_sysctl_sz(net, "net/vsock", table,

-- 
2.50.1



Reply via email to