aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2012-05-24 12:34:21 -0400
committerEric W. Biederman <ebiederm@xmission.com>2012-08-15 00:49:10 -0400
commit7064d16e162adf8199f0288b694e6af823ed5431 (patch)
tree02563996ee28d686b1cb9a16ba389b382aa6bb4f
parenta7cb5a49bf64ba64864ae16a6be028f8b0d3cc06 (diff)
userns: Use kgids for sysctl_ping_group_range
- Store sysctl_ping_group_range as a paire of kgid_t values instead of a pair of gid_t values. - Move the kgid conversion work from ping_init_sock into ipv4_ping_group_range - For invalid cases reset to the default disabled state. With the kgid_t conversion made part of the original value sanitation from userspace understand how the code will react becomes clearer and it becomes possible to set the sysctl ping group range from something other than the initial user namespace. Cc: Vasiliy Kulikov <segoon@openwall.com> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
-rw-r--r--include/net/netns/ipv4.h3
-rw-r--r--init/Kconfig1
-rw-r--r--net/ipv4/ping.c18
-rw-r--r--net/ipv4/sysctl_net_ipv4.c42
4 files changed, 35 insertions, 29 deletions
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index 1474dd65c66f..3516dc0cc615 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -5,6 +5,7 @@
5#ifndef __NETNS_IPV4_H__ 5#ifndef __NETNS_IPV4_H__
6#define __NETNS_IPV4_H__ 6#define __NETNS_IPV4_H__
7 7
8#include <linux/uidgid.h>
8#include <net/inet_frag.h> 9#include <net/inet_frag.h>
9 10
10struct tcpm_hash_bucket; 11struct tcpm_hash_bucket;
@@ -62,7 +63,7 @@ struct netns_ipv4 {
62 int sysctl_icmp_ratemask; 63 int sysctl_icmp_ratemask;
63 int sysctl_icmp_errors_use_inbound_ifaddr; 64 int sysctl_icmp_errors_use_inbound_ifaddr;
64 65
65 unsigned int sysctl_ping_group_range[2]; 66 kgid_t sysctl_ping_group_range[2];
66 long sysctl_tcp_mem[3]; 67 long sysctl_tcp_mem[3];
67 68
68 atomic_t rt_genid; 69 atomic_t rt_genid;
diff --git a/init/Kconfig b/init/Kconfig
index 25a6ebb50c64..f857f97bcef3 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -948,7 +948,6 @@ config UIDGID_CONVERTED
948 depends on NETFILTER_XT_MATCH_RECENT = n 948 depends on NETFILTER_XT_MATCH_RECENT = n
949 depends on NETFILTER_XT_TARGET_LOG = n 949 depends on NETFILTER_XT_TARGET_LOG = n
950 depends on NETFILTER_NETLINK_LOG = n 950 depends on NETFILTER_NETLINK_LOG = n
951 depends on INET = n
952 depends on IPV6 = n 951 depends on IPV6 = n
953 depends on AF_RXRPC = n 952 depends on AF_RXRPC = n
954 depends on NET_KEY = n 953 depends on NET_KEY = n
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index bee5eeb676f8..8f3d05424a3e 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -185,10 +185,10 @@ exit:
185 return sk; 185 return sk;
186} 186}
187 187
188static void inet_get_ping_group_range_net(struct net *net, gid_t *low, 188static void inet_get_ping_group_range_net(struct net *net, kgid_t *low,
189 gid_t *high) 189 kgid_t *high)
190{ 190{
191 gid_t *data = net->ipv4.sysctl_ping_group_range; 191 kgid_t *data = net->ipv4.sysctl_ping_group_range;
192 unsigned int seq; 192 unsigned int seq;
193 193
194 do { 194 do {
@@ -203,19 +203,13 @@ static void inet_get_ping_group_range_net(struct net *net, gid_t *low,
203static int ping_init_sock(struct sock *sk) 203static int ping_init_sock(struct sock *sk)
204{ 204{
205 struct net *net = sock_net(sk); 205 struct net *net = sock_net(sk);
206 gid_t group = current_egid(); 206 kgid_t group = current_egid();
207 gid_t range[2];
208 struct group_info *group_info = get_current_groups(); 207 struct group_info *group_info = get_current_groups();
209 int i, j, count = group_info->ngroups; 208 int i, j, count = group_info->ngroups;
210 kgid_t low, high; 209 kgid_t low, high;
211 210
212 inet_get_ping_group_range_net(net, range, range+1); 211 inet_get_ping_group_range_net(net, &low, &high);
213 low = make_kgid(&init_user_ns, range[0]); 212 if (gid_lte(low, group) && gid_lte(group, high))
214 high = make_kgid(&init_user_ns, range[1]);
215 if (!gid_valid(low) || !gid_valid(high) || gid_lt(high, low))
216 return -EACCES;
217
218 if (range[0] <= group && group <= range[1])
219 return 0; 213 return 0;
220 214
221 for (i = 0; i < group_info->nblocks; i++) { 215 for (i = 0; i < group_info->nblocks; i++) {
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 1b5ce96707a3..3e78c79b5586 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -76,9 +76,9 @@ static int ipv4_local_port_range(ctl_table *table, int write,
76} 76}
77 77
78 78
79static void inet_get_ping_group_range_table(struct ctl_table *table, gid_t *low, gid_t *high) 79static void inet_get_ping_group_range_table(struct ctl_table *table, kgid_t *low, kgid_t *high)
80{ 80{
81 gid_t *data = table->data; 81 kgid_t *data = table->data;
82 unsigned int seq; 82 unsigned int seq;
83 do { 83 do {
84 seq = read_seqbegin(&sysctl_local_ports.lock); 84 seq = read_seqbegin(&sysctl_local_ports.lock);
@@ -89,12 +89,12 @@ static void inet_get_ping_group_range_table(struct ctl_table *table, gid_t *low,
89} 89}
90 90
91/* Update system visible IP port range */ 91/* Update system visible IP port range */
92static void set_ping_group_range(struct ctl_table *table, gid_t range[2]) 92static void set_ping_group_range(struct ctl_table *table, kgid_t low, kgid_t high)
93{ 93{
94 gid_t *data = table->data; 94 kgid_t *data = table->data;
95 write_seqlock(&sysctl_local_ports.lock); 95 write_seqlock(&sysctl_local_ports.lock);
96 data[0] = range[0]; 96 data[0] = low;
97 data[1] = range[1]; 97 data[1] = high;
98 write_sequnlock(&sysctl_local_ports.lock); 98 write_sequnlock(&sysctl_local_ports.lock);
99} 99}
100 100
@@ -103,21 +103,33 @@ static int ipv4_ping_group_range(ctl_table *table, int write,
103 void __user *buffer, 103 void __user *buffer,
104 size_t *lenp, loff_t *ppos) 104 size_t *lenp, loff_t *ppos)
105{ 105{
106 struct user_namespace *user_ns = current_user_ns();
106 int ret; 107 int ret;
107 gid_t range[2]; 108 gid_t urange[2];
109 kgid_t low, high;
108 ctl_table tmp = { 110 ctl_table tmp = {
109 .data = &range, 111 .data = &urange,
110 .maxlen = sizeof(range), 112 .maxlen = sizeof(urange),
111 .mode = table->mode, 113 .mode = table->mode,
112 .extra1 = &ip_ping_group_range_min, 114 .extra1 = &ip_ping_group_range_min,
113 .extra2 = &ip_ping_group_range_max, 115 .extra2 = &ip_ping_group_range_max,
114 }; 116 };
115 117
116 inet_get_ping_group_range_table(table, range, range + 1); 118 inet_get_ping_group_range_table(table, &low, &high);
119 urange[0] = from_kgid_munged(user_ns, low);
120 urange[1] = from_kgid_munged(user_ns, high);
117 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); 121 ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
118 122
119 if (write && ret == 0) 123 if (write && ret == 0) {
120 set_ping_group_range(table, range); 124 low = make_kgid(user_ns, urange[0]);
125 high = make_kgid(user_ns, urange[1]);
126 if (!gid_valid(low) || !gid_valid(high) ||
127 (urange[1] < urange[0]) || gid_lt(high, low)) {
128 low = make_kgid(&init_user_ns, 1);
129 high = make_kgid(&init_user_ns, 0);
130 }
131 set_ping_group_range(table, low, high);
132 }
121 133
122 return ret; 134 return ret;
123} 135}
@@ -786,7 +798,7 @@ static struct ctl_table ipv4_net_table[] = {
786 { 798 {
787 .procname = "ping_group_range", 799 .procname = "ping_group_range",
788 .data = &init_net.ipv4.sysctl_ping_group_range, 800 .data = &init_net.ipv4.sysctl_ping_group_range,
789 .maxlen = sizeof(init_net.ipv4.sysctl_ping_group_range), 801 .maxlen = sizeof(gid_t)*2,
790 .mode = 0644, 802 .mode = 0644,
791 .proc_handler = ipv4_ping_group_range, 803 .proc_handler = ipv4_ping_group_range,
792 }, 804 },
@@ -830,8 +842,8 @@ static __net_init int ipv4_sysctl_init_net(struct net *net)
830 * Sane defaults - nobody may create ping sockets. 842 * Sane defaults - nobody may create ping sockets.
831 * Boot scripts should set this to distro-specific group. 843 * Boot scripts should set this to distro-specific group.
832 */ 844 */
833 net->ipv4.sysctl_ping_group_range[0] = 1; 845 net->ipv4.sysctl_ping_group_range[0] = make_kgid(&init_user_ns, 1);
834 net->ipv4.sysctl_ping_group_range[1] = 0; 846 net->ipv4.sysctl_ping_group_range[1] = make_kgid(&init_user_ns, 0);
835 847
836 tcp_init_mem(net); 848 tcp_init_mem(net);
837 849