diff options
author | Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | 2013-09-11 17:23:18 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-11 18:58:18 -0400 |
commit | 3ddc5b46a8e90f3c9251338b60191d0a804b0d92 (patch) | |
tree | 5c76cd730cb94e75f30953d6cd1aed9386fcee37 /net | |
parent | 20d0e57017b69e7e4ae7166c43f3a3f023ab9702 (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.c | 50 |
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; |