Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 12 Mar 2017 13:48:24 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r315155 - in head/sys: kern sys
Message-ID:  <201703121348.v2CDmOpp070774@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Sun Mar 12 13:48:24 2017
New Revision: 315155
URL: https://svnweb.freebsd.org/changeset/base/315155

Log:
  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

Modified:
  head/sys/kern/kern_event.c
  head/sys/kern/kern_ktrace.c
  head/sys/sys/ktrace.h

Modified: head/sys/kern/kern_event.c
==============================================================================
--- head/sys/kern/kern_event.c	Sun Mar 12 13:42:40 2017	(r315154)
+++ head/sys/kern/kern_event.c	Sun Mar 12 13:48:24 2017	(r315155)
@@ -887,6 +887,15 @@ kern_kqueue(struct thread *td, int flags
 	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 kev
 	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 kev
 
 #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 kev
 
 #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

Modified: head/sys/kern/kern_ktrace.c
==============================================================================
--- head/sys/kern/kern_ktrace.c	Sun Mar 12 13:42:40 2017	(r315154)
+++ head/sys/kern/kern_ktrace.c	Sun Mar 12 13:48:24 2017	(r315155)
@@ -132,7 +132,7 @@ static SYSCTL_NODE(_kern, OID_AUTO, ktra
 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");
 

Modified: head/sys/sys/ktrace.h
==============================================================================
--- head/sys/sys/ktrace.h	Sun Mar 12 13:42:40 2017	(r315154)
+++ head/sys/sys/ktrace.h	Sun Mar 12 13:48:24 2017	(r315155)
@@ -276,7 +276,7 @@ void	ktrcapfail(enum ktr_cap_fail_type, 
 	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>



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