Commit Graph

1251 Commits

Author SHA1 Message Date
Jens Axboe
00ef2248c5 nvme fixes for Linux 7.3
- Harden the tcp host and target against malformed PDUs: reject C2HData
    for a non-read command, bound an over-long PDU before copying it, and
    reject unsolicited H2CData (Yehyeong, Shivam)
  - Fix circular locking on TLS queues (Xixin)
  - Fix a soft lockup when scanning sparse namespace ID space (Mohamed)
  - Fix racy access to the FDP placement id array (Kanchan)
  - RDMA host and target fixes for a double cleanup on the queue_rq
    error path and a queue leak when the connect backlog is exceeded
    (Xixin)
  - Authentication fixes: drain the target's expiry work before the SQ
    is freed, and release the DH-CHAP secret when parsing fails (Kazuki,
    Xu Rao)
  - Fix nvme-fc options double free when nvme_add_ctrl() fails (Niklas)
  - Add missing SRCU grace period to nvme_alloc_ns() error path (Tristan)
  - Skip zoned limits update when the zone info query failed (Chao)
  - Reject enabling a target namespace with no device path (Seokgyu)
  - Add opcode filtering for fault injection (Mohamed)
  - Drop the kernel-doc comments from nvme-tcp.h (Randy)
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE3Fbyvv+648XNRdHTPe3zGtjzRgkFAmqZ46MACgkQPe3zGtjz
 RglHuRAAhB+37HZ4wsYuwIud6IwF4rrXMv/EU1C87Nt6ORXiTG892ECT+4G4ruZo
 GTxFl6UB+i8GRw+RivMpZAWoLtEclU1GZ/ijPpgQ4+QKva60q29/2oQQiqT+x5us
 Nhez9uuC1hywxY+HfVDfvx44ISXwPG/8ZTrGMfuEO8kbmiczY8X5LxnSicgWLTc8
 PTdXvSDw5mtinzCPozRDVuFRTcDwUhM3NzVIv7MVXgEyY1sCwcPbmj8GdCkFco1G
 WnIpWP3WplnO7yNcwMN+sSFvq8PjBFfW+LJ/25WRLQFvTpF5zwejPXNWPt90USU4
 hA9kXua1CRHuApKUeNSLMQ3PG2pbB+NjIN31ZpBnveXplmIudoQuT+wLwltBg3te
 9doRCqCGLMCNu+qPFquUOOr9+6+36pBlFTynNy5WGqen0YwY4/UEG4PEU649J3Ve
 N10KY+ttHgi3bY6JdcCVlDhdzGW/rSobNz1GL4IpqPcYdZsvMqSyLrQpZfdKfp5m
 4KWYyiVmydq6ixHpZF1yEM9y2+RZGi9AtOi6CCY5pNDt7lS257htsNSTX9T3pWcH
 IeknLIuseNEW1IgUa7RPUrEkQJsiQx7eb6wI13otJULA60T40rISshuC8yGZblni
 4zu5PQiaecjqXSWQfenEi6tvPuu9jV7YsuvK5x5qs21DnFy7pUo=
 =YJ4v
 -----END PGP SIGNATURE-----

Merge tag 'nvme-7.3-2026-09-03' of git://git.infradead.org/nvme into block-7.3

Pull NVMe fixes from Keith:

"- Harden the tcp host and target against malformed PDUs: reject C2HData
   for a non-read command, bound an over-long PDU before copying it, and
   reject unsolicited H2CData (Yehyeong, Shivam)
 - Fix circular locking on TLS queues (Xixin)
 - Fix a soft lockup when scanning sparse namespace ID space (Mohamed)
 - Fix racy access to the FDP placement id array (Kanchan)
 - RDMA host and target fixes for a double cleanup on the queue_rq
   error path and a queue leak when the connect backlog is exceeded
   (Xixin)
 - Authentication fixes: drain the target's expiry work before the SQ
   is freed, and release the DH-CHAP secret when parsing fails (Kazuki,
   Xu Rao)
 - Fix nvme-fc options double free when nvme_add_ctrl() fails (Niklas)
 - Add missing SRCU grace period to nvme_alloc_ns() error path (Tristan)
 - Skip zoned limits update when the zone info query failed (Chao)
 - Reject enabling a target namespace with no device path (Seokgyu)
 - Add opcode filtering for fault injection (Mohamed)
 - Drop the kernel-doc comments from nvme-tcp.h (Randy)"

* tag 'nvme-7.3-2026-09-03' of git://git.infradead.org/nvme: (21 commits)
  nvme-tcp.h: drop kernel-doc comments, fix a few descriptions
  nvme-fc: fix double free of fabrics options when nvme_add_ctrl() fails
  nvmet: reject namespace enable without device path
  nvmet-auth: Synchronize timeout work during SQ teardown
  MAINTAINERS: update nvme entry
  nvmet-tcp: reject unsolicited H2CData PDUs
  nvme-tcp: defer TLS inline send to io_work
  nvmet-tcp: fix out-of-bounds write when receiving an over-long PDU
  nvme-tcp: return -EPROTO for a C2HData on a write
  nvmet: print namespace IDs as unsigned 32bit value
  nvme: print namespace IDs as unsigned 32bit value
  nvme: remove stale namespaces by NSID range during scan
  nvme: add missing SRCU grace period in error path
  nvme-fabrics: fix DHCHAP secret leak on parse failure
  nvmet-rdma: fix queue leak when connect backlog is exceeded
  nvme: add opcode filtering for fault injection
  nvme: fix racy access to FDP placement id array
  nvme: set ns->head in nvme_alloc_ns_head
  nvme-rdma: fix -EIO cleanup order in queue_rq
  nvme: skip the zoned limits update if the zone info query failed
  ...
2026-09-03 19:48:07 -06:00
Seokgyu Choi
09d0c07bd9 nvmet: reject namespace enable without device path
A newly allocated namespace has a NULL device_path until userspace
configures the device_path attribute.

If buffered_io is enabled before device_path is configured,
nvmet_bdev_ns_enable() returns -ENOTBLK and nvmet_ns_enable() falls
back to nvmet_file_ns_enable(). The latter passes the NULL
device_path to filp_open(), causing a NULL pointer dereference in
getname_kernel().

Reject namespace enable when device_path has not been configured.

Reported-by: syzbot+f613f9f010ec98eb9d86@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=f613f9f010ec98eb9d86
Signed-off-by: Seokgyu Choi <tjrrb0313@gmail.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-09-03 14:15:11 -07:00
Kazuki Hanai
eaa948c0e1 nvmet-auth: Synchronize timeout work during SQ teardown
nvmet_auth_sq_free() cancels auth_expired_work with
cancel_delayed_work(). If the work has already started, cancellation does
not wait for the callback. Transport teardown can consequently free or
reuse the queue containing struct nvmet_sq while
nvmet_auth_expired_work() still accesses that SQ.

Add a teardown-specific helper that synchronously drains the delayed work
before freeing authentication state, and use it from nvmet_sq_destroy().
Keep the non-synchronous helper for in-band authentication state cleanup,
where the SQ owner remains alive.

Fixes: 1a70200f40 ("nvmet-auth: expire authentication sessions")
Cc: stable@vger.kernel.org
Signed-off-by: Kazuki Hanai <hnkz.64@gmail.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-09-03 14:15:11 -07:00
Shivam Kumar
db62b35cbc nvmet-tcp: reject unsolicited H2CData PDUs
nvmet_tcp_handle_h2c_data_pdu() accepts an H2CData PDU after only checking
that its TTAG is a valid in-range command index and that the command's
data buffers are mapped. It never checks that the target has actually
solicited that data by sending an R2T for the command.

A remote host can abuse this. It submits a write command that takes the
R2T path and, before the target transmits the R2T, sends an H2CData PDU
for that command's tag. The data completes the command early, and when
the command then fails synchronously (e.g. a length mismatch caught by
nvmet_check_transfer_len()), it is completed a second time. Each
completion calls nvmet_tcp_queue_response(), so the same command is added
to queue->resp_list twice while it is still linked; the second llist_add()
makes the node point to itself (lentry->next == lentry).

nvmet_tcp_process_resp_list() then walks that self-referential node and
adds the command to resp_send_list twice. With CONFIG_DEBUG_LIST this
trips the "list_add double add" check (kernel BUG); without it the loop
never terminates and the nvmet_tcp workqueue wedges (soft-lockup). It is
remotely triggerable and needs no authentication on an allow_any_host
subsystem.

Track whether an R2T has been transmitted for a command and reject an
H2CData PDU that arrives before it. The flag is cleared on command reuse
(nvmet_tcp_get_cmd() zeroes cmd->flags) and stays set across the multiple
H2CData PDUs of a single solicited transfer.

Fixes: 872d26a391 ("nvmet-tcp: add NVMe over TCP target driver")
Cc: stable@vger.kernel.org
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Shivam Kumar <kumar.shivam43666@gmail.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-09-03 14:15:10 -07:00
Shivam Kumar
14cc5a7e77 nvmet-tcp: fix out-of-bounds write when receiving an over-long PDU
nvmet_tcp_try_recv_pdu() reads a PDU header into the fixed 128-byte
queue->pdu union, then computes the remaining payload length as

	queue->left = hdr->hlen - queue->offset + hdgst;

and reads that many more bytes into &queue->pdu + queue->offset, without
ever bounding the result against sizeof(queue->pdu).

A struct nvme_tcp_icreq_pdu is itself 128 bytes, exactly the size of the
union. Once a header digest has been negotiated (hdgst = 4), a second
ICReq passes the hlen == nvmet_tcp_pdu_size() check but yields
queue->left = 128 - 8 + 4 = 124, so bytes 8..132 are written into the
128-byte buffer -- 4 bytes past its end, over queue->hdr_digest and
queue->data_digest. Those bytes are attacker-controlled (an ICReq
carries no digest), and the duplicate ICReq is only rejected later,
after the overflow. A remote unauthenticated host can thus corrupt
kernel memory adjacent to the receive buffer.

Reject any PDU whose declared length would read past the end of
queue->pdu before the second recv.

Fixes: 872d26a391 ("nvmet-tcp: add NVMe over TCP target driver")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Shivam Kumar <kumar.shivam43666@gmail.com>
Cc: stable@vger.kernel.org
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-09-03 14:15:10 -07:00
Mohamed Khalfella
59fe1cbc57 nvmet: print namespace IDs as unsigned 32bit value
struct nvmet_ns.nsid is a u32, but a few messages print it with %d.
An NSID larger than 0x7fffffff is rendered as a negative number, which
is misleading in general and particularly so for the configfs messages
that echo back the NSID the user just asked for.

For example:
[  T200] nvmet: adding nsid -16 to subsystem mysubsystem

Print them with %u. The invalid-NSID error in nvmet_ns_make() keeps its
%#x because the two values it rejects, 0 and NVME_NSID_ALL, are more
readable in hex format. No functional change other than how the NSID is
formatted.

Fixes: a07b4970f4 ("nvmet: add a generic NVMe target")
Fixes: c6925093d0 ("nvmet: Optionally use PCI P2P memory")
Fixes: 5a47c2080a ("nvmet: support reservation feature")
Signed-off-by: Mohamed Khalfella <mkhalfella@purestorage.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-09-03 14:15:10 -07:00
Linus Torvalds
66498c75b4 dmaengine updates for v7.3
Core:
   - New API to combine configuration and preparation and users
 
  New Support:
   - Mediatek MT8189 SoC uart dma support
 
  Updates:
   - Designware dma driver flatten desc structures and simplify code,
     interrupt-path groundwork changes, first part of PCI EP DMA support
   - Updates to zynqmp_dma with runtime PM and device removal improvments
   - Xilinx dma optimizations for AXIDMA and MCDMA channel management
 -----BEGIN PGP SIGNATURE-----
 
 iQIyBAABCgAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmqMgZEACgkQfBQHDyUj
 g0e82w/4oLwj2QUjUO3QEO2l4E/RVS2/7UyCYKoJDAh66aM8Z3QjQ+lUvy+4wHHE
 H8AtTpRzGEPpqqU+BckHEySf8mNhlA4ULhX17aPc+NKqYNlW8p2L63kPFYggI1ja
 Z6/zVFrJDLwWTI0bSxAyJ6OoaObSXY0P6qpMcXKcqoHc981+EHMGrt/iVJM4Et/c
 Q6nFMxIMgxYPI1VCMSrJqOBA4ZvymyWBisJPZf6SK0iH3PnaBnGWWWilpT8eUJxm
 /MbVf2aUMetdK1+QVx1nNQUdb1eyAw50zFgbeDFDTXQ85Mfbvwh8XxxuT4wXJS5b
 8MFwIEUq6iRgyjZYlykmFYBXw1A3SZWuWMUuMic4l13lw7dxk92wR31j99pIRaV3
 g2iykz+gzQNQ5RNPuo/9j0s26FAmMNxbFW1RPAMnoVc33vZakV4ueaYtIy7s7mMJ
 eDrE6YNDW24DWfWrSxkQGCW1qFGBUY20dXZ0sBmhUxpTLB0ubPZrWLvKKZe/qTUJ
 wmrGNtTBLAYJMsGBm5VMybXwrQXa2Hvqa6KKFR2TdjpdcJwyWVHzRPpR+sJ7GfxZ
 Lz59ODW3x1MnukRQS/T+RXGT42Tzk+qQQ+xK/yCrXq0VkxE3010n7SglTEEygGYP
 Zk2eos4fARpXOUNqAxoKTVRyvQBxrIrHuJuQjAys2RhLHARuCQ==
 =lUcr
 -----END PGP SIGNATURE-----

Merge tag 'dmaengine-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine

Pull dmaengine updates from Vinod Koul:
 "Core:

   - New API to combine configuration and preparation and users

  New hardware support:

   - Mediatek MT8189 SoC uart dma support

  Updates:

   - Designware dma driver flatten desc structures and simplify code,
     interrupt-path groundwork changes, first part of PCI EP DMA support

   - Updates to zynqmp_dma with runtime PM and device removal
     improvments

   - Xilinx dma optimizations for AXIDMA and MCDMA channel management"

* tag 'dmaengine-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/dmaengine: (73 commits)
  dmaengine: dw-edma: Mark emulated IRQ as level-triggered
  dmaengine: idxd: assign all engines to group 0 in IAA defaults
  dmaengine: qcom_hidma: remove conditional return with no effect
  dmaengine: qcom-bam-dma: fix autosuspend cleanup during removal
  dmaengine: fsl-edma: tracing: no ptr dereference during log output
  dmaengine: dw-edma: Program endpoint function numbers
  dmaengine: dw-edma-pcie: Add chip flags to match data
  dmaengine: dw-edma-pcie: Handle optional data blocks
  dmaengine: dw-edma-pcie: Factor out descriptor block address lookup
  dmaengine: dw-edma-pcie: Add register offset match flag
  dmaengine: dw-edma-pcie: Add platform ops to match data
  dmaengine: dw-edma-pcie: Rename vsec_data to dma_data
  dmaengine: dw-edma-pcie: Add capability match data
  dmaengine: dw-edma-pcie: Track non-LL mode in DMA data
  dmaengine: dw-edma: Add partial channel ownership mode
  dmaengine: dw-edma: Initialize IRQ data before requesting IRQs
  dmaengine: dw-edma: Add core quiesce operations
  dmaengine: dw-edma: Add per-channel interrupt routing control
  dmaengine: dw-edma: Factor out HDMA interrupt setup helper
  dmaengine: dw-edma: Defer channel IRQ handling to workqueue
  ...
2026-08-24 12:21:15 -07:00
Linus Torvalds
21bd0802cd RDMA v7.3 merge window pull
Quite alot of buf fixes again:
 
 - Assorted locking, bounds-checking, cleanup, and error-path fixes across
   UCMA/CMA, bng_re, bnxt_re, cxgb4, EFA, ERDMA, HFI1, HNS, ionic, iRDMA,
   mlx4/mlx5, RXE, SIW, SRP/SRPT, and iSER target.
 
 - netlink report for max # of supported resources
 
 - get_zeroed_page()/etc removal
 
 - Robust udata for ionic
 
 - Allow unique RDMA device names per network namespace
 
 - Completion counters and v2 admit queue support for EFA
 
 - UC QP support for MANA
 
 - Completion timestamps for ionic
 
 - Harden uverbs data validation and resource lifetime handling, fixing several core use-after-free conditions.
 
 - bnxt_re toggle-page ownership and lifetime bug fixes
 
 - dmabuf SRQ support for mlx5
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRRRCHOFoQz/8F5bUaFwuHvBreFYQUCaoeO2wAKCRCFwuHvBreF
 YcyJAQCn8JeqTuayLchCARJX+9fazTaJES9zj41i3M8a7BfxCAEA2b266g0S660m
 7eQ761NiIb1iklSl9rmt8vM22EMcngM=
 =qcwp
 -----END PGP SIGNATURE-----

Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma

Pull RDMA updates from Jason Gunthorpe:
 "About the normal size, still a lot of AI bug fixes and so on, but some
  interesting new functionality too:

   - Assorted locking, bounds-checking, cleanup, and error-path fixes
     across UCMA/CMA, bng_re, bnxt_re, cxgb4, EFA, ERDMA, HFI1, HNS,
     ionic, iRDMA, mlx4/mlx5, RXE, SIW, SRP/SRPT, and iSER target.

   - netlink report for max # of supported resources

   - get_zeroed_page()/etc removal

   - Robust udata for ionic

   - Allow unique RDMA device names per network namespace

   - Completion counters and v2 admit queue support for EFA

   - UC QP support for MANA

   - Completion timestamps for ionic

   - Harden uverbs data validation and resource lifetime handling,
     fixing several core use-after-free conditions.

   - bnxt_re toggle-page ownership and lifetime bug fixes

   - dmabuf SRQ support for mlx5"

* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma: (160 commits)
  RDMA/ucma: Allow path records to exactly fit the output buffer
  RDMA/uverbs: Guard legacy bundles without method_elm
  RDMA/efa: Add support for 128B admin v2 SQ entry
  RDMA/efa: Generalize the admin SQ
  RDMA/efa: Decouple admin command payload from admin header
  RDMA/rxe: Fix OOB in free_rd_atomic_resources()
  RDMA/cma: Fix WARNING in res_to_rt
  RDMA/cxgb4: Free debugfs on registration failure
  RDMA/cxgb4: Cancel reg_work before freeing device on remove
  RDMA/ucma: Lock the handler in ucma_set_ib_path()
  RDMA/ucma: Lock the handler in ucma_write_cm_event()
  RDMA/erdma: restrict the driver to little-endian systems
  RDMA/ionic: Embed counter driver data in rdma_counter allocation
  RDMA/ionic: Cap eq_count to the eth driver's interrupt vector budget
  RDMA/siw: Fix use-after-free in siw_accept()
  IB/isert: post the full-feature receive buffers after session registration
  IB/isert: delay the final Login Response until the session is registered
  RDMA/srp: fix heap information leak on a truncated SRP_CRED_REQ
  RDMA/erdma: Hold QP references for AE and CM processing
  RDMA/erdma: Hold CQ references when processing EQ events
  ...
2026-08-21 11:48:54 -07:00
Xixin Liu
fb1ed67788 nvmet-rdma: fix queue leak when connect backlog is exceeded
When pending disconnecting queues exceed the backlog limit, the
connect path only drops the device reference and leaks the newly
allocated queue and its IB resources.

Fixes: badc53620f ("nvme: target: rdma: fix ndev refcount leak on queue connect")
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Xixin Liu <liuxixin@kylinos.cn>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-08-19 07:52:05 -07:00
Maurizio Lombardi
f1a8846e06 nvmet: fix max_qid race between configfs and controller allocation
The function nvmet_subsys_attr_qid_max_store() can race against
nvmet_alloc_ctrl() when a subsystem's max_qid limit is modified.

Suppose max_qid is currently 64. If nvmet_alloc_ctrl() executes:
ctrl->sqs = kzalloc_objs(struct nvmet_sq *, subsys->max_qid + 1);
and at this exact point, a userspace process changes max_qid to 128,
nvmet_subsys_attr_qid_max_store() will set the new max_qid value. It
attempts to delete active controllers to force a reconnect, but the
new controller won't be deleted because it hasn't been added to the
subsys->ctrls list yet.

nvmet_alloc_ctrl() then proceeds and adds the new controller to the
subsys->ctrls list. Later, when nvmet_install_queue() is called, it
will see max_qid set to 128, but the memory allocated for sqs is only
sized for 64 entries. This results in a KASAN out-of-bounds warning
and potential memory corruptions.

Fix this by protecting the queue allocations and list insertion in
nvmet_alloc_ctrl() with down_read(&nvmet_config_sem). Because
nvmet_subsys_attr_qid_max_store() acquires down_write(&nvmet_config_sem)
to modify the attribute, this safely prevents the configfs writer from
modifying max_qid during controller creation.

Copy the max_qid from the subsystem to the controller's structure
during the allocation; ctrl->max_qid never changes as long as the
controller remains in LIVE state, so this will prevent similar race
conditions.

Fixes: 3e980f5995 ("nvmet: expose max queues to configfs")
Reported-by: syzbot+2626e846cd2585c9aa67@syzkaller.appspotmail.com
Signed-off-by: Maurizio Lombardi <mlombard@redhat.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-08-13 09:26:44 -07:00
Xixin Liu
86985da126 nvmet: zns: reject full zone report when buffer is too small
Zone Management Receive uses the Partial Report (PR) bit in dword 13.  On a
partial report (PR bit set), the host accepts an incomplete listing and
Number of Zones must not exceed the zone descriptors copied to the host
buffer.  On a full report (PR bit clear), Number of Zones is the total
number of matching zones and every descriptor must fit in the buffer (ZNS
Command Set Specification Rev 1.2, section 3.4.2).

nvmet_bdev_zone_zmgmt_recv_work() already caps Number of Zones for partial
reports, but on a full report it may still succeed when the buffer only
holds part of the matching descriptors.  Reject the command in that case.

Signed-off-by: Xixin Liu <liuxixin@kylinos.cn>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-08-11 08:53:29 -07:00
Guixin Liu
f594863967 nvmet: fix NULL pointer dereference in nvmet_execute_identify_ns_zns()
When a host issues an Identify command with CNS 05h (I/O Command Set
specific Identify Namespace) and CSI 02h (ZNS) targeting a file-backed
namespace, nvmet_execute_identify_ns_zns() calls bdev_is_zoned() on
req->ns->bdev. A file-backed namespace has no block device, so
req->ns->bdev is NULL and bdev_is_zoned() dereferences it, oopsing.

The I/O command set is selected by the host-supplied CSI field and the
command is routed here whenever CONFIG_BLK_DEV_ZONED is enabled,
independent of the namespace backing type, so any file-backed namespace
is exposed.

Reject the command with Invalid Field when the namespace is not backed
by a block device.

Fixes: aaf2e048af ("nvmet: add ZBD over ZNS backend support")
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-08-11 08:53:28 -07:00
Shin'ichiro Kawasaki
c9e9bb7579 nvmet: pci-epf: fix use-after-free in nvmet_pci_epf_exec_iod_work()
nvmet_pci_epf_exec_iod_work() submits an I/O command with req->execute()
and then waits for the command to complete and transfers the data back
to the host. This wait is not needed for commands that do not transfer
data from the device to the host. To decide whether that wait is needed,
it reads iod->data_len and iod->dma_dir after calling req->execute().

However, once req->execute() is called, the command may complete
asynchronously on another CPU. For commands that do not require a
device-to-host data transfer, nvmet_pci_epf_queue_response() calls
nvmet_pci_epf_complete_iod() directly, which can free the iod before it
reads iod->data_len and iod->dma_dir, resulting in the KFENCE use-after-
free:

 BUG: KFENCE: use-after-free read in nvmet_pci_epf_exec_iod_work+0x288/0x798 [nvmet_pci_epf]

 Use-after-free read at 0x00000000fdfa6d03 (in kfence-#63):
  nvmet_pci_epf_exec_iod_work+0x288/0x798 [nvmet_pci_epf]
  process_one_work+0x15c/0x4f0
  worker_thread+0x18c/0x30c
  kthread+0x130/0x140
  ret_from_fork+0x10/0x20

 kfence-#63: 0x00000000e3de0e71-0x00000000c938ad62, size=712, cache=kmalloc-1k

 allocated by task 10 on cpu 0 at 73.995480s (0.005122s ago):
  mempool_kmalloc+0x1c/0x28
  mempool_alloc_noprof+0x40/0x9c
  nvmet_pci_epf_poll_sqs_work+0xd4/0x344 [nvmet_pci_epf]
  process_one_work+0x15c/0x4f0
  worker_thread+0x18c/0x30c
  kthread+0x130/0x140
  ret_from_fork+0x10/0x20

 freed by task 131 on cpu 3 at 73.995521s (0.008385s ago):
  mempool_kfree+0x10/0x20
  mempool_free+0x44/0x64
  nvmet_pci_epf_free_iod+0x88/0x98 [nvmet_pci_epf]
  nvmet_pci_epf_cq_work+0xfc/0x280 [nvmet_pci_epf]
  process_one_work+0x15c/0x4f0
  worker_thread+0x18c/0x30c
  kthread+0x130/0x140
  ret_from_fork+0x10/0x20

Fix this by referring to iod->data_len and iod->dma_dir before calling
req->execute(). The remaining iod accesses such as iod->status are only
reached on the device-to-host read path. In this case,
nvmet_pci_epf_queue_response() signals iod->done instead of freeing the
iod, so the iod stays valid.

Fixes: 0faa0fe6f9 ("nvmet: New NVMe PCI endpoint function target driver")
Cc: stable@vger.kernel.org
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-08-11 08:53:28 -07:00
Yifei Gao
659ae9d02c nvmet: pci-epf: put CQ ref on create_cq mapping failure
nvmet_pci_epf_create_cq() calls nvmet_cq_create(), which takes a
reference on the controller and installs the completion queue. If the
subsequent PCI address-space mapping fails or returns a too-small partial
mapping, the function jumps to err_internal / err_unmap_queue without
calling nvmet_cq_put(). The matching put in nvmet_pci_epf_delete_cq() is
gated on NVMET_PCI_EPF_Q_LIVE, which is only set after the mapping
succeeds, so teardown never releases these references. A remote PCI host
that drives Create IO CQ commands with a failing PRP1/pci_addr therefore
leaks the CQ and a controller reference on each attempt.

Drop the CQ reference on the mapping-failure paths. The err_internal and
err_unmap_queue labels are only reachable after nvmet_cq_create() has
succeeded, so this pairs the create/put correctly.

Fixes: 0faa0fe6f9 ("nvmet: New NVMe PCI endpoint function target driver")
Cc: stable@vger.kernel.org
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Yifei Gao <gyf161023@gmail.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-08-11 08:53:28 -07:00
Guixin Liu
5bb96cc218 nvmet: fix heap out-of-bounds read in nvmet_auth_negotiate()
nvmet_execute_auth_send() allocates the DH-HMAC-CHAP message buffer with
the host-supplied transfer length (tl) and hands it to
nvmet_auth_negotiate() without passing tl along. nvmet_auth_negotiate()
then reads the negotiate header and, for each of the halen hash
identifiers and dhlen DH group identifiers, indexes into the fixed
idlist[60] array (hashes at idlist[0..halen), groups at idlist[30..]).

Neither the transfer length nor halen/dhlen is validated. A malicious or
non-conformant host can report a tl smaller than the negotiate structure,
or a halen/dhlen larger than the array (both are u8, up to 255), making
the loops read past the end of the allocated buffer (heap out-of-bounds
read). The sibling nvmet_auth_reply() already validates tl against the
structure size; the negotiate path did not.

Pass tl into nvmet_auth_negotiate(), reject a tl that does not cover the
negotiate data plus one full protocol descriptor, and reject halen/dhlen
larger than NVME_AUTH_DHCHAP_MAX_DH_IDS.

Fixes: db1312dd95 ("nvmet: implement basic In-Band Authentication")
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-08-11 08:53:26 -07:00
Guixin Liu
751709592d nvmet: propagate percpu_ref_init() failure in nvmet_ns_enable()
The return value of percpu_ref_init() is discarded. At this point ret is
0 from the preceding successful steps, so when the allocation inside
percpu_ref_init() fails the code jumps to the out_pr_exit cleanup chain
which ends with "return ret", i.e. reports success. The configfs enable
store then tells userspace the namespace was enabled even though it was
not and its backing device has already been torn down.

Capture the return value so the failure is propagated.

Fixes: 4082326807 ("nvmet: Fix crash when a namespace is disabled")
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-08-10 12:25:54 -07:00
Guixin Liu
79aba4c940 nvmet: fix NULL pointer dereference in nvmet_execute_identify_nslist()
When a host issues an Identify command with CNS 07h (Active Namespace ID
List for a specific I/O Command Set), nvmet_execute_identify_nslist() is
called with match_css set. The command-set filter dereferences req->ns,
but this handler never calls nvmet_req_find_ns(), so req->ns is always
NULL (nvmet_req_init() resets it to NULL). As soon as an enabled
namespace with an NSID greater than the requested value exists,
req->ns->csi dereferences a NULL pointer and oopses.

Besides the crash, the comparison is logically wrong: to filter the list
by command set it must test the command set of the namespace being
iterated, not a single fixed value. Use the loop variable ns->csi.

Fixes: 61c9967cd6 ("nvmet: implement active command set ns list")
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-08-10 12:25:54 -07:00
Zhengrong Li
0a96b9e440 nvmet: fix Reservation Register Replace for unregistered host with IEKEY
When a host sends a Reservation Register command with RREGA=Replace
and IEKEY=1 without being previously registered, nvmet returns
Reservation Conflict.

The NVMe specification states:

  "A host may replace its reservation key without regard to its
   registration status or current reservation key value by setting
   the Ignore Existing Key (IEKEY) bit to '1' in the Reservation
   Register command."

Fix nvmet_pr_replace() to add a new registrant when the host is not
found in the registrant list and IEKEY is set with a non-zero NRKEY.
If IEKEY is set but NRKEY is zero, return Invalid Field since there
is no valid reservation key to register.

Tested with nvme-cli against nvmet-tcp:

  # no prior registration
  nvme resv-register /dev/nvmeXn1 -n 1 --rrega=2 --iekey --nrkey=0x9999

  Before: RESERVATION_CONFLICT (0x4083)
  After:  success, registrant created with rkey 0x9999

Fixes: 5a47c2080a ("nvmet: support reservation feature")
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Guixin Liu <kanie@linux.alibaba.com>
Signed-off-by: Zhengrong Li <zhengrong_li@linux.alibaba.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-08-10 12:19:16 -07:00
Jiang HongHui
ba98d6796d nvmet-fc: fix invalid free in LS IOD error path
nvmet_fc_alloc_ls_iodlist() advances iod while initializing the LS IOD
array. If an rqstbuf allocation or response buffer DMA mapping fails,
the unwind loop decrements iod past the start of the array. The final
kfree(iod) therefore frees an address before the allocated object.

This can be reproduced with nvme-fcloop and failslab by setting
fail-nth to 6 before creating a target port. KASAN reports:

  BUG: KASAN: invalid-free in nvmet_fc_register_targetport
  Free of addr ffff88816cf8ff48 by task nvmet_fail_nth/9552

Free the original allocation base stored in tgtport->iod instead. With
this fix applied, the same sysfs write with fail-nth=6 returns -ENOMEM
without any KASAN report.

Fixes: c53432030d ("nvme-fabrics: Add target support for FC transport")
Cc: stable@vger.kernel.org
Reviewed-by: Maurizio Lombardi <mlombard@redhat.com>
Assisted-by: Codex:gpt-5
Signed-off-by: Jiang HongHui <jiang_hh2019@163.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-08-10 12:00:29 -07:00
Hari Mishal
bc7f75eba5 nvmet: passthru: fix OOB reads when parsing ns id descriptor list
nvmet_passthru_override_id_descs() walks a namespace identification
descriptor list populated from the underlying passthru controller's
Identify response, which is device reported. The loop advanced pos by
device controlled amounts (sizeof(*cur) + nidl) without checking that
the next descriptor header actually fits inside the buffer, so a
malicious device could push pos to within a few bytes of the buffer end
and cause cur->nidl, cur->nidt or the reserved field to be read past the
allocation.

Additionally, when a CSI descriptor lands exactly at the last valid
header offset, cur + 1 points one byte past the end of the buffer.
The unconditional memcpy(&csi, cur + 1, NVME_NIDT_CSI_LEN) could read
that out-of-bounds byte and copy it back to the initiator via
nvmet_copy_to_sgl(), leaking adjacent heap memory.

Bounds check both the descriptor header and the CSI value before
dereferencing them.

Signed-off-by: Hari Mishal <harimishal1@gmail.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-08-10 11:51:24 -07:00
Ibrahim Hashimov
4a3f00262a nvmet-tcp: bound SGL data length before allocating command buffers
nvmet_tcp_map_data() reads the host-controlled 32-bit sgl->length
and, for the in-capsule offset descriptor (type 0x01), checks it
against port->inline_data_size before use. Any other SGL descriptor
type -- including the non-inline transport SGL data-block descriptor
(type (NVME_TRANSPORT_SGL_DATA_DESC << 4) | NVME_SGL_FMT_TRANSPORT_A,
the type a real host uses for out-of-capsule writes) skips that check
entirely and falls straight through to:

	cmd->req.sg = sgl_alloc(len, GFP_KERNEL, &cmd->req.sg_cnt);

with len taken directly from the wire, unbounded up to 4 GiB.

nvmet_req_init() only parses the command and never inspects
sgl->length, and nvmet_check_transfer_len() -- the only other place
transfer_len is validated -- runs later, from req->execute(), after
the allocation has already happened. For a write command the target
responds with an R2T and parks the command waiting for the host to
send the data; if the host (or an unauthenticated peer that simply
never follows up) never does, the sgl_alloc() buffer stays resident
for the life of the command. NVMe/TCP has no mandatory authentication
in the default configuration, so any peer able to reach the target
portal and complete a Fabrics connect can drive this with a single
crafted command, repeatable across queues and connections for
amplification. This is unbounded kernel memory allocation
triggered by a remote, effectively unauthenticated peer.

Validate len against the same NVMET_TCP_MAXH2CDATA ceiling this file
already uses to bound per-PDU H2C data, for every SGL descriptor type,
before doing any allocation. This closes the gap for the non-inline
descriptor while leaving the existing, tighter inline_data_size check
in place for the in-capsule case.

Runtime-verified on a v6.19 KASAN stand: with this bound in place, a
crafted write command carrying an oversized non-inline SGL length is
rejected before sgl_alloc() runs, where the same request previously
drove an unbounded ~256 MiB kernel allocation (up to 4 GiB) that
stayed resident pending an R2T the host never satisfies.

Fixes: 872d26a391 ("nvmet-tcp: add NVMe over TCP target driver")
Cc: stable@vger.kernel.org
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Ibrahim Hashimov <security@auditcode.ai>
Assisted-by: AuditCode-AI:2026.07
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-08-10 10:34:14 -07:00
Guixin Liu
bf881dd200 nvmet: reject out-of-range mdts values in configfs store
nvmet_param_mdts_store() accepts any integer that kstrtoint() can parse
and stores it directly into port->mdts. The value is only range-checked
later, when the port is enabled: nvmet_enable_port() silently resets
port->mdts to 0 if it is negative or greater than NVMET_MAX_MDTS.

As a result, writing e.g. "mdts=1000" succeeds and reading the attribute
back returns 1000, yet enabling the port quietly turns it into 0. This
is confusing and hides the invalid input from the user.

Validate the value against [0, NVMET_MAX_MDTS] in the store handler and
reject anything out of range with -EINVAL, so the error is reported at
write time and port->mdts never holds a value the port cannot use.

Fixes: 0a5a946486 ("nvmet: introduce new mdts configuration entry")
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-07-29 08:08:01 -07:00
Guixin Liu
581d8bb556 nvmet: fix return status of RMI log page on allocation failure
nvmet_execute_get_log_page_rmi() leaves 'status' holding NVME_SC_SUCCESS
(set by the successful nvmet_req_find_ns() call) when the kzalloc() for
the log buffer fails. It then jumps to the out label and completes the
request with a success status, so the host is told the command succeeded
while no data was transferred.

Initialize 'status' to NVME_SC_INTERNAL, matching the smart log handler,
so an allocation failure is reported as an internal error.

Fixes: 5fd075cdaf ("nvmet: implement rotational media information log")
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-07-29 08:08:00 -07:00
Greg Kroah-Hartman
737a3b5352 nvmet-tcp: Do not WARN on remotely-controlled oversized SGL allocations
When fuzzing the nvme target code, I tripped a kernel warning in
nvmet_tcp_map_data() because the length passed into the allocator is
controlled by the remote initiator.

A remote initiator that sends a command with an SGL claiming a huge
number, can create a scatterlist and iovec allocation of over 1 million
entries, which causes the backing kmalloc call to exceed MAX_PAGE_ORDER
and then the page allocator will trip on a WARN_ON_ONCE_GFP() message:

  WARNING: mm/page_alloc.c:5280 __alloc_frozen_pages_noprof
  Workqueue: nvmet_tcp_wq nvmet_tcp_io_work
  ...
  sgl_alloc_order
  nvmet_tcp_map_data
  nvmet_tcp_try_recv_pdu

As it's never good to trip a kernel warning remotely due to many systems
having panic-on-warn enabled, let's silence it by just add GFP_NOWARN to
the allocation flags.

Assisted-by: gkh_clanker_2000
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-07-28 10:11:11 -07:00
Erni Sri Satya Vennela
eebd08d91d RDMA: Change capability fields in ib_device_attr from int to u32
The capability counter fields in struct ib_device_attr are declared
as signed int, but these values are inherently non-negative. Drivers
maintain their cached caps as u32 and assign them directly into these
int fields; if a cap exceeds INT_MAX the implicit narrowing yields a
negative value visible to the IB core.

Change the signed int capability fields to u32 to match the
underlying nature of the data. Also update consumers across the IB
core, ULPs, NVMe-oF target, RDS, and NFS/RDMA so the new u32 values
are not forced back through signed int or u8 via min()/min_t() or
narrowing local variables.

The nvmet-rdma consumer of max_srq clamps it against
ib_device.num_comp_vectors, which stays a signed int, so that site
uses min_t() instead of min() to handle the signed/unsigned mismatch.

Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Erni Sri Satya Vennela <ernis@linux.microsoft.com>
Link: https://patch.msgid.link/20260709055211.2498307-1-ernis@linux.microsoft.com
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Stefan Metzmacher <metze@samba.org> # smbdirect
Signed-off-by: Leon Romanovsky <leon@kernel.org>
2026-07-12 04:47:44 -04:00
Guixin Liu
1511516478 nvmet: expose reservation state through debugfs
Add a 'reservation' debugfs file under each namespace directory that
shows the persistent reservation state, including enable status,
generation counter, notify mask, current holder info, and the full
registrant list with hostid and reservation key.

Each attribute is emitted as a single "key=value" line so the output is
easy to parse from scripts. The registrant list is emitted as repeated
"reg=" lines. The notify mask is emitted as a comma-separated list of
masked notification names. Empty values are reported as "none". Example
output:

    enable=1
    generation=2
    notify_mask=reg_preempted,resv_released,resv_preempted
    rtype=write_exclusive
    holder=11111111-1111-1111-1111-111111111111,0x1111
    reg=11111111-1111-1111-1111-111111111111,0x1111
    reg=22222222-2222-2222-2222-222222222222,0x2222

When reservation is not enabled only "enable=0" is printed.

The output uses rcu_read_lock() for safe access to the holder and
registrant_list, consistent with other PR read paths.

Reviewed-by: Daniel Wagner <dwagner@suse.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-07-09 10:08:24 -07:00
Guixin Liu
8f82aaf16f nvmet: add namespace-level debugfs directory
Add per-namespace debugfs directory support under the subsystem debugfs
directory. Each enabled namespace gets a ns<nsid>/ directory created
during nvmet_ns_enable() and removed during nvmet_ns_disable().

This provides the infrastructure for exposing namespace-specific debug
information in subsequent patches.

Reviewed-by: Daniel Wagner <dwagner@suse.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-07-09 10:08:08 -07:00
Bryam Vargas
3ddcfb0133 nvmet-auth: zero the AUTH_RECEIVE response buffer
nvmet_execute_auth_receive() allocates the response buffer with kmalloc()
sized by the host-supplied AUTH_RECEIVE allocation length, but the
DH-HMAC-CHAP builders write only a fixed-size message into it. The full
allocation length is then copied to the wire by nvmet_copy_to_sgl(), so a
remote initiator receives the bytes past the built message -- up to nearly
a page of uninitialized slab -- during the pre-authentication handshake.

Allocate the buffer with kzalloc() so the unwritten tail is zeroed before
it is sent; conforming responses are unaffected.

Fixes: db1312dd95 ("nvmet: implement basic In-Band Authentication")
Cc: stable@vger.kernel.org
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-07-06 11:39:52 -07:00
Xixin Liu
3a6d89836a nvme-auth: use crypto_memneq for DH-HMAC-CHAP response comparison
DH-HMAC-CHAP authentication compares HMAC response digests with memcmp().
Standard memcmp() may stop at the first differing byte, which can leak
timing information to a remote attacker and allow incremental recovery
of the expected digest.

Use crypto_memneq() for constant-time comparison on both the host path
that validates the controller Success1 response and the target path that
validates the host Reply digest.  Other memcmp() uses in the NVMe auth
code (e.g. fixed string prefix checks) are not security-sensitive and
are left unchanged.

Signed-off-by: Xixin Liu <liuxixin@kylinos.cn>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-07-06 11:38:44 -07:00
Shin'ichiro Kawasaki
0114dd303b nvmet-rdma: fix response resource leak on queue teardown
When an nvme target with rdma transport is removed while I/Os are in
flight, a response can be posted but its send completion is never
delivered before the connection is torn down. As a result
nvmet_rdma_send_done() and nvmet_rdma_release_rsp() are never called for
the response, and this leaks the allocated RDMA read/write context and
request SGLs.

These leaks are recreated by running blktests nvme/061 with the rdma
transport and the siw driver. Kernel kmemleak feature reports them as
follows:

  unreferenced object 0xffff88812bc490c0 (size 32):
    comm "kworker/2:1H", pid 409, jiffies 4307744490
    backtrace (crc 89afd339):
      __kmalloc_noprof+0x5f9/0x890
      sgl_alloc_order+0x7b/0x380
      nvmet_req_alloc_sgls+0x290/0x4f0 [nvmet]
      nvmet_rdma_map_sgl_keyed+0x241/0x12e0 [nvmet_rdma]
      nvmet_rdma_handle_command+0x73e/0xb80 [nvmet_rdma]
      __ib_process_cq+0x149/0x4c0 [ib_core]
      ib_cq_poll_work+0x49/0x160 [ib_core]
      process_one_work+0x8b2/0x1640
      worker_thread+0x5fd/0xfe0
      kthread+0x367/0x460
      ret_from_fork+0x655/0x9d0
      ret_from_fork_asm+0x1a/0x30

  unreferenced object 0xffff88814bd05e80 (size 64):
    comm "kworker/3:1H", pid 148, jiffies 4295195428
    backtrace (crc e35510cb):
      __kmalloc_noprof+0x5f9/0x890
      rdma_rw_ctx_init+0x333/0x1fa0 [ib_core]
      nvmet_rdma_map_sgl_keyed+0x5c8/0x12e0 [nvmet_rdma]
      nvmet_rdma_handle_command+0x73e/0xb80 [nvmet_rdma]
      __ib_process_cq+0x149/0x4c0 [ib_core]
      ib_cq_poll_work+0x49/0x160 [ib_core]
      process_one_work+0x8b2/0x1640
      worker_thread+0x5fd/0xfe0
      kthread+0x367/0x460
      ret_from_fork+0x655/0x9d0
      ret_from_fork_asm+0x1a/0x30

To avoid the memory leaks, reclaim the memory of the in-flight responses
when the queue QP is torn down. Call nvmet_rdma_free_rsp_resources()
that frees up the RDMA read/write context and the request SGLs of such
responses.

Fixes: 8f000cac6e ("nvmet-rdma: add a NVMe over Fabrics RDMA target driver")
Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-07-06 11:33:15 -07:00
Shin'ichiro Kawasaki
9009617547 nvmet-rdma: factor out response resource cleanup
Move the RDMA read/write context teardown and the request SGL freeing
out of nvmet_rdma_release_rsp() into a new helper function
nvmet_rdma_free_rsp_resources().

This is a refactoring with no functional change, in preparation for the
following patch that uses nvmet_rdma_free_rsp_resources().

Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-07-06 11:33:15 -07:00
Guixin Liu
4fe024eeba nvme: fix typos in reservation related constants
Fix the following spelling errors:
- NVMET_PR_NOTIFI_MASK_ALL -> NVMET_PR_NOTIFY_MASK_ALL
- NVME_PR_LOG_RESERVATOIN_PREEMPTED -> NVME_PR_LOG_RESERVATION_PREEMPTED
- NVME_AEN_RESV_LOG_PAGE_AVALIABLE -> NVME_AEN_RESV_LOG_PAGE_AVAILABLE

Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-07-06 11:13:43 -07:00
Frank Li
a0fba0a49f nvmet: pci-epf: Use dmaengine_prep_config_single_safe() API
Use the new dmaengine_prep_config_single_safe() API to combine the
configuration and descriptor preparation into a single call.

Since dmaengine_prep_config_single_safe() performs the configuration and
preparation atomically and the mutex can be removed.

Tested-by: Niklas Cassel <cassel@kernel.org>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260521-dma_prep_config-v7-7-1f73f4899883@nxp.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
2026-06-30 16:47:24 +05:30
Frank Li
bd00d2c4a1 nvmet: pci-epf: Remove unnecessary dmaengine_terminate_sync() on each DMA transfer
dmaengine_terminate_sync() cancels all pending requests. Calling it for
every DMA transfer is unnecessary and counterproductive. This function is
generally intended for cleanup paths such as module removal, device close,
or unbind operations.

Remove the redundant calls for success path and keep it only at error path.

Tested-by: Niklas Cassel <cassel@kernel.org>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Acked-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260521-dma_prep_config-v7-6-1f73f4899883@nxp.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
2026-06-30 16:47:24 +05:30
Jens Axboe
29264400dd nvme fixes for Linux 7.2
- Apple A11 quirk for sharing tags across admin and IO queues (Nick)
  - Target fix for short AUTH_RECEIVE buffers (Michael)
  - Target fix for SQ refcount leak (Wentao)
  - Target RDMA handling inline data with nonzero offset (Bryam)
  - Target TCP fix handling the TCP_CLOSING state (Maurizio)
  - FC abort fixes in early initialization (Mohamed)
  - Controller device teardown fixes (Maurizio, John)
  - Allocate the target ana_state with the port (Rosen)
  - Quieten sparse and sysfs symbol warnings (John)
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE3Fbyvv+648XNRdHTPe3zGtjzRgkFAmo6m3MACgkQPe3zGtjz
 RgmySw/9FsJ9VJb6qII3+3e9Cse+fXT2OBQxpQQxW+togdgBSxHq5t8xc/wGhrqq
 wXv4+Z6X4ZdZAkSEHleg55mb9ebceRF4tH/Ua3EQi+aQ0YSrSaEdU8oBDlRs6e68
 f/F9L11wke3BK2D8ArHPgjph7hD11FXyI4RmfqNuPkqQdvV0paKWt/6SrLwwy1iz
 zQd+fDUOT+LgRsWD0zXYLxowKQSX4yVoMmigSSVT+JOjsA/vQq+sXjXUAcFZ6xhn
 cJ/FK0HzxDjF9iHyCv5K92zf3olaf4+Bs9Evh7JEJTp2opy0ETTKa2wGzmd9QDSu
 Xkfd0B/2Ecc73CYo7rB7D4asZlVw9y0Auy8BO6RLv27PDKnTeSmfUIkvyiDL4LnJ
 VEPCjLlXAxEGc6bM28UsSUflEe8HvALUgG58Zll3X6YTpwIFOX6PEBUmIzT9RA15
 8GfWeq8ffepNWyBibNClJHQTe5L8QnWg6IOyceIADJUFdCPgTD8w/gysNpL1vYTb
 ew4l+LUYWDiZRIXH1NjOs5ISLjvo8l38WQB+XfC48eKc1ipWC9OOgVsS/wBeXJXD
 mI15wpV3/oFMNW34gcwlSOoOZfd0UAslYa/s3CNMUlUMsFEqJdlRFS3Ty0CC8dZi
 GRqsVqJPJRSJMvrvMCZi8FT30+5azZkR8YB2Zr7PtYLyC52dCPU=
 =M7aO
 -----END PGP SIGNATURE-----

Merge tag 'nvme-7.2-2026-06-23' of git://git.infradead.org/nvme into block-7.2

Pull NVMe fixes from Keith:

"- Apple A11 quirk for sharing tags across admin and IO queues (Nick)
 - Target fix for short AUTH_RECEIVE buffers (Michael)
 - Target fix for SQ refcount leak (Wentao)
 - Target RDMA handling inline data with nonzero offset (Bryam)
 - Target TCP fix handling the TCP_CLOSING state (Maurizio)
 - FC abort fixes in early initialization (Mohamed)
 - Controller device teardown fixes (Maurizio, John)
 - Allocate the target ana_state with the port (Rosen)
 - Quieten sparse and sysfs symbol warnings (John)"

* tag 'nvme-7.2-2026-06-23' of git://git.infradead.org/nvme:
  nvmet-tcp: handle TCP_CLOSING state in nvmet_tcp_state_change
  nvmet-auth: reject short AUTH_RECEIVE buffers
  nvme-fc: Do not cancel requests in io target before it is initialized
  nvme: make nvme_add_ns{_head}_cdev return void
  nvme: make some sysfs diagnostic structures static
  nvmet-rdma: handle inline data with a nonzero offset
  nvme: target: allocate ana_state with port
  nvme: fix crash and memory leak during invalid cdev teardown
  nvmet: fix refcount leak in nvmet_sq_create()
  nvme: quieten sparse warning in valid LBA size check
  nvme-apple: Prevent shared tags across queues on Apple A11
2026-06-23 09:05:44 -06:00
Linus Torvalds
ba9c792c82 for-7.2/block-20260615
-----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCAAuFiEEwPw5LcreJtl1+l5K99NY+ylx4KYFAmowCYEQHGF4Ym9lQGtl
 cm5lbC5kawAKCRD301j7KXHgpjUvD/0YcIgniTL/BDQkEQk4+FBVOqLiyPFPhdEY
 z/zxMfvRDcUx48E5t4uDHMFwytugTtymRpmkpLANUuUHHpigLPWhT1kCjzIc8OOU
 534VJ2Ksay5f3i9gVBhpORmdcBokevdmt5KSqvc+it0k+DNUy1o8DJGcQqPSnRtA
 C5Kk6e9QNHpOR30pNygaxtaAsx2rlyrBYw0zWUy7yeUQqI9X+0yZDLC8FUsVDVXW
 fptHqQN4///4zm8DdNvTAGhGPGCAcyciXQbrJKBrH9DlZuD5XzrDBFieuhZ96H6M
 jvr6eL6XlNx3qd/3x9PYsV4zyArTQZw++XLHakNMoP7Gd3ddSVutfKPLN4TZf5ij
 TA4chrhMoIhrubU8LYmDHhTFFCXoRd5NCG5f6JKu7usEzBQVKNO4IJ4fJDA/efeG
 iy3W1mdyAAefLS/DfH+i5foWUJbl5VXe4H/d1o8uIdgU2y8rM9d6NdSFWIHNbvc/
 Dhq47AHExyWONtIpIPnRjgL9lMVqyG0KjmnPLq8hFhPRUzu5XxvxufyhEfCbWBEr
 x6gWvnQlY35DmZYCLzn0FOJRIpYXy49hcJw+FS6fkMaBELhj+OQ7nbaKvCWTw91H
 utTltXKvYjJwisMlzfH6/V2Gv7bE4ytRwRTU5GKQQjYIn572RUe4DPbPd3SGxm6T
 mt9q2CMGbw==
 =upvV
 -----END PGP SIGNATURE-----

Merge tag 'for-7.2/block-20260615' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux

Pull block updates from Jens Axboe:

 - NVMe pull request via Keith:
     - Per-controller admin and IO timeout sysfs attributes, and
       letting the block layer set request timeouts (Maurizio,
       Maximilian)
     - Multipath passthrough iostats, and PCI P2PDMA enablement for
       multipath devices (Keith, Kiran)
     - A new diag sysfs attribute group exporting per-controller
       counters (retries, multipath failover, error counters, requeue
       and failure counts, reset and reconnect events) (Nilay)
     - FDP configuration validation and bounds check fixes (liuxixin)
     - Various nvmet fixes, including a pre-auth out-of-bounds read in
       the Discovery Get Log Page handler, auth payload bounds
       validation, and tcp error-path leak fixes (Bryam, Tianchu,
       Geliang)
     - nvme-tcp lockdep and workqueue fixes (Shin'ichiro, Kuniyuki,
       Eric)
     - Assorted other fixes and cleanups (John, Yao, Chao, Mateusz,
       Achkinazi, Wentao)

 - MD pull request via Yu Kuai:
     - raid1/raid10 fixes for a deadlock in the read error recovery
       path, error-path detection and bio accounting with cloned bios,
       and an nr_pending leak in the REQ_ATOMIC bad-block error path
       (Abd-Alrhman)
     - PCI P2PDMA propagation from member devices to the RAID device
       (Kiran)
     - dm-raid bio requeue fix, and various smaller fixes and cleanups
       (Benjamin, Chen, Li, Thorsten)

 - Enable Clang lock context analysis for the block layer, with the
   accompanying annotations across queue limits, the blk_holder_ops
   callbacks, crypto, cgroup, iocost, kyber and mq-deadline (Bart)

 - Block status code infrastructure work: a tagged status table, a
   str_to_blk_op() helper, a bio_endio_status() helper, and on top of
   that a new configurable block-layer error injection facility
   (Christoph)

 - DRBD netlink rework, replacing the genl_magic machinery with explicit
   netlink serialization and moving the DRBD UAPI headers to
   include/uapi/linux/ (Christoph Böhmwalder)

 - bvec improvements: a bvec_folio() helper and making the bvec_iter
   helpers proper inline functions (Willy, Christoph)

 - ublk cleanups and a canceling-flag fix for the disk-not-allocated
   case (Caleb, Ming)

 - Partition handling fixes: bound the AIX pp_count scan, fix an of_node
   refcount leak, and replace __get_free_page() with kmalloc() (Bryam,
   Wentao, Mike)

 - Convert numa_node to int in blk_mq_hw_ctx and ->init_request, and add
   WQ_PERCPU to the block workqueue users (Mateusz, Marco)

 - Block statistics and tracing: propagate in-flight to the whole disk
   on partition IO, export passthrough stats, and a new
   block_rq_tag_wait tracepoint (Tang, Keith, Aaron)

 - A round of removals, unexports and cleanups across bio, direct-io and
   the bvec helpers (Christoph)

 - Various driver fixes (mtip32xx use-after-free, rbd snap_count
   validation and strscpy conversion, nbd socket lockdep reclassify,
   virtio-blk zone report clamp, floppy) and a batch of MAINTAINERS
   email/list updates (Coly, Li, Yu, Christoph Böhmwalder)

 - Other little fixes and cleanups all over

* tag 'for-7.2/block-20260615' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: (117 commits)
  MAINTAINERS: Update Coly Li's email address
  block: check bio split for unaligned bvec
  nbd: Reclassify sockets to avoid lockdep circular dependency
  block: add configurable error injection
  block: add a str_to_blk_op helper
  block: add a "tag" for block status codes
  block: add a macro to initialize the status table
  floppy: Drop unused pnp driver data
  block: propagate in_flight to whole disk on partition I/O
  virtio-blk: clamp zone report to the report buffer capacity
  block: optimize I/O merge hot path with unlikely() hints
  drivers/block/rbd: Use strscpy() to copy strings into arrays
  partitions: aix: bound the pp_count scan to the ppe array
  block: Enable lock context analysis
  block/mq-deadline: Make the lock context annotations compatible with Clang
  block/Kyber: Make the lock context annotations compatible with Clang
  block/blk-mq-debugfs: Improve lock context annotations
  block/blk-iocost: Inline iocg_lock() and iocg_unlock()
  block/blk-iocost: Split ioc_rqos_throttle()
  block/crypto: Annotate the crypto functions
  ...
2026-06-16 13:02:47 +05:30
Maurizio Lombardi
7d953c75f0 nvmet-tcp: handle TCP_CLOSING state in nvmet_tcp_state_change
When an NVMe/TCP connection shuts down, the underlying TCP socket can
enter the TCP_CLOSING state (state 11).  Currently, the
nvmet_tcp_state_change() callback does not explicitly handle this state,
which results in harmless but noisy kernel warnings:

nvmet_tcp: queue 2 unhandled state 11

Add TCP_CLOSING to the switch statement alongside TCP_FIN_WAIT2 and
TCP_LAST_ACK to silently ignore the state transition.

Signed-off-by: Maurizio Lombardi <mlombard@redhat.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-06-10 08:14:19 -07:00
Michael Bommarito
779575bc35 nvmet-auth: reject short AUTH_RECEIVE buffers
nvmet_execute_auth_receive() trusts the AUTH_RECEIVE allocation length
after checking only that it is nonzero and matches the transfer length.
In the SUCCESS1 and FAILURE1/default states, that lets a remote NVMe-oF
initiator reach the fixed-size DH-HMAC-CHAP response builders with a
kmalloc() buffer shorter than the response, so nvmet_auth_success1() and
nvmet_auth_failure1() write past the allocation; both only WARN_ON the
short length and then format the message anyway.

Impact: A remote NVMe-oF initiator with access to an auth-enabled target
can trigger a 16-byte heap out-of-bounds write via a one-byte
AUTH_RECEIVE allocation length.

Compute the minimum response length for the current DH-HMAC-CHAP step in
nvmet_auth_receive_data_len() and report a zero data length when the
host-supplied allocation length is shorter, so the existing zero-length
check in nvmet_execute_auth_receive() rejects the command before any
builder runs. The SUCCESS1 minimum is sizeof(struct
nvmf_auth_dhchap_success1_data) plus the HMAC hash length, because the
response hash is written into the rval[] flexible-array tail, so the
minimum is state dependent rather than a flat sizeof. CHALLENGE keeps its
existing variable-length guard in nvmet_auth_challenge().

This is reachable only when in-band DH-HMAC-CHAP authentication is
configured on the target.

Fixes: db1312dd95 ("nvmet: implement basic In-Band Authentication")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5-5-xhigh
Assisted-by: Claude:claude-opus-4-8
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-06-10 07:43:15 -07:00
Bryam Vargas
48c0162f64 nvmet-rdma: handle inline data with a nonzero offset
nvmet_rdma_use_inline_sg() maps the host-controlled inline data offset
into the per-command inline scatterlist.  The bounds check admits any
offset with off + len <= inline_data_size, but the mapping still assumes
the data begins in the first inline page:

	sg->offset = off;
	sg->length = min_t(int, len, PAGE_SIZE - off);

When a port is configured with inline_data_size > PAGE_SIZE (settable up
to max(SZ_16K, PAGE_SIZE)), an offset in (PAGE_SIZE, inline_data_size]
makes "PAGE_SIZE - off" underflow, so sg->length is set to ~4 GiB and
the block backend reads far past the first inline page.  num_pages(len)
also ignores the offset, so an in-bounds offset whose [off, off+len)
span crosses a page boundary under-counts the scatterlist.

Map the offset properly: split it into a page index and an in-page
offset, start the scatterlist at that page, and size the page count from
page_off + len.  Because the request scatterlist may now start at
inline_sg[page_idx] rather than inline_sg[0], generalize the inline-SGL
identity test in nvmet_rdma_release_rsp() to a range test; otherwise the
persistent inline scatterlist is mistaken for an allocated one and
nvmet_req_free_sgls() frees an inline page (and warns in
free_large_kmalloc()).

Fixes: 0d5ee2b2ab ("nvmet-rdma: support max(16KB, PAGE_SIZE) inline data")
Cc: stable@vger.kernel.org
Suggested-by: Keith Busch <kbusch@kernel.org>
Reported-by: Bryam Vargas <hexlabsecurity@proton.me>
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-06-09 14:53:00 -07:00
Rosen Penev
4fd1f5f6a6 nvme: target: allocate ana_state with port
Use a flexible array member to remove one allocation. Simplifies code
slightly.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-06-09 11:18:03 -07:00
Wentao Liang
34b9a83c50 nvmet: fix refcount leak in nvmet_sq_create()
In nvmet_sq_create(), a reference on the ctrl is taken
via kref_get_unless_zero() before calling nvmet_check_sqid().
If nvmet_check_sqid() fails, the function returns the error
directly without releasing the reference, leading to a leak.

Fix this by jumping to the "ctrl_put" label, which already
performs the necessary nvmet_ctrl_put(ctrl). This ensures the
reference is properly released on this error path.

Cc: stable@vger.kernel.org
Fixes: 1eb380caf5 ("nvmet: Introduce nvmet_sq_create() and nvmet_cq_create()")
Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-06-09 09:42:23 -07:00
Jens Axboe
ed60c09f29 nvme updates for Linux 7.2
- Per-controller timeouts
   - Multipath telemetry
   - Namespace format validation
   - Various other fixes
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE3Fbyvv+648XNRdHTPe3zGtjzRgkFAmohV0IACgkQPe3zGtjz
 Rgmc/A//Qm762VuLMr5oV3jtLyADBlNYS5ERMg+O+cefuQ+ckzHZfCQxGnoL6em+
 r1xsaNUqwj1VFykXc5Szdgr7hMRhtDVxYgkiQSpOu/Ui4ewlIlemK/6tZJFu97YG
 eqCkW5sMw8hyOLBs4JI0FYogx4nwSmCLfw8IiWUC5Cqa/j57elgv4aI7SV3fTDkF
 JsOUWE55tzCafWqhgcYngsNz+kjErV8DbEgY34l66ZrrJChLtcLQm0IT1pktwuXR
 KSAAcIBo6XtLM+DHNY68v/LmJD8MWz7BAZTt25aXt8ehRZVc9bYrKLJfZok95nyr
 CT+/Uz5CsyvNpLCOYKmxJV2t+WoqKkyhKQVJWN31Ms1/mO1+8cTydtRNcPH8ic/L
 Wl0m75fb+/uwAoAXgZE8dParDSft7vA0uguaN514qz872f9L3Bd0xZaD4OhfxBdw
 wWtIs+8mI7EBC1sDIgtLVkR/YEsBY+CQTantvZPI0R22fxmgiXQN9K9EKfy+ZJ58
 xH666mOeTmlDA5RUrEs22iMAx5ILCi5HpKX63iCaFDSrJC3ZcGd5vH34I1Csvx8n
 g4t3jzrHDzqB1dIrKknY7cZPLm5g8ny0uTFC7x26O6SVXZ+6TyfYG9gTyONQMZ1O
 AOLc8FCaT2vPVOXOKSTChD9LLZtGyLZjeQEnU2I2qiJpkxX6s+8=
 =W0b9
 -----END PGP SIGNATURE-----

Merge tag 'nvme-7.2-2026-06-04' of git://git.infradead.org/nvme into for-7.2/block

Pull NVMe updates from Keith:

"- Per-controller timeouts
 - Multipath telemetry
 - Namespace format validation
 - Various other fixes"

* tag 'nvme-7.2-2026-06-04' of git://git.infradead.org/nvme: (34 commits)
  nvme: export controller reconnect event count via sysfs
  nvme: export controller reset event count via sysfs
  nvme: export I/O failure count when no path is available via sysfs
  nvme: export I/O requeue count when no path is usable via sysfs
  nvme: export command error counters via sysfs
  nvme: export multipath failover count via sysfs
  nvme: export command retry count via sysfs
  nvme: add diag attribute group under sysfs
  nvme-tcp: lockdep: use dynamic lockdep keys per socket instance
  nvme-tcp: move nvme_tcp_reclassify_socket()
  nvme: validate FDP configuration descriptor sizes
  nvmet-auth: validate reply message payload bounds against transfer length
  nvme: refresh multipath head zoned limits from path limits
  nvme: fix FDP fdpcidx bounds check
  nvme-tcp: Use WQ_PERCPU explicitly if wq_unbound is false.
  nvmet: fix pre-auth out-of-bounds heap read in Discovery Get Log Page
  nvme-multipath: set BIO_REMAPPED on bios remapped to per-path namespace disks
  nvme-multipath: require exact iopolicy names for module parameter
  nvme-multipath: pass NS head to nvme_mpath_revalidate_paths()
  nvme-pci: fix out-of-bounds access in nvme_setup_descriptor_pools
  ...
2026-06-05 05:18:58 -06:00
Tianchu Chen
3a413ece25 nvmet-auth: validate reply message payload bounds against transfer length
nvmet_auth_reply() accesses the variable-length rval[] array using
attacker-controlled hl (hash length) and dhvlen (DH value length) fields
without verifying they fit within the allocated buffer of tl bytes.

A malicious NVMe-oF initiator can craft a DHCHAP_REPLY message with a
small transfer length but large hl/dhvlen values, causing out-of-bounds
heap reads when the target processes the DH public key (rval + 2*hl) or
performs the host response memcmp.

With DH authentication configured, the OOB pointer is passed directly to
sg_init_one() and read by crypto_kpp_compute_shared_secret(), reaching
up to 526 bytes past the buffer. This is exploitable pre-authentication.

Add bounds validation ensuring sizeof(*data) + 2*hl + dhvlen <= tl before
any access to the variable-length fields.

Discovered by Atuin - Automated Vulnerability Discovery Engine.

Fixes: db1312dd95 ("nvmet: implement basic In-Band Authentication")
Cc: stable@vger.kernel.org
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Signed-off-by: Tianchu Chen <flynnnchen@tencent.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-06-03 02:40:33 -07:00
Bryam Vargas
53cd102a7a nvmet: fix pre-auth out-of-bounds heap read in Discovery Get Log Page
nvmet_execute_disc_get_log_page() validates only the dword alignment
of the host-supplied Log Page Offset (lpo).  The 64-bit offset is then
added to a small kzalloc'd buffer that holds the discovery log page
and the result is passed straight to nvmet_copy_to_sgl(), which
memcpy()s data_len bytes out to the host with no source-side bound
check:

    u64 offset      = nvmet_get_log_page_offset(req->cmd);  /* 64-bit host */
    size_t data_len = nvmet_get_log_page_len(req->cmd);     /* 32-bit host */
    ...
    if (offset & 0x3) { ... }                               /* only check */
    ...
    alloc_len = sizeof(*hdr) + entry_size * discovery_log_entries(req);
    buffer = kzalloc(alloc_len, GFP_KERNEL);
    ...
    status = nvmet_copy_to_sgl(req, 0, buffer + offset, data_len);

The Discovery controller is unauthenticated -- nvmet_host_allowed()
returns true unconditionally for the discovery subsystem -- so the call
is reachable pre-authentication by any TCP/RDMA/FC peer that can reach
the nvmet target.  With a discovery log page of ~1 KiB, an attacker
requesting up to 4 KiB starting at offset == alloc_len reads the next
slab page out and gets its content returned over the fabric (an
empirical run on a default nvmet-tcp loopback target leaked 81
canonical kernel pointers in one Get Log Page response).  Pointing the
offset at unmapped kernel memory faults the in-kernel memcpy and
crashes (or panics, on panic_on_oops=1) the target host instead.

The attacker-controlled source-side offset pattern
"nvmet_copy_to_sgl(req, 0, buffer + ATTACKER_OFFSET, ...)" is unique
to nvmet_execute_disc_get_log_page in the entire nvmet codebase: every
other Get Log Page handler in admin-cmd.c either ignores lpo (and
silently starts every response at offset 0) or tracks a local
destination offset with a fixed source pointer.

Validate the host-supplied offset against the log page size, cap the
copy length to what is actually available, and zero-fill any remainder
of the host transfer buffer.  The zero-fill matches the existing
short-response pattern in nvmet_execute_get_log_changed_ns()
(admin-cmd.c) and prevents leaking transport SGL contents when the
host asks for more bytes than the log page contains.

Fixes: a07b4970f4 ("nvmet: add a generic NVMe target")
Cc: stable@vger.kernel.org
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-06-02 03:43:27 -07:00
Wentao Liang
badc53620f nvme: target: rdma: fix ndev refcount leak on queue connect
nvmet_rdma_queue_connect() calls nvmet_rdma_find_get_device() which
acquires a reference on the returned ndev via kref_get(). On the path
where the host queue backlog is exceeded and the function returns
NVME_SC_CONNECT_CTRL_BUSY, reference of ndev is not released, leaking
the kref.

Fix this by adding a goto to the existing put_device label before the
early return.

Fixes: 31deaeb11b ("nvmet-rdma: avoid circular locking dependency on install_queue()")
Cc: stable@vger.kernel.org
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Wentao Liang <vulab@iscas.ac.cn>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-05-27 08:40:35 -07:00
Geliang Tang
7ef789703e nvmet-tcp: check return value of nvmet_tcp_set_queue_sock
The return value of nvmet_tcp_set_queue_sock() is currently ignored in
nvmet_tcp_tls_handshake_done(). If it fails (e.g., due to the socket
not being in TCP_ESTABLISHED state), the socket callbacks will not be
properly set, leading to queue and socket leakage.

Fix this by capturing the return value and calling
nvmet_tcp_schedule_release_queue() on failure to ensure proper cleanup.

Fixes: 675b453e02 ("nvmet-tcp: enable TLS handshake upcall")
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-05-27 07:50:27 -07:00
Geliang Tang
4dae393956 nvmet-tcp: fix page fragment cache leak in error path
In nvmet_tcp_alloc_queue(), when a connection is closed during the
allocation process (e.g., nvmet_tcp_set_queue_sock() returns -ENOTCONN),
the error handling jumps to out_destroy_sq and then to out_ida_remove
without draining the page fragment cache.

Although nvmet_tcp_free_cmd() is called in some error paths to release
individual page fragments, the underlying page cache reference held by
queue->pf_cache is never released. The first allocation using pf_cache
is the call to nvmet_tcp_alloc_cmd() for queue->connect, which happens
after ida_alloc() returns successfully. This results in a page leak each
time a connection fails during allocation, which could lead to memory
exhaustion over time if connections are repeatedly opened and closed.

Fix this by calling page_frag_cache_drain() before freeing the queue
structure in the out_ida_remove label.

Fixes: 872d26a391 ("nvmet-tcp: add NVMe over TCP target driver")
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-05-27 07:16:49 -07:00
Mateusz Nowicki
b040a1a452 block: switch numa_node to int in blk_mq_hw_ctx and init_request
numa_node in blk_mq_hw_ctx and the matching argument of
blk_mq_ops::init_request can be NUMA_NO_NODE (-1).  Declared as
unsigned int, NUMA_NO_NODE becomes UINT_MAX and walks off
nvme_dev::descriptor_pools[] on CONFIG_NUMA=n [1].

Switch the field and the callback prototype to int and update all
in-tree init_request implementations.  No functional change:
cpu_to_node(), kmalloc_node() and blk_alloc_flush_queue() already
take int.

Link: https://lore.kernel.org/linux-nvme/20260522150628.399288-1-mateusz.nowicki@posteo.net/ [1]
Link: https://lore.kernel.org/linux-nvme/20260309062840.2937858-2-iam@sung-woo.kim/
Suggested-by: Caleb Sander Mateos <csander@purestorage.com>
Suggested-by: Sung-woo Kim <iam@sung-woo.kim>
Signed-off-by: Mateusz Nowicki <mateusz.nowicki@posteo.net>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20260523125210.272274-1-mateusz.nowicki@posteo.net
Signed-off-by: Jens Axboe <axboe@kernel.dk>
2026-05-26 11:01:55 -06:00
Maurizio Lombardi
233bbeb4a4 nvmet-loop: do not alloc admin tag set during reset
Currently, resetting a loopback controller unconditionally invokes
nvme_alloc_admin_tag_set() inside nvme_loop_configure_admin_queue().
Doing so drops the old queue and allocates a new one. Consequently,
this reverts the admin queue's timeout (q->rq_timeout) back to the
module default (NVME_ADMIN_TIMEOUT), completely wiping out any custom
timeout values the user may have configured via sysfs and potentially
racing against the sysfs nvme_admin_timeout_store() function
that may dereference the admin_q pointer during the RESETTING state.

Decouple the admin tag set lifecycle from the admin queue
configuration and destruction paths, which are executed during resets;
Specifically:

* Move nvme_alloc_admin_tag_set() into nvme_loop_create_ctrl() so it
  is only allocated once during the initial controller creation.

* Defer the destruction of the admin tag set to
  nvme_loop_delete_ctrl_host() and the terminal error-handling
  paths of nvme_loop_reset_ctrl_work() and
  nvme_loop_create_ctrl().

Reviewed-by: Daniel Wagner <dwagner@suse.de>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Signed-off-by: Maurizio Lombardi <mlombard@redhat.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-05-20 11:45:44 -07:00
Sagi Grimberg
dbbd07d0a7 nvmet-tcp: Fix potential UAF when ddgst mismatch
Shivam Kumar found via vulnerability testing:
When data digest is enabled on an NVMe/TCP connection and a digest
mismatch occurs on a non-final H2C_DATA PDU during an R2T-based
data transfer, the digest error handler in nvmet_tcp_try_recv_ddgst()
calls nvmet_req_uninit() — which performs percpu_ref_put() on the
submission queue — but does NOT mark the command as completed. It
does not set cqe->status, does not modify rbytes_done, and does not
clear any flag. When the subsequent fatal error triggers queue
teardown, nvmet_tcp_uninit_data_in_cmds() iterates all commands,
checks nvmet_tcp_need_data_in() for each one, and finds that the
already-uninited command still appears to need data (because
rbytes_done < transfer_len and cqe->status == 0). It therefore calls
nvmet_req_uninit() a second time on the same command — a double
percpu_ref_put against a single percpu_ref_get.

Reported-by: Shivam Kumar <kumar.shivam43666@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Sagi Grimberg <sagi@grimberg.me>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2026-05-11 08:07:40 -07:00