net: Don't export sysctls to unprivileged users
authorEric W. Biederman <ebiederm@xmission.com>
Fri, 16 Nov 2012 03:02:59 +0000 (03:02 +0000)
committerDavid S. Miller <davem@davemloft.net>
Mon, 19 Nov 2012 01:30:55 +0000 (20:30 -0500)
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" <ebiederm@xmission.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
22 files changed:
net/core/neighbour.c
net/core/sysctl_net_core.c
net/ipv4/devinet.c
net/ipv4/ip_fragment.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv6/addrconf.c
net/ipv6/icmp.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/sysctl_net_ipv6.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_lblc.c
net/netfilter/ipvs/ip_vs_lblcr.c
net/netfilter/nf_conntrack_acct.c
net/netfilter/nf_conntrack_ecache.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_proto_dccp.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_conntrack_timestamp.c
net/unix/sysctl_net_unix.c
net/xfrm/xfrm_sysctl.c

index 2257148..f1c0c2e 100644 (file)
@@ -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 =
index a7c3684..d1b0804 100644 (file)
@@ -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);
index f6db227..6e06e92 100644 (file)
@@ -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
        }
 
index 448e685..1cf6a76 100644 (file)
@@ -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);
index a8c6512..5b58788 100644 (file)
@@ -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;
 
index 63d4ecc..d84400b 100644 (file)
@@ -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;
        }
 
        /*
index cb803b7..b24b4de 100644 (file)
@@ -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);
index b4a9fd5..d77dc1e 100644 (file)
@@ -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
index da8a4e3..e5253ec 100644 (file)
@@ -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);
index 11249d2..021a48e 100644 (file)
@@ -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;
index e85c48b..b06fd07 100644 (file)
@@ -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;
index c4ee437..c6cebd5 100644 (file)
@@ -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 */
index cbd3748..d742aa9 100644 (file)
@@ -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;
        }
 
index 161b679..c03b6a3 100644 (file)
@@ -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;
index d61e078..7df424e 100644 (file)
@@ -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) {
index de9781b..faa978f 100644 (file)
@@ -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) {
index c4bc637..884f2b3 100644 (file)
@@ -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);
 
index 6535326..a8ae287 100644 (file)
@@ -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 = {
index 9b39432..363285d 100644 (file)
@@ -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;
index dbb364f..7ea8026 100644 (file)
@@ -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) {
index b34b5b9..8800604 100644 (file)
@@ -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)
index 380976f..05a6e3d 100644 (file)
@@ -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;