Bug 10423

Summary: (Patch queued)af_rose sendmsg length check
Product: Networking Reporter: tp (thomas.pollet)
Component: OtherAssignee: Arnaldo Carvalho de Melo (acme)
Status: RESOLVED CODE_FIX    
Severity: normal CC: alan, eugeneteo, ralf
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 2.6.24.4 Subsystem:
Regression: No Bisected commit-id:

Description tp 2008-04-08 06:48:26 UTC
Hi,

the code from rose_sendmsg in sys/net/af_rose.c doesn't check the value of len. 
suppose len is very big (0xfffffff8 for example) then "size" would overflow.

        size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN;

resulting in a buffer that's too small.

if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
                return err;

the buffer is filled here:

1115         skb_put(skb, len);
1116 
1117         err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);


Regards,
Thomas Pollet
Comment 1 Anonymous Emailer 2008-04-08 10:39:48 UTC
Reply-To: akpm@linux-foundation.org


(switched to email.  Please respond via emailed reply-to-all, not via the
bugzilla web interface).

On Tue,  8 Apr 2008 06:48:27 -0700 (PDT) bugme-daemon@bugzilla.kernel.org wrote:

> http://bugzilla.kernel.org/show_bug.cgi?id=10423
> 
>            Summary: af_rose sendmsg length check
>            Product: Networking
>            Version: 2.5
>      KernelVersion: 2.6.24.4
>           Platform: All
>         OS/Version: Linux
>               Tree: Mainline
>             Status: NEW
>           Severity: normal
>           Priority: P1
>          Component: Other
>         AssignedTo: acme@ghostprotocols.net
>         ReportedBy: thomas.pollet@gmail.com
> 
> 
> Hi,
> 
> the code from rose_sendmsg in sys/net/af_rose.c doesn't check the value of
> len. 
> suppose len is very big (0xfffffff8 for example) then "size" would overflow.
> 
>         size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN +
>         ROSE_MIN_LEN;
> 
> resulting in a buffer that's too small.
> 
> if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT,
> &err))
> == NULL)
>                 return err;
> 
> the buffer is filled here:
> 
> 1115         skb_put(skb, len);
> 1116 
> 1117         err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov,
> len);
> 
> 

It might be that it doesn't need to check.  We check that the total length
didn't overflow negative in sys_sendmsg()'s call to verify_iovec().

Of course, the addition which you identify might make a very large length
overflow 0x7fffffff, and subsequent code might handle that incorrectly.
Comment 2 Eugene Teo 2008-09-25 00:06:09 UTC
(In reply to comment #0)
> the code from rose_sendmsg in sys/net/af_rose.c doesn't check the value of
> len. 
> suppose len is very big (0xfffffff8 for example) then "size" would overflow.
> 
>         size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN +
>         ROSE_MIN_LEN;
> 
> resulting in a buffer that's too small.

I believe that if sock_alloc_send_skb() is called with a wrapped size, it might actually create a larger buffer than necessary.

1883 asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
1884 {
[...]
1895         int err, ctl_len, iov_size, total_len;
[...]
1930                 err = verify_iovec(&msg_sys, iov,
1931                                    (struct sockaddr *)&address,
1932                                    VERIFY_READ);
1933         if (err < 0)
1934                 goto out_freeiov;
1935         total_len = err;
                    ^ total_len is not negative
[...]
1971         err = sock_sendmsg(sock, &msg_sys, total_len);
                             ^ total_len casted to size_t

 567 int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
 568 {
[...]
 575         ret = __sock_sendmsg(&iocb, sock, msg, size);

 549 static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
 550                                  struct msghdr *msg, size_t size)
 551 {
[...]
 558         si->size = size;
                 ^ size_t to positive signed int
[...]
 564         return sock->ops->sendmsg(iocb, sock, msg, size);

1063 static int rose_sendmsg(struct kiocb *iocb, struct socket *sock,
1064                         struct msghdr *msg, size_t len)
1065 {
[...]
1073         int n, size, qbit = 0;
[...]
1123         size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN;
                   ^ the summation is converted into a signed int
1124 
1125         if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
                                                ^ converted to unsigned long
                       ^ size could wrap, and become a huge value. it will in turn,
                       ^ truncate to an unsigned int when it is called with alloc_skb
1126                 return err;
1127
1128         skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN);
[...]
1136         skb_put(skb, len);
                          ^ unsigned int
1137 
1138         err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);
                     ^ len is signed int; only copy if len is more than > 0
1139         if (err) {
1140                 kfree_skb(skb);
1141                 return err;
1142         }