[Bug 207629] Integer overflow in sysctl_kern_proc_args

bugzilla-noreply at freebsd.org bugzilla-noreply at freebsd.org
Tue Mar 1 22:25:22 UTC 2016


https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=207629

            Bug ID: 207629
           Summary: Integer overflow in sysctl_kern_proc_args
           Product: Base System
           Version: 11.0-CURRENT
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Only Me
          Priority: ---
         Component: kern
          Assignee: freebsd-bugs at FreeBSD.org
          Reporter: cturt at hardenedbsd.org

The `sysctl_kern_proc_args` (`CTLFLAG_ANYBODY`) handler
(`sys/kern/kern_proc.c`) has an integer overflow vulnerability.

Relevant code:

static int
sysctl_kern_proc_args(SYSCTL_HANDLER_ARGS)
{
    int *name = (int *)arg1;
    u_int namelen = arg2;
    struct pargs *newpa, *pa;
    struct proc *p;
    struct sbuf sb;
    int flags, error = 0, error2;

    ...

    if (req->newlen + sizeof(struct pargs) > ps_arg_cache_limit)
        return (ENOMEM);
    newpa = pargs_alloc(req->newlen);
    error = SYSCTL_IN(req, newpa->ar_args, req->newlen);

    ...
}

struct pargs *
pargs_alloc(int len)
{
    struct pargs *pa;

    pa = malloc(sizeof(struct pargs) + len, M_PARGS,
        M_WAITOK);
    refcount_init(&pa->ar_ref, 1);
    pa->ar_length = len;
    return (pa);
}

If `newlen` is high enough such that `req->newlen + sizeof(struct pargs)`
overflows, the check against `ps_arg_cache_limit` will be bypassed:

    if (req->newlen + sizeof(struct pargs) > ps_arg_cache_limit)
        return (ENOMEM);

For example, since `sizeof(struct pargs)` is `12`, passing `0xffffffffffffffff`
will result in checking `11` against `ps_arg_cache_limit`.

Since `pargs_alloc` takes `len` as a `signed int`, the value passed to it will
be `-1`, and the value passed to `malloc` will be `11`.

In `pargs_alloc` this pointer is then written to:

    refcount_init(&pa->ar_ref, 1);
    pa->ar_length = len;

And the code will then pass the full size of `0xffffffffffffffff` bytes to
SYSCTL_IN of this allocation of `11` bytes:

    SYSCTL_IN(req, newpa->ar_args, req->newlen);

However, `SYSCTL_IN` has more checks than `copyin`, which makes it impossible
for a buffer overflow to occur here.

There is another possibility though; if `req->newlen` is `-12`, the allocation
will be 0, and the 2 writes in `pargs_alloc` will be out of bounds.

Disassembly of this (FreeBSD 9.0):

.text:FFFFFFFF8082646E                 call    malloc
.text:FFFFFFFF80826473                 mov     dword ptr [rax], 1
.text:FFFFFFFF80826479                 mov     [rax+4], ebx

-- 
You are receiving this mail because:
You are the assignee for the bug.


More information about the freebsd-bugs mailing list