| Age | Commit message (Collapse) | Author |
|
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
...
|
|
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
...
|
|
for-7.3/block
Pull NVMe updates from Keith:
"- Enable context analysis for the nvme host driver, annotating the
subsystem's locks, along with the LIST_HEAD_GUARDED support it needs
(Nilay, Marco)
- Harden the tcp host and target against malformed PDUs and out of
range SGL lengths (Yehyeong, Ibrahim, Greg)
- Fix unserialized page_frag_cache use in nvme-tcp request setup
(Dmitry)
- Bound identify, FDP and passthrough descriptor parsing to the
allocated buffers (Hari, Guixin)
- Zoned namespace fixes for host and the target (Xixin, Guixin, Yao)
- Apple controller fixes: page aligned admin queue buffers, NVMMU TCB
setup, DMA direction and admin queue teardown (Sven, Gui-Dong)
- Add a namespace level debugfs directory exposing reservation state,
and ABI documentation for the host sysfs and target configfs
interfaces (Guixin)
- Fix cdev and namespace lifetimes (John)
- Parallelize nvme-rdma I/O queue allocation and startup (Surabhi)
- Fix nvmet-rdma response resource leak on queue teardown (Shin'ichiro)
- Authentication fixes: AUTH_RECEIVE buffer and an out of bounds read
in negotiate (Xixin, Bryam, Guixin, Eric)
- Fix pci-epf use-after-free and CQ reference leak (Shin'ichiro, Yifei)
- Reject passthrough of driver managed Set Features (Chao)
- Various error path and teardown fixes across the host and target
addressing issues with use-after-free and leaking resources (Guixin,
Maurizio, Ewan, Zhengrong, Jiang HongHui, Myeonghun, Yang, Geliang,
Yehyeong)
- Various cleanups and typo fixes (Nilay, Guixin, Pan Chuang)"
* tag 'nvme-7.3-2026-08-13' of git://git.infradead.org/nvme: (81 commits)
nvmet: fix max_qid race between configfs and controller allocation
nvme: nvme-fc: Fix nvme_fc_create_hw_io_queues() queue deletion in error path
nvme: ratelimit the completion-path messages driven by device data
nvme-tcp: fix host memory disclosure on R2T for a read command
nvme-tcp: do not accept C2HData based on blk_rq_payload_bytes() alone
nvme-tcp: reject a read that transferred too few bytes
nvmet: zns: reject full zone report when buffer is too small
nvme-tcp: fix usage of page_frag_cache
nvme: reject passthrough of driver-managed Set Features
nvmet: fix NULL pointer dereference in nvmet_execute_identify_ns_zns()
nvmet: pci-epf: fix use-after-free in nvmet_pci_epf_exec_iod_work()
nvmet: pci-epf: put CQ ref on create_cq mapping failure
nvme-apple: Drop the PRP null check chicken bit
nvme-apple: Require page aligned buffers on the admin queue
nvme: Add a quirk for page aligned admin queue buffers
nvme-apple: Never set the opcode in the NVMMU TCB
nvme-apple: Don't set a DMA direction for commands without a data transfer
nvme-apple: Destroy the admin queue on removal
nvmet: fix heap out-of-bounds read in nvmet_auth_negotiate()
nvme: raise FDP placement handle cap to U8_MAX and warn on overflow
...
|
|
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: 3e980f5995e0 ("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>
|
|
nvme_fc_create_hw_io_queues() will call __nvme_fc_delete_hw_queue() for the
last queue on which __nvme_fc_create_hw_queue() reported an error when deleting
all the io queues if they cannot all be created. This is incorrect since the
last queue did not actually get created.
The most recent change to this code was commit 17a1ec08ce70 ("nvme/fc: simplify
error handling of nvme_fc_create_hw_io_queues") which moved the cleanup to the
delete_queues: label and changed the loop bounds, however the code was not
correct prior to this change in a different way. The original commit
e399441de911 ("nvme-fabrics: Add host support for FC transport") had a
different error which called __nvme_fc_delete_hw_queue() on queue index 0 which
is used for the admin queue.
Fix this by correcting the initial loop index when deleting the io queues.
Fixes: 17a1ec08ce70 ("nvme/fc: simplify error handling of nvme_fc_create_hw_io_queues")
Fixes: e399441de911 ("nvme-fabrics: Add host support for FC transport")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-6
Reviewed-by: Maurizio Lombardi <mlombard@redhat.com>
Reviewed-by: Laurence Oberman <loberman@redhat.com>
Reviewed-by: Justin Tee <justin.tee@broadcom.com>
Signed-off-by: Ewan D. Milne <emilne@redhat.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
nvme_find_rq() and nvme_handle_cqe() print an unratelimited message for
every completion queue entry whose command id does not resolve to an
in-flight request. Both are reached from the completion interrupt path
(nvme_irq() -> nvme_poll_cq() -> nvme_handle_cqe()) and the decision to
print is made entirely from device-supplied data, so a controller that
posts a stream of bogus command ids drives unbounded printk from hard
interrupt context.
This is not hypothetical. A single boot under an emulated controller
that posts invalid completions produced 846 "could not locate request
for tag 0x0", 846 "invalid id 0 completed on queue 2" and 123 "genctr
mismatch" lines. Once the tag set has been torn down every subsequent
completion resolves to nothing, so the print rate is bounded only by how
fast the device can post entries.
Ratelimit the three messages. The information they carry is diagnostic
and repeats, so the suppression count printed by the ratelimit helpers
is enough to tell that the condition persists. This matches how the
other device-driven error prints in the driver are already handled, for
example the status messages in nvme_log_error() and
nvme_log_err_passthru().
nvme_find_rq() lives in nvme.h and is shared by pci, tcp, rdma, apple and
target-loop, so all transports are covered.
Found by FuzzNvme.
Signed-off-by: Chao Shi <coshi036@gmail.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
nvme_tcp_handle_r2t() does not check the direction of the request the
R2T refers to. A malicious controller can send an R2T for a READ and
the host will answer it: nvme_tcp_setup_h2c_data_pdu() builds the
H2CData header and nvme_tcp_try_send_data() sends the request's data
buffer. That buffer is the READ destination, so its contents go to the
controller.
The command then completes normally and nothing is logged.
Against a test controller that answers every READ with an R2T, a 4096
byte buffered read returned all 4096 bytes, split over two R2Ts. The
pages contained stale kernel data, including an array of struct page
pointers.
Reject an R2T for a request that is not a write.
Fixes: 3f2304f8c6d6 ("nvme-tcp: add NVMe over TCP host driver")
Cc: stable@vger.kernel.org
Signed-off-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
Commit 25e5cb780e62 ("nvme-tcp: fix possible crash in write_zeroes
processing") established that blk_rq_payload_bytes() must not be read
without first checking blk_rq_nr_phys_segments(), and recorded the
result in nvme_tcp_setup_cmd_pdu() as req->data_len. The receive side
was left as it was.
The two differ for REQ_OP_WRITE_ZEROES, which has no physical segments
but a non-zero blk_rq_bytes(), so setup leaves req->iter untouched
while the receive gate lets a C2HData through and nvme_tcp_recv_data()
copies into whatever the previous command on that tag left there. The
driver-private area is zeroed only when the tag set is allocated.
Reproduced with a test target that leaves a residual iterator on a tag
and then sends a C2HData for a WRITE_ZEROES command on the same tag:
BUG: KASAN: wild-memory-access in _copy_to_iter+0x642/0x1330
Write of size 512 at addr ffe728c2175dfa81 by task kworker/0:1H/103
CPU: 0 UID: 0 PID: 103 Comm: kworker/0:1H Not tainted 7.2.0-rc5-NVMETCP-gf5098b6bae76 #1 PREEMPT(lazy)
Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Workqueue: nvme_tcp_wq nvme_tcp_io_work
Call Trace:
<TASK>
dump_stack_lvl+0x53/0x70
kasan_report+0xce/0x100
? _copy_to_iter+0x642/0x1330
kasan_check_range+0x105/0x1b0
__asan_memcpy+0x3c/0x60
_copy_to_iter+0x642/0x1330
? __pfx_sock_has_perm+0x10/0x10
? worker_thread+0x45b/0xd10
? __pfx__copy_to_iter+0x10/0x10
? _raw_spin_lock_bh+0x83/0xe0
? __pfx__raw_spin_lock_bh+0x10/0x10
__skb_datagram_iter+0xf3/0x820
? __pfx_simple_copy_to_iter+0x10/0x10
? __asan_memcpy+0x3c/0x60
? skb_copy_bits+0x58d/0x830
skb_copy_datagram_iter+0x37/0x120
nvme_tcp_recv_skb+0xa07/0x4320
? __pfx_nvme_tcp_recv_skb+0x10/0x10
__tcp_read_sock+0x1ab/0x810
? __pfx_nvme_tcp_recv_skb+0x10/0x10
? __pfx_lock_sock_nested+0x10/0x10
? __pfx___tcp_read_sock+0x10/0x10
nvme_tcp_try_recv+0x152/0x1e0
? __pfx_nvme_tcp_try_recv+0x10/0x10
? __pfx_mutex_unlock+0x10/0x10
nvme_tcp_io_work+0x1e4/0x6c0
? __schedule+0x181a/0x49f0
? __pfx_nvme_tcp_io_work+0x10/0x10
process_one_work+0x633/0x1030
Keep the blk_rq_payload_bytes() test and add req->data_len to it. The
old test is what rejects a C2HData naming a tag that is no longer in
flight, because blk_update_request() zeroes rq->__data_len on
completion; req->data_len and req->curr_bio are driver-private and
survive completion, so they cannot stand in for it. Setup initialises
the iterator only when both req->curr_bio and req->data_len are set, so
the gate now tests the same two.
Fixes: 25e5cb780e62 ("nvme-tcp: fix possible crash in write_zeroes processing")
Cc: stable@vger.kernel.org
Signed-off-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
nvme_tcp_recv_data() completes a request once the current C2HData PDU
has been consumed. Nothing compares the total bytes received against
the length the command asked for: struct nvme_tcp_request has no
receive-side counter, queue->data_remaining is per queue, and
blk_mq_end_request() completes for blk_rq_bytes(rq) unconditionally
with no residual concept anywhere above.
A controller can therefore answer a 4096-byte read with 512 bytes and
have it reported as a complete read; user space then gets 4096 bytes of
which 3584 are whatever was already in the page. I reproduced that with
a test target.
Count the bytes received and refuse to complete a successful read whose
count does not match, at the two NVME_TCP_F_DATA_SUCCESS paths and in
nvme_tcp_process_nvme_cqe(). The success test shifts req->status right
by one, because the driver keeps the wire value there and shifts it on
completion, so the check must see what the completion path will see.
Only REQ_OP_READ is checked, because there the length comes from the
sectors the request covers; a passthrough command is built by its
submitter, which picks both command and buffer, so the kernel has
nothing to compare against.
Fixes: 3f2304f8c6d6 ("nvme-tcp: add NVMe over TCP host driver")
Cc: stable@vger.kernel.org
Signed-off-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
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>
|
|
nvme uses page_frag_cache to preallocate PDU for each preallocated request
of block device. Block devices are created in parallel threads,
consequently page_frag_cache is used in not thread-safe manner.
That leads to incorrect refcounting of backstore pages and premature free.
That can be catched by !sendpage_ok inside network stack:
WARNING: CPU: 7 PID: 467 at ../net/core/skbuff.c:6931 skb_splice_from_iter+0xfa/0x310.
tcp_sendmsg_locked+0x782/0xce0
tcp_sendmsg+0x27/0x40
sock_sendmsg+0x8b/0xa0
nvme_tcp_try_send_cmd_pdu+0x149/0x2a0
Then random panic may occur.
Fix that by serializing the usage of page_frag_cache.
Fixes: 4e893ca81170 ("nvme_core: scan namespaces asynchronously")
Signed-off-by: Dmitry Bogdanov <d.bogdanov@yadro.com>
Signed-off-by: Daniel Wagner <wagi@kernel.org>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
Since commit b58da2d270db ("nvme: update keep alive interval when kato
is modified"), a Set Features (KATO) passthrough command lets userspace
start keep-alive on any transport. nvme_keep_alive_work() allocates with
BLK_MQ_REQ_RESERVED, but nvme_alloc_admin_tag_set() reserves admin tags
only for fabrics, so on other transports the allocation trips
WARN_ON_ONCE() in blk_mq_get_tag() and fails:
nvme nvme0: keep-alive failed: -11
Several Set Features change controller state the driver manages itself
and cannot react to when set behind its back. Reject these in
nvme_admin_cmd_allowed():
- KATO on non-fabrics (keep-alive is only armed for fabrics; on PCIe
it has no reserved tag and harms idle power states)
- Host Behavior Support, Host Memory Buffer, Number of Queues, and
Autonomous Power State Transition (all driver-managed)
Keep Alive on fabrics is unchanged; I/O commands are unaffected as the
check is confined to the admin path (ns == NULL).
Link: https://lore.kernel.org/linux-nvme/20260523225629.3964037-1-coshi036@gmail.com/
Fixes: b58da2d270db ("nvme: update keep alive interval when kato is modified")
Found by FuzzNvme.
Acked-by: Sungwoo Kim <iam@sung-woo.kim>
Acked-by: Dave Tian <daveti@purdue.edu>
Acked-by: Weidong Zhu <weizhu@fiu.edu>
Signed-off-by: Chao Shi <coshi036@gmail.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
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: aaf2e048af27 ("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>
|
|
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: 0faa0fe6f90e ("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>
|
|
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: 0faa0fe6f90e ("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>
|
|
Now that we program the DMA direction correctly the NULL check that used
to make commands fail passes. Another side effect of this bit was that
non-align buffers on the admin queue were silently allowed and that's
been fixed now as well and we this don't need this chicken bit anymore.
More importantly, starting with the firmware installed with macOS 15,
which is required for M4 but can also be installed on the previous SoCs,
the controller no longer exposes this control register and any access
SErrors instead. Just drop the write entirely.
Fixes: 5bd2927aceba ("nvme-apple: Add initial Apple SoC NVMe driver")
Tested-by: Joshua Peisach <jpeisach@ubuntu.com>
Tested-by: Janne Grunau <j@jannau.net>
Tested-by: Nick Chan <towinchenmi@gmail.com>
Signed-off-by: Sven Peter <sven@kernel.org>
|
|
Now that we have a quick to align buffers on the admin queue to the NVMe
controller page size use it for Apple controllers. This fixes pre-M1
controllers, which always rejected unaligned requests, and also makes
this driver work for M4 SoCs and for M1/M2/M3 SoCs that have been
updated to the firmware shipped with macOS 15.
Fixes: 5bd2927aceba ("nvme-apple: Add initial Apple SoC NVMe driver")
Tested-by: Joshua Peisach <jpeisach@ubuntu.com>
Tested-by: Janne Grunau <j@jannau.net>
Tested-by: Nick Chan <towinchenmi@gmail.com>
Signed-off-by: Sven Peter <sven@kernel.org>
|
|
Apple controllers seem to require any queue buffers on the admin queue
to be aligned to the NVMe controller page size. Weirdly, this constraint
does not apply to the i/o queue where any alignment is fine. This has
always been required on pre-M1 controllers and is required starting with
macOS 15 firmware or post-M4 controllers again. On M1/M2/M3 we only got
away with this because there was a chicken bit to disable this
requirement. Let's add a quirk that enforces this alignment.
Tested-by: Joshua Peisach <jpeisach@ubuntu.com>
Tested-by: Janne Grunau <j@jannau.net>
Tested-by: Nick Chan <towinchenmi@gmail.com>
Signed-off-by: Sven Peter <sven@kernel.org>
|
|
macOS always sets this to zero and the firmware starting with macOS 15
has started to complain about what we're doing here.
Fixes: 5bd2927aceba ("nvme-apple: Add initial Apple SoC NVMe driver")
Tested-by: Joshua Peisach <jpeisach@ubuntu.com>
Tested-by: Janne Grunau <j@jannau.net>
Tested-by: Nick Chan <towinchenmi@gmail.com>
Signed-off-by: Sven Peter <sven@kernel.org>
|
|
Setting the DMA direction for commands that don't do any transfer likely
triggered the PRP NULL check for which we needed a chicken bit. That bit
has disappeared starting with macOS 15 so let's just do this correctly
instead.
Fixes: 5bd2927aceba ("nvme-apple: Add initial Apple SoC NVMe driver")
Tested-by: Joshua Peisach <jpeisach@ubuntu.com>
Tested-by: Janne Grunau <j@jannau.net>
Tested-by: Nick Chan <towinchenmi@gmail.com>
Signed-off-by: Sven Peter <sven@kernel.org>
|
|
The admin queue is allocated with blk_mq_alloc_queue() but never
destroyed. nvme_free_ctrl() only drops the last reference and
blk_mq_exit_queue() and blk_sync_queue() never run: the hctx is never
moved to q->unused_hctx_list and the timeout timer and work stay armed on
a queue that is about to be freed which will eventually oops inside
blk_mq_timeout_work().
This can only be triggered when the controller fails to come up and is
then immediately torn down again which is why no one ever ran into this
before.
Let's just copy what the pcie driver does: unquiesce and destroy the admin
queue before nvme_uninit_ctrl().
With this the following WARN followed by a panic no longer happens:
WARNING: block/blk-mq.c:4390 at blk_mq_release+0x194/0x238, CPU#4: kworker/u34:4/119
CPU: 4 UID: 0 PID: 119 Comm: kworker/u34:4 Not tainted 7.2.0-rc1-dirty #248 PREEMPT
Hardware name: Apple Mac mini (M1, 2020) (DT)
Workqueue: nvme-wq apple_nvme_remove_dead_ctrl_work
pstate: 61400005 (nZCv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
pc : blk_mq_release+0x194/0x238
lr : blk_mq_release+0x58/0x238
sp : ffffc000833a3b50
x29: ffffc000833a3b50 x28: ffff80001d0450f8 x27: ffff800020c95200
x26: 0000000000000088 x25: 0000000000000000 x24: ffff800020f36805
x23: 0000000000000000 x22: ffffc00081a86878 x21: ffff800020be9c60
x20: 0000000000000000 x19: ffff800022501698 x18: 000000000000000a
x17: 7365757165722066 x16: 666f7265776f7020 x15: 0000000000000000
x14: 0000000000000028 x13: 0000000000004def x12: 0000000000000003
x11: 0000000000000000 x10: 0000000000000000 x9 : ffffc000805b4fc8
x8 : ffffc00081915820 x7 : ffffc00081c4f3c8 x6 : 0000000000000001
x5 : 0000000000000004 x4 : ffff800022498d80 x3 : ffffc000833a3b14
x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff800022501698
Call trace:
blk_mq_release+0x194/0x238 (P)
blk_put_queue+0x8c/0xf0
nvme_free_ctrl+0x4c/0x260
device_release+0x44/0x128
kobject_put+0xa0/0x120
put_device+0x1c/0x40
nvme_uninit_ctrl+0x48/0x60
apple_nvme_remove+0x54/0xb0
platform_remove+0x28/0x40
device_remove+0x54/0x98
device_release_driver_internal+
device_release_driver+0x20/0x38
apple_nvme_remove_dead_ctrl_wor
process_one_work+0x1f4/0x770
worker_thread+0x1b8/0x360
kthread+0x140/0x160
ret_from_fork+0x10/0x20
irq event stamp: 448
hardirqs last enabled at (447):in_unlock_irqrestore+0x74/0x80
hardirqs last disabled at (448): [<ffffc000811cf5c0>] el1_brk64+0x20/0x60
softirqs last enabled at (0): [ess+0xb28/0x2698
softirqs last disabled at (0): [<0000000000000000>] 0x0
---[ end trace 0000000000000000
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
Mem abort info:
ESR = 0x0000000096000005
EC = 0x25: DABT (current EL),
SET = 0, FnV = 0
EA = 0, S1PTW = 0
FSC = 0x05: level 1 translation fault
Data abort info:
ISV = 0, ISS = 0x00000005, ISS2 = 0x00000000
CM = 0, WnR = 0, TnD = 0, TagA
GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[0000000000000000] user address
Internal error: Oops: 0000000096000005 [#1] SMP
CPU: 7 UID: 0 PID: 54 Comm: kwor 7.2.0-rc1-dirty #248PREEMPT
Tainted: [W]=WARN
Hardware name: Apple Mac mini (M1, 2020) (DT)
Workqueue: kblockd blk_mq_timeou
pstate: 01400005 (nzcv daif +PAN -UAO -TCO +DIT -SSBS BTYPE=--)
pc : percpu_ref_tryget_many.cons
lr : percpu_ref_tryget_many.constprop.0+0xc0/0x168
sp : ffffc000829cbce0
x29: ffffc000829cbce0 x28: ffff800020be9f48 x27: ffff800013e503c0
x26: 0000000000000108 x25: 000009c05
x23: 0000000000000000 x22: ffffc000819f5000 x21: ffff800020be9f48
x20: ffff8001deda4808 x19: ffff8000a
x17: 00000000580e1fac x16: ffffc00082bbbb7c x15: 0000000000000000
x14: 0000000000000028 x13: 000000001
x11: 0000000000000000 x10: 0000000000000000 x9 : ffffc000829cbc20
x8 : ffffc00081915820 x7 : ffffc0001
x5 : ffff80001ca77d08 x4 : 0000000000000000 x3 : ffff80001ca77cb8
x2 : 0000000000000000 x1 : 000000007
Call trace:
percpu_ref_tryget_many.constpro
blk_mq_timeout_work+0x48/0x298
process_one_work+0x1f4/0x770
worker_thread+0x1b8/0x360
kthread+0x140/0x160
ret_from_fork+0x10/0x20
Code: 91282000 97ed44b2 17ffffd2
---[ end trace 0000000000000000 ]---
Fixes: 5bd2927aceba ("nvme-apple: Add initial Apple SoC NVMe driver")
Tested-by: Joshua Peisach <jpeisach@ubuntu.com>
Tested-by: Janne Grunau <j@jannau.net>
Tested-by: Nick Chan <towinchenmi@gmail.com>
Signed-off-by: Sven Peter <sven@kernel.org>
|
|
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: db1312dd9548 ("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>
|
|
The RUH status buffer and the placement-handle clamp used S8_MAX - 1
(126) as the maximum descriptor count. That value was picked only so the
io-mgmt-receive result fit in a page, not because of any protocol or
driver restriction.
The meaningful upper bound is U8_MAX: write hints (bio->bi_write_stream)
are u8, so placement handles beyond U8_MAX can never be selected. Size
the buffer and clamp nr_plids to U8_MAX.
Suggested-by: Kanchan Joshi <joshi.k@samsung.com>
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Reviewed-by: Kanchan Joshi <joshi.k@samsung.com>
Reviewed-by: Nilay Shroff <nilay@linux.ibm.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
The per-NUMA-node descriptor DMA pools are created lazily from
nvme_init_hctx_common() once the admin tag set is allocated, but they are
only destroyed in nvme_remove() via nvme_release_descriptor_pools(). Any
probe failure after the admin tag set has been allocated unwinds through
the out_disable label and nvme_pci_free_ctrl(), neither of which releases
the pools, leaking the dma_pool objects.
Release the descriptor pools in the out_disable error path. It must not
be added to nvme_pci_free_ctrl(), as that would double-free against
nvme_remove() on the normal teardown path.
Fixes: d977506f8863 ("nvme-pci: make PRP list DMA pools per-NUMA-node")
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: Kanchan Joshi <joshi.k@samsung.com>
Reviewed-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
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: 408232680707 ("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>
|
|
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: 61c9967cd634 ("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>
|
|
nvme_setup_discard() always maps sizeof(struct nvme_dsm_range) *
NVME_DSM_MAX_RANGES = 4096 bytes as the DSM payload however many ranges
the command declares, because some devices ignore the 'Number of Ranges'
field - the Fixes: commit records two that read past the declared ranges.
A single-range discard fills only the first 16 bytes.
Normally the buffer comes from kzalloc() and the other 4080 bytes are
zero. When that allocation fails the code falls back to the
per-controller ctrl->discard_page, which nvme_init_ctrl() obtains with
alloc_page(GFP_KERNEL) and nothing ever zeroes, so those 4080 bytes are
whatever the page last held and are handed to the controller. Reaching
it requires the kzalloc(GFP_ATOMIC | __GFP_NOWARN) to fail, that is
memory pressure; it is not remotely triggerable. Failing the allocation
under KMSAN reproduces it, with the leaked tail full of vmemmap struct
page pointers. The extent in the report is a partial transfer of the
payload, not the whole 4096 bytes; the 16-byte boundary in it is the one
declared range:
[ 11.991601] BUG: KMSAN: uninit-value in dma_map_phys+0x14c8/0x1900
[ 11.991969] dma_map_phys+0x14c8/0x1900
[ 11.992220] dma_map_page_attrs+0xcf/0x130
[ 11.992485] e1000_xmit_frame+0x4099/0x6d10
[ 11.992768] dev_hard_start_xmit+0x22f/0xa80
[ 11.993068] sch_direct_xmit+0x35c/0xcb0
[ 11.993315] __dev_queue_xmit+0x1ee5/0x5eb0
[ 11.993608] ip_finish_output2+0x1903/0x1c30
[ 11.993881] ip_finish_output+0x288/0x870
[ 11.994125] ip_output+0x15e/0x400
[ 11.994365] __ip_queue_xmit+0x1e85/0x1fb0
[ 11.994639] ip_queue_xmit+0x60/0x80
[ 11.994899] __tcp_transmit_skb+0x4e71/0x5fa0
[ 11.995210] tcp_write_xmit+0x3a36/0x9160
[ 11.995533] __tcp_push_pending_frames+0xc5/0x3c0
[ 11.995854] tcp_push+0x7dc/0x840
[ 11.996076] tcp_sendmsg_locked+0x766c/0x8400
[ 11.996371] tcp_sendmsg+0x4b/0x90
[ 11.996572] inet_sendmsg+0x134/0x2a0
[ 11.996823] __sock_sendmsg+0x265/0x360
[ 11.997076] sock_sendmsg+0x100/0x1e0
[ 11.997293] nvme_tcp_try_send+0x196f/0x6370
[ 11.997605] nvme_tcp_queue_rq+0x1d54/0x20b0
[ 11.997882] blk_mq_dispatch_rq_list+0x5ee/0x2e50
[ 11.998175] __blk_mq_sched_dispatch_requests+0x16dc/0x24a0
[ 11.998539] blk_mq_sched_dispatch_requests+0x11b/0x2c0
[ 11.998865] blk_mq_run_work_fn+0x13b/0x280
[ 11.999146] process_scheduled_works+0x966/0x1ad0
[ 11.999465] worker_thread+0xe44/0x1480
[ 11.999709] kthread+0x53b/0x600
[ 11.999927] ret_from_fork+0x29f/0x7c0
[ 12.000191] ret_from_fork_asm+0x1a/0x30
[ 12.000460]
[ 12.000558] Uninit was created at:
[ 12.000788] __alloc_frozen_pages_noprof+0x8bf/0xd30
[ 12.001096] alloc_pages_mpol+0x1d0/0x5f0
[ 12.001326] alloc_pages_noprof+0x102/0x290
[ 12.001627] nvme_init_ctrl+0x5a3/0x9f0
[ 12.001891] nvme_tcp_create_ctrl+0xd75/0x19b0
[ 12.002170] nvmf_dev_write+0x4c68/0x4fd0
[ 12.002426] vfs_write+0x587/0x1a10
[ 12.002636] __x64_sys_write+0x207/0x4f0
[ 12.002874] x64_sys_call+0x2ff0/0x3ea0
[ 12.003123] do_syscall_64+0x147/0x3b0
[ 12.003400] entry_SYSCALL_64_after_hwframe+0x77/0x7f
[ 12.003680]
[ 12.003777] Bytes 16-2843 of 2844 are uninitialized
[ 12.004068] Memory access of size 2844 starts at ffff888109f82000
[ 12.004412]
[ 12.004530] CPU: 0 UID: 0 PID: 101 Comm: kworker/0:1H Not tainted 7.2.0-rc5-NVMECTL-gf5098b6bae76 #1 PREEMPT(lazy)
[ 12.005127] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[ 12.005762] Workqueue: kblockd blk_mq_run_work_fn
[ 12.006073] =====================================================
Allocate the page with __GFP_ZERO. The single allocation site covers
every use of it: bytes no discard has written stay zero, and bytes one
did write hold that controller's own range list, which it has already
been sent.
Fixes: 530436c45ef2 ("nvme: Discard workaround for non-conformant devices")
Cc: stable@vger.kernel.org
Signed-off-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
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: 5a47c2080a73 ("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>
|
|
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: c53432030d86 ("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>
|
|
nvme_tcp_alloc_ctrl() looks opts->host_iface up in &init_net, the boot-time
netns. When called from any other netns - e.g. the selftest's ns2, where
ns2eth1 actually lives - the lookup misses and the controller setup fails
with "invalid interface passed":
nvmet: adding nsid 1 to subsystem nqn.2014-08.org.nvmexpress.mptcpdev
nvmet_tcp: enabling port 24660 (0.0.0.0:24099)
# nvme discover -a 10.1.1.1 --tos=0x10 --host-iface=ns2eth1
nvme_tcp: invalid interface passed: ns2eth1
# failed to add controller, error invalid interface
Look the device up in current->nsproxy->net_ns instead so the check sees
the calling task's netns.
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
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>
|
|
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: 872d26a391da ("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>
|
|
struct bvec_iter::bi_bvec_done is used an offset in the current bvec,
let's rename it accordingly for better clarity. I also plan to use it
for non-bvec based iteration in the future like dma-buf, so drop the
"bvec" part.
Suggested-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Link: https://patch.msgid.link/4e4c21858705a200bd8848ffe4080522e3eb5c1c.1786018753.git.asml.silence@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
|
|
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: 0a5a94648627 ("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>
|
|
quirks_param_set() reuses 'err', which param_set_copystring() left as 0,
as the return value of the whole function. When nvme_parse_quirk_entry()
fails to parse a field, the code jumps to out_free_qlist and returns that
stale 0, so a malformed quirks= parameter is silently accepted as valid.
Set err to -EINVAL before jumping out on a parse failure.
Fixes: 7bb8c40f5ad8 ("nvme: add support for dynamic quirk configuration via module parameter")
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Daniel Wagner <dwagner@suse.de>
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
__nvme_fc_init_request() maps cmd_iu and then rsp_iu for DMA. If the
rsp_iu mapping fails, the original code only recorded the error and fell
through: it left the already-mapped cmd_iu unmapped and still marked the
op as FCPOP_STATE_IDLE before returning. Since blk-mq does not call
.exit_request() when .init_request() fails, the cmd_iu mapping is leaked
for every op whose rsp_iu mapping fails.
Jump to an error path on rsp_iu mapping failure that unmaps cmd_iu and
returns the error without marking the op idle, so it stays in the
FCPOP_STATE_UNINIT state set by the initial memset().
Fixes: e399441de911 ("nvme-fabrics: Add host support for FC transport")
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
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: 5fd075cdaf36 ("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>
|
|
Unlike IO_CMD / IO64_CMD, NVME_IOCTL_SUBMIT_IO never calls
nvme_cmd_allowed(). Unprivileged callers can thus issue I/O on a
partition device or write through a read-only file descriptor.
Pass flags and open_for_write through and reject disallowed commands
with -EACCES.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Yang Xiuwei <yangxiuwei@kylinos.cn>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
Since commit 55b48e23f5c4 ("genirq/devres: Add error handling in
devm_request_*_irq()"), devm_request_irq() automatically logs
detailed error messages on failure. Remove the now-redundant
driver-specific dev_err_probe() calls.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Pan Chuang <panchuang@vivo.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
nvme_pci_configure_admin_queue() enables the controller and then requests
the admin queue interrupt. If queue_request_irq() fails it returns without
disabling the controller, and no caller compensates: nvme_pci_enable() only
frees the IRQ vectors and calls pci_disable_device(), after which
nvme_dev_disable() treats the controller as dead and skips nvme_disable_ctrl().
The controller is left enabled (CC.EN set) on this error path.
Disable it in the failure path, while the PCI device is still enabled so the
CC.EN clear handshake completes.
This issue was identified during our ongoing static-analysis research while
reviewing kernel code.
Fixes: b60503ba432b ("NVMe: New driver")
Cc: stable@vger.kernel.org
Reviewed-by: Christoph Hellwig <hch@lst.de>
Co-developed-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Ijae Kim <ae878000@gmail.com>
Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
Update nvme host driver makefile to enable support for the Clang's
context anaysis.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
After adding Clang context annotations, compiling tcp.c reports the
following warning while context analysis is enabled:
drivers/nvme/host/tcp.c:2572:24: warning: passing pointer to variable 'list' requires holding mutex 'nvme_tcp_ctrl_mutex'
[-Wthread-safety-pointer]
2572 | if (list_empty(&ctrl->list))
| ^
The above warning is triggered because ctrl->list is guarded with mutex
nvme_tcp_ctrl_mutex but when list_empty(&ctrl->list) is invoked it
doesn't acquire nvme_tcp_ctrl_mutex.
Replace list_empty() with list_empty_careful(), which is intended
for lockless inspection of list heads during teardown when no concurrent
list modifications are expected. This suppresses the corresponding
Clang context analysis warning while preserving the existing behavior.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
The nvme_tcp_ctrl_list and nvme_tcp_ctrl::list are protected by
nvme_tcp_ctrl_mutex. Define nvme_tcp_ctrl_list using
LIST_HEAD_GUARDED(nvme_tcp_ctrl_list, nvme_tcp_ctrl_mutex) and
annotate nvme_tcp_ctrl::list using
__guarded_by(&nvme_tcp_ctrl_mutex) so that Clang's context analysis
can validate accesses against the corresponding locking requirements.
It is safe to initialize nvme_tcp_ctrl::list while allocating the
controller object because the list entry has not yet been added to
nvme_tcp_ctrl_list. Annotate the initialization with context_unsafe()
to suppress the corresponding Clang warning.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
After adding Clang lock context annotations in rdma.c, Clang reports
the following warning when context analysis is enabled:
drivers/nvme/host/rdma.c:972:24: warning: passing pointer to variable 'list' requires holding mutex 'nvme_rdma_ctrl_mutex'
[-Wthread-safety-pointer]
972 | if (list_empty(&ctrl->list))
| ^
The warning is triggered because ctrl->list is annotated as being
protected by nvme_rdma_ctrl_mutex, but list_empty(&ctrl->list) is
invoked without holding that mutex.
Replace list_empty() with list_empty_careful(), which is intended
for lockless inspection of list heads during teardown when no concurrent
list modifications are expected. This suppresses the corresponding
context analysis warning while preserving the existing behavior.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
device_list and nvme_rdma_device::entry are protected by
device_list_mutex. Define device_list using
LIST_HEAD_GUARDED(device_list, device_list_mutex) and annotate
nvme_rdma_device::entry with __guarded_by(&device_list_mutex) so that
Clang's context analysis can validate accesses against the corresponding
locking requirements.
Similarly, nvme_rdma_ctrl_list and nvme_rdma_ctrl::list are
protected by nvme_rdma_ctrl_mutex. Define nvme_rdma_ctrl_list using
LIST_HEAD_GUARDED(nvme_rdma_ctrl_list, nvme_rdma_ctrl_mutex) and
annotate nvme_rdma_ctrl::list with __guarded_by(&nvme_rdma_ctrl_mutex).
It is safe to initialize nvme_rdma_ctrl::list while allocating the
controller object because the list entry has not yet been added to
nvme_rdma_ctrl_list. Annotate the initialization with context_unsafe()
to suppress the corresponding Clang context analysis warning.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
nvme_queue::sq_tail, nvme_queue::last_sq_tail and nvme_queue::sq_cmds
are protected by nvme_queue::sq_lock. Annotate each field with
__guarded_by(&sq_lock) and annotate helpers that access them with
__must_hold(&sq_lock) so that Clang's context analysis can validate
the locking requirements.
Access to nvme_queue::sq_tail used solely for tracing is annotated with
data_race(), as they only require a lockless snapshot of the value.
nvme_init_queue() initializes nvme_queue::sq_tail and
nvme_queue::last_sq_tail before the queue is published and thus do not
require nvme_queue::sq_lock protection. So annotate nvme_init_queue()
with context_unsafe() to suppress false positive context analyzer
warning.
nvme_free_queue() operate on queues which are no longer reachable, and
therefore do not require nvme_queue::sq_lock protection. Similarly,
nvme_alloc_sq_cmds() allocates memory for nvme_queue::sq_cmds for the
queue which is not yet published or in use and hence it's safe to
annotate all these helpers using context_unsafe.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
The global nvmf_transports list is protected by nvmf_transports_rwsem
and the global nvmf_hosts list is protected by nvmf_hosts_mutex.
Define both lists using LIST_HEAD_GUARDED() so that Clang's context
analysis can validate accesses to the lists against the corresponding
locking requirements.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
The global nvme_subsystems list, nvme_subsystem::entry,
nvme_subsystem::ctrls, and nvme_ctrl::subsys_entry are protected by
nvme_subsystems_lock. Annotate these objects with
__guarded_by(&nvme_subsystems_lock) so that Clang's context analysis
can validate accesses to them.
__nvme_find_get_subsystem() and nvme_validate_cntlid() traverse the
global subsystem list and subsystem controller list and therefore
require callers to hold nvme_subsystems_lock. Annotate both helpers
with __must_hold(&nvme_subsystems_lock).
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
nvme_parse_ana_log() accesses ANA state protected by ctrl->ana_lock and
therefore requires callers to hold the lock.
Annotate nvme_parse_ana_log() with __must_hold(&ctrl->ana_lock) so that
Clang's lock context analysis can verify the locking requirement at
compile time.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|
|
Several helpers access or traverse data structures protected by
nvme_subsystem::lock and therefore require callers to hold the lock.
Annotate nvme_mpath_unfreeze(), nvme_mpath_wait_freeze(),
nvme_mpath_start_freeze(), nvme_find_ns_head(), nvme_alloc_ns_head()
and nvme_subsys_check_duplicate_ids() with __must_hold(&subsys->lock)
so that Clang's lock context analysis can validate the locking
requirements at compile time.
Also annotate nvme_subsystem::nsheads and
nvme_ns_head::delayed_removal_secs with __guarded_by(&subsys->lock),
as both are protected by the subsystem lock.
Annotate nvme_init_subsystem() with __context_unsafe(), as it
initializes these lock-protected members before the object is published,
suppressing a false positive from Clang's context analysis.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
|