Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 19 Dec 2025 18:06:11 +0000
From:      Dag-Erling=?utf-8?Q? Sm=C3=B8rg?=rav <des@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 1a67e18678f6 - stable/14 - ipfilter: Prevent stack buffer overflow
Message-ID:  <69459413.22ac8.2ce0e534@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch stable/14 has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=1a67e18678f68e616896ace72f79cd4e399b0bd3

commit 1a67e18678f68e616896ace72f79cd4e399b0bd3
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2025-12-16 16:11:24 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2025-12-19 18:06:01 +0000

    ipfilter: Prevent stack buffer overflow
    
    When copying ipfs data from user space, don't just check that the payload
    length is nonzero, but also that it does not exceed the size of the stack
    buffer we're copying it into.
    
    While we're at it, use a union to create a buffer of the exact size we
    need instead of guessing that 2048 will be enough (and not too much).
    
    Finally, check the size of the payload once it gets to where it's used.
    
    MFC after:      3 days
    Reported by:    Ilja Van Sprundel <ivansprundel@ioactive.com>
    Reviewed by:    cy
    Differential Revision:  https://reviews.freebsd.org/D54194
    
    (cherry picked from commit a34c50fbd2a52bb63acde82e5aec4cb57880e39b)
---
 sbin/ipf/libipf/interror.c             |  5 ++++
 sys/netpfil/ipfilter/netinet/ip_sync.c | 51 ++++++++++++++++++++++++----------
 2 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/sbin/ipf/libipf/interror.c b/sbin/ipf/libipf/interror.c
index 5b3836f36d60..73521a67a1b8 100644
--- a/sbin/ipf/libipf/interror.c
+++ b/sbin/ipf/libipf/interror.c
@@ -472,6 +472,11 @@ log" },
 	{	110019,	"sync update could not find NAT entry" },
 	{	110020,	"unrecognised sync NAT command" },
 	{	110021,	"ioctls are not handled with sync" },
+	/* missing entries 110022-110024 */
+	{	110025,	"invalid payload length (sync create state)" },
+	{	110026,	"invalid payload length (sync update state)" },
+	{	110027,	"invalid payload length (sync create NAT)" },
+	{	110028,	"invalid payload length (sync update NAT)" },
 /* -------------------------------------------------------------------------- */
 	{	120001,	"null data pointer for iterator" },
 	{	120002,	"unit outside of acceptable range" },
diff --git a/sys/netpfil/ipfilter/netinet/ip_sync.c b/sys/netpfil/ipfilter/netinet/ip_sync.c
index b7afe45c8f7e..51b2e544ec52 100644
--- a/sys/netpfil/ipfilter/netinet/ip_sync.c
+++ b/sys/netpfil/ipfilter/netinet/ip_sync.c
@@ -412,13 +412,16 @@ ipf_sync_write(ipf_main_softc_t *softc, struct uio *uio)
 {
 	ipf_sync_softc_t *softs = softc->ipf_sync_soft;
 	synchdr_t sh;
-
-	/*
-	 * THIS MUST BE SUFFICIENT LARGE TO STORE
-	 * ANY POSSIBLE DATA TYPE
-	 */
-	char data[2048];
-
+	union ipf_sync_data {
+		union ipf_sync_state_data {
+			ipstate_t create;
+			synctcp_update_t update;
+		} state;
+		union ipf_sync_nat_data {
+			nat_t create;
+			syncupdent_t update;
+		} nat;
+	} data;
 	int err = 0;
 
 #  if defined(__NetBSD__) || defined(__FreeBSD__)
@@ -497,18 +500,18 @@ ipf_sync_write(ipf_main_softc_t *softc, struct uio *uio)
 		 * needed for the request
 		 */
 
-		/* not supported */
-		if (sh.sm_len == 0) {
+		/* too short or too long */
+		if (sh.sm_len == 0 || sh.sm_len > sizeof(data)) {
 			if (softs->ipf_sync_debug > 2)
-				printf("uiomove(data zero length %s\n",
-					"not supported");
+				printf("uiomove(data) invalid length %d\n",
+					sh.sm_len);
 			IPFERROR(110006);
 			return (EINVAL);
 		}
 
 		if (uio->uio_resid >= sh.sm_len) {
 
-			err = UIOMOVE(data, sh.sm_len, UIO_WRITE, uio);
+			err = UIOMOVE(&data, sh.sm_len, UIO_WRITE, uio);
 
 			if (err) {
 				if (softs->ipf_sync_debug > 2)
@@ -522,9 +525,9 @@ ipf_sync_write(ipf_main_softc_t *softc, struct uio *uio)
 					sh.sm_len);
 
 			if (sh.sm_table == SMC_STATE)
-				err = ipf_sync_state(softc, &sh, data);
+				err = ipf_sync_state(softc, &sh, &data);
 			else if (sh.sm_table == SMC_NAT)
-				err = ipf_sync_nat(softc, &sh, data);
+				err = ipf_sync_nat(softc, &sh, &data);
 			if (softs->ipf_sync_debug > 7)
 				printf("[%d] Finished with error %d\n",
 					sh.sm_num, err);
@@ -654,6 +657,11 @@ ipf_sync_state(ipf_main_softc_t *softc, synchdr_t *sp, void *data)
 	{
 	case SMC_CREATE :
 
+		if (sp->sm_len != sizeof(sn)) {
+			IPFERROR(110025);
+			err = EINVAL;
+			break;
+		}
 		bcopy(data, &sn, sizeof(sn));
 		KMALLOC(is, ipstate_t *);
 		if (is == NULL) {
@@ -720,6 +728,11 @@ ipf_sync_state(ipf_main_softc_t *softc, synchdr_t *sp, void *data)
 		break;
 
 	case SMC_UPDATE :
+		if (sp->sm_len != sizeof(su)) {
+			IPFERROR(110026);
+			err = EINVAL;
+			break;
+		}
 		bcopy(data, &su, sizeof(su));
 
 		if (softs->ipf_sync_debug > 4)
@@ -895,6 +908,11 @@ ipf_sync_nat(ipf_main_softc_t *softc, synchdr_t *sp, void *data)
 			break;
 		}
 
+		if (sp->sm_len != sizeof(*nat)) {
+			IPFERROR(110027);
+			err = EINVAL;
+			break;
+		}
 		nat = (nat_t *)data;
 		bzero((char *)n, offsetof(nat_t, nat_age));
 		bcopy((char *)&nat->nat_age, (char *)&n->nat_age,
@@ -918,6 +936,11 @@ ipf_sync_nat(ipf_main_softc_t *softc, synchdr_t *sp, void *data)
 		break;
 
 	case SMC_UPDATE :
+		if (sp->sm_len != sizeof(su)) {
+			IPFERROR(110028);
+			err = EINVAL;
+			break;
+		}
 		bcopy(data, &su, sizeof(su));
 
 		for (sl = softs->syncnattab[hv]; (sl != NULL);


help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69459413.22ac8.2ce0e534>