Signedness bug in sctp_setsockopt() (security vulnerability).

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi guys,

After skipping through some of the SCTP Linux Kernel
net code, I discovered what appears to be a signedness
bug, potentially allowing overwriting of kernel memory
- thus presenting a security vulnerability.

Please note that this issue is present in 2.4.25, but
I think the socket option vulnerable was for some
reason removed in the 2.4.26 patch.  I've only really
checked 2.4.25 for this.

The issue presents itself in net/sctp/socket.c in the
source tree:

--- net/sctp/socket.c ---
SCTP_STATIC int sctp_setsockopt(struct sock *sk, int
level, int optname,
                                char *optval, int
optlen)
{
        int retval = 0;
        char *tmp;

        SCTP_DEBUG_PRINTK("sctp_setsockopt(sk: %p...
optname: %d)\n",
                          sk, optname);


[ ... ]

 switch (optname) {
        case SCTP_SOCKOPT_DEBUG_NAME:
                /* BUG! we don't ever seem to free
this memory. --jgrimm */
                if (NULL == (tmp = kmalloc(optlen + 1,
GFP_KERNEL))) {
                        retval = -ENOMEM;
                        goto out_unlock;
                }

                if (copy_from_user(tmp, optval,
optlen)) {
                        retval = -EFAULT;
                        goto out_unlock;
                }
                tmp[optlen] = '\000';
                sctp_sk(sk)->ep->debug_name = tmp;
                break;

[ ... ]

--- EO snippet ---

>From the code above, we can see that the 'optname'
variable passed to sctp_setsockopt() is parsed, and
should the option be 'SCTP_SOCKOPT_DEBUG_NAME', the
above code is ran.  Notice, from the declaration of
sctp_setsockopt(), 'optlen' is an integer variable,
and remains unsanitised or checked throughout the
entire function.  Now, here is where the bug
manifests:

---
if (NULL == (tmp = kmalloc(optlen + 1, GFP_KERNEL))) {
                        retval = -ENOMEM;
                        goto out_unlock;
                }
---

As I can recall, kmalloc takes the size of memory to
be allocated as an unsigned int, and due to the lack
of checks on 'optlen' passed by the user, HUGE numbers
could end up being interpreted by kmalloc() if a
negative integer is passed to sctp_setsockopt() in the
'optlen' variable.  Of course, kmalloc() would fail,
because such a large amount of memory cannot be
allocated.  However, with a bit of thinking, it is
easy to remember that the signed integer '-1' is
represented as 0xffffffff by unsigned variables - and
this is the maximum number representable by unsigned
integers (at least on my hardware).  All would be
well, except for the fact that 'optlen + 1' is infact
allocated.  This, in itself, is a major flaw;

What if -1 is passed to sctp_setsockopt() as optlen? 
Let's do the calculation:

(optlen = -1)

-1 will be represented as 0xffffffff by unsigned ints,
thus the equivalent of this kmalloc() call is invoked
(assuming optlen = -1):

(kmalloc(0xffffffff + 1, GFP_KERNEL) )

However, this will cause the maximum value
representable by an unsigned integer variable to be
exceeded, causing the value to wrap around - to 0. 
Thus, we now have the equivalent of the below
kmalloc() call:

kmalloc(0x0, GFP_KERNEL)


Hence, 0 bytes are attempted to be allocated (however,
around 32 bytes will probably be allocated, if I
remember correctly). 


Now, assuming the kmalloc() call succeeded, a
copy_from_user call is invoked:

---
copy_from_user(tmp, optval, optlen)
---

Assuming we did infact pass -1 to optlen when calling
the sctp_setsockopt() function, we have a
copy_from_user call looking like this:

---
copy_from_user(tmp, optval, 0xffffffff)
---

Of course, a would-be attacker is unlikely to pass
0xffffffff bytes to the function (as optval), but due
to the nature of copy_from_user, copying will be
performed until the end of the data is reached.


>From my sloppy explanations above, the vulnerability
should be apparent: by exploiting the signedness
bug/sanity check bug above, an amount of memory LESS
than the length of 'optval' can be allocated - thus
causing writing into unallocated kernel memory.  If I
haven't fudged up, this is most probably a security
issue in itself.  Does anyone agree?  Please note that
this bug only manifests when parsing and acting upon
the SCTP_SOCKOPT_DEBUG_NAME sctp socket option!

By the way, please note that I HAVEN'T actually tested
this issue on my system, because I forgot to compile
SCTP support into my kernel.  However, it should be
pretty simple for all of you SCTP experts out there. 
A small example snippet:

--- test.c ---
[ ... ]

char buf[200];
memset(buf, 'a', sizeof(buf));

sctp_setsockopt(sock, SOL_SCTP,
SCTP_SOCKOPT_DEBUG_NAME, &buf, -1);

[ ... ]

--- EOF ---


Due to the fact that I haven't had the resources to
test the impact of the issue, I am posting here for
discussion of the bug, if it actually exists.  If I
have made a mistake, or sanity checks are performed
somewhere earlier down the line, please let me know
kindly.  Other than that, just by auditing the code,
it looks to me like a definite security hole.  Does
anyone else agree?



Thank you for your time.
Shaun.








	
	
		
____________________________________________________________
Yahoo! Messenger - Communicate instantly..."Ping" 
your friends today! Download Messenger Now 
http://uk.messenger.yahoo.com/download/index.html
-
: send the line "unsubscribe linux-net" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux 802.1Q VLAN]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Git]     [Bugtraq]     [Yosemite News and Information]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux PCI]     [Linux Admin]     [Samba]

  Powered by Linux