From 464dc801c76aa0db88e16e8f5f47c6879858b9b2 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 16 Nov 2012 03:02:59 +0000 Subject: [PATCH] net: Don't export sysctls to unprivileged users In preparation for supporting the creation of network namespaces by unprivileged users, modify all of the per net sysctl exports and refuse to allow them to unprivileged users. This makes it safe for unprivileged users in general to access per net sysctls, and allows sysctls to be exported to unprivileged users on an individual basis as they are deemed safe. Signed-off-by: "Eric W. Biederman" Signed-off-by: David S. Miller --- net/core/neighbour.c | 4 ++++ net/core/sysctl_net_core.c | 5 +++++ net/ipv4/devinet.c | 8 ++++++++ net/ipv4/ip_fragment.c | 4 ++++ net/ipv4/route.c | 4 ++++ net/ipv4/sysctl_net_ipv4.c | 3 +++ net/ipv6/addrconf.c | 4 ++++ net/ipv6/icmp.c | 7 ++++++- net/ipv6/reassembly.c | 4 ++++ net/ipv6/route.c | 4 ++++ net/ipv6/sysctl_net_ipv6.c | 4 ++++ net/netfilter/ipvs/ip_vs_ctl.c | 4 ++++ net/netfilter/ipvs/ip_vs_lblc.c | 7 ++++++- net/netfilter/ipvs/ip_vs_lblcr.c | 4 ++++ net/netfilter/nf_conntrack_acct.c | 4 ++++ net/netfilter/nf_conntrack_ecache.c | 4 ++++ net/netfilter/nf_conntrack_helper.c | 4 ++++ net/netfilter/nf_conntrack_proto_dccp.c | 8 ++++++-- net/netfilter/nf_conntrack_standalone.c | 4 ++++ net/netfilter/nf_conntrack_timestamp.c | 4 ++++ net/unix/sysctl_net_unix.c | 4 ++++ net/xfrm/xfrm_sysctl.c | 4 ++++ 22 files changed, 98 insertions(+), 4 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 22571488730a..f1c0c2e9cad5 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2987,6 +2987,10 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].extra1 = dev; } + /* Don't export sysctls to unprivileged users */ + if (neigh_parms_net(p)->user_ns != &init_user_ns) + t->neigh_vars[0].procname = NULL; + snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s", p_name, dev_name_source); t->sysctl_header = diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index a7c36845b123..d1b08045a9df 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -216,6 +216,11 @@ static __net_init int sysctl_core_net_init(struct net *net) goto err_dup; tbl[0].data = &net->core.sysctl_somaxconn; + + /* Don't export any sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) { + tbl[0].procname = NULL; + } } net->core.sysctl_hdr = register_net_sysctl(net, "net/core", tbl); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index f6db227c1fd9..6e06e924ed99 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1815,6 +1815,10 @@ static int __devinet_sysctl_register(struct net *net, char *dev_name, t->devinet_vars[i].extra2 = net; } + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + t->devinet_vars[0].procname = NULL; + snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name); t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars); @@ -1900,6 +1904,10 @@ static __net_init int devinet_init_net(struct net *net) tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1]; tbl[0].extra1 = all; tbl[0].extra2 = net; + + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + tbl[0].procname = NULL; #endif } diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 448e68546827..1cf6a768cd53 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -802,6 +802,10 @@ static int __net_init 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; + + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + table[0].procname = NULL; } hdr = register_net_sysctl(net, "net/ipv4", table); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index a8c651216fa6..5b58788db863 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2493,6 +2493,10 @@ static __net_init int sysctl_route_net_init(struct net *net) tbl = kmemdup(tbl, sizeof(ipv4_route_flush_table), GFP_KERNEL); if (tbl == NULL) goto err_dup; + + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + tbl[0].procname = NULL; } tbl[0].extra1 = net; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 63d4eccc674d..d84400b65049 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -883,6 +883,9 @@ static __net_init int ipv4_sysctl_init_net(struct net *net) table[6].data = &net->ipv4.sysctl_ping_group_range; + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + table[0].procname = NULL; } /* diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index cb803b7bb0d8..b24b4de5cd26 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4735,6 +4735,10 @@ static int __addrconf_sysctl_register(struct net *net, char *dev_name, t->addrconf_vars[i].extra2 = net; } + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + t->addrconf_vars[0].procname = NULL; + snprintf(path, sizeof(path), "net/ipv6/conf/%s", dev_name); t->sysctl_header = register_net_sysctl(net, path, t->addrconf_vars); diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index b4a9fd51dae7..d77dc1e2a42b 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -967,9 +967,14 @@ struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net) sizeof(ipv6_icmp_table_template), GFP_KERNEL); - if (table) + if (table) { table[0].data = &net->ipv6.sysctl.icmpv6_time; + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + table[0].procname = NULL; + } + return table; } #endif diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index da8a4e301b1b..e5253ec9e0fc 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -616,6 +616,10 @@ static int __net_init 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; + + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + table[0].procname = NULL; } hdr = register_net_sysctl(net, "net/ipv6", table); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 11249d211ea9..021a48e8a5e2 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2989,6 +2989,10 @@ struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net) table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires; table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss; table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; + + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + table[0].procname = NULL; } return table; diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index e85c48bd404f..b06fd078e6c7 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -52,6 +52,10 @@ static int __net_init ipv6_sysctl_net_init(struct net *net) goto out; ipv6_table[0].data = &net->ipv6.sysctl.bindv6only; + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + ipv6_table[0].procname = NULL; + ipv6_route_table = ipv6_route_sysctl_init(net); if (!ipv6_route_table) goto out_ipv6_table; diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index c4ee43710aab..c6cebd560936 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -3699,6 +3699,10 @@ static int __net_init ip_vs_control_net_init_sysctl(struct net *net) tbl = kmemdup(vs_vars, sizeof(vs_vars), GFP_KERNEL); if (tbl == NULL) return -ENOMEM; + + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + tbl[0].procname = NULL; } else tbl = vs_vars; /* Initialize sysctl defaults */ diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c index cbd37489ac77..d742aa9780ec 100644 --- a/net/netfilter/ipvs/ip_vs_lblc.c +++ b/net/netfilter/ipvs/ip_vs_lblc.c @@ -560,6 +560,11 @@ static int __net_init __ip_vs_lblc_init(struct net *net) GFP_KERNEL); if (ipvs->lblc_ctl_table == NULL) return -ENOMEM; + + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + ipvs->lblc_ctl_table[0].procname = NULL; + } else ipvs->lblc_ctl_table = vs_vars_table; ipvs->sysctl_lblc_expiration = DEFAULT_EXPIRATION; @@ -569,7 +574,7 @@ static int __net_init __ip_vs_lblc_init(struct net *net) register_net_sysctl(net, "net/ipv4/vs", ipvs->lblc_ctl_table); if (!ipvs->lblc_ctl_header) { if (!net_eq(net, &init_net)) - kfree(ipvs->lblc_ctl_table); + kfree(ipvs->lblc_ctl_table);\ return -ENOMEM; } diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c index 161b67972e3f..c03b6a3ade2f 100644 --- a/net/netfilter/ipvs/ip_vs_lblcr.c +++ b/net/netfilter/ipvs/ip_vs_lblcr.c @@ -754,6 +754,10 @@ static int __net_init __ip_vs_lblcr_init(struct net *net) GFP_KERNEL); if (ipvs->lblcr_ctl_table == NULL) return -ENOMEM; + + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + ipvs->lblcr_ctl_table[0].procname = NULL; } else ipvs->lblcr_ctl_table = vs_vars_table; ipvs->sysctl_lblcr_expiration = DEFAULT_EXPIRATION; diff --git a/net/netfilter/nf_conntrack_acct.c b/net/netfilter/nf_conntrack_acct.c index d61e0782a797..7df424e2d10c 100644 --- a/net/netfilter/nf_conntrack_acct.c +++ b/net/netfilter/nf_conntrack_acct.c @@ -69,6 +69,10 @@ static int nf_conntrack_acct_init_sysctl(struct net *net) table[0].data = &net->ct.sysctl_acct; + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + table[0].procname = NULL; + net->ct.acct_sysctl_header = register_net_sysctl(net, "net/netfilter", table); if (!net->ct.acct_sysctl_header) { diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index de9781b6464f..faa978f1714b 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -196,6 +196,10 @@ static int nf_conntrack_event_init_sysctl(struct net *net) table[0].data = &net->ct.sysctl_events; table[1].data = &net->ct.sysctl_events_retry_timeout; + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + table[0].procname = NULL; + net->ct.event_sysctl_header = register_net_sysctl(net, "net/netfilter", table); if (!net->ct.event_sysctl_header) { diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index c4bc637feb76..884f2b39319a 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -64,6 +64,10 @@ static int nf_conntrack_helper_init_sysctl(struct net *net) table[0].data = &net->ct.sysctl_auto_assign_helper; + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + table[0].procname = NULL; + net->ct.helper_sysctl_header = register_net_sysctl(net, "net/netfilter", table); diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index 6535326cf07c..a8ae287bc7af 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -815,7 +815,7 @@ static struct ctl_table dccp_sysctl_table[] = { }; #endif /* CONFIG_SYSCTL */ -static int dccp_kmemdup_sysctl_table(struct nf_proto_net *pn, +static int dccp_kmemdup_sysctl_table(struct net *net, struct nf_proto_net *pn, struct dccp_net *dn) { #ifdef CONFIG_SYSCTL @@ -836,6 +836,10 @@ static int dccp_kmemdup_sysctl_table(struct nf_proto_net *pn, pn->ctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING]; pn->ctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT]; pn->ctl_table[7].data = &dn->dccp_loose; + + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + pn->ctl_table[0].procname = NULL; #endif return 0; } @@ -857,7 +861,7 @@ static int dccp_init_net(struct net *net, u_int16_t proto) dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL; } - return dccp_kmemdup_sysctl_table(pn, dn); + return dccp_kmemdup_sysctl_table(net, pn, dn); } static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 9b3943252a5e..363285d544a1 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -489,6 +489,10 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net) table[3].data = &net->ct.sysctl_checksum; table[4].data = &net->ct.sysctl_log_invalid; + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + table[0].procname = NULL; + net->ct.sysctl_header = register_net_sysctl(net, "net/netfilter", table); if (!net->ct.sysctl_header) goto out_unregister_netfilter; diff --git a/net/netfilter/nf_conntrack_timestamp.c b/net/netfilter/nf_conntrack_timestamp.c index dbb364f62d6f..7ea8026f07c9 100644 --- a/net/netfilter/nf_conntrack_timestamp.c +++ b/net/netfilter/nf_conntrack_timestamp.c @@ -51,6 +51,10 @@ static int nf_conntrack_tstamp_init_sysctl(struct net *net) table[0].data = &net->ct.sysctl_tstamp; + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + table[0].procname = NULL; + net->ct.tstamp_sysctl_header = register_net_sysctl(net, "net/netfilter", table); if (!net->ct.tstamp_sysctl_header) { diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c index b34b5b9792f0..8800604c93f4 100644 --- a/net/unix/sysctl_net_unix.c +++ b/net/unix/sysctl_net_unix.c @@ -34,6 +34,10 @@ int __net_init unix_sysctl_register(struct net *net) if (table == NULL) goto err_alloc; + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + table[0].procname = NULL; + table[0].data = &net->unx.sysctl_max_dgram_qlen; net->unx.ctl = register_net_sysctl(net, "net/unix", table); if (net->unx.ctl == NULL) diff --git a/net/xfrm/xfrm_sysctl.c b/net/xfrm/xfrm_sysctl.c index 380976f74c4c..05a6e3d9c258 100644 --- a/net/xfrm/xfrm_sysctl.c +++ b/net/xfrm/xfrm_sysctl.c @@ -54,6 +54,10 @@ int __net_init xfrm_sysctl_init(struct net *net) table[2].data = &net->xfrm.sysctl_larval_drop; table[3].data = &net->xfrm.sysctl_acq_expires; + /* Don't export sysctls to unprivileged users */ + if (net->user_ns != &init_user_ns) + table[0].procname = NULL; + net->xfrm.sysctl_hdr = register_net_sysctl(net, "net/core", table); if (!net->xfrm.sysctl_hdr) goto out_register; -- 2.20.1