Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 07 Sep 2023 21:36:02 +0000
From:      bugzilla-noreply@freebsd.org
To:        bugs@FreeBSD.org
Subject:   [Bug 273626] Memory leak in ioctl nvme passthrough commands
Message-ID:  <bug-273626-227@https.bugs.freebsd.org/bugzilla/>

next in thread | raw e-mail | index | archive | help
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=3D273626

            Bug ID: 273626
           Summary: Memory leak in ioctl nvme passthrough commands
           Product: Base System
           Version: 13.2-STABLE
          Hardware: Any
                OS: Any
            Status: New
          Severity: Affects Some People
          Priority: ---
         Component: kern
          Assignee: bugs@FreeBSD.org
          Reporter: david.sloan@eideticom.com

When running nvme passthrough commands through the ioctl interface buffers =
are
never released from the kernel and increase the wired memory count permanen=
tly.
This will eventually lead to system lockup if enough buffers are sent throu=
gh
the passthrough command interface. This can be replicated with C program at=
 the
end of this bug report, which will leak 512 KB of memory per execution. We =
have
tested this on 13.2 and 15-current with the same result.

On inspection of sys/dev/nvme/nvme_ctrlr.c it appears that
nvme_ctrlr_passthrough_cmd() is missing a call to vunmapbuf() on exit when =
user
buffers are mapped. Applying the diff:

diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index c4a75090174..608b738a1ff 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -1361,8 +1361,9 @@ nvme_ctrlr_passthrough_cmd(struct nvme_controller *ct=
rlr,
                mtx_sleep(pt, mtx, PRIBIO, "nvme_pt", 0);
        mtx_unlock(mtx);

-err:
        if (buf !=3D NULL) {
+               vunmapbuf(buf);
+err:
                uma_zfree(pbuf_zone, buf);
                PRELE(curproc);
        }

Resolves the issue.

Example program to reproduce the issue:

#include <dev/nvme/nvme.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h>

#define SZ_512K (512 * 1024)

int nvme_read(int fd, void *data, size_t len, uint64_t pos) {
        // Assumes device with 512 byte lbas
        struct nvme_pt_command pt =3D {
                .cmd =3D {
                        .opc =3D NVME_OPC_READ,
                        // LBA
                        .cdw10 =3D (pos / 512) & 0xffffffff,
                        .cdw11 =3D (pos / 512) >> 32,
                        // nblocks
                        .cdw12 =3D len / 512 - 1,
                },
                .buf =3D data,
                .len =3D len,
                .is_read =3D 1,
        };
        return ioctl(fd, NVME_PASSTHROUGH_CMD, &pt);
}

int main(int argc, const char **argv) {
        void *buf;
        int rc;
        int fd;

        if (argc !=3D 2) {
                fprintf(stderr, "Expected single nvme namespace argument\n"=
);
                exit(1);
        }

        fd =3D open(argv[1], O_RDWR);
        if (fd =3D=3D -1) {
                fprintf(stderr, "error opening device %s: %m\n", argv[1]);
                exit(1);
        }

        rc =3D posix_memalign(&buf, 4096, SZ_512K);
        if (rc) {
                errno =3D rc;
                fprintf(stderr, "error allocating buffer %m\n");
                exit(1);
        }

        rc =3D nvme_read(fd, buf, SZ_512K, 0);
        if (rc) {
                fprintf(stderr, "error reading from nvme device: %m\n");
                exit(1);
        }

        free(buf);
        close(fd);

        return 0;
}

--=20
You are receiving this mail because:
You are the assignee for the bug.=



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-273626-227>