[PATCH v3 2/2] IB/isert: reject full-feature PDUs that arrive before registration
From: Yehyeong Lee
Date: Thu Jul 30 2026 - 10:08:50 EST
The full-feature receive buffers are posted from isert_put_login_tx(),
which runs before __transport_register_session(). An initiator that does
not wait for the final Login Response can therefore still have a SCSI
command executed against an se_session whose se_tpg is NULL, with the same
oops as the previous patch.
Move the ISER_CONN_FULL_FEATURE transition into isert_get_rx_pdu(), where
it happens after the session has been registered, and reinstate the
connection on any PDU that arrives before it, the same call this function
already makes when a work completion fails. The state is read without
isert_conn->mutex because isert_recv_done() runs on ib-comp-wq; the acquire
load pairs with the release store so that the session registration
preceding it is visible.
Measured over rxe with an initiator that fires SCSI commands into that
window without waiting for the Login Response, 400 login cycles per run:
the oops appeared in 7 of 10 runs with only the previous patch applied and
in 0 of 10 runs with this one on top. The check fired 22 times across
those 10 runs, 16 in ISER_CONN_BOUND and 6 in ISER_CONN_TERMINATING, where
the reinstatement is a no-op because teardown has already latched.
Well-formed traffic is unaffected: 20 runs of a spec-conforming initiator,
400 login cycles each, pass with the check never firing.
Fixes: b8d26b3be8b3 ("iser-target: Add iSCSI Extensions for RDMA (iSER) target driver")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Yehyeong Lee <yhlee@xxxxxxxxxxxxxxxxxx>
---
v3: unmap login_tx_desc in isert_connect_release() (1/2); make the
FULL_FEATURE store a release and the state check an acquire load, and
log the value actually tested (2/2). Both from Sashiko's review of v2.
v2: https://lore.kernel.org/all/20260730063124.1554460-1-yhlee@xxxxxxxxxxxxxxxxxx/
Depends on 1/2 and must not be backported without it.
drivers/infiniband/ulp/isert/ib_isert.c | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index e117cd2e62c9..40290ab4bdb5 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -956,11 +956,6 @@ isert_put_login_tx(struct iscsit_conn *conn, struct iscsi_login *login,
if (ret)
return ret;
- /* Now we are in FULL_FEATURE phase */
- mutex_lock(&isert_conn->mutex);
- isert_conn->state = ISER_CONN_FULL_FEATURE;
- mutex_unlock(&isert_conn->mutex);
-
/* Sent from isert_get_rx_pdu() after registration. */
isert_conn->login_rsp_pending = true;
return 0;
@@ -1327,6 +1322,7 @@ isert_recv_done(struct ib_cq *cq, struct ib_wc *wc)
struct iser_ctrl *iser_ctrl = isert_get_iser_hdr(rx_desc);
uint64_t read_va = 0, write_va = 0;
uint32_t read_stag = 0, write_stag = 0;
+ enum iser_conn_state state;
if (unlikely(wc->status != IB_WC_SUCCESS)) {
isert_print_wc(wc, "recv");
@@ -1335,6 +1331,15 @@ isert_recv_done(struct ib_cq *cq, struct ib_wc *wc)
return;
}
+ /* A full-feature PDU before registration is a protocol violation. */
+ state = smp_load_acquire(&isert_conn->state);
+ if (unlikely(state != ISER_CONN_FULL_FEATURE)) {
+ isert_err("PDU received in state %d, resetting connection\n",
+ state);
+ iscsit_cause_connection_reinstatement(isert_conn->conn, 0);
+ return;
+ }
+
rx_desc->in_use = true;
ib_dma_sync_single_for_cpu(ib_dev, rx_desc->dma_addr,
@@ -2598,6 +2603,12 @@ static void isert_get_rx_pdu(struct iscsit_conn *conn)
/* The session is registered by now; see isert_put_login_tx(). */
if (isert_conn->login_rsp_pending) {
isert_conn->login_rsp_pending = false;
+
+ mutex_lock(&isert_conn->mutex);
+ /* Pairs with the acquire in isert_recv_done(). */
+ smp_store_release(&isert_conn->state, ISER_CONN_FULL_FEATURE);
+ mutex_unlock(&isert_conn->mutex);
+
if (isert_login_post_send(isert_conn,
&isert_conn->login_tx_desc))
return;
--
2.43.0