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 22571488730a7d1bbc2f5f2ec545abf850dcdf4a..f1c0c2e9cad5fd860e367b5bc63716714b14df79 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 a7c36845b123c09f727931cfe3ef3e4ad0365432..d1b08045a9dfbf4dbee4255c68cdcd6ad1e026a2 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 f6db227c1fd9282c63d12848539b4c350945534d..6e06e924ed99599344b231ce93a28e2cc0f045a8 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 448e68546827431098c980bafc4a63967764942f..1cf6a768cd53d7a0effdca659dff243689cb9bf6 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 a8c651216fa62a44d9226eed3294e3e5f3484a3d..5b58788db863c439b0bdc82d45e07efa70308e85 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 63d4eccc674ddd1d297368166792e99c636658f6..d84400b65049e61bc64f8f8eef37e2be2aaf2eda 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 cb803b7bb0d8dc534781ee6c241bd18d88d6e90c..b24b4de5cd26352031258d385b0c315e2edfd53b 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 b4a9fd51dae74bd8143b2d32e791e089f1d8562f..d77dc1e2a42bc783b6e337aee6bef9943e766731 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 da8a4e301b1b04ec5d8d0d7aa042a328c986e1d9..e5253ec9e0fcd8b80e506956e68b29407b0be3c6 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 11249d211ea9a167cecb11962f44fa62625b6f53..021a48e8a5e2e7f9dec2ec03b6c8705373c635ef 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 e85c48bd404f4036b0c4e7db1e29bd6a92192f75..b06fd078e6c7a290a2af60806da6a288436847e6 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 c4ee43710aab63ce34657a06ba9d26d3862a6a61..c6cebd560936b6e70737d9e03814e2fe16fb9a45 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 cbd37489ac77bfabaa78bb8811a3f34c35829ed1..d742aa9780ec30445a46d8c50e9445ce83f2054b 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 161b67972e3f6febf944d79cf0e41a63d7f29460..c03b6a3ade2f90a4c9d96f8a3a11dceb1b3df130 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 d61e0782a797db1d4f4548ef583108f08272b6f4..7df424e2d10cf6146e7c3b38eaf0bf86a2bb0544 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 de9781b6464f0940d391555489782bf63f1c956e..faa978f1714b831ff81d81e9ec4732eb3f167fb7 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 c4bc637feb76b3e542ac0eaac9c76198e38188cf..884f2b39319a258ffbaa4360736fd7f83b867195 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 6535326cf07c773ba9166c6cbba16b9e7f29fb75..a8ae287bc7afe00ec89ed8032f3cbd7ea1c54b7a 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 9b3943252a5e9c0b0dd6d2127606d11ac4e502b9..363285d544a1c7402152e6a7da3a7129d94b83ae 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 dbb364f62d6f03b593b7b804251f48c2dcf7b845..7ea8026f07c9c843698bb54c68eb236840956bf9 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 b34b5b9792f0eb7dd677525b543082d4f521115f..8800604c93f459e1db124aa2a9cafb1a7b5cdb8f 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 380976f74c4c90f0159c11740be35dc40602c6c6..05a6e3d9c258c0815e870db6660fda8e4802d31f 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;