Bug 475733 (CVE-2008-5702)

Summary: CVE-2008-5702 kernel: watchdog: ib700wdt.c - buffer_underflow bug
Product: [Other] Security Response Reporter: Eugene Teo (Security Response) <eteo>
Component: vulnerabilityAssignee: Red Hat Product Security <security-response-team>
Status: CLOSED ERRATA QA Contact:
Severity: low Docs Contact:
Priority: low    
Version: unspecifiedCC: dhoward, lwang, qcai, vgoyal
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2010-12-24 03:52:28 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On: 475735, 475736, 475737, 475738, 475739    
Bug Blocks:    

Description Eugene Teo (Security Response) 2008-12-10 07:27:46 UTC
From Zvonimir Rakamaric:
Steps to a possible buffer_underflow bug in ib700wdt.c, function ibwdt_ioctl:

1. new margin is loaded using get_user(new_margin, p) in case WDIOC_SETTIMEOUT in the function ibwdt_ioctl. Important: assume that new_margin == 30
2. ibwdt_set_heartbeat(new_margin) is called
3. the check "if ((t < 0) || (t > 30))" in ibwdt_set_heartbeat is not going to fail because t == 30 (t is new_margin)
4. in the loop, the check wd_times[i] > t is never going to be true because none of the wd_times are greater than the value of t (i.e. 30)
5. we are exiting the loop with i == -1 and therefore setting wd_margin to -1 in the line wd_margin = i;
6. we are returning from ibwdt_set_heartbeat and wd_margin is -1
7. we fall through to case WDIOC_GETTIMEOUT
8. we access the wd_times array with wd_margin == -1 on line "return put_user(wd_times[wd_margin], p);"

[...]
Furthermore, here are the pieces of code which are causing this
buffer-underflow bug in ib700wdt.c:

static int wd_times[] = {
        30,     /* 0x0 */
        28,     /* 0x1 */
        26,     /* 0x2 */
        24,     /* 0x3 */
        22,     /* 0x4 */
        20,     /* 0x5 */
        18,     /* 0x6 */
        16,     /* 0x7 */
        14,     /* 0x8 */
        12,     /* 0x9 */
        10,     /* 0xA */
        8,      /* 0xB */
        6,      /* 0xC */
        4,      /* 0xD */
        2,      /* 0xE */
        0,      /* 0xF */
};

function ibwdt_ioctl:
.....
  case WDIOC_SETTIMEOUT:
    if (get_user(new_margin, p))
      return -EFAULT;
    if (ibwdt_set_heartbeat(new_margin))
      return -EINVAL;
    ibwdt_ping();
    /* Fall */

  case WDIOC_GETTIMEOUT:
    return put_user(wd_times[wd_margin], p);
.....

function ibwdt_set_heartbeat:
static int
ibwdt_set_heartbeat(int t)
{
        int i;

        if ((t < 0) || (t > 30))
                return -EINVAL;

        for (i = 0x0F; i > -1; i--)
                if (wd_times[i] > t)
                        break;
        wd_margin = i;
        return 0;
}

Comment 3 Eugene Teo (Security Response) 2008-12-10 07:34:54 UTC
Reference: http://bugzilla.kernel.org/show_bug.cgi?id=11399

Comment 4 Eugene Teo (Security Response) 2008-12-10 07:35:39 UTC
Upstream commit:
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=7c2500f

Comment 7 Vincent Danen 2010-12-24 03:52:28 UTC
This was addressed via:

Red Hat Enterprise Linux version 4 (RHSA-2009:0014)