Skip to content

Commit 1f0304d

Browse files
Jason Andryukjgross1
authored andcommitted
xenbus: Use kref to track req lifetime
Marek reported seeing a NULL pointer fault in the xenbus_thread callstack: BUG: kernel NULL pointer dereference, address: 0000000000000000 RIP: e030:__wake_up_common+0x4c/0x180 Call Trace: <TASK> __wake_up_common_lock+0x82/0xd0 process_msg+0x18e/0x2f0 xenbus_thread+0x165/0x1c0 process_msg+0x18e is req->cb(req). req->cb is set to xs_wake_up(), a thin wrapper around wake_up(), or xenbus_dev_queue_reply(). It seems like it was xs_wake_up() in this case. It seems like req may have woken up the xs_wait_for_reply(), which kfree()ed the req. When xenbus_thread resumes, it faults on the zero-ed data. Linux Device Drivers 2nd edition states: "Normally, a wake_up call can cause an immediate reschedule to happen, meaning that other processes might run before wake_up returns." ... which would match the behaviour observed. Change to keeping two krefs on each request. One for the caller, and one for xenbus_thread. Each will kref_put() when finished, and the last will free it. This use of kref matches the description in Documentation/core-api/kref.rst Link: https://lore.kernel.org/xen-devel/ZO0WrR5J0xuwDIxW@mail-itl/ Reported-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com> Fixes: fd8aa90 ("xen: optimize xenbus driver for multiple concurrent xenstore accesses") Cc: stable@vger.kernel.org Signed-off-by: Jason Andryuk <jason.andryuk@amd.com> Reviewed-by: Juergen Gross <jgross@suse.com> Signed-off-by: Juergen Gross <jgross@suse.com> Message-ID: <20250506210935.5607-1-jason.andryuk@amd.com>
1 parent 9098986 commit 1f0304d

File tree

4 files changed

+23
-8
lines changed

4 files changed

+23
-8
lines changed

drivers/xen/xenbus/xenbus.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ enum xb_req_state {
7777
struct xb_req_data {
7878
struct list_head list;
7979
wait_queue_head_t wq;
80+
struct kref kref;
8081
struct xsd_sockmsg msg;
8182
uint32_t caller_req_id;
8283
enum xsd_sockmsg_type type;
@@ -103,6 +104,7 @@ int xb_init_comms(void);
103104
void xb_deinit_comms(void);
104105
int xs_watch_msg(struct xs_watch_event *event);
105106
void xs_request_exit(struct xb_req_data *req);
107+
void xs_free_req(struct kref *kref);
106108

107109
int xenbus_match(struct device *_dev, const struct device_driver *_drv);
108110
int xenbus_dev_probe(struct device *_dev);

drivers/xen/xenbus/xenbus_comms.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -309,8 +309,8 @@ static int process_msg(void)
309309
virt_wmb();
310310
req->state = xb_req_state_got_reply;
311311
req->cb(req);
312-
} else
313-
kfree(req);
312+
}
313+
kref_put(&req->kref, xs_free_req);
314314
}
315315

316316
mutex_unlock(&xs_response_mutex);
@@ -386,14 +386,13 @@ static int process_writes(void)
386386
state.req->msg.type = XS_ERROR;
387387
state.req->err = err;
388388
list_del(&state.req->list);
389-
if (state.req->state == xb_req_state_aborted)
390-
kfree(state.req);
391-
else {
389+
if (state.req->state != xb_req_state_aborted) {
392390
/* write err, then update state */
393391
virt_wmb();
394392
state.req->state = xb_req_state_got_reply;
395393
wake_up(&state.req->wq);
396394
}
395+
kref_put(&state.req->kref, xs_free_req);
397396

398397
mutex_unlock(&xb_write_mutex);
399398

drivers/xen/xenbus/xenbus_dev_frontend.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ void xenbus_dev_queue_reply(struct xb_req_data *req)
406406
mutex_unlock(&u->reply_mutex);
407407

408408
kfree(req->body);
409-
kfree(req);
409+
kref_put(&req->kref, xs_free_req);
410410

411411
kref_put(&u->kref, xenbus_file_free);
412412

drivers/xen/xenbus/xenbus_xs.c

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ static void xs_suspend_exit(void)
112112
wake_up_all(&xs_state_enter_wq);
113113
}
114114

115+
void xs_free_req(struct kref *kref)
116+
{
117+
struct xb_req_data *req = container_of(kref, struct xb_req_data, kref);
118+
kfree(req);
119+
}
120+
115121
static uint32_t xs_request_enter(struct xb_req_data *req)
116122
{
117123
uint32_t rq_id;
@@ -237,6 +243,12 @@ static void xs_send(struct xb_req_data *req, struct xsd_sockmsg *msg)
237243
req->caller_req_id = req->msg.req_id;
238244
req->msg.req_id = xs_request_enter(req);
239245

246+
/*
247+
* Take 2nd ref. One for this thread, and the second for the
248+
* xenbus_thread.
249+
*/
250+
kref_get(&req->kref);
251+
240252
mutex_lock(&xb_write_mutex);
241253
list_add_tail(&req->list, &xb_write_list);
242254
notify = list_is_singular(&xb_write_list);
@@ -261,8 +273,8 @@ static void *xs_wait_for_reply(struct xb_req_data *req, struct xsd_sockmsg *msg)
261273
if (req->state == xb_req_state_queued ||
262274
req->state == xb_req_state_wait_reply)
263275
req->state = xb_req_state_aborted;
264-
else
265-
kfree(req);
276+
277+
kref_put(&req->kref, xs_free_req);
266278
mutex_unlock(&xb_write_mutex);
267279

268280
return ret;
@@ -291,6 +303,7 @@ int xenbus_dev_request_and_reply(struct xsd_sockmsg *msg, void *par)
291303
req->cb = xenbus_dev_queue_reply;
292304
req->par = par;
293305
req->user_req = true;
306+
kref_init(&req->kref);
294307

295308
xs_send(req, msg);
296309

@@ -319,6 +332,7 @@ static void *xs_talkv(struct xenbus_transaction t,
319332
req->num_vecs = num_vecs;
320333
req->cb = xs_wake_up;
321334
req->user_req = false;
335+
kref_init(&req->kref);
322336

323337
msg.req_id = 0;
324338
msg.tx_id = t.id;

0 commit comments

Comments
 (0)