: Revisit read-only-in-namespaces sysctls.
Subsystems (3)
cover : Revisit read-only-in-namespaces sysctls.
Hope, it's not too early to post to net-next, but the one looks alive for quite a long time already :)
After sysctl tables permissions are finally (thanks to Andrew) in mainline I have revisited issue with sysctls, that are to be read-only in net namespaces.
PATCH 1/6 : Introduce sysctl root for read-only net sysctls.
This one stores all ctl-heads in one list and restricts the permissions not give write access to non-init net namespaces.
--- include/net/net_namespace.h | 3 +++ net/sysctl_net.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 0 deletions(-)
include/net/net_namespace.h +3 -0
@@ -201,8 +201,11 @@ extern void unregister_pernet_gen_device(int id, struct pernet_operations *);struct ctl_path ;struct ctl_table ;struct ctl_table_header ; +extern struct ctl_table_header *register_net_sysctl_table (struct net *net,const struct ctl_path *path,struct ctl_table *table); +extern struct ctl_table_header *register_net_sysctl_rotable ( +const struct ctl_path *path,struct ctl_table *table);extern void unregister_net_sysctl_table (struct ctl_table_header *header);#endif /* __NET_NET_NAMESPACE_H */
net/sysctl_net.c +30 -0
@@ -40,6 +40,27 @@ static struct ctl_table_root net_sysctl_root = { .lookup = net_ctl_header_lookup, }; +static LIST_HEAD (net_sysctl_ro_tables); +static struct list_head *net_ctl_ro_header_lookup (struct ctl_table_root *root, +struct nsproxy *namespaces) +{ +return &net_sysctl_ro_tables; +} + +static int net_ctl_ro_header_perms (struct ctl_table_root *root, +struct nsproxy *namespaces,struct ctl_table *table) +{ +if (namespaces->net_ns == &init_net) +return table->mode; +else +return table->mode & ~0222 ; +} + +static struct ctl_table_root net_sysctl_ro_root = { + .lookup = net_ctl_ro_header_lookup, + .permissions = net_ctl_ro_header_perms, +}; +static int sysctl_net_init (struct net *net) {INIT_LIST_HEAD (&net->sysctl_table_headers);
@@ -64,6 +85,7 @@ static __init int sysctl_init(void)if (ret) goto out;register_sysctl_root (&net_sysctl_root); +register_sysctl_root (&net_sysctl_ro_root); out:return ret; }
@@ -80,6 +102,14 @@ struct ctl_table_header *register_net_sysctl_table(struct net *net, }EXPORT_SYMBOL_GPL (register_net_sysctl_table); +struct ctl_table_header *register_net_sysctl_rotable (const +struct ctl_path *path,struct ctl_table *table) +{ +return __register_sysctl_paths (&net_sysctl_ro_root, + &init_nsproxy, path, table); +} +EXPORT_SYMBOL_GPL (register_net_sysctl_rotable); +void unregister_net_sysctl_table (struct ctl_table_header *header) {unregister_sysctl_table (header);
Signature · 1 line
1.5.3.4
Re: [PATCH net-next 1/6][NETNS]: Introduce sysctl root for read-only net sysctls.
From: Pavel Emelyanov <[email protected]>
Date: Mon, 19 May 2008 19:52:43 +0400
Quoted 4 lines
This one stores all ctl-heads in one list and restricts the permissions not give write access to non-init net namespaces.
Signed-off-by Pavel Emelyanov <[email protected]>
Applied.
PATCH 2/6 : Register net/core/ sysctls at read-only root.
In reply to Pavel EmelyanovMost of the net/core/xxx sysctls are read-only now, but this goal is achieved with excessive memory consumption in each namespace - the whole table is cloned and most of the entries in it are ~= 0222.
Split it into two parts and register (the largest) one at the read-only root.
--- net/core/sysctl_net_core.c | 39 +++++++++++++++++++-------------------- 1 files changed, 19 insertions(+), 20 deletions(-)
net/core/sysctl_net_core.c +19 -20
@@ -125,14 +125,6 @@ static struct ctl_table net_core_table[] = {#endif /* CONFIG_XFRM */ #endif /* CONFIG_NET */ { - .ctl_name = NET_CORE_SOMAXCONN, - .procname = "somaxconn", - .data = &init_net.core.sysctl_somaxconn, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { .ctl_name = NET_CORE_BUDGET, .procname = "netdev_budget", .data = &netdev_budget,
@@ -151,6 +143,18 @@ static struct ctl_table net_core_table[] = { { .ctl_name = 0 } }; +static struct ctl_table netns_core_table[] = { + { + .ctl_name =NET_CORE_SOMAXCONN , + .procname ="somaxconn" , + .data = &init_net.core.sysctl_somaxconn, + .maxlen =sizeof (int ), + .mode =0644 , + .proc_handler = &proc_dointvec + }, + { .ctl_name =0 } +}; +static __net_initdata struct ctl_path net_core_path[] = { { .procname ="net" , .ctl_name =CTL_NET , }, { .procname ="core" , .ctl_name =NET_CORE , },
@@ -159,23 +163,17 @@ static __net_initdata struct ctl_path net_core_path[] = {static __net_init int sysctl_core_net_init (struct net *net) { -struct ctl_table *tbl, *tmp; +struct ctl_table *tbl; net->core.sysctl_somaxconn =SOMAXCONN ; - tbl = net_core_table; + tbl = netns_core_table;if (net != &init_net) { - tbl =kmemdup (tbl,sizeof (net_core_table),GFP_KERNEL ); + tbl =kmemdup (tbl,sizeof (netns_core_table),GFP_KERNEL );if (tbl ==NULL ) goto err_dup; -for (tmp = tbl; tmp->procname; tmp++) { -if (tmp->data >= (void *)&init_net && - tmp->data < (void *)(&init_net +1 )) - tmp->data += (char *)net - (char *)&init_net; -else - tmp->mode &= ~0222 ; - } + tbl[0 ].data = &net->core.sysctl_somaxconn; } net->core.sysctl_hdr = register_net_sysctl_table(net,
@@ -186,7 +184,7 @@ static __net_init int sysctl_core_net_init(struct net *net)return 0 ; err_reg: -if (tbl != net_core_table) +if (tbl != netns_core_table)kfree (tbl); err_dup:return -ENOMEM ;
@@ -198,7 +196,7 @@ static __net_exit void sysctl_core_net_exit(struct net *net) tbl = net->core.sysctl_hdr->ctl_table_arg;unregister_net_sysctl_table (net->core.sysctl_hdr); -BUG_ON (tbl == net_core_table); +BUG_ON (tbl == netns_core_table);kfree (tbl); }
@@ -209,6 +207,7 @@ static __net_initdata struct pernet_operations sysctl_core_ops = {static __init int sysctl_core_init (void ) { +register_net_sysctl_rotable (net_core_path, net_core_table);return register_pernet_subsys (&sysctl_core_ops); }
Signature · 1 line
1.5.3.4
Re: [PATCH net-next 2/6][NETNS]: Register net/core/ sysctls at read-only root.
From: Pavel Emelyanov <[email protected]>
Date: Mon, 19 May 2008 19:55:01 +0400
Quoted 9 lines
Most of the
net/core/xxxsysctls are read-only now, but this goal is achieved with excessive memory consumption in each namespace - the whole table is cloned and most of the entries in it are ~= 0222.Split it into two parts and register (the largest) one at the read-only root.
Signed-off-by Pavel Emelyanov <[email protected]>
Applied.
PATCH 3/6 : Rename sysctl-related functions/variables.
In reply to Pavel EmelyanovThe fragments sysctls also contains some, that are to be visible, but read-only in net namespaces.
The naming in net/core/sysctl_net_core.c is - tables, that are to be registered in namespaces have a "ns" word in their names. So rename ones in ipv4/ip_fragment.c and ipv6/reassembly.c to fit this.
--- net/ipv4/ip_fragment.c | 18 +++++++++--------- net/ipv6/reassembly.c | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-)
net/ipv4/ip_fragment.c +9 -9
@@ -598,7 +598,7 @@ int ip_defrag(struct sk_buff *skb, u32 user) #ifdef CONFIG_SYSCTL static int zero; -static struct ctl_table ip4_frags_ctl_table[] = { +static struct ctl_table ip4_frags_ns_ctl_table[] = { { .ctl_name = NET_IPV4_IPFRAG_HIGH_THRESH, .procname = "ipfrag_high_thresh",
@@ -644,14 +644,14 @@ static struct ctl_table ip4_frags_ctl_table[] = { { } }; -static int ip4_frags_ctl_register (struct net *net) +static int ip4_frags_ns_ctl_register (struct net *net) {struct ctl_table *table;struct ctl_table_header *hdr; - table = ip4_frags_ctl_table; + table = ip4_frags_ns_ctl_table;if (net != &init_net) { - table =kmemdup (table,sizeof (ip4_frags_ctl_table),GFP_KERNEL ); + table =kmemdup (table,sizeof (ip4_frags_ns_ctl_table),GFP_KERNEL );if (table ==NULL ) goto err_alloc;
@@ -676,7 +676,7 @@ err_alloc:return -ENOMEM ; } -static void ip4_frags_ctl_unregister (struct net *net) +static void ip4_frags_ns_ctl_unregister (struct net *net) {struct ctl_table *table;
@@ -685,12 +685,12 @@ static void ip4_frags_ctl_unregister(struct net *net) kfree(table); }#else -static inline int ip4_frags_ctl_register (struct net *net) +static inline int ip4_frags_ns_ctl_register (struct net *net) {return 0 ; } -static inline void ip4_frags_ctl_unregister (struct net *net) +static inline void ip4_frags_ns_ctl_unregister (struct net *net) { }#endif
@@ -714,12 +714,12 @@ static int ipv4_frags_init_net(struct net *net)inet_frags_init_net (&net->ipv4.frags); -return ip4_frags_ctl_register (net); +return ip4_frags_ns_ctl_register (net); }static void ipv4_frags_exit_net (struct net *net) { -ip4_frags_ctl_unregister (net); +ip4_frags_ns_ctl_unregister (net);inet_frags_exit_net (&net->ipv4.frags, &ip4_frags); }
net/ipv6/reassembly.c +9 -9
@@ -632,7 +632,7 @@ static struct inet6_protocol frag_protocol = }; #ifdef CONFIG_SYSCTL -static struct ctl_table ip6_frags_ctl_table[] = { +static struct ctl_table ip6_frags_ns_ctl_table[] = { { .ctl_name = NET_IPV6_IP6FRAG_HIGH_THRESH, .procname = "ip6frag_high_thresh",
@@ -670,14 +670,14 @@ static struct ctl_table ip6_frags_ctl_table[] = { { } }; -static int ip6_frags_sysctl_register (struct net *net) +static int ip6_frags_ns_sysctl_register (struct net *net) {struct ctl_table *table;struct ctl_table_header *hdr; - table = ip6_frags_ctl_table; + table = ip6_frags_ns_ctl_table;if (net != &init_net) { - table =kmemdup (table,sizeof (ip6_frags_ctl_table),GFP_KERNEL ); + table =kmemdup (table,sizeof (ip6_frags_ns_ctl_table),GFP_KERNEL );if (table ==NULL ) goto err_alloc;
@@ -701,7 +701,7 @@ err_alloc:return -ENOMEM ; } -static void ip6_frags_sysctl_unregister (struct net *net) +static void ip6_frags_ns_sysctl_unregister (struct net *net) {struct ctl_table *table;
@@ -710,12 +710,12 @@ static void ip6_frags_sysctl_unregister(struct net *net) kfree(table); }#else -static inline int ip6_frags_sysctl_register (struct net *net) +static inline int ip6_frags_ns_sysctl_register (struct net *net) {return 0 ; } -static inline void ip6_frags_sysctl_unregister (struct net *net) +static inline void ip6_frags_ns_sysctl_unregister (struct net *net) { }#endif
@@ -728,12 +728,12 @@ static int ipv6_frags_init_net(struct net *net)inet_frags_init_net (&net->ipv6.frags); -return ip6_frags_sysctl_register (net); +return ip6_frags_ns_sysctl_register (net); }static void ipv6_frags_exit_net (struct net *net) { -ip6_frags_sysctl_unregister (net); +ip6_frags_ns_sysctl_unregister (net);inet_frags_exit_net (&net->ipv6.frags, &ip6_frags); }
Signature · 1 line
1.5.3.4
Re: [PATCH net-next 3/6][FRAGS]: Rename sysctl-related functions/variables.
From: Pavel Emelyanov <[email protected]>
Date: Mon, 19 May 2008 19:58:40 +0400
Quoted 9 lines
The fragments sysctls also contains some, that are to be visible, but read-only in net namespaces.
The naming in
net/core/sysctl_net_core.cis - tables, that are to be registered in namespaces have a "ns" word in their names. So rename ones inipv4/ip_fragment.candipv6/reassembly.cto fit this.Signed-off-by Pavel Emelyanov <[email protected]>
Applied.
PATCH 4/6 : Handle error, returned from register_pernet_subsys.
In reply to Pavel EmelyanovThe error code is ignored now, but ipv6 is a module and one can be loaded under memory pressure, so the error may occur (in theory).
Besides, I'm going to handle error returned from registering a read-only part of the table, so ignoring this one, while handing the other one would look strange.
(However, this possibility of error is rather small, so I'm not
sure whether this is a candidate for current net tree).
--- net/ipv6/reassembly.c | 8 +++++++- 1 files changed, 7 insertions(+), 1 deletions(-)
net/ipv6/reassembly.c +7 -1
@@ -750,7 +750,9 @@ int __init ipv6_frag_init(void)if (ret) goto out; -register_pernet_subsys (&ip6_frags_ops); + ret =register_pernet_subsys (&ip6_frags_ops); +if (ret) + goto err_pernet; ip6_frags.hashfn = ip6_hashfn; ip6_frags.constructor = ip6_frag_init;
@@ -763,6 +765,10 @@ int __init ipv6_frag_init(void)inet_frags_init (&ip6_frags); out:return ret; + +err_pernet: +inet6_del_protocol (&frag_protocol,IPPROTO_FRAGMENT ); + goto out; }void ipv6_frag_exit (void )
Signature · 1 line
1.5.3.4
Re: [PATCH net-next 4/6][IP6FRAGS]: Handle error, returned from register_pernet_subsys.
From: Pavel Emelyanov <[email protected]>
Date: Mon, 19 May 2008 20:02:25 +0400
Quoted 9 lines
The error code is ignored now, but ipv6 is a module and one can be loaded under memory pressure, so the error may occur (in theory).
Besides, I'm going to handle error returned from registering a read-only part of the table, so ignoring this one, while handing the other one would look strange.
(However, this possibility of error is rather small, so I'm not
sure whether this is a candidate for current net tree).
I definitely don't consider it -stable material.
Quoted 1 line
Signed-off-by Pavel Emelyanov <[email protected]>
Applied, thanks!
PATCH 5/6 : Register some ctls at read-only root.
In reply to Pavel EmelyanovParts of fragments-related sysctls are read-only, but this is done by cloning all the tables and dropping write-bits from mode. Do the same but with read-only root.
--- net/ipv4/ip_fragment.c | 16 ++++++++++++++-- net/ipv6/reassembly.c | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 3 deletions(-)
net/ipv4/ip_fragment.c +14 -2
@@ -624,6 +624,10 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = { .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies }, + { } +}; + +static struct ctl_table ip4_frags_ctl_table[] = { { .ctl_name =NET_IPV4_IPFRAG_SECRET_INTERVAL , .procname ="ipfrag_secret_interval" ,
@@ -658,8 +662,6 @@ static int ip4_frags_ns_ctl_register(struct net *net) table[0 ].data = &net->ipv4.frags.high_thresh; table[1 ].data = &net->ipv4.frags.low_thresh; table[2 ].data = &net->ipv4.frags.timeout; - table[3 ].mode &= ~0222 ; - table[4 ].mode &= ~0222 ; } hdr =register_net_sysctl_table (net, net_ipv4_ctl_path, table);
@@ -684,6 +686,11 @@ static void ip4_frags_ns_ctl_unregister(struct net *net)unregister_net_sysctl_table (net->ipv4.frags_hdr); kfree(table); } + +static void ip4_frags_ctl_register (void ) +{ +register_net_sysctl_rotable (net_ipv4_ctl_path, ip4_frags_ctl_table); +}#else static inline int ip4_frags_ns_ctl_register (struct net *net) {
@@ -693,6 +700,10 @@ static inline int ip4_frags_ns_ctl_register(struct net *net)static inline void ip4_frags_ns_ctl_unregister (struct net *net) { } + +static inline void ip4_frags_ctl_register (void ) +{ +}#endif static int ipv4_frags_init_net (struct net *net)
@@ -730,6 +741,7 @@ static struct pernet_operations ip4_frags_ops = {void __init ipfrag_init (void ) { +ip4_frags_ctl_register ();register_pernet_subsys (&ip4_frags_ops); ip4_frags.hashfn = ip4_hashfn; ip4_frags.constructor = ip4_frag_init;
net/ipv6/reassembly.c +34 -1
@@ -658,6 +658,10 @@ static struct ctl_table ip6_frags_ns_ctl_table[] = { .proc_handler = &proc_dointvec_jiffies, .strategy = &sysctl_jiffies, }, + { } +}; + +static struct ctl_table ip6_frags_ctl_table[] = { { .ctl_name =NET_IPV6_IP6FRAG_SECRET_INTERVAL , .procname ="ip6frag_secret_interval" ,
@@ -684,7 +688,6 @@ static int ip6_frags_ns_sysctl_register(struct net *net) table[0 ].data = &net->ipv6.frags.high_thresh; table[1 ].data = &net->ipv6.frags.low_thresh; table[2 ].data = &net->ipv6.frags.timeout; - table[3 ].mode &= ~0222 ; } hdr =register_net_sysctl_table (net, net_ipv6_ctl_path, table);
@@ -709,6 +712,20 @@ static void ip6_frags_ns_sysctl_unregister(struct net *net)unregister_net_sysctl_table (net->ipv6.sysctl.frags_hdr); kfree(table); } + +static struct ctl_table_header *ip6_ctl_header; + +static int ip6_frags_sysctl_register (void ) +{ + ip6_ctl_header =register_net_sysctl_rotable (net_ipv6_ctl_path, + ip6_frags_ctl_table); +return ip6_ctl_header ==NULL ? -ENOMEM :0 ; +} + +static void ip6_frags_sysctl_unregister (void ) +{ +unregister_net_sysctl_table (ip6_ctl_header); +}#else static inline int ip6_frags_ns_sysctl_register (struct net *net) {
@@ -718,6 +735,15 @@ static inline int ip6_frags_ns_sysctl_register(struct net *net)static inline void ip6_frags_ns_sysctl_unregister (struct net *net) { } + +static inline int ip6_frags_sysctl_register (void ) +{ +return 0 ; +} + +static inline void ip6_frags_sysctl_unregister (void ) +{ +}#endif static int ipv6_frags_init_net (struct net *net)
@@ -750,6 +776,10 @@ int __init ipv6_frag_init(void)if (ret) goto out; + ret =ip6_frags_sysctl_register (); +if (ret) + goto err_sysctl; + ret =register_pernet_subsys (&ip6_frags_ops);if (ret) goto err_pernet;
@@ -767,6 +797,8 @@ out:return ret; err_pernet: +ip6_frags_sysctl_unregister (); +err_sysctl:inet6_del_protocol (&frag_protocol,IPPROTO_FRAGMENT ); goto out; }
@@ -774,6 +806,7 @@ err_pernet:void ipv6_frag_exit (void ) {inet_frags_fini (&ip6_frags); +ip6_frags_sysctl_unregister ();unregister_pernet_subsys (&ip6_frags_ops);inet6_del_protocol (&frag_protocol,IPPROTO_FRAGMENT ); }
Signature · 1 line
1.5.3.4
Re: [PATCH net-next 5/6][FRAGS]: Register some ctls at read-only root.
From: Pavel Emelyanov <[email protected]>
Date: Mon, 19 May 2008 20:04:07 +0400
Quoted 5 lines
Parts of fragments-related sysctls are read-only, but this is done by cloning all the tables and dropping write-bits from mode. Do the same but with read-only root.
Signed-off-by Pavel Emelyanov <[email protected]>
Applied.
PATCH 6/6 : Register some net/ipv6/ core sysctls at read-only root.
In reply to Pavel EmelyanovThere are some sysctls left to be switched to read-only, but they are all in ipv6, so complete with them.
--- net/ipv6/sysctl_net_ipv6.c | 29 ++++++++++++++++++++++------- 1 files changed, 22 insertions(+), 7 deletions(-)
net/ipv6/sysctl_net_ipv6.c +22 -7
@@ -37,6 +37,10 @@ static ctl_table ipv6_table_template[] = { .mode = 0644, .proc_handler = &proc_dointvec }, + { .ctl_name = 0 } +}; + +static ctl_table ipv6_table[] = { { .ctl_name =NET_IPV6_MLD_MAX_MSF , .procname ="mld_max_msf" ,
@@ -80,12 +84,6 @@ static int ipv6_sysctl_net_init(struct net *net) ipv6_table[2 ].data = &net->ipv6.sysctl.bindv6only; -/* We don't want this value to be per namespace, it should be global -to all namespaces, so make it read-only when we are not in the -init network namespace */ -if (net != &init_net) - ipv6_table[3 ].mode =0444 ; - net->ipv6.sysctl.table =register_net_sysctl_table (net, net_ipv6_ctl_path, ipv6_table);if (!net->ipv6.sysctl.table)
@@ -126,12 +124,29 @@ static struct pernet_operations ipv6_sysctl_net_ops = { .exit = ipv6_sysctl_net_exit, }; +static struct ctl_table_header *ip6_header; +int ipv6_sysctl_register (void ) { -return register_pernet_subsys (&ipv6_sysctl_net_ops); +int err = -ENOMEM ;; + + ip6_header =register_net_sysctl_rotable (net_ipv6_ctl_path, ipv6_table); +if (ip6_header ==NULL ) + goto out; + + err =register_pernet_subsys (&ipv6_sysctl_net_ops); +if (err) + goto err_pernet; +out: +return err; + +err_pernet: +unregister_net_sysctl_table (ip6_header); + goto out; }void ipv6_sysctl_unregister (void ) { +unregister_net_sysctl_table (ip6_header);unregister_pernet_subsys (&ipv6_sysctl_net_ops); }
Signature · 1 line
1.5.3.4
David Miller
maintainerRe: [PATCH net-next 6/6][IPV6]: Register some net/ipv6/ core sysctls at read-only root.
From: Pavel Emelyanov <[email protected]>
Date: Mon, 19 May 2008 20:06:36 +0400
Quoted 4 lines
There are some sysctls left to be switched to read-only, but they are all in ipv6, so complete with them.
Signed-off-by Pavel Emelyanov <[email protected]>
Also applied, thanks a lot Pavel!