<<< Date Index >>>     <<< Thread Index >>>

Re: [Linux kernel ipv6_setsockopt integer overflow]



On Thu, 3 Feb 2005, qobaiashi wrote:

There's no integer overflow here since there's the test for optlen < 0 in 
linux/net/socket.c

> 
> there exists an integer bug in the ipv6 implementation of the linux kernel.
> (at least in 2.4.20 and 2.6.4 )
> in /linux/net/ipv6/ipv6_sockglue.c:
> 
> 
> int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
>                int optlen)
> {
>         struct ipv6_pinfo *np = inet6_sk(sk);
>         int val, valbool;
>         int retv = -ENOPROTOOPT;
> 
>         if (level == SOL_IP && sk->sk_type != SOCK_RAW)
>                 return udp_prot.setsockopt(sk, level, optname, optval,optlen);
> 
>         if(level!=SOL_IPV6)
>                 goto out;
> 
>         if (optval == NULL)
>                 val=0;
>         else if (get_user(val, (int *) optval))
>                 return -EFAULT;
> 
>         valbool = (val!=0);
> 
>         lock_sock(sk);
> 
>         switch (optname) {
>  [...]
> 
>  case IPV6_PKTOPTIONS:
>         {
>                 struct ipv6_txoptions *opt = NULL;
>                 struct msghdr msg;
>                 struct flowi fl;
>                 int junk;
> 
>                 fl.fl6_flowlabel = 0;
>                 fl.oif = sk->sk_bound_dev_if;
> 
> [1]            if (optlen == 0)
>                         goto update;
> 
>                 /* 1K is probably excessive
>                  * 1K is surely not enough, 2K per standard header is 16K.
>                  */
>                 retv = -EINVAL;
> [2]             if (optlen > 64*1024) 
>                         break;
> 
> [3]            opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL);
>                 retv = -ENOBUFS; sizeof(*opt)+0xfffffff8
>                 if (opt == NULL)
>                         break;
> 
> [4]            memset(opt, 0, sizeof(*opt));
>                 opt->tot_len = sizeof(*opt) + optlen;
>                 retv = -EFAULT;
> [5]            if (copy_from_user(opt+1, optval, optlen))
> [...]
> 
> details:
> 
> condition [1] and [2] are easily passed for a value like -100, then at [3] 
> sock_kmalloc allocates a too small object of the size (sizeof(*opt) + (-100))
> which is then overflowed in [4] and [5] leading to a dos of the kernel...
> 
> that's it 
> over and out!
> 
> 

-- 

    Sincerely Your, Dan.