From ca62b42d44a6871f84d2280c8c31340cb2537e27 Mon Sep 17 00:00:00 2001 From: Martin Belanger Date: Tue, 5 May 2026 17:04:52 -0400 Subject: [PATCH] libnvme: fix NULL handle dereference in discovery and identify paths libnvme_ctrl_get_transport_handle() opens the device lazily and returns NULL if the open fails. This can happen when a udev-triggered nvmf-connect@.service fires for a discovery controller that is already in the process of being removed: the device is still visible in sysfs at scan time but the kernel returns EAGAIN on open because the controller is no longer in LIVE state. None of the callers checked the returned handle before passing it to libnvme_get_log() or libnvme_submit_admin_passthru(), causing a segmentation fault. Add NULL handle guards with appropriate log messages in nvme_discovery_log(), nvmf_dim(), and libnvme_ctrl_identify(). Add a silent safety net with a comment in libnvme_get_log() itself as a last line of defence against future callers that omit the check. Signed-off-by: Martin Belanger Assisted-by: Claude:claude-sonnet-4-6 [Claude Code] --- libnvme/src/nvme/fabrics.c | 13 +++++++++++++ libnvme/src/nvme/nvme-cmds.c | 2 ++ libnvme/src/nvme/tree.c | 6 ++++++ 3 files changed, 21 insertions(+) diff --git a/libnvme/src/nvme/fabrics.c b/libnvme/src/nvme/fabrics.c index 4572b9c5b7..2e049fb5ed 100644 --- a/libnvme/src/nvme/fabrics.c +++ b/libnvme/src/nvme/fabrics.c @@ -1389,6 +1389,12 @@ static int nvme_discovery_log(libnvme_ctrl_t ctrl, struct libnvme_transport_handle *hdl; hdl = libnvme_ctrl_get_transport_handle(ctrl); + if (!hdl) { + libnvme_msg(ctx, LIBNVME_LOG_DEBUG, + "%s: failed to get discovery log, device not accessible\n", + name); + return -ENODEV; + } struct libnvme_passthru_cmd cmd; log = __libnvme_alloc(sizeof(*log)); @@ -1641,6 +1647,13 @@ static int nvmf_dim(libnvme_ctrl_t c, enum nvmf_dim_tas tas, __u8 trtype, __u32 tel; int ret; + if (!hdl) { + libnvme_msg(ctx, LIBNVME_LOG_DEBUG, + "%s: failed to perform DIM, device not accessible\n", + c->name); + return -ENODEV; + } + if (!c->s) { libnvme_msg(ctx, LIBNVME_LOG_ERR, "%s: failed to perform DIM. subsystem undefined.\n", diff --git a/libnvme/src/nvme/nvme-cmds.c b/libnvme/src/nvme/nvme-cmds.c index f3c378e811..c4ff61570a 100644 --- a/libnvme/src/nvme/nvme-cmds.c +++ b/libnvme/src/nvme/nvme-cmds.c @@ -36,6 +36,8 @@ __public int libnvme_get_log(struct libnvme_transport_handle *hdl, struct libnvme_passthru_cmd *cmd, bool rae, __u32 xfer_len) { + if (!hdl) + return -ENODEV; /* safety net; callers must validate hdl */ __u64 offset = 0, xfer, data_len = cmd->data_len; __u64 start = (__u64)cmd->cdw13 << 32 | cmd->cdw12; __u64 lpo; diff --git a/libnvme/src/nvme/tree.c b/libnvme/src/nvme/tree.c index 36dc94671f..7c50e99d0c 100644 --- a/libnvme/src/nvme/tree.c +++ b/libnvme/src/nvme/tree.c @@ -1497,6 +1497,12 @@ __public int libnvme_ctrl_identify(libnvme_ctrl_t c, struct nvme_id_ctrl *id) libnvme_ctrl_get_transport_handle(c); struct libnvme_passthru_cmd cmd; + if (!hdl) { + libnvme_msg(c->ctx, LIBNVME_LOG_DEBUG, + "%s: failed to identify ctrl, device not accessible\n", + c->name); + return -ENODEV; + } nvme_init_identify_ctrl(&cmd, id); return libnvme_submit_admin_passthru(hdl, &cmd); }