git: c92ac2c311c6 - stable/13 - netlink: fix snl_writer and linear_buffer re-allocation logic

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Wed, 27 Dec 2023 21:06:17 UTC
The branch stable/13 has been updated by kp:

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

commit c92ac2c311c6fe18d57dd4395c75686f0e053a87
Author:     Igor Ostapenko <pm@igoro.pro>
AuthorDate: 2023-12-12 18:26:21 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2023-12-27 20:53:21 +0000

    netlink: fix snl_writer and linear_buffer re-allocation logic
    
    - Use the correct base pointer after re-allocation to avoid buffer
      overflows.
    
    - Maintain correct snl_writer.size, which avoids redundant memory
      allocation, e.g. a need for ~1k bytes may end up with ~32k
      linear_buffer actually allocated.
    
    This fixes a pfctl regression at least for armv7 after the addrule logic
    migration to netlink:
      ffbf25951e7b ("pf: convert rule addition to netlink")
    
    The add rule command creates a bigger than default size netlink requests
    which triggers the re-allocation logic.
    
    Reviewed by:    kp
    MFC after:      2 weeks
    Differnetial Revision:  https://reviews.freebsd.org/D43003
    
    (cherry picked from commit 0c511bafdd5b309505c13c8dc7c6816686d1e103)
---
 sys/netlink/netlink_snl.h | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/sys/netlink/netlink_snl.h b/sys/netlink/netlink_snl.h
index 78d0f75333e3..8c31c5d31671 100644
--- a/sys/netlink/netlink_snl.h
+++ b/sys/netlink/netlink_snl.h
@@ -714,18 +714,23 @@ snl_realloc_msg_buffer(struct snl_writer *nw, size_t sz)
 	if (nw->error)
 		return (false);
 
-	void *new_base = snl_allocz(nw->ss, new_size);
-	if (new_base == NULL) {
+	if (snl_allocz(nw->ss, new_size) == NULL) {
 		nw->error = true;
 		return (false);
 	}
+	nw->size = new_size;
 
-	memcpy(new_base, nw->base, nw->offset);
-	if (nw->hdr != NULL) {
-		int hdr_off = (char *)(nw->hdr) - nw->base;
-		nw->hdr = (struct nlmsghdr *)(void *)((char *)new_base + hdr_off);
+	void *new_base = nw->ss->lb->base;
+	if (new_base != nw->base) {
+		memcpy(new_base, nw->base, nw->offset);
+		if (nw->hdr != NULL) {
+			int hdr_off = (char *)(nw->hdr) - nw->base;
+
+			nw->hdr = (struct nlmsghdr *)
+			    (void *)((char *)new_base + hdr_off);
+		}
+		nw->base = new_base;
 	}
-	nw->base = new_base;
 
 	return (true);
 }