Skip to contentSkip to conversation

: Revisit read-only-in-namespaces sysctls.

PATCH Applied Pavel Emelyanov 2 participants 13 messages May 19, 2008

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

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.

#1 lore raw

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
index aa540e6..8df751b 100644
@@ -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
index b4f0525..d8e7916 100644
@@ -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
maintainer Applied
#2 lore raw

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.

Applied.

#3 lore raw

PATCH 2/6 : Register net/core/ sysctls at read-only root.

In reply to Pavel Emelyanov

Most 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
index 5fc8010..a570e2a 100644
@@ -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
maintainer Applied
#4 lore raw

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/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.

Applied.

#5 lore raw

PATCH 3/6 : Rename sysctl-related functions/variables.

In reply to Pavel Emelyanov

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.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
index cd6ce6a..7f102ee 100644
@@ -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
index 798cabc..7e008de 100644
@@ -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
maintainer Applied
#6 lore raw

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.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.

Applied.

#7 lore raw

PATCH 4/6 : Handle error, returned from register_pernet_subsys.

In reply to Pavel Emelyanov

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).

---
 net/ipv6/reassembly.c |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)
net/ipv6/reassembly.c +7 -1
index 7e008de..130d6f6 100644
@@ -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
maintainer Applied
#8 lore raw

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

Applied, thanks!

#9 lore raw

PATCH 5/6 : Register some ctls at read-only root.

In reply to Pavel Emelyanov

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.

---
 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
index 7f102ee..be1cb89 100644
@@ -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
index 130d6f6..9391a69 100644
@@ -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
maintainer Applied
#10 lore raw

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.

Applied.

#11 lore raw

PATCH 6/6 : Register some net/ipv6/ core sysctls at read-only root.

In reply to Pavel Emelyanov

There 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
index 3804dcb..5c99274 100644
@@ -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
maintainer
#12 lore raw

Re: [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.

Also applied, thanks a lot Pavel!