Skip to content

Commit 38290b1

Browse files
author
Sudeep Holla
committed
firmware: arm_ffa: Snapshot notifier callbacks under lock
Both notification handlers currently look up a notifier callback under notify_lock, drop the lock, and then dereference the returned notifier entry. A concurrent unregister can delete and free that entry in the gap, leaving the handler to dereference stale memory. Copy the callback pointer and callback data while notify_lock is still held and invoke the callback only after the lock is dropped. This keeps the existing callback execution model while removing the use-after-free window in both the framework and non-framework notification paths. Fixes: 285a5ea ("firmware: arm_ffa: Add support for handling framework notifications") Link: https://patch.msgid.link/20260428-ffa_fixes-v2-10-8595ae450034@kernel.org Signed-off-by: Sudeep Holla <sudeep.holla@kernel.org>
1 parent 0399e3f commit 38290b1

1 file changed

Lines changed: 23 additions & 12 deletions

File tree

drivers/firmware/arm_ffa/driver.c

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,30 +1463,36 @@ static int ffa_notify_send(struct ffa_device *dev, int notify_id,
14631463

14641464
static void handle_notif_callbacks(u64 bitmap, enum notify_type type)
14651465
{
1466+
ffa_notifier_cb cb;
1467+
void *cb_data;
14661468
int notify_id;
1467-
struct notifier_cb_info *cb_info = NULL;
14681469

14691470
for (notify_id = 0; notify_id <= FFA_MAX_NOTIFICATIONS && bitmap;
14701471
notify_id++, bitmap >>= 1) {
14711472
if (!(bitmap & 1))
14721473
continue;
14731474

1474-
read_lock(&drv_info->notify_lock);
1475-
cb_info = notifier_hnode_get_by_type(notify_id, type);
1476-
read_unlock(&drv_info->notify_lock);
1475+
scoped_guard(read_lock, &drv_info->notify_lock) {
1476+
struct notifier_cb_info *cb_info;
1477+
1478+
cb_info = notifier_hnode_get_by_type(notify_id, type);
1479+
cb = cb_info ? cb_info->cb : NULL;
1480+
cb_data = cb_info ? cb_info->cb_data : NULL;
1481+
}
14771482

1478-
if (cb_info && cb_info->cb)
1479-
cb_info->cb(notify_id, cb_info->cb_data);
1483+
if (cb)
1484+
cb(notify_id, cb_data);
14801485
}
14811486
}
14821487

14831488
static void handle_fwk_notif_callbacks(u32 bitmap)
14841489
{
14851490
void *buf;
14861491
uuid_t uuid;
1492+
void *fwk_cb_data;
14871493
int notify_id = 0, target;
1494+
ffa_fwk_notifier_cb fwk_cb;
14881495
struct ffa_indirect_msg_hdr *msg;
1489-
struct notifier_cb_info *cb_info = NULL;
14901496
size_t min_offset = offsetof(struct ffa_indirect_msg_hdr, uuid);
14911497

14921498
/* Only one framework notification defined and supported for now */
@@ -1522,12 +1528,17 @@ static void handle_fwk_notif_callbacks(u32 bitmap)
15221528
ffa_rx_release();
15231529
}
15241530

1525-
read_lock(&drv_info->notify_lock);
1526-
cb_info = notifier_hnode_get_by_vmid_uuid(notify_id, target, &uuid);
1527-
read_unlock(&drv_info->notify_lock);
1531+
scoped_guard(read_lock, &drv_info->notify_lock) {
1532+
struct notifier_cb_info *cb_info;
1533+
1534+
cb_info = notifier_hnode_get_by_vmid_uuid(notify_id, target,
1535+
&uuid);
1536+
fwk_cb = cb_info ? cb_info->fwk_cb : NULL;
1537+
fwk_cb_data = cb_info ? cb_info->cb_data : NULL;
1538+
}
15281539

1529-
if (cb_info && cb_info->fwk_cb)
1530-
cb_info->fwk_cb(notify_id, cb_info->cb_data, buf);
1540+
if (fwk_cb)
1541+
fwk_cb(notify_id, fwk_cb_data, buf);
15311542
kfree(buf);
15321543
}
15331544

0 commit comments

Comments
 (0)