| 0/0 |
2026/02/24 22:49 |
flow |
assessment-kcsan |
11m
Results: map[Benign:false Confident:true Explanation:The data race occurs between `addr_handler` in `drivers/infiniband/core/cma.c` and `ucma_query_addr` in `drivers/infiniband/core/ucma.c`.
### Analysis:
1. **The Race**: `addr_handler` is a callback function triggered when address resolution completes. It updates the source address of an `rdma_cm_id` using `memcpy` (line 3523 in `cma.c`). Concurrently, a user-space process can call `ucma_query` (which calls `ucma_query_addr`), which reads the same source address using `memcpy` (line 925 in `ucma.c`) to return it to user-space.
2. **Locking**:
* `addr_handler` holds `id_priv->handler_mutex`.
* `ucma_query` holds `ctx->mutex`.
* These are two different mutexes. `id_priv` is the internal RDMA CM ID structure, while `ctx` is the user-space context structure. Although `ctx->cm_id` points to `id_priv->id`, the locks are not synchronized.
3. **Consequences**:
* Since `memcpy` of a 28-byte structure (like `struct sockaddr_in6`) is not atomic, the reading thread (`ucma_query_addr`) can read a partially updated address.
* This results in corrupted data being returned to user-space. For example, if the address family changes from IPv4 to IPv6 during the race, the user-space might receive a structure with an IPv6 family but only partial address data, or vice versa.
* Beyond just the address, other fields in `rdma_cm_id->route` (like `path_rec` or `service_recs`) are also accessed by `ucma_query` without holding the `handler_mutex`. In the case of `path_rec`, which is a pointer, this could even lead to a use-after-free if the pointer is being reallocated by a concurrent callback.
4. **Verdict**: This is a **harmful** data race. It is a bug in the `ucma_query` implementation where it fails to acquire the `handler_mutex` (via `rdma_lock_handler`) before accessing fields of the `rdma_cm_id` that are modified by asynchronous kernel callbacks. Returning inconsistent or corrupted networking metadata to user-space is not considered benign behavior in the kernel.
### Conclusion:
The data race is non-benign as it leads to data corruption in a user-facing API and indicates a broader synchronization issue in the `ucma_query` path.]
|
| 1/1 |
2026/02/24 22:49 |
action |
kernel-checkouter |
0m
Results: map[KernelSrc:/usr/local/google/home/dvyukov/syzkaller/agent/workdir/cache/src/fc53729d572e64505e85850e48eb68d1ffb0de74]
|
| 2/1 |
2026/02/24 22:50 |
action |
kernel-builder |
3m
Results: map[KernelObj:/usr/local/google/home/dvyukov/syzkaller/agent/workdir/cache/build/030403186f37049337087d3eee0fbb317405a545]
|
| 3/1 |
2026/02/24 22:54 |
action |
codesearch-prepare |
3m
Results: map[Index:codesearch-index]
|
| 4/1 |
2026/02/24 22:57 |
agent |
expert |
3m
Model:
Results: map[Benign:false Confident:true]
Instruction:
You are an experienced Linux kernel developer tasked with determining if the given kernel
data race is benign or not. The data race report is from KCSAN tool.
It contains 2 stack traces of the memory accesses that constitute a data race.
A "benign" data races are on a simple int/bool variable or similar field,
and the accesses are not supposed to be protected by any mutual exclusion primitives.
Common examples of such "benign" data races are accesses to various flags fields,
statistics counters, and similar. A "benign" data race does not lead to memory corruption/crash
with a conservative compiler that compiles memory accesses to primitive types
effectively as atomic.
A non-benign (or "harmful" data race) can lead to corruption/crash even with
a conservative compiler that compiles memory accesses to primitive types
effectively as atomic. A common example of a "harmful" data races is race on
a complex container (list/hashmap/etc), where accesses are supposed to be protected
by a mutual exclusion primitive.
Also consider races that happen at the same time with the given one.
If there is no synchronization in between, other memory accesses in the involved threads
race with each other if they access the same memory. For example, if both threads execute:
some_struct->have_elements = true;
list_add(new_node, &some_struct->list_head);
the race on some_struct->have_elements may appear benign, however it also implies there
is a race on some_struct->list_head which is not benign, since the list is not thread-safe.
Take into account that on 32-bit systems 64-bit memory accesses may be split into two accesses,
and thus even with a conservative compiler may not be fully atomic. However, such races may
still be benign depending on how writes are done, and how read data is used.
In the final reply explain why you think the given data race is benign or is harmful.
Use the provided tools to confirm any assumptions, variables/fields being accessed, etc.
In particular, don't make assumptions about the kernel source code,
use codesearch tools to read the actual source code.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt:
The data race report is:
==================================================================
BUG: KCSAN: data-race in addr_handler / ucma_query
write to 0xffff88812ddf7820 of 28 bytes by task 7338 on cpu 1:
addr_handler+0x10d/0x2f0 drivers/infiniband/core/cma.c:3523
process_one_req+0x1f5/0x2e0 drivers/infiniband/core/addr.c:622
process_one_work kernel/workqueue.c:3257 [inline]
process_scheduled_works+0x4cd/0x9d0 kernel/workqueue.c:3340
worker_thread+0x581/0x770 kernel/workqueue.c:3421
kthread+0x488/0x510 kernel/kthread.c:463
ret_from_fork+0x148/0x280 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:246
read to 0xffff88812ddf7820 of 28 bytes by task 13116 on cpu 0:
ucma_query_addr drivers/infiniband/core/ucma.c:925 [inline]
ucma_query+0x773/0xe70 drivers/infiniband/core/ucma.c:1081
ucma_write+0x1c9/0x260 drivers/infiniband/core/ucma.c:1856
do_loop_readv_writev fs/read_write.c:850 [inline]
vfs_writev+0x42b/0x900 fs/read_write.c:1059
do_writev+0xe9/0x210 fs/read_write.c:1103
__do_sys_writev fs/read_write.c:1171 [inline]
__se_sys_writev fs/read_write.c:1168 [inline]
__x64_sys_writev+0x45/0x50 fs/read_write.c:1168
x64_sys_call+0x1ba5/0x3000 arch/x86/include/generated/asm/syscalls_64.h:21
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xc0/0x2a0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Reported by Kernel Concurrency Sanitizer on:
CPU: 0 UID: 0 PID: 13116 Comm: syz.0.2525 Tainted: G W syzkaller #0 PREEMPT(voluntary)
Tainted: [W]=WARN
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/25/2025
==================================================================
Reply: The data race occurs between `addr_handler` in `drivers/infiniband/core/cma.c` and `ucma_query_addr` in `drivers/infiniband/core/ucma.c`.
### Analysis:
1. **The Race**: `addr_handler` is a callback function triggered when address resolution completes. It updates the source address of an `rdma_cm_id` using `memcpy` (line 3523 in `cma.c`). Concurrently, a user-space process can call `ucma_query` (which calls `ucma_query_addr`), which reads the same source address using `memcpy` (line 925 in `ucma.c`) to return it to user-space.
2. **Locking**:
* `addr_handler` holds `id_priv->handler_mutex`.
* `ucma_query` holds `ctx->mutex`.
* These are two different mutexes. `id_priv` is the internal RDMA CM ID structure, while `ctx` is the user-space context structure. Although `ctx->cm_id` points to `id_priv->id`, the locks are not synchronized.
3. **Consequences**:
* Since `memcpy` of a 28-byte structure (like `struct sockaddr_in6`) is not atomic, the reading thread (`ucma_query_addr`) can read a partially updated address.
* This results in corrupted data being returned to user-space. For example, if the address family changes from IPv4 to IPv6 during the race, the user-space might receive a structure with an IPv6 family but only partial address data, or vice versa.
* Beyond just the address, other fields in `rdma_cm_id->route` (like `path_rec` or `service_recs`) are also accessed by `ucma_query` without holding the `handler_mutex`. In the case of `path_rec`, which is a pointer, this could even lead to a use-after-free if the pointer is being reallocated by a concurrent callback.
4. **Verdict**: This is a **harmful** data race. It is a bug in the `ucma_query` implementation where it fails to acquire the `handler_mutex` (via `rdma_lock_handler`) before accessing fields of the `rdma_cm_id` that are modified by asynchronous kernel callbacks. Returning inconsistent or corrupted networking metadata to user-space is not considered benign behavior in the kernel.
### Conclusion:
The data race is non-benign as it leads to data corruption in a user-facing API and indicates a broader synchronization issue in the `ucma_query` path.
|
| 5/2 |
2026/02/24 22:57 |
llm |
expert |
0m
Model:
Tokens:
input: 3876
output: 93
thoughts: 105
Thoughts: **Analyzing a Data Race in Infiniband Core**
Okay, so the report flags a nasty data race – a write from `addr_handler` conflicting with a read from `ucma_query` – specifically, both accessing a 28-byte chunk of memory. The write is happening in `cma.c:3523`, and that read's buried within `ucma_query_addr` at `ucma.c:925`. Time to dig into the code and see exactly what's going on. I need to understand how these two functions are interacting and, more importantly, *why* this race condition exists. Let's see if we can identify the shared data structure involved and pinpoint the exact source of the problem. Hopefully it's something relatively simple to address.
|
| 6/2 |
2026/02/24 22:57 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/infiniband/core/cma.c IncludeLines:true Name:addr_handler]
Results: map[SourceCode:3503: static void addr_handler(int status, struct sockaddr *src_addr,
3504: struct rdma_dev_addr *dev_addr, void *context)
3505: {
3506: struct rdma_id_private *id_priv = context;
3507: struct rdma_cm_event event = {};
3508: struct sockaddr *addr;
3509: struct sockaddr_storage old_addr;
3510:
3511: mutex_lock(&id_priv->handler_mutex);
3512: if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY,
3513: RDMA_CM_ADDR_RESOLVED))
3514: goto out;
3515:
3516: /*
3517: * Store the previous src address, so that if we fail to acquire
3518: * matching rdma device, old address can be restored back, which helps
3519: * to cancel the cma listen operation correctly.
3520: */
3521: addr = cma_src_addr(id_priv);
3522: memcpy(&old_addr, addr, rdma_addr_size(addr));
3523: memcpy(addr, src_addr, rdma_addr_size(src_addr));
3524: if (!status && !id_priv->cma_dev) {
3525: status = cma_acquire_dev_by_src_ip(id_priv);
3526: if (status)
3527: pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to acquire device. status %d\n",
3528: status);
3529: rdma_restrack_add(&id_priv->res);
3530: } else if (status) {
3531: pr_debug_ratelimited("RDMA CM: ADDR_ERROR: failed to resolve IP. status %d\n", status);
3532: }
3533:
3534: if (status) {
3535: memcpy(addr, &old_addr,
3536: rdma_addr_size((struct sockaddr *)&old_addr));
3537: if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED,
3538: RDMA_CM_ADDR_BOUND))
3539: goto out;
3540: event.event = RDMA_CM_EVENT_ADDR_ERROR;
3541: event.status = status;
3542: } else
3543: event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
3544:
3545: if (cma_cm_event_handler(id_priv, &event)) {
3546: destroy_id_handler_unlock(id_priv);
3547: return;
3548: }
3549: out:
3550: mutex_unlock(&id_priv->handler_mutex);
3551: }
SourceFile:drivers/infiniband/core/cma.c]
|
| 7/2 |
2026/02/24 22:57 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/infiniband/core/ucma.c IncludeLines:true Name:ucma_query_addr]
Results: map[SourceCode: 911: static ssize_t ucma_query_addr(struct ucma_context *ctx,
912: void __user *response, int out_len)
913: {
914: struct rdma_ucm_query_addr_resp resp;
915: struct sockaddr *addr;
916: int ret = 0;
917:
918: if (out_len < offsetof(struct rdma_ucm_query_addr_resp, ibdev_index))
919: return -ENOSPC;
920:
921: memset(&resp, 0, sizeof resp);
922:
923: addr = (struct sockaddr *) &ctx->cm_id->route.addr.src_addr;
924: resp.src_size = rdma_addr_size(addr);
925: memcpy(&resp.src_addr, addr, resp.src_size);
926:
927: addr = (struct sockaddr *) &ctx->cm_id->route.addr.dst_addr;
928: resp.dst_size = rdma_addr_size(addr);
929: memcpy(&resp.dst_addr, addr, resp.dst_size);
930:
931: ucma_query_device_addr(ctx->cm_id, &resp);
932:
933: if (copy_to_user(response, &resp, min_t(size_t, out_len, sizeof(resp))))
934: ret = -EFAULT;
935:
936: return ret;
937: }
SourceFile:drivers/infiniband/core/ucma.c]
|
| 8/2 |
2026/02/24 22:57 |
llm |
expert |
0m
Model:
Tokens:
input: 5590
output: 46
thoughts: 278
Thoughts: **Analyzing Potential Race Conditions in RDMA Address Handling**
Okay, so I'm looking at this code and immediately see a potential race condition. The key locations are `addr` in `addr_handler` (specifically computed using `cma_src_addr(id_priv)`) and `addr` in `ucma_query_addr` (which is `&ctx->cm_id->route.addr.src_addr`). Both seem to be accessing and manipulating address data, which is a red flag.
Diving deeper into `addr_handler`, lines 3521-3523 show a clear sequence: the source address (`cma_src_addr`) is retrieved, copied to a `old_addr` buffer, and then *overwritten* with a new `src_addr`. I'm reminded that this function is protected by `id_priv->handler_mutex`, which is at least a start. However, this raises the question if `src_addr` is ever being written to or modified, and if so, when and where.
Then there's `ucma_query_addr`. Here, on lines 923-925, we're grabbing the source address again (`&ctx->cm_id->route.addr.src_addr`), determining its size, and then copying it into a response buffer. This is called from `ucma_query`, and that's the crucial point - I need to check if `ucma_query` holds any locks. If it *doesn't*, we have a classic read-write race between `addr_handler` (which modifies the `src_addr` potentially) and `ucma_query_addr` (which reads it), even though `addr_handler` has the mutex. We'd need to confirm if `ucma_query` has a similar lock, or some other mechanism to synchronize. Otherwise, there's a definite window for corruption or inconsistent data. I must investigate how `ucma_query` is being used and the context it's running in.
|
| 9/2 |
2026/02/24 22:57 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/infiniband/core/ucma.c IncludeLines:true Name:ucma_query]
Results: map[SourceCode:1061: static ssize_t ucma_query(struct ucma_file *file,
1062: const char __user *inbuf,
1063: int in_len, int out_len)
1064: {
1065: struct rdma_ucm_query cmd;
1066: struct ucma_context *ctx;
1067: void __user *response;
1068: int ret;
1069:
1070: if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
1071: return -EFAULT;
1072:
1073: response = u64_to_user_ptr(cmd.response);
1074: ctx = ucma_get_ctx(file, cmd.id);
1075: if (IS_ERR(ctx))
1076: return PTR_ERR(ctx);
1077:
1078: mutex_lock(&ctx->mutex);
1079: switch (cmd.option) {
1080: case RDMA_USER_CM_QUERY_ADDR:
1081: ret = ucma_query_addr(ctx, response, out_len);
1082: break;
1083: case RDMA_USER_CM_QUERY_PATH:
1084: ret = ucma_query_path(ctx, response, out_len);
1085: break;
1086: case RDMA_USER_CM_QUERY_GID:
1087: ret = ucma_query_gid(ctx, response, out_len);
1088: break;
1089: case RDMA_USER_CM_QUERY_IB_SERVICE:
1090: ret = ucma_query_ib_service(ctx, response, out_len);
1091: break;
1092: default:
1093: ret = -ENOSYS;
1094: break;
1095: }
1096: mutex_unlock(&ctx->mutex);
1097:
1098: ucma_put_ctx(ctx);
1099: return ret;
1100: }
SourceFile:drivers/infiniband/core/ucma.c]
|
| 10/2 |
2026/02/24 22:57 |
llm |
expert |
0m
Model:
Tokens:
input: 6980
output: 96
thoughts: 138
Thoughts: **Mutex Relationships in UCMA and RDMA Contexts**
Okay, so I'm looking at `ucma_query` which has a hold on `ctx->mutex`, and `addr_handler` which seems to be holding `id_priv->handler_mutex`. Hmm, are these two mutexes related in some way? They seem to be protecting related resources.
Let me refresh my memory: `ctx` is a `struct ucma_context`, and `id_priv` is a `struct rdma_id_private`. Now, I recall `ctx->cm_id` is a `struct rdma_cm_id *`. And right, `struct rdma_id_private` actually contains a `struct rdma_cm_id id`... so `ctx->cm_id` and `id_priv->id` are linked through some indirection.
Alright, let's dive into the structures themselves to see if there's any direct or indirect relationship between these mutexes. Time to verify my assumptions and see how the locking hierarchy actually works in these contexts.
|
| 11/2 |
2026/02/24 22:57 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/infiniband/core/ucma.c IncludeLines:true Name:ucma_context]
Results: map[SourceCode: 86: struct ucma_context {
87: u32 id;
88: struct completion comp;
89: refcount_t ref;
90: int events_reported;
91: atomic_t backlog;
92:
93: struct ucma_file *file;
94: struct rdma_cm_id *cm_id;
95: struct mutex mutex;
96: u64 uid;
97:
98: struct list_head list;
99: struct list_head mc_list;
100: struct work_struct close_work;
101: };
SourceFile:drivers/infiniband/core/ucma.c]
|
| 12/2 |
2026/02/24 22:57 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/infiniband/core/cma_priv.h IncludeLines:true Name:rdma_id_private]
Results: map[SourceCode: 55: struct rdma_id_private {
56: struct rdma_cm_id id;
57:
58: struct rdma_bind_list *bind_list;
59: struct hlist_node node;
60: union {
61: struct list_head device_item; /* On cma_device->id_list */
62: struct list_head listen_any_item; /* On listen_any_list */
63: };
64: union {
65: /* On rdma_id_private->listen_list */
66: struct list_head listen_item;
67: struct list_head listen_list;
68: };
69: struct list_head id_list_entry;
70: struct cma_device *cma_dev;
71: struct list_head mc_list;
72:
73: int internal_id;
74: enum rdma_cm_state state;
75: spinlock_t lock;
76: struct mutex qp_mutex;
77:
78: struct completion comp;
79: refcount_t refcount;
80: struct mutex handler_mutex;
81:
82: int backlog;
83: int timeout_ms;
84: struct ib_sa_query *query;
85: int query_id;
86: union {
87: struct ib_cm_id *ib;
88: struct iw_cm_id *iw;
89: } cm_id;
90:
91: u32 seq_num;
92: u32 qkey;
93: u32 qp_num;
94: u32 options;
95: u8 srq;
96: u8 tos;
97: u8 tos_set:1;
98: u8 timeout_set:1;
99: u8 min_rnr_timer_set:1;
100: u8 reuseaddr;
101: u8 afonly;
102: u8 timeout;
103: u8 min_rnr_timer;
104: u8 used_resolve_ip;
105: enum ib_gid_type gid_type;
106:
107: /*
108: * Internal to RDMA/core, don't use in the drivers
109: */
110: struct rdma_restrack_entry res;
111: struct rdma_ucm_ece ece;
112: };
SourceFile:drivers/infiniband/core/cma_priv.h]
|
| 13/2 |
2026/02/24 22:57 |
llm |
expert |
0m
Model:
Tokens:
input: 8475
output: 46
thoughts: 195
Thoughts: **Analyzing Potential Data Races in RDMA Address Resolution**
Okay, so I'm looking at this RDMA code, and I've spotted a potential issue, a classic data race scenario. It's concerning because we're dealing with concurrent access, and that always requires careful synchronization. Here's what I'm seeing:
It looks like we have `rdma_id_private` and `ucma_context` structures. The first one, `rdma_id_private`, has a `handler_mutex`, and `ucma_context` has a `mutex`. Now, the issue arises when `ucma_query` gets called. My understanding is that `ucma_query` locks `ctx->mutex`. The `ctx->cm_id` pointer then references `id_priv->id`.
The problem appears in the `addr_handler` callback, specifically at line 3511: `mutex_lock(&id_priv->handler_mutex)`. `addr_handler` is called as part of the address resolution process, and is a callback from the kernel. This is where I start to get a bit worried. We have a user-space query, `ucma_query_addr`, that is taking `ctx->mutex`, and then a kernel handler that's taking a different mutex, the `id_priv->handler_mutex`. My immediate thought is, are these mutexes protecting the same critical data?
Specifically, it looks like they are protecting `id_priv->id.route.addr.src_addr`. I need to confirm where that member variable is defined, and it should be in `struct rdma_cm_id`. The critical issue here is that these two code paths appear to be using different mutexes to protect the same data. It's very possible we have a race condition. I need to dig deeper into the code to confirm if there are any write operations, or even read operations, on that particular piece of data in the different critical sections, and whether they are protected by their respective mutexes. This demands careful examination.
|
| 14/2 |
2026/02/24 22:57 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:include/rdma/rdma_cm.h IncludeLines:true Name:rdma_cm_id]
Results: map[SourceCode: 120: struct rdma_cm_id {
121: struct ib_device *device;
122: void *context;
123: struct ib_qp *qp;
124: rdma_cm_event_handler event_handler;
125: struct rdma_route route;
126: enum rdma_ucm_port_space ps;
127: enum ib_qp_type qp_type;
128: u32 port_num;
129: struct work_struct net_work;
130: };
SourceFile:include/rdma/rdma_cm.h]
|
| 15/2 |
2026/02/24 22:57 |
llm |
expert |
0m
Model:
Tokens:
input: 9356
output: 44
thoughts: 8
Thoughts: Okay, here's my interpretation of that thought process, summarized as you requested:
**Navigating the RDMA Landscape**
Alright, let's see... the text seems to be focusing on the structures used in RDMA, and right now I'm thinking specifically about `struct rdma_route`. This is where I start to hone in on the core of how routing information is managed within this architecture. What I really need to know is how the route is defined within the RDMA fabric, how to get the most efficient routes and how to manage the routes. This is the foundation to truly efficient RDMA communication and it's something that I'm always looking to refine.
|
| 16/2 |
2026/02/24 22:57 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:include/rdma/rdma_cm.h IncludeLines:true Name:rdma_route]
Results: map[SourceCode: 56: struct rdma_route {
57: struct rdma_addr addr;
58: struct sa_path_rec *path_rec;
59:
60: /* Optional path records of primary path */
61: struct sa_path_rec *path_rec_inbound;
62: struct sa_path_rec *path_rec_outbound;
63:
64: /*
65: * 0 - No primary nor alternate path is available
66: * 1 - Only primary path is available
67: * 2 - Both primary and alternate path are available
68: */
69: int num_pri_alt_paths;
70:
71: unsigned int num_service_recs;
72: struct sa_service_rec *service_recs;
73: };
SourceFile:include/rdma/rdma_cm.h]
|
| 17/2 |
2026/02/24 22:57 |
llm |
expert |
0m
Model:
Tokens:
input: 9816
output: 44
thoughts: 8
Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person:
**My Deep Dive into `struct rdma_addr`**
Alright, so I'm thinking about the low-level details, as usual. We're talking about RDMA, and a fundamental structure here is `struct rdma_addr`. My mind immediately goes to the potential ways this struct is implemented on various hardware platforms, and how much of its design is abstracted vs. hardware-dependent. I'm wondering about the implications this struct holds for addressing remote memory regions, not just the network addressing, but also the physical memory mapping and translation. I know these details are critical for maximizing RDMA's performance.
I'm mentally outlining the likely members: likely there's an IP address (IPv4 and/or IPv6, of course), a port, possibly a transport type identifier (TCP, RoCE, iWARP). I'm also anticipating some kind of context identifier or handle, a key element that ties into the specific RDMA device and its capabilities.
I'm considering the interplay between this address structure and the `struct ibv_pd` (protection domain) and `struct ibv_mr` (memory region) in the verbs API. It's the glue that connects the local memory to the remote counterpart. Are there any assumptions or guarantees built into the design about how memory addressing will be handled, and what are they? Will the design need to deal with the subtleties of virtual vs. physical addressing, and how will it handle things like page tables and translation lookaside buffers (TLBs)?
I'm thinking about the potential challenges for the developer when they're actually using `struct rdma_addr`. I want to consider things like the need to properly initialize the `rdma_addr` struct for various transport types, the need to carefully handle endianness considerations, especially across different architectures, and the potential for off-by-one errors when dealing with offsets.
Finally, I'm already asking myself the question of how to extend or customize the `struct rdma_addr` if this address is being built as a custom struct for my particular use-case.
|
| 18/2 |
2026/02/24 22:57 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:include/rdma/rdma_cm.h IncludeLines:true Name:rdma_addr]
Results: map[SourceCode: 50: struct rdma_addr {
51: struct sockaddr_storage src_addr;
52: struct sockaddr_storage dst_addr;
53: struct rdma_dev_addr dev_addr;
54: };
SourceFile:include/rdma/rdma_cm.h]
|
| 19/2 |
2026/02/24 22:57 |
llm |
expert |
0m
Model:
Tokens:
input: 10430
output: 46
thoughts: 535
Thoughts: **Race Condition in RDMA Address Handling**
Okay, so I'm looking at this `addr_handler` function, specifically this `memcpy`: `memcpy(addr, src_addr, rdma_addr_size(src_addr))`. This copies the resolved address into `addr`, which is actually `id_priv->id.route.addr.src_addr`. Meanwhile, `ucma_query_addr` is doing something similar: `memcpy(&resp.src_addr, addr, resp.src_size)`, where `addr` here is `ctx->cm_id->route.addr.src_addr`. And the kicker is that `ctx->cm_id` *is* `&id_priv->id`, so they're both accessing the same memory location, at different times.
`addr_handler` is called after address resolution completes, while `ucma_query_addr` is invoked when a user-space process needs to know the resolved address. This is screaming race condition. If these two operations happen concurrently, `ucma_query_addr` could read a partially updated address from `addr_handler`. The report mentions a discrepancy between the size of `struct sockaddr_storage` (128 bytes) and the reported size (28 bytes). That 28 bytes sounds like the size of a `struct sockaddr_in6`. `struct sockaddr_in` is smaller, at 16 bytes.
Now, if `ucma_query_addr` grabs a partially updated address, it could return garbage to user-space. Generally, returning inconsistent data is considered a bug, but maybe not a critical security issue in itself. But if the address size is also changing at the same time, this is where it might become much more serious.
In `ucma_query_addr`, it's calculating the size *before* copying: `resp.src_size = rdma_addr_size(addr);` and then `memcpy(&resp.src_addr, addr, resp.src_size);`. `rdma_addr_size(addr)` seems to be relying on `addr->sa_family` to determine the address family and, therefore, the size.
The problem lies here, in `addr_handler`: `memcpy(addr, src_addr, rdma_addr_size(src_addr))`. This line *overwrites* the entire `sockaddr` struct. If `addr->sa_family` changes while `ucma_query_addr` is in the middle of execution, `rdma_addr_size(addr)` could return a value that doesn't correspond to the data being copied, or, even worse, read a stale `sa_family` value before it is updated.
|
| 20/2 |
2026/02/24 22:57 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:include/rdma/rdma_cm.h IncludeLines:true Name:rdma_addr_size]
Results: map[SourceCode: 182: int rdma_addr_size(const struct sockaddr *addr)
183: {
184: switch (addr->sa_family) {
185: case AF_INET:
186: return sizeof(struct sockaddr_in);
187: case AF_INET6:
188: return sizeof(struct sockaddr_in6);
189: case AF_IB:
190: return sizeof(struct sockaddr_ib);
191: default:
192: return 0;
193: }
194: }
SourceFile:drivers/infiniband/core/addr.c]
|
| 21/2 |
2026/02/24 22:57 |
llm |
expert |
0m
Model:
Tokens:
input: 11795
output: 24
thoughts: 831
Thoughts: **Analyzing a Potential Race Condition in RDMA Address Handling**
Okay, here's what's running through my head. I'm looking at this potential bug and my primary concern is with the address family change and a race condition. Specifically, if the `addr->sa_family` changes from `AF_INET` to `AF_INET6` (or vice versa), the `rdma_addr_size` function might return an incorrect size, potentially leading to a buffer overflow in `addr_handler`. It looks like `addr_handler` is supposed to update the address with a resolved one. The `src_addr` passed to it *should* have the same family as what was requested, but I'm questioning that assumption.
Looking at the code snippet in `addr_handler`, it first saves the old address, then copies the new address over the old one. If `ucma_query_addr` is running concurrently, it reads `addr->sa_family` to get the source address size, and then copies that many bytes. If `addr_handler` overwrites the `addr` structure in between those two steps, then `ucma_query_addr` could copy a mix of old and new data, or it could copy the wrong number of bytes if the family changed. This is the crux of the problem.
I'm wondering if a family change is even possible. Typically, an `rdma_cm_id` is tied to a specific address family. But I need to verify that assumption.
My next line of thought is around the locking mechanisms. I need to know if `ucma_query_addr` should be holding `id_priv->handler_mutex`, or some other mutex. Most other functions accessing `id_priv` in `cma.c` seem to use either `handler_mutex` or some other `lock`. I see that `ucma_query` holds `ctx->mutex`, but `addr_handler` doesn't hold `ctx->mutex` since it's a kernel callback. However, the `id_priv->id.context` for a user-space ID does point to `ucma_context`.
I need to trace how `addr_handler` is called. It's passed as a callback to `rdma_resolve_addr`, which calls `addr_resolve`, and then eventually `process_one_req`. The report shows that `addr_handler` is called at `drivers/infiniband/core/cma.c:3523` which is the `memcpy` statement.
Aha! Looking at `addr_handler` again, there's a `mutex_lock(&id_priv->handler_mutex);`. That looks like `handler_mutex` is intended to protect the ID state during callbacks. And `ucma_query` holds `ctx->mutex`, protecting the `ucma_context`. So the code seems to have some protection in place, but I need to know if it's sufficient.
So, if `ucma_query_addr` is trying to read `ctx->cm_id->route.addr.src_addr` safely, it *probably* needs to also lock something that `addr_handler` locks.
Wait, looking at the definition of `rdma_id_private`, there's also a spinlock called `lock`. I need to figure out how this is used and if it's used correctly. I need to investigate where `cma_src_addr` is used elsewhere and how that access is protected. That's the key to understanding if there's a race, or if this is protected.
|
| 22/2 |
2026/02/24 22:58 |
tool |
codesearch-find-references |
0m
Args:
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:addr_handler SourceFile:drivers/infiniband/core/cma.c SourceLine:3521] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_bind_loopback SourceFile:drivers/infiniband/core/cma.c SourceLine:3497] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_bind_port SourceFile:drivers/infiniband/core/cma.c SourceLine:3654] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_cancel_operation SourceFile:drivers/infiniband/core/cma.c SourceLine:1978] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_check_port SourceFile:drivers/infiniband/core/cma.c SourceLine:3802] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_check_port SourceFile:drivers/infiniband/core/cma.c SourceLine:3810] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_connect_iw SourceFile:drivers/infiniband/core/cma.c SourceLine:4438] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_connect_iw SourceFile:drivers/infiniband/core/cma.c SourceLine:4438] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_connect_iw SourceFile:drivers/infiniband/core/cma.c SourceLine:4438] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_connect_iw SourceFile:drivers/infiniband/core/cma.c SourceLine:4438] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_format_hdr SourceFile:drivers/infiniband/core/cma.c SourceLine:4198] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_format_hdr SourceFile:drivers/infiniband/core/cma.c SourceLine:4208] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_get_port SourceFile:drivers/infiniband/core/cma.c SourceLine:3908] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_get_roce_udp_flow_label SourceFile:drivers/infiniband/core/cma.c SourceLine:3282] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_get_roce_udp_flow_label SourceFile:drivers/infiniband/core/cma.c SourceLine:3286] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_ib_listen SourceFile:drivers/infiniband/core/cma.c SourceLine:2659] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_ib_new_conn_id SourceFile:drivers/infiniband/core/cma.c SourceLine:2312] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_ib_new_conn_id SourceFile:drivers/infiniband/core/cma.c SourceLine:2316] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_ib_new_conn_id SourceFile:drivers/infiniband/core/cma.c SourceLine:2317] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_ib_new_udp_id SourceFile:drivers/infiniband/core/cma.c SourceLine:2361] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_ib_new_udp_id SourceFile:drivers/infiniband/core/cma.c SourceLine:2362] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_iw_handler SourceFile:drivers/infiniband/core/cma.c SourceLine:2536] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_iw_handler SourceFile:drivers/infiniband/core/cma.c SourceLine:2536] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_iw_handler SourceFile:drivers/infiniband/core/cma.c SourceLine:2536] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_iw_listen SourceFile:drivers/infiniband/core/cma.c SourceLine:2688] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_iw_listen SourceFile:drivers/infiniband/core/cma.c SourceLine:2688] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_iw_listen SourceFile:drivers/infiniband/core/cma.c SourceLine:2688] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_iw_listen SourceFile:drivers/infiniband/core/cma.c SourceLine:2688] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_listen_on_dev SourceFile:drivers/infiniband/core/cma.c SourceLine:2737] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_listen_on_dev SourceFile:drivers/infiniband/core/cma.c SourceLine:2737] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_listen_on_dev SourceFile:drivers/infiniband/core/cma.c SourceLine:2737] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_listen_on_dev SourceFile:drivers/infiniband/core/cma.c SourceLine:2737] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_listen_on_dev SourceFile:drivers/infiniband/core/cma.c SourceLine:2737] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_listen_on_dev SourceFile:drivers/infiniband/core/cma.c SourceLine:2737] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_listen_on_dev SourceFile:drivers/infiniband/core/cma.c SourceLine:2737] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_match_private_data SourceFile:drivers/infiniband/core/cma.c SourceLine:1725] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_port_is_unique SourceFile:drivers/infiniband/core/cma.c SourceLine:3707] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_port_is_unique SourceFile:drivers/infiniband/core/cma.c SourceLine:3714] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_query_ib_route SourceFile:drivers/infiniband/core/cma.c SourceLine:2979] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_query_ib_route SourceFile:drivers/infiniband/core/cma.c SourceLine:2984] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_resolve_ib_dev SourceFile:drivers/infiniband/core/cma.c SourceLine:989] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_select_ib_ps SourceFile:drivers/infiniband/core/cma.c SourceLine:3870] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:cma_use_port SourceFile:drivers/infiniband/core/cma.c SourceLine:3833] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:iw_conn_req_handler SourceFile:drivers/infiniband/core/cma.c SourceLine:2634] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:iw_conn_req_handler SourceFile:drivers/infiniband/core/cma.c SourceLine:2634] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:iw_conn_req_handler SourceFile:drivers/infiniband/core/cma.c SourceLine:2634] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:rdma_bind_addr_dst SourceFile:drivers/infiniband/core/cma.c SourceLine:4023] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:rdma_bind_addr_dst SourceFile:drivers/infiniband/core/cma.c SourceLine:4023] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:rdma_bind_addr_dst SourceFile:drivers/infiniband/core/cma.c SourceLine:4023] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:rdma_resolve_addr SourceFile:drivers/infiniband/core/cma.c SourceLine:4164]] TruncatedOutput:false]
|
| 23/2 |
2026/02/24 22:58 |
llm |
expert |
0m
Model:
Tokens:
input: 16363
output: 48
thoughts: 22
Thoughts: Here's my take on those thoughts, tailored for an expert audience:
**Analyzing the Scope of `cma_src_addr`**
Okay, so `cma_src_addr` is cropping up all over the place. Hmm, it's clearly a key variable in this system, isn't it? Before I dig in too deep on *where* it's being used, I need to understand *what* it is. I'm going to track down its definition, and hopefully its associated documentation. I'm betting that understanding its purpose, its type, and especially its limitations and intended usage will unlock the meaning of all these usages I am seeing. That's the best way to determine if the uses I am seeing are sound or a code smell!
|
| 24/2 |
2026/02/24 22:58 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/infiniband/core/cma.c IncludeLines:true Name:cma_src_addr]
Results: map[SourceCode: 426: static struct sockaddr *cma_src_addr(struct rdma_id_private *id_priv)
427: {
428: return (struct sockaddr *)&id_priv->id.route.addr.src_addr;
429: }
SourceFile:drivers/infiniband/core/cma.c]
|
| 25/2 |
2026/02/24 22:58 |
llm |
expert |
0m
Model:
Tokens:
input: 16704
output: 43
thoughts: 906
Thoughts: **Data Race Concerns in UCMA Address Handling**
Okay, so I'm looking at this UCMA code and I see a potential race condition. Specifically, the code's returning the address of `id_priv->id.route.addr.src_addr`. Now, `ucma_query_addr` accesses this address like so: `addr = (struct sockaddr *) &ctx->cm_id->route.addr.src_addr;` which is the same thing, of course.
The race is between `addr_handler`, which is writing to this address, and `ucma_query_addr`, which is reading it. `addr_handler` is protected by `id_priv->handler_mutex`, while `ucma_query_addr` is protected by `ctx->mutex`. My immediate concern is whether `ctx->mutex` offers sufficient protection.
`ucma_query` retrieves `ctx` using `cmd.id`, and `ucma_get_ctx` probably increments a refcount. If `addr_handler` is running, then address resolution is underway for this `id`, and user-space might be querying it concurrently.
The impact of getting a partially updated address is probably minor for the kernel itself, but it’s definitely a data race. However, `memcpy` of 28 bytes is not atomic, so that is a worry.
Here's the problem: if `rdma_addr_size(addr)` in `ucma_query_addr` returns 16 (for `AF_INET`), but `addr_handler` then overwrites it with a `sockaddr_in6` (28 bytes), `ucma_query_addr` will only copy 16 bytes of the *new* `sockaddr_in6`. This results in a corrupted address being returned to user-space.
Are there other dangers? The code uses `rdma_addr_size` to determine how many bytes to copy, and if it returns 0 (the default), `memcpy` copies zero bytes.
In `addr_handler`, this is the line: `memcpy(addr, src_addr, rdma_addr_size(src_addr));` which uses `rdma_addr_size(src_addr)` where `src_addr` is the new address.
And in `ucma_query_addr`:
```c
resp.src_size = rdma_addr_size(addr);
memcpy(&resp.src_addr, addr, resp.src_size);
```
Here, it uses `rdma_addr_size(addr)`, and `addr` is the current address within the `cm_id`.
If `addr->sa_family` is changed by `addr_handler` between lines 924 and 925 of `ucma_query_addr`, then `resp.src_size` won’t match the family of the data being copied. That's really bad!
Now, I see that `addr_handler` is called when the state is `RDMA_CM_ADDR_QUERY`:
```c
if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY,
RDMA_CM_ADDR_RESOLVED))
```
It changes the state to `RDMA_CM_ADDR_RESOLVED`. Does `ucma_query_addr` check the state? No.
Ah, `ucma_query_addr` is called from `ucma_query`, which in turn is called from `ucma_write`.
Even if the worst-case scenario is a garbage address to user-space, is there a chance of a kernel crash? The `memcpy` to `&resp.src_addr` should be safe, because `resp.src_addr` is a `struct sockaddr_storage` (128 bytes). `resp.src_size` is at most 28 bytes (IPv6). But what about IB? `rdma_addr_size` for `AF_IB` returns `sizeof(struct sockaddr_ib)`. I should check the size of that structure. I need to be sure that the copy doesn't write past the buffer.
|
| 26/2 |
2026/02/24 22:58 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:include/rdma/ib_addr.h IncludeLines:true Name:sockaddr_ib]
Results: map[SourceCode: 56: struct sockaddr_ib {
57: unsigned short int sib_family; /* AF_IB */
58: __be16 sib_pkey;
59: __be32 sib_flowinfo;
60: struct ib_addr sib_addr;
61: __be64 sib_sid;
62: __be64 sib_sid_mask;
63: __u64 sib_scope_id;
64: };
SourceFile:include/rdma/ib.h]
|
| 27/2 |
2026/02/24 22:58 |
llm |
expert |
0m
Model:
Tokens:
input: 18719
output: 40
thoughts: 10
Thoughts: Here's my thought process, as if I were considering that code:
**Diving into `struct ib_addr`**
Okay, let's take a look at `struct ib_addr`. I need to refresh my memory on the Infiniband address structure. I expect it to contain the usual suspects: things like the Global Identifier (GID), perhaps a LID (Local Identifier), and probably some information related to the physical port and link layer. I'm curious if it's evolved any since the last time I dug into this level of the stack. Are there any new fields for RDMA over Converged Ethernet (RoCE) support? Or perhaps something related to the newer InfiniBand enhancements? I'll be looking for how it handles different address families and if there are any vendor-specific extensions baked in. It's a critical structure, so a careful inspection is warranted. Let's see what we've got.
|
| 28/2 |
2026/02/24 22:58 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:include/rdma/ib.h IncludeLines:true Name:ib_addr]
Results: map[SourceCode: 15: struct ib_addr {
16: union {
17: __u8 uib_addr8[16];
18: __be16 uib_addr16[8];
19: __be32 uib_addr32[4];
20: __be64 uib_addr64[2];
21: } ib_u;
22: #define sib_addr8 ib_u.uib_addr8
23: #define sib_addr16 ib_u.uib_addr16
24: #define sib_addr32 ib_u.uib_addr32
25: #define sib_addr64 ib_u.uib_addr64
26: #define sib_raw ib_u.uib_addr8
27: #define sib_subnet_prefix ib_u.uib_addr64[0]
28: #define sib_interface_id ib_u.uib_addr64[1]
29: };
SourceFile:include/rdma/ib.h]
|
| 29/2 |
2026/02/24 22:58 |
llm |
expert |
0m
Model:
Tokens:
input: 19281
output: 17
thoughts: 415
Thoughts: **Analyzing Potential Data Races in UCMA Address Handling**
Okay, let's break this down. First, I'm thinking about the size of `struct sockaddr_ib`. Adding up the fields, it's 2 + 2 + 4 + 16 + 8 + 8 + 8 = 48 bytes. That's well within the 128 bytes allocated for `struct sockaddr_storage`. Good, so the `memcpy` operation in `ucma_query_addr` shouldn't overflow `resp.src_addr`.
Now, looking at the `memcpy` in `addr_handler`:
```c
3523: memcpy(addr, src_addr, rdma_addr_size(src_addr));
```
Here, `addr` is actually `&id_priv->id.route.addr.src_addr`, which is that `sockaddr_storage`. The `src_addr` comes into `addr_handler` as a parameter. `rdma_addr_size(src_addr)` will be at most 48 for IB or 28 for IPv6, so that `memcpy` also appears safe from an overflow perspective.
The real issue is the potential data race itself. This `memcpy` could be happening at the same time as something else is writing to that memory location, resulting in inconsistent data in `ucma_query_addr`. That’s the real worry. I would expect some kind of signal of intent – like a comment or `READ_ONCE`/`WRITE_ONCE` – if this were intentional. But it's just a plain `memcpy`.
Wait a minute... `addr_handler` holds `id_priv->handler_mutex`. `ucma_query` holds `ctx->mutex`. Ah, if `ucma_query` also held `id_priv->handler_mutex`, the race would be eliminated. That's a key observation.
I need to see if other `ucma_` functions are using `handler_mutex` to get a better handle on the situation. I'll search for `handler_mutex` in `drivers/infiniband/core/ucma.c` and see if there are other access patterns.
|
| 30/2 |
2026/02/24 22:58 |
tool |
grepper |
0m
Args: map[Expression:handler_mutex]
Results: map[Output:drivers/acpi/wakeup.c=21=static LIST_HEAD(acpi_wakeup_handler_head);
drivers/acpi/wakeup.c:22:static DEFINE_MUTEX(acpi_wakeup_handler_mutex);
drivers/acpi/wakeup.c-23-
--
drivers/acpi/wakeup.c=111=int acpi_register_wakeup_handler(int wake_irq, bool (*wakeup)(void *context),
--
drivers/acpi/wakeup.c-129-
drivers/acpi/wakeup.c:130: mutex_lock(&acpi_wakeup_handler_mutex);
drivers/acpi/wakeup.c-131- list_add(&handler->list_node, &acpi_wakeup_handler_head);
drivers/acpi/wakeup.c:132: mutex_unlock(&acpi_wakeup_handler_mutex);
drivers/acpi/wakeup.c-133-
--
drivers/acpi/wakeup.c=143=void acpi_unregister_wakeup_handler(bool (*wakeup)(void *context),
--
drivers/acpi/wakeup.c-147-
drivers/acpi/wakeup.c:148: mutex_lock(&acpi_wakeup_handler_mutex);
drivers/acpi/wakeup.c-149- list_for_each_entry(handler, &acpi_wakeup_handler_head, list_node) {
--
drivers/acpi/wakeup.c-155- }
drivers/acpi/wakeup.c:156: mutex_unlock(&acpi_wakeup_handler_mutex);
drivers/acpi/wakeup.c-157-}
--
drivers/infiniband/core/cma.c=394=static int cma_comp_exch(struct rdma_id_private *id_priv,
--
drivers/infiniband/core/cma.c-401- * The FSM uses a funny double locking where state is protected by both
drivers/infiniband/core/cma.c:402: * the handler_mutex and the spinlock. State is not allowed to change
drivers/infiniband/core/cma.c:403: * to/from a handler_mutex protected value without also holding
drivers/infiniband/core/cma.c:404: * handler_mutex.
drivers/infiniband/core/cma.c-405- */
drivers/infiniband/core/cma.c-406- if (comp == RDMA_CM_CONNECT || exch == RDMA_CM_CONNECT)
drivers/infiniband/core/cma.c:407: lockdep_assert_held(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-408-
--
drivers/infiniband/core/cma.c=1007=__rdma_create_id(struct net *net, rdma_cm_event_handler event_handler,
--
drivers/infiniband/core/cma.c-1029- refcount_set(&id_priv->refcount, 1);
drivers/infiniband/core/cma.c:1030: mutex_init(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-1031- INIT_LIST_HEAD(&id_priv->device_item);
--
drivers/infiniband/core/cma.c=1959=static void cma_cancel_operation(struct rdma_id_private *id_priv,
--
drivers/infiniband/core/cma.c-1968- * outside this state, however due to the interaction with the
drivers/infiniband/core/cma.c:1969: * handler_mutex the work is guaranteed not to touch id_priv
drivers/infiniband/core/cma.c-1970- * during exit.
--
drivers/infiniband/core/cma.c=2053=static void _destroy_id(struct rdma_id_private *id_priv,
--
drivers/infiniband/core/cma.c-2088-/*
drivers/infiniband/core/cma.c:2089: * destroy an ID from within the handler_mutex. This ensures that no other
drivers/infiniband/core/cma.c-2090- * handlers can start running concurrently.
--
drivers/infiniband/core/cma.c=2092=static void destroy_id_handler_unlock(struct rdma_id_private *id_priv)
drivers/infiniband/core/cma.c:2093: __releases(&idprv->handler_mutex)
drivers/infiniband/core/cma.c-2094-{
--
drivers/infiniband/core/cma.c-2105- */
drivers/infiniband/core/cma.c:2106: lockdep_assert_held(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-2107- spin_lock_irqsave(&id_priv->lock, flags);
--
drivers/infiniband/core/cma.c-2110- spin_unlock_irqrestore(&id_priv->lock, flags);
drivers/infiniband/core/cma.c:2111: mutex_unlock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-2112- _destroy_id(id_priv, state);
--
drivers/infiniband/core/cma.c=2115=void rdma_destroy_id(struct rdma_cm_id *id)
--
drivers/infiniband/core/cma.c-2119-
drivers/infiniband/core/cma.c:2120: mutex_lock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-2121- destroy_id_handler_unlock(id_priv);
--
drivers/infiniband/core/cma.c=2169=static int cma_cm_event_handler(struct rdma_id_private *id_priv,
--
drivers/infiniband/core/cma.c-2173-
drivers/infiniband/core/cma.c:2174: lockdep_assert_held(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-2175-
--
drivers/infiniband/core/cma.c=2182=static int cma_ib_handler(struct ib_cm_id *cm_id,
--
drivers/infiniband/core/cma.c-2189-
drivers/infiniband/core/cma.c:2190: mutex_lock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-2191- state = READ_ONCE(id_priv->state);
--
drivers/infiniband/core/cma.c-2262-out:
drivers/infiniband/core/cma.c:2263: mutex_unlock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-2264- return 0;
--
drivers/infiniband/core/cma.c=2404=static int cma_ib_req_handler(struct ib_cm_id *cm_id,
--
drivers/infiniband/core/cma.c-2423-
drivers/infiniband/core/cma.c:2424: mutex_lock(&listen_id->handler_mutex);
drivers/infiniband/core/cma.c-2425- if (READ_ONCE(listen_id->state) != RDMA_CM_LISTEN) {
--
drivers/infiniband/core/cma.c-2446-
drivers/infiniband/core/cma.c:2447: mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
drivers/infiniband/core/cma.c-2448- ret = cma_ib_acquire_dev(conn_id, listen_id, &req);
--
drivers/infiniband/core/cma.c-2461- conn_id->cm_id.ib = NULL;
drivers/infiniband/core/cma.c:2462: mutex_unlock(&listen_id->handler_mutex);
drivers/infiniband/core/cma.c-2463- destroy_id_handler_unlock(conn_id);
--
drivers/infiniband/core/cma.c-2471- }
drivers/infiniband/core/cma.c:2472: mutex_unlock(&conn_id->handler_mutex);
drivers/infiniband/core/cma.c-2473-
drivers/infiniband/core/cma.c-2474-err_unlock:
drivers/infiniband/core/cma.c:2475: mutex_unlock(&listen_id->handler_mutex);
drivers/infiniband/core/cma.c-2476-
--
drivers/infiniband/core/cma.c=2519=static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
--
drivers/infiniband/core/cma.c-2526-
drivers/infiniband/core/cma.c:2527: mutex_lock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-2528- if (READ_ONCE(id_priv->state) != RDMA_CM_CONNECT)
--
drivers/infiniband/core/cma.c-2578-out:
drivers/infiniband/core/cma.c:2579: mutex_unlock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-2580- return ret;
--
drivers/infiniband/core/cma.c=2583=static int iw_conn_req_handler(struct iw_cm_id *cm_id,
--
drivers/infiniband/core/cma.c-2599-
drivers/infiniband/core/cma.c:2600: mutex_lock(&listen_id->handler_mutex);
drivers/infiniband/core/cma.c-2601- if (READ_ONCE(listen_id->state) != RDMA_CM_LISTEN)
--
drivers/infiniband/core/cma.c-2612- }
drivers/infiniband/core/cma.c:2613: mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
drivers/infiniband/core/cma.c-2614- conn_id->state = RDMA_CM_CONNECT;
--
drivers/infiniband/core/cma.c-2617- if (ret) {
drivers/infiniband/core/cma.c:2618: mutex_unlock(&listen_id->handler_mutex);
drivers/infiniband/core/cma.c-2619- destroy_id_handler_unlock(conn_id);
--
drivers/infiniband/core/cma.c-2624- if (ret) {
drivers/infiniband/core/cma.c:2625: mutex_unlock(&listen_id->handler_mutex);
drivers/infiniband/core/cma.c-2626- destroy_id_handler_unlock(conn_id);
--
drivers/infiniband/core/cma.c-2640- conn_id->cm_id.iw = NULL;
drivers/infiniband/core/cma.c:2641: mutex_unlock(&listen_id->handler_mutex);
drivers/infiniband/core/cma.c-2642- destroy_id_handler_unlock(conn_id);
--
drivers/infiniband/core/cma.c-2645-
drivers/infiniband/core/cma.c:2646: mutex_unlock(&conn_id->handler_mutex);
drivers/infiniband/core/cma.c-2647-
drivers/infiniband/core/cma.c-2648-out:
drivers/infiniband/core/cma.c:2649: mutex_unlock(&listen_id->handler_mutex);
drivers/infiniband/core/cma.c-2650- return ret;
--
drivers/infiniband/core/cma.c=2999=static void cma_iboe_join_work_handler(struct work_struct *work)
--
drivers/infiniband/core/cma.c-3006-
drivers/infiniband/core/cma.c:3007: mutex_lock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-3008- if (READ_ONCE(id_priv->state) == RDMA_CM_DESTROYING ||
--
drivers/infiniband/core/cma.c-3015-out_unlock:
drivers/infiniband/core/cma.c:3016: mutex_unlock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-3017- if (event->event == RDMA_CM_EVENT_MULTICAST_JOIN)
--
drivers/infiniband/core/cma.c=3021=static void cma_work_handler(struct work_struct *_work)
--
drivers/infiniband/core/cma.c-3025-
drivers/infiniband/core/cma.c:3026: mutex_lock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-3027- if (READ_ONCE(id_priv->state) == RDMA_CM_DESTROYING ||
--
drivers/infiniband/core/cma.c-3041-out_unlock:
drivers/infiniband/core/cma.c:3042: mutex_unlock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-3043- cma_id_put(id_priv);
--
drivers/infiniband/core/cma.c=3503=static void addr_handler(int status, struct sockaddr *src_addr,
--
drivers/infiniband/core/cma.c-3510-
drivers/infiniband/core/cma.c:3511: mutex_lock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-3512- if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY,
--
drivers/infiniband/core/cma.c-3549-out:
drivers/infiniband/core/cma.c:3550: mutex_unlock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-3551-}
--
drivers/infiniband/core/cma.c=4219=static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
--
drivers/infiniband/core/cma.c-4227-
drivers/infiniband/core/cma.c:4228: mutex_lock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-4229- if (READ_ONCE(id_priv->state) != RDMA_CM_CONNECT)
--
drivers/infiniband/core/cma.c-4279-out:
drivers/infiniband/core/cma.c:4280: mutex_unlock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-4281- return 0;
--
drivers/infiniband/core/cma.c=4474=int rdma_connect_locked(struct rdma_cm_id *id,
--
drivers/infiniband/core/cma.c-4480-
drivers/infiniband/core/cma.c:4481: lockdep_assert_held(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-4482-
--
drivers/infiniband/core/cma.c=4522=int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
--
drivers/infiniband/core/cma.c-4527-
drivers/infiniband/core/cma.c:4528: mutex_lock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-4529- ret = rdma_connect_locked(id, conn_param);
drivers/infiniband/core/cma.c:4530: mutex_unlock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-4531- return ret;
--
drivers/infiniband/core/cma.c=4663=int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
--
drivers/infiniband/core/cma.c-4668-
drivers/infiniband/core/cma.c:4669: lockdep_assert_held(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-4670-
--
drivers/infiniband/core/cma.c=4724=void rdma_lock_handler(struct rdma_cm_id *id)
--
drivers/infiniband/core/cma.c-4728-
drivers/infiniband/core/cma.c:4729: mutex_lock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-4730-}
--
drivers/infiniband/core/cma.c=4733=void rdma_unlock_handler(struct rdma_cm_id *id)
--
drivers/infiniband/core/cma.c-4737-
drivers/infiniband/core/cma.c:4738: mutex_unlock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-4739-}
--
drivers/infiniband/core/cma.c=4867=static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
--
drivers/infiniband/core/cma.c-4873-
drivers/infiniband/core/cma.c:4874: mutex_lock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-4875- if (READ_ONCE(id_priv->state) == RDMA_CM_DEVICE_REMOVAL ||
--
drivers/infiniband/core/cma.c-4887-out:
drivers/infiniband/core/cma.c:4888: mutex_unlock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-4889- return 0;
--
drivers/infiniband/core/cma.c=5180=static void cma_netevent_work_handler(struct work_struct *_work)
--
drivers/infiniband/core/cma.c-5185-
drivers/infiniband/core/cma.c:5186: mutex_lock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-5187-
--
drivers/infiniband/core/cma.c-5195- if (cma_cm_event_handler(id_priv, &event)) {
drivers/infiniband/core/cma.c:5196: __acquire(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-5197- id_priv->cm_id.ib = NULL;
--
drivers/infiniband/core/cma.c-5203-out_unlock:
drivers/infiniband/core/cma.c:5204: mutex_unlock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-5205- cma_id_put(id_priv);
--
drivers/infiniband/core/cma.c=5261=static void cma_send_device_removal_put(struct rdma_id_private *id_priv)
--
drivers/infiniband/core/cma.c-5266-
drivers/infiniband/core/cma.c:5267: mutex_lock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-5268- /* Record that we want to remove the device */
--
drivers/infiniband/core/cma.c-5272- spin_unlock_irqrestore(&id_priv->lock, flags);
drivers/infiniband/core/cma.c:5273: mutex_unlock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-5274- cma_id_put(id_priv);
--
drivers/infiniband/core/cma.c-5285- cma_id_put(id_priv);
drivers/infiniband/core/cma.c:5286: mutex_unlock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-5287- trace_cm_id_destroy(id_priv);
--
drivers/infiniband/core/cma.c-5290- }
drivers/infiniband/core/cma.c:5291: mutex_unlock(&id_priv->handler_mutex);
drivers/infiniband/core/cma.c-5292-
--
drivers/infiniband/core/cma_priv.h=55=struct rdma_id_private {
--
drivers/infiniband/core/cma_priv.h-79- refcount_t refcount;
drivers/infiniband/core/cma_priv.h:80: struct mutex handler_mutex;
drivers/infiniband/core/cma_priv.h-81-
--
drivers/macintosh/adb.c=95=static struct adb_handler {
--
drivers/macintosh/adb.c-102-/*
drivers/macintosh/adb.c:103: * The adb_handler_mutex mutex protects all accesses to the original_address
drivers/macintosh/adb.c-104- * and handler_id fields of adb_handler[i] for all i, and changes to the
--
drivers/macintosh/adb.c-110- */
drivers/macintosh/adb.c:111:static DEFINE_MUTEX(adb_handler_mutex);
drivers/macintosh/adb.c-112-static DEFINE_RWLOCK(adb_handler_lock);
--
drivers/macintosh/adb.c=358=do_adb_reset_bus(void)
--
drivers/macintosh/adb.c-375-
drivers/macintosh/adb.c:376: mutex_lock(&adb_handler_mutex);
drivers/macintosh/adb.c-377- write_lock_irq(&adb_handler_lock);
--
drivers/macintosh/adb.c-396- }
drivers/macintosh/adb.c:397: mutex_unlock(&adb_handler_mutex);
drivers/macintosh/adb.c-398-
--
drivers/macintosh/adb.c=472=adb_register(int default_id, int handler_id, struct adb_ids *ids,
--
drivers/macintosh/adb.c-476-
drivers/macintosh/adb.c:477: mutex_lock(&adb_handler_mutex);
drivers/macintosh/adb.c-478- ids->nids = 0;
--
drivers/macintosh/adb.c-493- }
drivers/macintosh/adb.c:494: mutex_unlock(&adb_handler_mutex);
drivers/macintosh/adb.c-495- return ids->nids;
--
drivers/macintosh/adb.c=500=adb_unregister(int index)
--
drivers/macintosh/adb.c-503-
drivers/macintosh/adb.c:504: mutex_lock(&adb_handler_mutex);
drivers/macintosh/adb.c-505- write_lock_irq(&adb_handler_lock);
--
drivers/macintosh/adb.c-515- write_unlock_irq(&adb_handler_lock);
drivers/macintosh/adb.c:516: mutex_unlock(&adb_handler_mutex);
drivers/macintosh/adb.c-517- return ret;
--
drivers/macintosh/adb.c=577=adb_try_handler_change(int address, int new_id)
--
drivers/macintosh/adb.c-580-
drivers/macintosh/adb.c:581: mutex_lock(&adb_handler_mutex);
drivers/macintosh/adb.c-582- ret = try_handler_change(address, new_id);
drivers/macintosh/adb.c:583: mutex_unlock(&adb_handler_mutex);
drivers/macintosh/adb.c-584- if (ret)
--
drivers/macintosh/adb.c=591=adb_get_infos(int address, int *original_address, int *handler_id)
drivers/macintosh/adb.c-592-{
drivers/macintosh/adb.c:593: mutex_lock(&adb_handler_mutex);
drivers/macintosh/adb.c-594- *original_address = adb_handler[address].original_address;
drivers/macintosh/adb.c-595- *handler_id = adb_handler[address].handler_id;
drivers/macintosh/adb.c:596: mutex_unlock(&adb_handler_mutex);
drivers/macintosh/adb.c-597-
--
drivers/macintosh/adb.c=646=do_adb_query(struct adb_request *req)
--
drivers/macintosh/adb.c-653- break;
drivers/macintosh/adb.c:654: mutex_lock(&adb_handler_mutex);
drivers/macintosh/adb.c-655- req->reply[0] = adb_handler[req->data[2]].original_address;
drivers/macintosh/adb.c-656- req->reply[1] = adb_handler[req->data[2]].handler_id;
drivers/macintosh/adb.c:657: mutex_unlock(&adb_handler_mutex);
drivers/macintosh/adb.c-658- req->complete = 1;
--
drivers/s390/block/dasd_eckd.c=110=static struct pe_handler_work_data *pe_handler_worker;
drivers/s390/block/dasd_eckd.c:111:static DEFINE_MUTEX(dasd_pe_handler_mutex);
drivers/s390/block/dasd_eckd.c-112-
--
drivers/s390/block/dasd_eckd.c=1434=static void do_pe_handler_work(struct work_struct *work)
--
drivers/s390/block/dasd_eckd.c-1460- if (data->isglobal)
drivers/s390/block/dasd_eckd.c:1461: mutex_unlock(&dasd_pe_handler_mutex);
drivers/s390/block/dasd_eckd.c-1462- else
--
drivers/s390/block/dasd_eckd.c=1466=static int dasd_eckd_pe_handler(struct dasd_device *device,
--
drivers/s390/block/dasd_eckd.c-1472- if (!data) {
drivers/s390/block/dasd_eckd.c:1473: if (mutex_trylock(&dasd_pe_handler_mutex)) {
drivers/s390/block/dasd_eckd.c-1474- data = pe_handler_worker;
--
drivers/s390/cio/crw.c-18-
drivers/s390/cio/crw.c:19:static DEFINE_MUTEX(crw_handler_mutex);
drivers/s390/cio/crw.c-20-static crw_handler_t crw_handlers[NR_RSCS];
--
drivers/s390/cio/crw.c=31=int crw_register_handler(int rsc, crw_handler_t handler)
--
drivers/s390/cio/crw.c-36- return -EINVAL;
drivers/s390/cio/crw.c:37: mutex_lock(&crw_handler_mutex);
drivers/s390/cio/crw.c-38- if (crw_handlers[rsc])
--
drivers/s390/cio/crw.c-41- crw_handlers[rsc] = handler;
drivers/s390/cio/crw.c:42: mutex_unlock(&crw_handler_mutex);
drivers/s390/cio/crw.c-43- return rc;
--
drivers/s390/cio/crw.c=50=void crw_unregister_handler(int rsc)
--
drivers/s390/cio/crw.c-53- return;
drivers/s390/cio/crw.c:54: mutex_lock(&crw_handler_mutex);
drivers/s390/cio/crw.c-55- crw_handlers[rsc] = NULL;
drivers/s390/cio/crw.c:56: mutex_unlock(&crw_handler_mutex);
drivers/s390/cio/crw.c-57-}
--
drivers/s390/cio/crw.c=62=static int crw_collect_info(void *unused)
--
drivers/s390/cio/crw.c-107- pr_debug("%s: crw overflow detected!\n", __func__);
drivers/s390/cio/crw.c:108: mutex_lock(&crw_handler_mutex);
drivers/s390/cio/crw.c-109- for (i = 0; i < NR_RSCS; i++) {
--
drivers/s390/cio/crw.c-112- }
drivers/s390/cio/crw.c:113: mutex_unlock(&crw_handler_mutex);
drivers/s390/cio/crw.c-114- chain = 0;
--
drivers/s390/cio/crw.c-120- }
drivers/s390/cio/crw.c:121: mutex_lock(&crw_handler_mutex);
drivers/s390/cio/crw.c-122- handler = crw_handlers[crw[chain].rsc];
--
drivers/s390/cio/crw.c-124- handler(&crw[0], chain ? &crw[1] : NULL, 0);
drivers/s390/cio/crw.c:125: mutex_unlock(&crw_handler_mutex);
drivers/s390/cio/crw.c-126- /* chain is always 0 or 1 here. */
--
sound/soc/sof/core.c=630=int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
--
sound/soc/sof/core.c-681- mutex_init(&sdev->ipc_client_mutex);
sound/soc/sof/core.c:682: mutex_init(&sdev->client_event_handler_mutex);
sound/soc/sof/core.c-683-
--
sound/soc/sof/sof-client.c=510=void sof_client_ipc_rx_dispatcher(struct snd_sof_dev *sdev, void *msg_buf)
--
sound/soc/sof/sof-client.c-528-
sound/soc/sof/sof-client.c:529: mutex_lock(&sdev->client_event_handler_mutex);
sound/soc/sof/sof-client.c-530-
--
sound/soc/sof/sof-client.c-535-
sound/soc/sof/sof-client.c:536: mutex_unlock(&sdev->client_event_handler_mutex);
sound/soc/sof/sof-client.c-537-}
--
sound/soc/sof/sof-client.c=539=int sof_client_register_ipc_rx_handler(struct sof_client_dev *cdev,
--
sound/soc/sof/sof-client.c-569- /* add to list of SOF client devices */
sound/soc/sof/sof-client.c:570: mutex_lock(&sdev->client_event_handler_mutex);
sound/soc/sof/sof-client.c-571- list_add(&event->list, &sdev->ipc_rx_handler_list);
sound/soc/sof/sof-client.c:572: mutex_unlock(&sdev->client_event_handler_mutex);
sound/soc/sof/sof-client.c-573-
--
sound/soc/sof/sof-client.c=578=void sof_client_unregister_ipc_rx_handler(struct sof_client_dev *cdev,
--
sound/soc/sof/sof-client.c-583-
sound/soc/sof/sof-client.c:584: mutex_lock(&sdev->client_event_handler_mutex);
sound/soc/sof/sof-client.c-585-
--
sound/soc/sof/sof-client.c-593-
sound/soc/sof/sof-client.c:594: mutex_unlock(&sdev->client_event_handler_mutex);
sound/soc/sof/sof-client.c-595-}
--
sound/soc/sof/sof-client.c=599=void sof_client_fw_state_dispatcher(struct snd_sof_dev *sdev)
--
sound/soc/sof/sof-client.c-602-
sound/soc/sof/sof-client.c:603: mutex_lock(&sdev->client_event_handler_mutex);
sound/soc/sof/sof-client.c-604-
--
sound/soc/sof/sof-client.c-607-
sound/soc/sof/sof-client.c:608: mutex_unlock(&sdev->client_event_handler_mutex);
sound/soc/sof/sof-client.c-609-}
--
sound/soc/sof/sof-client.c=611=int sof_client_register_fw_state_handler(struct sof_client_dev *cdev,
--
sound/soc/sof/sof-client.c-627- /* add to list of SOF client devices */
sound/soc/sof/sof-client.c:628: mutex_lock(&sdev->client_event_handler_mutex);
sound/soc/sof/sof-client.c-629- list_add(&event->list, &sdev->fw_state_handler_list);
sound/soc/sof/sof-client.c:630: mutex_unlock(&sdev->client_event_handler_mutex);
sound/soc/sof/sof-client.c-631-
--
sound/soc/sof/sof-client.c=636=void sof_client_unregister_fw_state_handler(struct sof_client_dev *cdev)
--
sound/soc/sof/sof-client.c-640-
sound/soc/sof/sof-client.c:641: mutex_lock(&sdev->client_event_handler_mutex);
sound/soc/sof/sof-client.c-642-
--
sound/soc/sof/sof-client.c-650-
sound/soc/sof/sof-client.c:651: mutex_unlock(&sdev->client_event_handler_mutex);
sound/soc/sof/sof-client.c-652-}
--
sound/soc/sof/sof-priv.h=547=struct snd_sof_dev {
--
sound/soc/sof/sof-priv.h-679- /* to protect the ipc_rx_handler_list and dsp_state_handler_list list */
sound/soc/sof/sof-priv.h:680: struct mutex client_event_handler_mutex;
sound/soc/sof/sof-priv.h-681-
]
|
| 31/2 |
2026/02/24 22:58 |
llm |
expert |
0m
Model:
Tokens:
input: 29922
output: 20
thoughts: 210
Thoughts: **Investigating the Handler Mutex**
Okay, so the initial `grep` for `handler_mutex` within `ucma.c` didn't turn up anything particularly interesting. But wait a second... I jumped the gun a bit. I should have broadened the scope of my search. Given the nature of this, the relevant locking mechanism is likely within the core Infiniband drivers. Let me focus my attention on `drivers/infiniband/core/` instead.
Aha! It looks like `rdma_lock_handler` and `rdma_unlock_handler` are exported functions, and those are responsible for locking and unlocking the `handler_mutex`. That's precisely what I was looking for. Now to see how `ucma.c` actually utilizes these exported functions to ensure proper synchronization. That should tell the tale.
|
| 32/2 |
2026/02/24 22:58 |
tool |
grepper |
0m
Args: map[Expression:rdma_lock_handler]
Results: map[Output:drivers/infiniband/core/cma.c=4722=EXPORT_SYMBOL(rdma_accept_ece);
drivers/infiniband/core/cma.c-4723-
drivers/infiniband/core/cma.c:4724:void rdma_lock_handler(struct rdma_cm_id *id)
drivers/infiniband/core/cma.c-4725-{
--
drivers/infiniband/core/cma.c-4730-}
drivers/infiniband/core/cma.c:4731:EXPORT_SYMBOL(rdma_lock_handler);
drivers/infiniband/core/cma.c-4732-
--
drivers/infiniband/core/ucma.c=511=static void ucma_cleanup_mc_events(struct ucma_multicast *mc)
--
drivers/infiniband/core/ucma.c-514-
drivers/infiniband/core/ucma.c:515: rdma_lock_handler(mc->ctx->cm_id);
drivers/infiniband/core/ucma.c-516- mutex_lock(&mc->ctx->file->mut);
--
drivers/infiniband/core/ucma.c=1179=static ssize_t ucma_accept(struct ucma_file *file, const char __user *inbuf,
--
drivers/infiniband/core/ucma.c-1206- mutex_lock(&ctx->mutex);
drivers/infiniband/core/ucma.c:1207: rdma_lock_handler(ctx->cm_id);
drivers/infiniband/core/ucma.c-1208- ret = rdma_accept_ece(ctx->cm_id, &conn_param, &ece);
--
drivers/infiniband/core/ucma.c-1216- mutex_lock(&ctx->mutex);
drivers/infiniband/core/ucma.c:1217: rdma_lock_handler(ctx->cm_id);
drivers/infiniband/core/ucma.c-1218- ret = rdma_accept_ece(ctx->cm_id, NULL, &ece);
--
drivers/infiniband/core/ucma.c=1678=static ssize_t ucma_migrate_id(struct ucma_file *new_file,
--
drivers/infiniband/core/ucma.c-1705-
drivers/infiniband/core/ucma.c:1706: rdma_lock_handler(ctx->cm_id);
drivers/infiniband/core/ucma.c-1707- /*
--
fs/smb/server/transport_rdma.c=452=static void free_transport(struct smb_direct_transport *t)
--
fs/smb/server/transport_rdma.c-477- if (sc->rdma.cm_id)
fs/smb/server/transport_rdma.c:478: rdma_lock_handler(sc->rdma.cm_id);
fs/smb/server/transport_rdma.c-479-
--
include/rdma/rdma_cm.h=276=int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param);
include/rdma/rdma_cm.h-277-
include/rdma/rdma_cm.h:278:void rdma_lock_handler(struct rdma_cm_id *id);
include/rdma/rdma_cm.h-279-void rdma_unlock_handler(struct rdma_cm_id *id);
--
net/sunrpc/xprtrdma/svc_rdma_transport.c=407=static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
--
net/sunrpc/xprtrdma/svc_rdma_transport.c-549- conn_param.private_data_len = sizeof(pmsg);
net/sunrpc/xprtrdma/svc_rdma_transport.c:550: rdma_lock_handler(newxprt->sc_cm_id);
net/sunrpc/xprtrdma/svc_rdma_transport.c-551- newxprt->sc_cm_id->event_handler = svc_rdma_cma_handler;
]
|
| 33/2 |
2026/02/24 22:58 |
llm |
expert |
0m
Model:
Tokens:
input: 31487
output: 50
thoughts: 654
Thoughts: **Addressing Potential Data Races in ucma_query_addr**
Okay, so I've been digging into this `ucma_` code and it looks like `ucma_query` isn't calling `rdma_lock_handler`, which is odd because `ucma_accept` and `ucma_migrate_id` do. This immediately raises a red flag. I'm worried about concurrent access. If `ucma_query_addr` is meant to safely read the address, it probably *should* be locking the handler too.
Let's dissect `ucma_query_addr` line by line. I'm focusing on lines 923-930:
```c
923: addr = (struct sockaddr *) &ctx->cm_id->route.addr.src_addr;
924: resp.src_size = rdma_addr_size(addr);
925: memcpy(&resp.src_addr, addr, resp.src_size);
...
927: addr = (struct sockaddr *) &ctx->cm_id->route.addr.dst_addr;
928: resp.dst_size = rdma_addr_size(addr);
929: memcpy(&resp.dst_addr, addr, resp.dst_size);
930:
```
My concern is that if `addr_handler` is called, it signals that address resolution is in progress or completed. If `ucma_query_addr` is called at the same time, it could potentially read a stale, inconsistent, or partially updated address. The user space could end up with a mix of old and new data.
Now, while the RDMA CM state machine is complex, I have to think about the possible consequences of user-space getting corrupted data. On the one hand, a bad address *might* lead to a simple failure in later calls. But given that `rdma_lock_handler` *exists* and *is* used elsewhere, it suggests that accessing `cm_id` fields that are modified by callbacks needs locking.
I need to check *where else* `route.addr` is modified. I've found it's modified in `addr_handler` and `cma_bind_addr`. Wait. `addr_handler` is a callback from `rdma_resolve_addr`. This means the user-space is *waiting* for the address to be resolved. It's almost a user-space race condition. But, the kernel *should* prevent kernel data races, so this shouldn't be possible.
Now I am going to see if any other `cm_id` fields are being read in `ucma_query_addr`. Line 927 shows that `dst_addr` is also being read. The same race condition would exist for the destination address. I'm going to look at `ucma_query_device_addr` next and see if it reads any more data.
|
| 34/2 |
2026/02/24 22:58 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/infiniband/core/ucma.c IncludeLines:true Name:ucma_query_device_addr]
Results: map[SourceCode: 898: static void ucma_query_device_addr(struct rdma_cm_id *cm_id,
899: struct rdma_ucm_query_addr_resp *resp)
900: {
901: if (!cm_id->device)
902: return;
903:
904: resp->node_guid = (__force __u64) cm_id->device->node_guid;
905: resp->ibdev_index = cm_id->device->index;
906: resp->port_num = cm_id->port_num;
907: resp->pkey = (__force __u16) cpu_to_be16(
908: ib_addr_get_pkey(&cm_id->route.addr.dev_addr));
909: }
SourceFile:drivers/infiniband/core/ucma.c]
|
| 35/2 |
2026/02/24 22:58 |
llm |
expert |
0m
Model:
Tokens:
input: 33110
output: 54
thoughts: 217
Thoughts: **Tracing the `dev_addr` Assignment**
Okay, so I'm digging into this code and trying to figure out where `dev_addr` is actually being populated, specifically in the context of `cm_id->route.addr.dev_addr`. I noticed it's being read there, but I don't see the write operation within `addr_handler` itself.
Aha! Upon closer inspection, `addr_handler` *does* receive `dev_addr` as an argument. Good. Now, I have to find out what happens to that argument. It doesn't look like it's a direct copy to the destination.
Then it hits me... `cma_acquire_dev_by_src_ip`. This looks like a promising lead. Line 3525 calls it, and it's the next place I need to investigate to determine where the argument ends up, and when, and how, the `dev_addr` field actually gets set for the route. Let's dive into `cma_acquire_dev_by_src_ip`.
|
| 36/2 |
2026/02/24 22:59 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/infiniband/core/cma.c IncludeLines:true Name:cma_acquire_dev_by_src_ip]
Results: map[SourceCode: 765: /**
766: * cma_acquire_dev_by_src_ip - Acquire cma device, port, gid attribute
767: * based on source ip address.
768: * @id_priv: cm_id which should be bound to cma device
769: *
770: * cma_acquire_dev_by_src_ip() binds cm id to cma device, port and GID attribute
771: * based on source IP address. It returns 0 on success or error code otherwise.
772: * It is applicable to active and passive side cm_id.
773: */
774: static int cma_acquire_dev_by_src_ip(struct rdma_id_private *id_priv)
775: {
776: struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr;
777: const struct ib_gid_attr *sgid_attr;
778: union ib_gid gid, iboe_gid, *gidp;
779: struct cma_device *cma_dev;
780: enum ib_gid_type gid_type;
781: int ret = -ENODEV;
782: u32 port;
783:
784: if (dev_addr->dev_type != ARPHRD_INFINIBAND &&
785: id_priv->id.ps == RDMA_PS_IPOIB)
786: return -EINVAL;
787:
788: rdma_ip2gid((struct sockaddr *)&id_priv->id.route.addr.src_addr,
789: &iboe_gid);
790:
791: memcpy(&gid, dev_addr->src_dev_addr +
792: rdma_addr_gid_offset(dev_addr), sizeof(gid));
793:
794: mutex_lock(&lock);
795: list_for_each_entry(cma_dev, &dev_list, list) {
796: rdma_for_each_port (cma_dev->device, port) {
797: gidp = rdma_protocol_roce(cma_dev->device, port) ?
798: &iboe_gid : &gid;
799: gid_type = cma_dev->default_gid_type[port - 1];
800: sgid_attr = cma_validate_port(cma_dev->device, port,
801: gid_type, gidp, id_priv);
802: if (!IS_ERR(sgid_attr)) {
803: id_priv->id.port_num = port;
804: cma_bind_sgid_attr(id_priv, sgid_attr);
805: cma_attach_to_dev(id_priv, cma_dev);
806: ret = 0;
807: goto out;
808: }
809: }
810: }
811: out:
812: mutex_unlock(&lock);
813: return ret;
814: }
SourceFile:drivers/infiniband/core/cma.c]
|
| 37/2 |
2026/02/24 22:59 |
llm |
expert |
0m
Model:
Tokens:
input: 34544
output: 46
thoughts: 89
Thoughts: Okay, let me think this through.
**Investigating a Device Address Issue**
Right, so it appears the code isn't *writing* to `dev_addr`, which is what I was expecting. Instead, it's reading from it. That's the first thing I've noticed. Hmm, okay, now I need to figure out *where* `id_priv->id.route.addr.dev_addr` is actually being updated, because if it's not being written to, it's likely a read of a stale value and needs to be handled in a very specific way.
Ah, I remember! `addr_handler`. It's passed as an argument there. So the `dev_addr` value is being passed to the `addr_handler` but is this the only place? That means `addr_handler` is the logical place to start looking for updates to this variable, but I need to make sure I understand the full call graph. Actually, wait a minute, I think `process_one_req` in `addr.c` calls `addr_handler`. That's it! That's the key. I need to trace back from that call to understand how `dev_addr` is getting its value. Time to dive into `process_one_req`.
|
| 38/2 |
2026/02/24 22:59 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/infiniband/core/addr.c IncludeLines:true Name:process_one_req]
Results: map[SourceCode: 597: static void process_one_req(struct work_struct *_work)
598: {
599: struct addr_req *req;
600: struct sockaddr *src_in, *dst_in;
601:
602: req = container_of(_work, struct addr_req, work.work);
603:
604: if (req->status == -ENODATA) {
605: src_in = (struct sockaddr *)&req->src_addr;
606: dst_in = (struct sockaddr *)&req->dst_addr;
607: req->status = addr_resolve(src_in, dst_in, req->addr,
608: true, req->resolve_by_gid_attr,
609: req->seq);
610: if (req->status && time_after_eq(jiffies, req->timeout)) {
611: req->status = -ETIMEDOUT;
612: } else if (req->status == -ENODATA) {
613: /* requeue the work for retrying again */
614: spin_lock_bh(&lock);
615: if (!list_empty(&req->list))
616: set_timeout(req, req->timeout);
617: spin_unlock_bh(&lock);
618: return;
619: }
620: }
621:
622: req->callback(req->status, (struct sockaddr *)&req->src_addr,
623: req->addr, req->context);
624: req->callback = NULL;
625:
626: spin_lock_bh(&lock);
627: /*
628: * Although the work will normally have been canceled by the workqueue,
629: * it can still be requeued as long as it is on the req_list.
630: */
631: cancel_delayed_work(&req->work);
632: if (!list_empty(&req->list)) {
633: list_del_init(&req->list);
634: kfree(req);
635: }
636: spin_unlock_bh(&lock);
637: }
SourceFile:drivers/infiniband/core/addr.c]
|
| 39/2 |
2026/02/24 22:59 |
llm |
expert |
0m
Model:
Tokens:
input: 35625
output: 48
thoughts: 96
Thoughts: **Analyzing the Address Resolution Process**
Okay, so I'm looking at this code and trying to trace how the device address is handled. The callback function receives `req->addr`, that's clear enough. Then, inside `addr_handler`, the corresponding address becomes `dev_addr`. However, I'm not seeing any explicit copying of this `dev_addr` to `id_priv->id.route.addr.dev_addr`. That's a potential oversight, something I need to investigate further.
Now, I remember `rdma_resolve_addr` calls `rdma_addr_resolve`. Aha! That's where the real magic likely happens, or *doesn't* happen, as the case might be. I need to dive into `rdma_resolve_addr` now to fully grasp the address resolution and how the device address gets populated (or *isn't* populated) within that flow.
|
| 40/2 |
2026/02/24 22:59 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/infiniband/core/cma.c IncludeLines:true Name:rdma_resolve_addr]
Results: map[SourceCode:4132: int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
4133: const struct sockaddr *dst_addr, unsigned long timeout_ms)
4134: {
4135: struct rdma_id_private *id_priv =
4136: container_of(id, struct rdma_id_private, id);
4137: int ret;
4138:
4139: ret = resolve_prepare_src(id_priv, src_addr, dst_addr);
4140: if (ret)
4141: return ret;
4142:
4143: if (cma_any_addr(dst_addr)) {
4144: ret = cma_resolve_loopback(id_priv);
4145: } else {
4146: if (dst_addr->sa_family == AF_IB) {
4147: ret = cma_resolve_ib_addr(id_priv);
4148: } else {
4149: /*
4150: * The FSM can return back to RDMA_CM_ADDR_BOUND after
4151: * rdma_resolve_ip() is called, eg through the error
4152: * path in addr_handler(). If this happens the existing
4153: * request must be canceled before issuing a new one.
4154: * Since canceling a request is a bit slow and this
4155: * oddball path is rare, keep track once a request has
4156: * been issued. The track turns out to be a permanent
4157: * state since this is the only cancel as it is
4158: * immediately before rdma_resolve_ip().
4159: */
4160: if (id_priv->used_resolve_ip)
4161: rdma_addr_cancel(&id->route.addr.dev_addr);
4162: else
4163: id_priv->used_resolve_ip = 1;
4164: ret = rdma_resolve_ip(cma_src_addr(id_priv), dst_addr,
4165: &id->route.addr.dev_addr,
4166: timeout_ms, addr_handler,
4167: false, id_priv);
4168: }
4169: }
4170: if (ret)
4171: goto err;
4172:
4173: return 0;
4174: err:
4175: cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND);
4176: return ret;
4177: }
SourceFile:drivers/infiniband/core/cma.c]
|
| 41/2 |
2026/02/24 22:59 |
llm |
expert |
0m
Model:
Tokens:
input: 36744
output: 47
thoughts: 127
Thoughts: Okay, let's break this down.
**Investigating a Potential Race Condition in RDMA Address Resolution**
Right, so I'm seeing this code flow where `&id->route.addr.dev_addr` is passed to `rdma_resolve_ip`. My intuition immediately flags this; I know `rdma_resolve_ip` is going to populate this `dev_addr` field at some point. It's essentially the output of this address resolution process.
The crux of my concern is that `rdma_resolve_ip`, or the address resolution it orchestrates, is actively *writing* to `id->route.addr.dev_addr`. Simultaneously, I'm thinking about `ucma_query_addr`, and the nagging feeling that it might be *reading* this same location. Bingo, that screams potential race condition to me. Data corruption, inconsistent reads, the usual suspects...
Let me just quickly confirm where `rdma_resolve_ip` lives. Ah, yes, it's deep within the `drivers/infiniband/core/addr.c` module. Good, that gives me a handle. Now, my next step is clear. I need to dive into `rdma_resolve_ip` and meticulously trace all the writes to `dev_addr` to get a definitive picture of the access patterns and confirm my suspicion. Let's see what's actually going on in that function...
|
| 42/2 |
2026/02/24 22:59 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/infiniband/core/addr.c IncludeLines:true Name:rdma_resolve_ip]
Results: map[SourceCode: 639: int rdma_resolve_ip(struct sockaddr *src_addr, const struct sockaddr *dst_addr,
640: struct rdma_dev_addr *addr, unsigned long timeout_ms,
641: void (*callback)(int status, struct sockaddr *src_addr,
642: struct rdma_dev_addr *addr, void *context),
643: bool resolve_by_gid_attr, void *context)
644: {
645: struct sockaddr *src_in, *dst_in;
646: struct addr_req *req;
647: int ret = 0;
648:
649: req = kzalloc(sizeof *req, GFP_KERNEL);
650: if (!req)
651: return -ENOMEM;
652:
653: src_in = (struct sockaddr *) &req->src_addr;
654: dst_in = (struct sockaddr *) &req->dst_addr;
655:
656: if (src_addr) {
657: if (src_addr->sa_family != dst_addr->sa_family) {
658: ret = -EINVAL;
659: goto err;
660: }
661:
662: memcpy(src_in, src_addr, rdma_addr_size(src_addr));
663: } else {
664: src_in->sa_family = dst_addr->sa_family;
665: }
666:
667: memcpy(dst_in, dst_addr, rdma_addr_size(dst_addr));
668: req->addr = addr;
669: req->callback = callback;
670: req->context = context;
671: req->resolve_by_gid_attr = resolve_by_gid_attr;
672: INIT_DELAYED_WORK(&req->work, process_one_req);
673: req->seq = (u32)atomic_inc_return(&ib_nl_addr_request_seq);
674:
675: req->status = addr_resolve(src_in, dst_in, addr, true,
676: req->resolve_by_gid_attr, req->seq);
677: switch (req->status) {
678: case 0:
679: req->timeout = jiffies;
680: queue_req(req);
681: break;
682: case -ENODATA:
683: req->timeout = msecs_to_jiffies(timeout_ms) + jiffies;
684: queue_req(req);
685: break;
686: default:
687: ret = req->status;
688: goto err;
689: }
690: return ret;
691: err:
692: kfree(req);
693: return ret;
694: }
SourceFile:drivers/infiniband/core/addr.c]
|
| 43/2 |
2026/02/24 22:59 |
llm |
expert |
0m
Model:
Tokens:
input: 38113
output: 48
thoughts: 1199
Thoughts: **Race Condition in RDMA CM Address Resolution**
Okay, so I'm looking at this KCSAN report, and it's pointing to a potential data race within the RDMA connection manager (CM) code, specifically around address resolution. It's calling `addr_resolve`, and it seems that `addr_resolve` is writing to the `dev_addr` field of an `id->route.addr` structure.
The report mentions `addr_handler` writing to a specific memory location. I traced that back to this `memcpy` within the `addr_handler` function. It's updating the source address (`src_addr`) with the resolved address. The key thing is that the source address *might* have been modified during the resolution process, for example if it was initially `INADDR_ANY`.
Now, I'm looking at `ucma_query_addr`. It appears to be reading the source address, copying it into a response structure to pass back to user-space. The problem is, this read (`ucma_query_addr`) is potentially racing with the write from `addr_handler`.
So, `addr_handler` is updating the source address *while* `ucma_query_addr` is trying to read it. If `ucma_query_addr` returns a corrupted address to the user, that's a problem, that's a definite bug. It's not just a benign race; this is structured data that *must* be consistent.
I checked for potential buffer overflows due to size mismatches. However, the `sockaddr_storage` is 128 bytes, so it's safe. However, the `rdma_addr_size` function reads `sa_family`. If `sa_family` changes from, say, `AF_INET` to `AF_INET6` *between* the size check and the `memcpy` in `ucma_query_addr`, it gets messy. `rdma_addr_size` might return 16, but `memcpy` could copy 16 bytes of what's now a 28-byte `sockaddr_in6`. The user-space receives a mangled address: it will have `AF_INET6` but only 16 bytes. That is a real bug because the address will be truncated/corrupted!
This needs fixing with proper locking. The `ucma_query` function should probably grab the right mutex to ensure a consistent view of the `cm_id` structure.
Wait, though... `ucma_query` already holds `ctx->mutex`. Why isn't `addr_handler` using that mutex? Well, `addr_handler` is a generic RDMA CM callback, not inherently tied to `ucma` or its context. But, for user-space IDs, the `context` of the `rdma_cm_id` *is* the `ucma_context`.
But `addr_handler` is *defined* in `cma.c`, which is the core CM. It's a static function in that file, used as a callback for `rdma_resolve_ip`. Aha! `addr_handler` is not the user-provided callback. It's an *internal* callback used by the CM! The user's callback is called later through `cma_cm_event_handler`.
`cma_cm_event_handler` eventually calls the `ucma` event handler if it's a user-space ID. So the race is happening because `ucma_query` (which is called by the `ucma` event handler) isn't using the same lock as `addr_handler`. `addr_handler` is using `id_priv->handler_mutex`, while `ucma_query` uses `ctx->mutex`.
So, if I change `ucma_query` to also take `handler_mutex`, that *should* solve the race. Is there any reason *not* to do that? Maybe deadlocks? `ucma_query` would take `ctx->mutex` *then* it would take `handler_mutex`. `addr_handler` takes `handler_mutex`... Does it *ever* take `ctx->mutex`? Let me trace that... `cma_cm_event_handler` calls the event handler, and for `ucma`, that's `ucma_event_handler`. I need to check `ucma_event_handler` to be sure.
|
| 44/2 |
2026/02/24 22:59 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/infiniband/core/ucma.c IncludeLines:true Name:ucma_event_handler]
Results: map[SourceCode: 339: static int ucma_event_handler(struct rdma_cm_id *cm_id,
340: struct rdma_cm_event *event)
341: {
342: struct ucma_event *uevent;
343: struct ucma_context *ctx = cm_id->context;
344:
345: if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST)
346: return ucma_connect_event_handler(cm_id, event);
347:
348: /*
349: * We ignore events for new connections until userspace has set their
350: * context. This can only happen if an error occurs on a new connection
351: * before the user accepts it. This is okay, since the accept will just
352: * fail later. However, we do need to release the underlying HW
353: * resources in case of a device removal event.
354: */
355: if (ctx->uid) {
356: uevent = ucma_create_uevent(ctx, event);
357: if (!uevent)
358: return 0;
359:
360: mutex_lock(&ctx->file->mut);
361: list_add_tail(&uevent->list, &ctx->file->event_list);
362: mutex_unlock(&ctx->file->mut);
363: wake_up_interruptible(&ctx->file->poll_wait);
364: }
365:
366: if (event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) {
367: xa_lock(&ctx_table);
368: if (xa_load(&ctx_table, ctx->id) == ctx)
369: queue_work(system_dfl_wq, &ctx->close_work);
370: xa_unlock(&ctx_table);
371: }
372: return 0;
373: }
SourceFile:drivers/infiniband/core/ucma.c]
|
| 45/2 |
2026/02/24 22:59 |
llm |
expert |
0m
Model:
Tokens:
input: 40939
output: 20
thoughts: 1828
Thoughts: **Data Race Analysis in UCMA Query Functions**
Okay, so I've been looking at the `ucma_event_handler` and how it interacts with `ucma_query` functions. It appears there's a potential data race here that warrants deeper investigation. My initial thought is that `ucma_event_handler` takes the `ctx->file->mut` lock, but crucially *not* `ctx->mutex`, which means a possible lock order of `handler_mutex` -> `ctx->file->mut` exists. The function `ucma_query` takes `ctx->mutex`. If it *also* took `handler_mutex`, the order would be `ctx->mutex` -> `handler_mutex`.
However, after examining `ucma_accept`, I realize that `ctx->mutex` -> `handler_mutex` is *already* an established lock order due to `rdma_lock_handler`. So, it follows that `ucma_query` should likely also take `handler_mutex` to maintain lock order consistency and prevent races.
The fact that it doesn't is almost certainly an oversight, suggesting a data race.
Now, is this race "harmful"? KCSAN would flag this as a potential bug, since it leads to data corruption in user-space. It doesn't seem to cause a kernel crash, but it definitely leads to corrupted data from a user-space perspective.
I considered a situation where if `rdma_addr_size` returned 0, a zero-byte `memcpy` would occur. That wouldn't crash the system.
However, if `addr->sa_family` is garbage, then `rdma_addr_size` returns 0, and that's the only safe scenario here. The more interesting scenario involves `addr_handler`, which is responsible for the following:
```c
3523: memcpy(addr, src_addr, rdma_addr_size(src_addr));
```
This overwrites `addr->sa_family` first, which is at the *beginning* of the struct. On little-endian systems, this is the first two bytes of the `struct`. The `memcpy` will overwrite it.
So, if `ucma_query_addr` reads `sa_family` while it's being written to, it could get a partially updated, or even garbage value. This is where I start to see a potential problem. Though it is likely that on x86, overwriting the two bytes should be atomic, `memcpy` isn't necessarily atomic.
The real concern is that `addr` is a `struct sockaddr *` that includes `sa_family_t sa_family`.
The likely scenario is that a bad `sa_family` will cause `rdma_addr_size` to return 0, resulting in zero bytes being copied.
But, there's a race here, of 28 bytes:
```
write to 0xffff88812ddf7820 of 28 bytes by task 7338 on cpu 1:
addr_handler+0x10d/0x2f0 drivers/infiniband/core/cma.c:3523
```
28 bytes is the size of `struct sockaddr_in6`.
If we have two `memcpy`s in conflict, it is a non-benign scenario.
In `ucma_query_addr` there's a read from `addr`:
```c
925: memcpy(&resp.src_addr, addr, resp.src_size);
```
And in `addr_handler` there is a write to `addr`:
```c
3523: memcpy(addr, src_addr, rdma_addr_size(src_addr));
```
If these run concurrently, `resp.src_addr` will contain a mix of old and new data. This is a classic data race on a non-atomic object.
Is it harmful? It's harmful because it's returning corrupted data. It isn't a kernel crash or memory corruption, but corrupted data is a problem. Especially given past RDMA CM bugs, corrupted addresses can lead to exploitable flaws.
Even if we're "just" querying, a corrupted address *could* be used to bypass checks or lead to more significant issues if the checks or other code rely on the same potentially racy data.
I should also consider, what happens if `rdma_addr_size(addr)` is also racing?
```c
924: resp.src_size = rdma_addr_size(addr);
925: memcpy(&resp.src_addr,
|
| 46/2 |
2026/02/24 22:59 |
tool |
grepper |
0m
Args: map[Expression:ucma_query_addr]
Results: map[Output:drivers/infiniband/core/ucma.c=898=static void ucma_query_device_addr(struct rdma_cm_id *cm_id,
--
drivers/infiniband/core/ucma.c-910-
drivers/infiniband/core/ucma.c:911:static ssize_t ucma_query_addr(struct ucma_context *ctx,
drivers/infiniband/core/ucma.c-912- void __user *response, int out_len)
--
drivers/infiniband/core/ucma.c=1061=static ssize_t ucma_query(struct ucma_file *file,
--
drivers/infiniband/core/ucma.c-1080- case RDMA_USER_CM_QUERY_ADDR:
drivers/infiniband/core/ucma.c:1081: ret = ucma_query_addr(ctx, response, out_len);
drivers/infiniband/core/ucma.c-1082- break;
]
|
| 47/2 |
2026/02/24 22:59 |
llm |
expert |
0m
Model:
Tokens:
input: 44092
output: 48
thoughts: 1749
Thoughts: **Analyzing Potential Data Races in UCMA Query Operations**
Okay, so I'm digging into `ucma_query` and I'm seeing a potential issue. There doesn't appear to be a recent history available for this function, so I'll need to analyze the code directly. My immediate thought is to check if `ucma_query` should be holding a lock, in this case it looks like the `ctx->mutex`, as the `ucma_query` function itself holds this lock as per the code snippet:
```c
1078: mutex_lock(&ctx->mutex);
1079: switch (cmd.option) {
...
1096: mutex_unlock(&ctx->mutex);
```
I see that `rdma_destroy_id` takes the `handler_mutex` lock which is associated with the `cm_id`:
```c
2115: void rdma_destroy_id(struct rdma_cm_id *id)
2116: {
...
2120: mutex_lock(&id_priv->handler_mutex);
2121: destroy_id_handler_unlock(id_priv);
```
If `ucma_query` is running, `ctx` is alive. However, the `cm_id` within the `ctx` might be modified by callbacks. This raises a red flag. The RDMA CM documentation or comments *should* clarify the synchronization requirements here. Looking into `cma.c`:
```c
401: * The FSM uses a funny double locking where state is protected by both
402: * the handler_mutex and the spinlock. State is not allowed to change
403: * to/from a handler_mutex protected value without also holding
404: * handler_mutex.
```
The address fields within the `cm_id` are part of the state and are definitely modified under `handler_mutex`. Since they are modified under the `handler_mutex`, they *should* be read under `handler_mutex` as well (or the spinlock if applicable, but a memcpy of 28 bytes isn't likely atomic so best to avoid spinlock). Since `addr_handler` is a callback, the `handler_mutex` exists specifically to synchronize callbacks and other operations on the `cm_id`. It seems like `ucma_query` is missing the appropriate lock!
My question now is whether this is harmful. KCSAN reports a data race, which means it is a bug. If this leads to corrupted data returned to user-space, it's a critical bug, particularly in the kernel. In many kernel subsystems, this type of bug is considered a security vulnerability if the corruption could be used to bypass security checks. Even if it's not a security vulnerability, it's definitely a bug that needs fixing.
Is this "benign"? I don't think so. A benign race would involve something like a counter being slightly off. Here, the outcome could be a corrupted `sockaddr` returned to user-space, which is definitely not benign.
Now I need to check for any similar races that have been reported or fixed. I'll go back and check `ucma_query_path`. It copies `struct sa_path_rec`:
```c
58: struct sa_path_rec *path_rec;
```
Wait, `path_rec` is a pointer. Let me double-check `struct rdma_route`:
```c
56: struct rdma_route {
57: struct rdma_addr addr;
58: struct sa_path_rec *path_rec;
```
Yes, it's a pointer. In `ucma_query_path`:
```c
984: resp.path_data[i_path] = ctx->cm_id->route.path_rec[i];
```
It dereferences the pointer and copies the struct. If `path_rec` is being reallocated or freed by a callback while this is happening, this is a USE-AFTER-FREE! This is far more serious.
I need to see where `path_rec` is modified. In `cma_path_handler`:
```c
3055: static void cma_path_handler(int status, struct sa_path_rec *path_rec,
3056: int num_paths, void *context)
...
3062: mutex_lock(&id_priv->handler_mutex);
...
307
|
| 48/2 |
2026/02/24 23:00 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/infiniband/core/cma.c IncludeLines:true Name:rdma_query_gid]
Results: map[SourceCode: 935: /**
936: * rdma_query_gid - Read the GID content from the GID software cache
937: * @device: Device to query the GID
938: * @port_num: Port number of the device
939: * @index: Index of the GID table entry to read
940: * @gid: Pointer to GID where to store the entry's GID
941: *
942: * rdma_query_gid() only reads the GID entry content for requested device,
943: * port and index. It reads for IB, RoCE and iWarp link layers. It doesn't
944: * hold any reference to the GID table entry in the HCA or software cache.
945: *
946: * Returns 0 on success or appropriate error code.
947: *
948: */
949: int rdma_query_gid(struct ib_device *device, u32 port_num,
950: int index, union ib_gid *gid)
951: {
952: struct ib_gid_table *table;
953: unsigned long flags;
954: int res;
955:
956: if (!rdma_is_port_valid(device, port_num))
957: return -EINVAL;
958:
959: table = rdma_gid_table(device, port_num);
960: read_lock_irqsave(&table->rwlock, flags);
961:
962: if (index < 0 || index >= table->sz) {
963: res = -EINVAL;
964: goto done;
965: }
966:
967: if (!is_gid_entry_valid(table->data_vec[index])) {
968: res = -ENOENT;
969: goto done;
970: }
971:
972: memcpy(gid, &table->data_vec[index]->attr.gid, sizeof(*gid));
973: res = 0;
974:
975: done:
976: read_unlock_irqrestore(&table->rwlock, flags);
977: return res;
978: }
SourceFile:drivers/infiniband/core/cache.c]
|
| 49/2 |
2026/02/24 23:00 |
llm |
expert |
0m
Model:
Tokens:
input: 47610
output: 50
thoughts: 1870
Thoughts: **Data Race Analysis: ucma_query and addr_handler**
Okay, let's break this down. My initial thought was that I had missed something – and I did. It was the `->device` dereference in `rdma_query_gid`. That's where it all started. Now, `ctx->cm_id->device` is what `ucma_query_gid` uses and that member is being set in `cma_acquire_dev_by_src_ip`, which is called within `addr_handler`. `cm_id->device` gets written in `addr_handler`, which is a workqueue function.
So, if `ucma_query_gid` reads `ctx->cm_id->device` concurrently with `addr_handler` writing to it, there's a potential for a race condition. It could see a NULL or partially written pointer. Although there's a check for NULL, it's racy because the value can change between the check and the call to `rdma_query_gid`. While pointer writes on x86 are atomic, the `cm_id->device` value is initialized to NULL and then updated in `addr_handler`, so there's definitely a window.
Now, `addr_handler` is called after address resolution is done, and before that, `cm_id->device` is likely NULL. The race reported by KCSAN is on `src_addr` contents, which is definitely *not* atomic. The KCSAN report confirms the race is related to `src_addr`.
`ucma_query_addr` also checks `cm_id->device`, but again, the check is racy. In the code, it uses `memcpy`. This is a clear data race, and it can lead to returning corrupted data to user-space.
Is it intentional? Unlikely. I can't imagine kernel developers intentionally corrupting data in an API, especially in the context of RDMA where address correctness is critical.
I need to confirm there is no synchronization in the code. I know `ucma_get_ctx` takes a reference and holds `ctx->mutex`, but `addr_handler` doesn't use `ctx->mutex` so it doesn't solve this.
Could `addr_handler` be called after `ucma_query` has started? Yes! `addr_handler` is called from a workqueue. User-space can call `ucma_query` at any time. So if user-space calls `RDMA_USER_CM_QUERY_ADDR`, it's asking for the current address. It could get either the old address or the new one, but not a mix.
The fix would be to take `handler_mutex` in `ucma_query`.
I'm confident this is a non-benign data race.
I should verify that `addr_handler` uses `handler_mutex`, and it does. But `ucma_query` doesn't take this mutex. They use different mutexes: `ctx->mutex` and `id_priv->handler_mutex`, which are in different structs.
I checked for other synchronization paths. `addr_handler` isn't called only when the state is such that nobody else is querying. Actually, `ucma_query` is a generic function to query various CM ID properties. It's valid to query an ID in the middle of an operation.
I'll conclude it's harmful.
I should look for other similar reports. I see from the report that it's `memcpy` from `src_addr` and the size is 28 bytes. The address is the same. The size confirms it's an IPv6 address (`sizeof(struct sockaddr_in6)` is 28). If it were IPv4 it would be 16 bytes.
This is a harmful race that can corrupt the contents of a `sockaddr`.
Are there any reasons to call it benign? Some kernel developers might call it "benign", but in RDMA addresses are important. The KCSAN reports are generally taken seriously unless there's a good reason. Corrupting a `sockaddr` is not a good thing.
`ucma_query_path` could have a UAF, and this is about `src_addr`, it's about a lack of synchronization in `ucma_query`.
All the `RDMA_USER_CM_QUERY_*` calls need to hold `handler_mutex`.
|
| 50/2 |
2026/02/24 23:00 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:drivers/infiniband/core/ucma.c IncludeLines:true Name:ucma_query_ib_service]
Results: map[SourceCode:1024: static ssize_t ucma_query_ib_service(struct ucma_context *ctx,
1025: void __user *response, int out_len)
1026: {
1027: struct rdma_ucm_query_ib_service_resp *resp;
1028: int n, ret = 0;
1029:
1030: if (out_len < sizeof(struct rdma_ucm_query_ib_service_resp))
1031: return -ENOSPC;
1032:
1033: if (!ctx->cm_id->route.service_recs)
1034: return -ENODATA;
1035:
1036: resp = kzalloc(out_len, GFP_KERNEL);
1037: if (!resp)
1038: return -ENOMEM;
1039:
1040: resp->num_service_recs = ctx->cm_id->route.num_service_recs;
1041:
1042: n = (out_len - sizeof(struct rdma_ucm_query_ib_service_resp)) /
1043: sizeof(struct ib_user_service_rec);
1044:
1045: if (!n)
1046: goto out;
1047:
1048: if (n > ctx->cm_id->route.num_service_recs)
1049: n = ctx->cm_id->route.num_service_recs;
1050:
1051: memcpy(resp->recs, ctx->cm_id->route.service_recs,
1052: sizeof(*resp->recs) * n);
1053: if (copy_to_user(response, resp, struct_size(resp, recs, n)))
1054: ret = -EFAULT;
1055:
1056: out:
1057: kfree(resp);
1058: return ret;
1059: }
SourceFile:drivers/infiniband/core/ucma.c]
|
| 51/2 |
2026/02/24 23:00 |
llm |
expert |
0m
Model:
Tokens:
input: 51086
output: 19
thoughts: 55
Thoughts: Okay, here's my understanding, considering I'm deep in the weeds with this code:
**Definitive Conclusion on `ucma_query` and Mutex Requirements**
Alright, let's nail this down. I've traced it through. The `ucma_query` function, without a doubt, interacts with `route.service_recs` and `route.num_service_recs`. And we know, from previous analysis, that these variables are, in turn, *modified* by callbacks. That's the key.
Given this dependency on shared data that's potentially altered asynchronously, the need for the `handler_mutex` within `ucma_query` is absolutely confirmed. There's no way around it. Concurrency control is a must-have here to prevent race conditions and ensure data integrity. I'm comfortable with that assessment, and here is my final answer.
|
| 52/2 |
2026/02/24 23:00 |
tool |
set-results |
0m
Args: map[Benign:false Confident:true]
Results: map[Benign:false Confident:true]
|
| 53/2 |
2026/02/24 23:00 |
llm |
expert |
0m
Model:
Tokens:
input: 51372
output: 609
thoughts: 218
Thoughts: **Analyzing the Potential for Corruption**
Okay, so the user wants me to break down why I think this is a potential problem. Let's see... my initial assessment is that this looks harmful, and here's why.
First, I see a classic data race situation here. We're dealing with a `struct sockaddr_storage`, a non-atomic structured object, which is always a red flag when you've got multiple threads interacting with it. The race is specifically between `addr_handler` and `ucma_query_addr`. `addr_handler` is locking the `id_priv->handler_mutex` while `ucma_query_addr` is only protecting itself with `ctx->mutex`. This immediately tells me there's a synchronization gap.
The concern is the potential for corrupted data. What that means is we have the risk of a mix of old and new address data getting written to user-space. This is bad, of course.
The core issue seems to be that `ucma_query` *should* be holding that `handler_mutex` to properly synchronize with CM callbacks. These callbacks are the ones that can modify the state of the `cm_id` and therefore the underlying addresses.
And it's not just this specific query. Looking at `ucma_query`, I can see other queries, like `ucma_query_path`, that suffer from the same lack of synchronization. That's worrying, because it suggests a systemic problem and the potential for even worse scenarios, like use-after-free, if pointers are being mishandled.
Ultimately, returning corrupted networking addresses to user-space is a significant bug. It's almost guaranteed to cause application failures, and, depending on how this corrupted data is used in other parts of the application, could introduce security vulnerabilities. It's a risk that needs to be addressed.
|