mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 15:41:52 +02:00
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: 285a5ea0f5 ("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>
This commit is contained in:
parent
0399e3f872
commit
38290b180a
|
|
@ -1463,20 +1463,25 @@ static int ffa_notify_send(struct ffa_device *dev, int notify_id,
|
|||
|
||||
static void handle_notif_callbacks(u64 bitmap, enum notify_type type)
|
||||
{
|
||||
ffa_notifier_cb cb;
|
||||
void *cb_data;
|
||||
int notify_id;
|
||||
struct notifier_cb_info *cb_info = NULL;
|
||||
|
||||
for (notify_id = 0; notify_id <= FFA_MAX_NOTIFICATIONS && bitmap;
|
||||
notify_id++, bitmap >>= 1) {
|
||||
if (!(bitmap & 1))
|
||||
continue;
|
||||
|
||||
read_lock(&drv_info->notify_lock);
|
||||
cb_info = notifier_hnode_get_by_type(notify_id, type);
|
||||
read_unlock(&drv_info->notify_lock);
|
||||
scoped_guard(read_lock, &drv_info->notify_lock) {
|
||||
struct notifier_cb_info *cb_info;
|
||||
|
||||
if (cb_info && cb_info->cb)
|
||||
cb_info->cb(notify_id, cb_info->cb_data);
|
||||
cb_info = notifier_hnode_get_by_type(notify_id, type);
|
||||
cb = cb_info ? cb_info->cb : NULL;
|
||||
cb_data = cb_info ? cb_info->cb_data : NULL;
|
||||
}
|
||||
|
||||
if (cb)
|
||||
cb(notify_id, cb_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1484,9 +1489,10 @@ static void handle_fwk_notif_callbacks(u32 bitmap)
|
|||
{
|
||||
void *buf;
|
||||
uuid_t uuid;
|
||||
void *fwk_cb_data;
|
||||
int notify_id = 0, target;
|
||||
ffa_fwk_notifier_cb fwk_cb;
|
||||
struct ffa_indirect_msg_hdr *msg;
|
||||
struct notifier_cb_info *cb_info = NULL;
|
||||
size_t min_offset = offsetof(struct ffa_indirect_msg_hdr, uuid);
|
||||
|
||||
/* Only one framework notification defined and supported for now */
|
||||
|
|
@ -1522,12 +1528,17 @@ static void handle_fwk_notif_callbacks(u32 bitmap)
|
|||
ffa_rx_release();
|
||||
}
|
||||
|
||||
read_lock(&drv_info->notify_lock);
|
||||
cb_info = notifier_hnode_get_by_vmid_uuid(notify_id, target, &uuid);
|
||||
read_unlock(&drv_info->notify_lock);
|
||||
scoped_guard(read_lock, &drv_info->notify_lock) {
|
||||
struct notifier_cb_info *cb_info;
|
||||
|
||||
if (cb_info && cb_info->fwk_cb)
|
||||
cb_info->fwk_cb(notify_id, cb_info->cb_data, buf);
|
||||
cb_info = notifier_hnode_get_by_vmid_uuid(notify_id, target,
|
||||
&uuid);
|
||||
fwk_cb = cb_info ? cb_info->fwk_cb : NULL;
|
||||
fwk_cb_data = cb_info ? cb_info->cb_data : NULL;
|
||||
}
|
||||
|
||||
if (fwk_cb)
|
||||
fwk_cb(notify_id, fwk_cb_data, buf);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user