aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>2013-09-11 17:23:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-11 18:58:18 -0400
commit3ddc5b46a8e90f3c9251338b60191d0a804b0d92 (patch)
tree5c76cd730cb94e75f30953d6cd1aed9386fcee37 /net
parent20d0e57017b69e7e4ae7166c43f3a3f023ab9702 (diff)
kernel-wide: fix missing validations on __get/__put/__copy_to/__copy_from_user()
I found the following pattern that leads in to interesting findings: grep -r "ret.*|=.*__put_user" * grep -r "ret.*|=.*__get_user" * grep -r "ret.*|=.*__copy" * The __put_user() calls in compat_ioctl.c, ptrace compat, signal compat, since those appear in compat code, we could probably expect the kernel addresses not to be reachable in the lower 32-bit range, so I think they might not be exploitable. For the "__get_user" cases, I don't think those are exploitable: the worse that can happen is that the kernel will copy kernel memory into in-kernel buffers, and will fail immediately afterward. The alpha csum_partial_copy_from_user() seems to be missing the access_ok() check entirely. The fix is inspired from x86. This could lead to information leak on alpha. I also noticed that many architectures map csum_partial_copy_from_user() to csum_partial_copy_generic(), but I wonder if the latter is performing the access checks on every architectures. Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Richard Henderson <rth@twiddle.net> Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru> Cc: Matt Turner <mattst88@gmail.com> Cc: Jens Axboe <axboe@kernel.dk> Cc: Oleg Nesterov <oleg@redhat.com> Cc: David Miller <davem@davemloft.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'net')
-rw-r--r--net/socket.c50
1 files changed, 25 insertions, 25 deletions
diff --git a/net/socket.c b/net/socket.c
index b2d7c629eeb9..0ceaa5cb9ead 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -3072,12 +3072,12 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd,
3072 3072
3073 uifmap32 = &uifr32->ifr_ifru.ifru_map; 3073 uifmap32 = &uifr32->ifr_ifru.ifru_map;
3074 err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name)); 3074 err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name));
3075 err |= __get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); 3075 err |= get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start);
3076 err |= __get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); 3076 err |= get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end);
3077 err |= __get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); 3077 err |= get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr);
3078 err |= __get_user(ifr.ifr_map.irq, &uifmap32->irq); 3078 err |= get_user(ifr.ifr_map.irq, &uifmap32->irq);
3079 err |= __get_user(ifr.ifr_map.dma, &uifmap32->dma); 3079 err |= get_user(ifr.ifr_map.dma, &uifmap32->dma);
3080 err |= __get_user(ifr.ifr_map.port, &uifmap32->port); 3080 err |= get_user(ifr.ifr_map.port, &uifmap32->port);
3081 if (err) 3081 if (err)
3082 return -EFAULT; 3082 return -EFAULT;
3083 3083
@@ -3088,12 +3088,12 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd,
3088 3088
3089 if (cmd == SIOCGIFMAP && !err) { 3089 if (cmd == SIOCGIFMAP && !err) {
3090 err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name)); 3090 err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name));
3091 err |= __put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); 3091 err |= put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start);
3092 err |= __put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); 3092 err |= put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end);
3093 err |= __put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); 3093 err |= put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr);
3094 err |= __put_user(ifr.ifr_map.irq, &uifmap32->irq); 3094 err |= put_user(ifr.ifr_map.irq, &uifmap32->irq);
3095 err |= __put_user(ifr.ifr_map.dma, &uifmap32->dma); 3095 err |= put_user(ifr.ifr_map.dma, &uifmap32->dma);
3096 err |= __put_user(ifr.ifr_map.port, &uifmap32->port); 3096 err |= put_user(ifr.ifr_map.port, &uifmap32->port);
3097 if (err) 3097 if (err)
3098 err = -EFAULT; 3098 err = -EFAULT;
3099 } 3099 }
@@ -3167,25 +3167,25 @@ static int routing_ioctl(struct net *net, struct socket *sock,
3167 struct in6_rtmsg32 __user *ur6 = argp; 3167 struct in6_rtmsg32 __user *ur6 = argp;
3168 ret = copy_from_user(&r6.rtmsg_dst, &(ur6->rtmsg_dst), 3168 ret = copy_from_user(&r6.rtmsg_dst, &(ur6->rtmsg_dst),
3169 3 * sizeof(struct in6_addr)); 3169 3 * sizeof(struct in6_addr));
3170 ret |= __get_user(r6.rtmsg_type, &(ur6->rtmsg_type)); 3170 ret |= get_user(r6.rtmsg_type, &(ur6->rtmsg_type));
3171 ret |= __get_user(r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len)); 3171 ret |= get_user(r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len));
3172 ret |= __get_user(r6.rtmsg_src_len, &(ur6->rtmsg_src_len)); 3172 ret |= get_user(r6.rtmsg_src_len, &(ur6->rtmsg_src_len));
3173 ret |= __get_user(r6.rtmsg_metric, &(ur6->rtmsg_metric)); 3173 ret |= get_user(r6.rtmsg_metric, &(ur6->rtmsg_metric));
3174 ret |= __get_user(r6.rtmsg_info, &(ur6->rtmsg_info)); 3174 ret |= get_user(r6.rtmsg_info, &(ur6->rtmsg_info));
3175 ret |= __get_user(r6.rtmsg_flags, &(ur6->rtmsg_flags)); 3175 ret |= get_user(r6.rtmsg_flags, &(ur6->rtmsg_flags));
3176 ret |= __get_user(r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex)); 3176 ret |= get_user(r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex));
3177 3177
3178 r = (void *) &r6; 3178 r = (void *) &r6;
3179 } else { /* ipv4 */ 3179 } else { /* ipv4 */
3180 struct rtentry32 __user *ur4 = argp; 3180 struct rtentry32 __user *ur4 = argp;
3181 ret = copy_from_user(&r4.rt_dst, &(ur4->rt_dst), 3181 ret = copy_from_user(&r4.rt_dst, &(ur4->rt_dst),
3182 3 * sizeof(struct sockaddr)); 3182 3 * sizeof(struct sockaddr));
3183 ret |= __get_user(r4.rt_flags, &(ur4->rt_flags)); 3183 ret |= get_user(r4.rt_flags, &(ur4->rt_flags));
3184 ret |= __get_user(r4.rt_metric, &(ur4->rt_metric)); 3184 ret |= get_user(r4.rt_metric, &(ur4->rt_metric));
3185 ret |= __get_user(r4.rt_mtu, &(ur4->rt_mtu)); 3185 ret |= get_user(r4.rt_mtu, &(ur4->rt_mtu));
3186 ret |= __get_user(r4.rt_window, &(ur4->rt_window)); 3186 ret |= get_user(r4.rt_window, &(ur4->rt_window));
3187 ret |= __get_user(r4.rt_irtt, &(ur4->rt_irtt)); 3187 ret |= get_user(r4.rt_irtt, &(ur4->rt_irtt));
3188 ret |= __get_user(rtdev, &(ur4->rt_dev)); 3188 ret |= get_user(rtdev, &(ur4->rt_dev));
3189 if (rtdev) { 3189 if (rtdev) {
3190 ret |= copy_from_user(devname, compat_ptr(rtdev), 15); 3190 ret |= copy_from_user(devname, compat_ptr(rtdev), 15);
3191 r4.rt_dev = (char __user __force *)devname; 3191 r4.rt_dev = (char __user __force *)devname;