aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/netmap
diff options
context:
space:
mode:
authorVincenzo Maffione <vmaffione@FreeBSD.org>2022-04-05 23:26:02 +0000
committerEd Maste <emaste@FreeBSD.org>2022-04-05 23:26:02 +0000
commit00ca345e83ada8b68e302f5406f9799209872c90 (patch)
treebe40643fcbe6c4d8c96c98b450b6d59db77d1245 /sys/dev/netmap
parent5b789e0c92a7c363b36111b1f75519f2acd21f97 (diff)
netmap: Fix integer overflow in nmreq_copyin
An unsanitized field in an option could be abused, causing an integer overflow followed by kernel memory corruption. This might be used to escape jails/containers. Reported by: Reno Robert and Lucas Leong (@_wmliang_) of Trend Micro Zero Day Initiative Security: CVE-2022-23085 (cherry picked from commit 694ea59c7021c25417e6d516362d2f59b4e2c343) (cherry picked from commit 9df8dd3ea36c8b3abe8fc182647472ca9cd83efd) Approved by: so Security: FreeBSD-SA-22:04.netmap
Diffstat (limited to 'sys/dev/netmap')
-rw-r--r--sys/dev/netmap/netmap.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 0bc723f6963d..c635c3d66314 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3096,7 +3096,7 @@ nmreq_opt_size_by_type(uint32_t nro_reqtype, uint64_t nro_size)
int
nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
{
- size_t rqsz, optsz, bufsz;
+ size_t rqsz, optsz, bufsz, optbodysz;
int error = 0;
char *ker = NULL, *p;
struct nmreq_option **next, *src, **opt_tab;
@@ -3144,8 +3144,18 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user)
error = copyin(src, &buf, sizeof(*src));
if (error)
goto out_err;
+ /* Validate nro_size to avoid integer overflow of optsz and bufsz. */
+ if (buf.nro_size > NETMAP_REQ_MAXSIZE) {
+ error = EMSGSIZE;
+ goto out_err;
+ }
optsz += sizeof(*src);
- optsz += nmreq_opt_size_by_type(buf.nro_reqtype, buf.nro_size);
+ optbodysz = nmreq_opt_size_by_type(buf.nro_reqtype, buf.nro_size);
+ if (optbodysz > NETMAP_REQ_MAXSIZE) {
+ error = EMSGSIZE;
+ goto out_err;
+ }
+ optsz += optbodysz;
if (rqsz + optsz > NETMAP_REQ_MAXSIZE) {
error = EMSGSIZE;
goto out_err;