git: 242a062841e7 - stable/13 - nvme: Fix memory leak in pt ioctl commands

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Mon, 09 Oct 2023 00:59:01 UTC
The branch stable/13 has been updated by markj:

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

commit 242a062841e7166d8354470835dc1d94773b5c01
Author:     David Sloan <david.sloan@eideticom.com>
AuthorDate: 2023-09-07 16:22:21 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2023-10-09 00:41:52 +0000

    nvme: Fix memory leak in pt ioctl commands
    
    When running nvme passthrough commands through the ioctl interface
    memory is mapped with vmapbuf() but not unmapped. This results in leaked
    memory whenever a process executes an nvme passthrough command with a
    data buffer. This can be replicated with a simple c function (error
    checks skipped for brevity):
    
    void leak_memory(int nvme_ns_fd, uint16_t nblocks) {
            struct nvme_pt_command pt = {
                    .cmd = {
                            .opc = NVME_OPC_READ,
                            .cdw12 = nblocks - 1,
                    },
                    .len = nblocks * 512, // Assumes devices with 512 byte lba
                    .is_read = 1, // Reads and writes should both trigger leak
            }
            void *buf;
    
            posix_memalign(&buf, nblocks * 512);
            pt.buf = buf;
            ioctl(nvme_ns_fd, NVME_PASSTHROUGH_COMMAND, &pt);
            free(buf);
    }
    
    Signed-off-by: David Sloan <david.sloan@eideticom.com>
    
    PR:             273626
    Reviewed by:    imp, markj
    MFC after:      1 week
    
    (cherry picked from commit 7ea866eb14f8ec869a525442c03228b6701e1dab)
---
 sys/dev/nvme/nvme_ctrlr.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index ae1aea18adb6..84aa402af4f8 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -1319,8 +1319,9 @@ nvme_ctrlr_passthrough_cmd(struct nvme_controller *ctrlr,
 		mtx_sleep(pt, mtx, PRIBIO, "nvme_pt", 0);
 	mtx_unlock(mtx);
 
-err:
 	if (buf != NULL) {
+		vunmapbuf(buf);
+err:
 		uma_zfree(pbuf_zone, buf);
 		PRELE(curproc);
 	}