Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 01 Mar 2016 22:25:22 +0000
From:      bugzilla-noreply@freebsd.org
To:        freebsd-bugs@FreeBSD.org
Subject:   [Bug 207629] Integer overflow in sysctl_kern_proc_args
Message-ID:  <bug-207629-8@https.bugs.freebsd.org/bugzilla/>

next in thread | raw e-mail | index | archive | help
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=3D207629

            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@FreeBSD.org
          Reporter: cturt@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 =3D (int *)arg1;
    u_int namelen =3D arg2;
    struct pargs *newpa, *pa;
    struct proc *p;
    struct sbuf sb;
    int flags, error =3D 0, error2;

    ...

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

    ...
}

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

    pa =3D malloc(sizeof(struct pargs) + len, M_PARGS,
        M_WAITOK);
    refcount_init(&pa->ar_ref, 1);
    pa->ar_length =3D 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 `0xfffffffffffff=
fff`
will result in checking `11` against `ps_arg_cache_limit`.

Since `pargs_alloc` takes `len` as a `signed int`, the value passed to it w=
ill
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 =3D 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 impossib=
le
for a buffer overflow to occur here.

There is another possibility though; if `req->newlen` is `-12`, the allocat=
ion
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

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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-207629-8>