Linux Kernel sctp_setsockopt() Integer Overflow

From: Shaun Colley (shaunige_at_yahoo.co.uk)
Date: 05/11/04

  • Next message: Florian Weimer: "Re: NISCC Vulnerability Advisory 236929: Vulnerability Issues in TCP"
    Date: Tue, 11 May 2004 19:58:56 +0100 (BST)
    To: bugtraq@securityfocus.com
    
    

    ~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*

    Product: Linux Kernel
    Versions: <= 2.4.25
    Bug: Integer overflow
    Impact: Attackers may be able to execute
                  arbitrary code with kernel-level
                  privileges.
    Risk: High
    Date: May 11, 2004
    Author: Shaun Colley
                  Email: shaunige yahoo co uk
                  WWW: http://www.nettwerked.co.uk

    ~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*~*

    Introduction
    #############

    The Linux Kernel is the core of the Linux Operating
    System, written entirely from scratch with assistance
    from a group of loosely-knit hackers across the Net.
    The Linux Kernel project aims for POSIX compatibility,
    and implements everything one would expect from a
    modern, rapidly-developed kernel; networking,
    multimedia support, peripheral support, etc.

    Within the vast support for networking, there lies a
    bug, in kernel versions 2.4.25 and below. The bug is
    an integer overflow, which could result in too little
    memory being allocated, resulting in overwriting of
    kernel memory.

    Versions 2.4.26 and above, and 2.6.X are not
    vulnerable to the issue, as they removed the
    vulnerable socket option, as it was considered less
    than mandatory.

    Details
    ########

    The bug exists in the SCTP implementation, which
    resides in 'net/sctp' in the Linux Kernel source tree.
     Due to insufficient sanitizing of function arguments,
    the sctp_setsockopt() is vulnerable to an integer
    overflow when parsing and dealing with the SCTP
    'SCTP_SOCKOPT_DEBUG_NAME' socket option, leading up to
    the allocation of memory.

    Below is the vulnerable code:

    --- net/sctp/socket.c snippet ---
    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;

    ---
    When the kmalloc() call is invoked to allocate
    'optlen' amount of memory, 1 is incremented to
    'optlen' to ensure enough memory is allocated for the
    option value (optval).  However, since sanitization of
    function arguments are failed to be performed,
    'optlen' could be the maximum value that an unsigned
    integer can hold correctly, thus causing the value to
    wrap around when the calculation 'optlen + 1' is
    performed.
    Below is the vulnerable call:
    ---
    if (NULL == (tmp = kmalloc(optlen + 1, GFP_KERNEL))) {
                            retval = -ENOMEM;
                            goto out_unlock;
                    }
    ---
    Because kmalloc() takes the 'count' variable as an
    unsigned number, negative numbers are interpreted as
    large unsigned numbers.  However, if -1 is passed as
    'optlen' (represented as 0xffffffff (hex) in unsigned
    variables, which is the largest value an unsigned
    integer can hold correctly), an integer overflow will
    occur in optlen (as a result of the kmalloc call
    incrementing optlen by 1), causing the value to wrap
    around to 0.  This is illustrated below:
    ---
    User passes: optlen = -1 (signed)
    (-1 = 0xffffffff unsigned)
    kmalloc interprets the optlen variable as unsigned:
    --
    if (NULL == (tmp = kmalloc(0xffffffff + 1,
    GFP_KERNEL))) {
                            retval = -ENOMEM;
                            goto out_unlock;
                    }
    0xffffffff + 1
    = 0x0
    ---
    And thus, due to the integer overflow, 0 is passed to
    kmalloc(), causing too little memory to be allocated
    to hold 'optval'.
    Following the memory allocation, a copy_from_user()
    call is implemented to copy the contents of the
    user-supplied 'optval' into the new memory freshly
    allocated:
    ---
    if (copy_from_user(tmp, optval, optlen)) {
                            retval = -EFAULT;
                            goto out_unlock;
                    }
    ---
    Assuming the user passed -1 as optlen, the above
    copy_from_user call can be represented as below:
    ---
    optlen = -1
    (0xffffffff unsigned (-1))
    copy_from_user() call:
    --
    if (copy_from_user(tmp, optval, 0xffffffff)) {
                            retval = -EFAULT;
                            goto out_unlock;
                    }
    ---
    Because of the integer overflow in the kmalloc() call,
    too little memory was allocated for optval, followed
    by a copy_from_user() call which copies a large amount
    of data from user-space (optval) into the allocated
    memory.  Since too little memory may have been
    allocated, this could result in overwriting of kernel
    memory, and ultimately privilege elevation to
    kernel-level privileges, if exploited properly.
    Please note that this vulnerability only exists in the
    SCTP_SOCKOPT_DEBUG_NAME SCTP socket option.
    Exploitation
    #############
    To exploit the flaw, a sctp_setsockopt() call with the
    following values would need to be implemented:
    ---
    level = SOL_SCTP
    optname = SCTP_SOCKOPT_DEBUG_NAME
    optval = expl_payload
    optlen = -1
    [ ... ]
    sctp_setsockopt(mysock, SOL_SCTP,
    SCTP_SOCKOPT_DEBUG_NAME, expl_payload, -1);
    [ ... ]
    ---
    Note that the level SOL_SCTP must be supplied, rather
    than IPPROTO_SCTP level, because IPPROTO_SCTP causes
    the causes the function to set options via another
    function.
    Solution
    #########
    I reported this bug to the linux-net list, but since
    the 'SCTP_SOCKOPT_DEBUG_NAME' SCTP socket option was
    removed in kernels 2.4.26 (and above) and 2.6, this
    was considered to be an easily resolvable issue:
    Upgrade to Linux Kernel 2.4.6 or 2.6.
    This removes all possibility of the vulnerability,
    since the offending socket option has essentially been
    removed.  Another benefit of upgrading to the latest
    kernel version if the vast improvements in the SCTP
    implementation - the implementation has been improved
    and expanded some.  Please note that the flaw reported
    in this advisory was dismissed as a "non-issue" on the
    linux-net mailing-list, so I saw it appropriate to
    post this here.
    A quick fix for the issue is to apply the following
    patch:
    --- sctp_vuln.patch ---
    --- socket.orig.c       2004-05-11 18:31:45.000000000
    +0100
    +++ socket.c    2004-05-11 18:32:40.000000000 +0100
    @@ -1516,18 +1516,7 @@
            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;
    +               /* do nothing */
                    break;
            case SCTP_SOCKOPT_BINDX_ADD:
    --- EOF ---
    (patch also available here:
    <hXXp://www.nettwerked.co.uk/code/sctp_vuln.patch>)
    Apply the patch and recompile the kernel:
    ---
    root# cd /usr/src/linux/net/sctp
    root# patch < sctp_vuln.patch
    patching file socket.c
    root# cd /usr/src/linux
    root# make oldconfig && make dep && make bzImage &&
    make modules && make modules_install
    ---
    The above patch was created to apply cleanly to the
    2.4.25 Linux Kernel version.  The above patch removes
    the code which handles the vulnerable socket option.
    Credit
    #######
    This vulnerability was discovered by Shaun Colley /
    shaun2k2 - <shaunige yahoo co uk>.
    Thanks to people on the linux-net list for
    acknowledging the issue (or at least in part).
    Disclaimer
    ###########
    The information contained within this document was
    believed to be accurate at the time of it's
    publishing.  However, it may be inaccurate at times,
    so don't consider any information to be 'set in
    stone', and I do not guarantee the accuracy of
    information contained within this 'advisory'.
    Please feel free to email me with mistakes or errors I
    have made, as long as they are nicely phrased.  Flames
    should be directed to /dev/null - I am not interested
    in any policies I may or may not have followed.
    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
    

  • Next message: Florian Weimer: "Re: NISCC Vulnerability Advisory 236929: Vulnerability Issues in TCP"

    Relevant Pages