git: 0d1f1dc951c6 - releng/12.3 - netmap: Fix integer overflow in nmreq_copyin

From: Ed Maste <emaste_at_FreeBSD.org>
Date: Wed, 06 Apr 2022 03:04:45 UTC
The branch releng/12.3 has been updated by emaste:

URL: https://cgit.FreeBSD.org/src/commit/?id=0d1f1dc951c667f9d993acba42358d115997564e

commit 0d1f1dc951c667f9d993acba42358d115997564e
Author:     Vincenzo Maffione <vmaffione@FreeBSD.org>
AuthorDate: 2022-04-05 23:19:58 +0000
Commit:     Ed Maste <emaste@FreeBSD.org>
CommitDate: 2022-04-05 23:19:58 +0000

    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 95602165e33a3045a27245cc1e61e67bf4feeed1)
    
    Approved by:    so
    Security:       FreeBSD-SA-22:04.netmap
---
 sys/dev/netmap/netmap.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c
index 6532856b21a1..cefc72c60817 100644
--- a/sys/dev/netmap/netmap.c
+++ b/sys/dev/netmap/netmap.c
@@ -3086,7 +3086,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;
@@ -3134,8 +3134,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;