Ktracing kevent(2) calls with unusual arguments might leads to an
overly large allocation requests. When ktrace-ing io, sys_kevent() allocates memory to copy the requested changes and reported events. Allocations are sized by the incoming syscall lengths arguments, which are user-controlled, and might cause overflow in calculations or too large allocations. Since io trace chunks are limited by ktr_geniosize, there is no sense it even trying to satisfy unbounded allocations. Export ktr_geniosize and clamp the buffers sizes in advance. PR: 217435 Reported by: Tim Newsham <tim.newsham@nccgroup.trust> Sponsored by: The FreeBSD Foundation MFC after: 1 week
This commit is contained in:
parent
2b665a98b5
commit
1e4296c919
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=315155
@ -887,6 +887,15 @@ kern_kqueue(struct thread *td, int flags, struct filecaps *fcaps)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static size_t
|
||||
kev_iovlen(int n, u_int kgio)
|
||||
{
|
||||
|
||||
if (n < 0 || n >= kgio / sizeof(struct kevent))
|
||||
return (kgio);
|
||||
return (n * sizeof(struct kevent));
|
||||
}
|
||||
|
||||
#ifndef _SYS_SYSPROTO_H_
|
||||
struct kevent_args {
|
||||
int fd;
|
||||
@ -910,6 +919,7 @@ sys_kevent(struct thread *td, struct kevent_args *uap)
|
||||
struct iovec ktriov;
|
||||
struct uio *ktruioin = NULL;
|
||||
struct uio *ktruioout = NULL;
|
||||
u_int kgio;
|
||||
#endif
|
||||
|
||||
if (uap->timeout != NULL) {
|
||||
@ -922,13 +932,15 @@ sys_kevent(struct thread *td, struct kevent_args *uap)
|
||||
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(td, KTR_GENIO)) {
|
||||
kgio = ktr_geniosize;
|
||||
ktriov.iov_base = uap->changelist;
|
||||
ktriov.iov_len = uap->nchanges * sizeof(struct kevent);
|
||||
ktriov.iov_len = kev_iovlen(uap->nchanges, kgio);
|
||||
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 = kev_iovlen(uap->nevents, kgio);
|
||||
ktriov.iov_len = uap->nevents * sizeof(struct kevent);
|
||||
ktruioout = cloneuio(&ktruio);
|
||||
}
|
||||
@ -939,9 +951,9 @@ sys_kevent(struct thread *td, struct kevent_args *uap)
|
||||
|
||||
#ifdef KTRACE
|
||||
if (ktruioin != NULL) {
|
||||
ktruioin->uio_resid = uap->nchanges * sizeof(struct kevent);
|
||||
ktruioin->uio_resid = kev_iovlen(uap->nchanges, kgio);
|
||||
ktrgenio(uap->fd, UIO_WRITE, ktruioin, 0);
|
||||
ktruioout->uio_resid = td->td_retval[0] * sizeof(struct kevent);
|
||||
ktruioout->uio_resid = kev_iovlen(td->td_retval[0], kgio);
|
||||
ktrgenio(uap->fd, UIO_READ, ktruioout, error);
|
||||
}
|
||||
#endif
|
||||
|
@ -132,7 +132,7 @@ static SYSCTL_NODE(_kern, OID_AUTO, ktrace, CTLFLAG_RD, 0, "KTRACE options");
|
||||
static u_int ktr_requestpool = KTRACE_REQUEST_POOL;
|
||||
TUNABLE_INT("kern.ktrace.request_pool", &ktr_requestpool);
|
||||
|
||||
static u_int ktr_geniosize = PAGE_SIZE;
|
||||
u_int ktr_geniosize = PAGE_SIZE;
|
||||
SYSCTL_UINT(_kern_ktrace, OID_AUTO, genio_size, CTLFLAG_RWTUN, &ktr_geniosize,
|
||||
0, "Maximum size of genio event payload");
|
||||
|
||||
|
@ -276,7 +276,7 @@ void ktrcapfail(enum ktr_cap_fail_type, const cap_rights_t *,
|
||||
ktrstruct("sockaddr", (s), ((struct sockaddr *)(s))->sa_len)
|
||||
#define ktrstat(s) \
|
||||
ktrstruct("stat", (s), sizeof(struct stat))
|
||||
|
||||
extern u_int ktr_geniosize;
|
||||
#else
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
Loading…
Reference in New Issue
Block a user