Skip to content

Commit d1f29ea

Browse files
committed
Merge tag 'ffa-fixes-7.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into arm/fixes
Arm FF-A fixes for v7.1 The updates fix several robustness issues in the FF-A bus and core driver, mostly around notification handling, RxTx buffer sizing, firmware-provided bounds, and cleanup paths. The notification fixes make per-CPU notification work truly per-CPU, avoid running per-vCPU notification handling from IPI context, keep RX buffer release serialized under rx_lock, validate framework notification payload layout before copying from the shared RX buffer, and avoid dereferencing notifier entries after they may have been unregistered. The remaining fixes reject FF-A drivers without an ID table at registration time, avoid freeing an unallocated RX buffer after allocation failure, unregister the FF-A v1.0 bus notifier on teardown, bound register-based PARTITION_INFO_GET descriptor copies, align the stored RxTx buffer size with the size mapped to firmware, and fix sched-recv callback partition lookup on the circular partition list. * tag 'ffa-fixes-7.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux: firmware: arm_ffa: Fix sched-recv callback partition lookup firmware: arm_ffa: Snapshot notifier callbacks under lock firmware: arm_ffa: Align RxTx buffer size before mapping firmware: arm_ffa: Validate framework notification message layout firmware: arm_ffa: Keep framework RX release under lock firmware: arm_ffa: Bound PARTITION_INFO_GET_REGS copies firmware: arm_ffa: Unregister bus notifier on teardown for FF-A v1.0 firmware: arm_ffa: Fix per-vcpu self notifications handling in workqueue firmware: arm_ffa: Avoid collapsing NPI work from different CPUs firmware: arm_ffa: Skip free_pages on RX buffer alloc failure firmware: arm_ffa: Check for NULL FF-A ID table while driver registration Signed-off-by: Arnd Bergmann <arnd@arndb.de>
2 parents 79524be + a6848a5 commit d1f29ea

2 files changed

Lines changed: 104 additions & 44 deletions

File tree

drivers/firmware/arm_ffa/bus.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ static int ffa_device_match(struct device *dev, const struct device_driver *drv)
2626

2727
id_table = to_ffa_driver(drv)->id_table;
2828
ffa_dev = to_ffa_dev(dev);
29+
if (!id_table)
30+
return 0;
2931

3032
while (!uuid_is_null(&id_table->uuid)) {
3133
/*
@@ -123,7 +125,7 @@ int ffa_driver_register(struct ffa_driver *driver, struct module *owner,
123125
{
124126
int ret;
125127

126-
if (!driver->probe)
128+
if (!driver->probe || !driver->id_table)
127129
return -EINVAL;
128130

129131
driver->driver.bus = &ffa_bus_type;

drivers/firmware/arm_ffa/driver.c

Lines changed: 101 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ static inline int ffa_to_linux_errno(int errno)
8787

8888
struct ffa_pcpu_irq {
8989
struct ffa_drv_info *info;
90+
struct work_struct notif_pcpu_work;
9091
};
9192

9293
struct ffa_drv_info {
@@ -100,13 +101,13 @@ struct ffa_drv_info {
100101
bool mem_ops_native;
101102
bool msg_direct_req2_supp;
102103
bool bitmap_created;
104+
bool bus_notifier_registered;
103105
bool notif_enabled;
104106
unsigned int sched_recv_irq;
105107
unsigned int notif_pend_irq;
106108
unsigned int cpuhp_state;
107109
struct ffa_pcpu_irq __percpu *irq_pcpu;
108110
struct workqueue_struct *notif_pcpu_wq;
109-
struct work_struct notif_pcpu_work;
110111
struct work_struct sched_recv_irq_work;
111112
struct xarray partition_info;
112113
DECLARE_HASHTABLE(notifier_hash, ilog2(FFA_MAX_NOTIFICATIONS));
@@ -322,22 +323,26 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
322323
#define PART_INFO_ID_MASK GENMASK(15, 0)
323324
#define PART_INFO_EXEC_CXT_MASK GENMASK(31, 16)
324325
#define PART_INFO_PROPS_MASK GENMASK(63, 32)
326+
#define FFA_PART_INFO_GET_REGS_FIRST_REG 3
327+
#define FFA_PART_INFO_GET_REGS_REGS_PER_DESC 3
328+
#define FFA_PART_INFO_GET_REGS_MAX_DESC \
329+
(((sizeof(ffa_value_t) / sizeof_field(ffa_value_t, a0)) - \
330+
FFA_PART_INFO_GET_REGS_FIRST_REG) / \
331+
FFA_PART_INFO_GET_REGS_REGS_PER_DESC)
325332
#define PART_INFO_ID(x) ((u16)(FIELD_GET(PART_INFO_ID_MASK, (x))))
326333
#define PART_INFO_EXEC_CXT(x) ((u16)(FIELD_GET(PART_INFO_EXEC_CXT_MASK, (x))))
327334
#define PART_INFO_PROPERTIES(x) ((u32)(FIELD_GET(PART_INFO_PROPS_MASK, (x))))
328335
static int
329336
__ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
330337
struct ffa_partition_info *buffer, int num_parts)
331338
{
332-
u16 buf_sz, start_idx, cur_idx, count = 0, prev_idx = 0, tag = 0;
339+
u16 buf_sz, start_idx = 0, cur_idx, count = 0, tag = 0;
333340
struct ffa_partition_info *buf = buffer;
334341
ffa_value_t partition_info;
335342

336343
do {
337344
__le64 *regs;
338-
int idx;
339-
340-
start_idx = prev_idx ? prev_idx + 1 : 0;
345+
int idx, nr_desc, buf_idx;
341346

342347
invoke_ffa_fn((ffa_value_t){
343348
.a0 = FFA_PARTITION_INFO_GET_REGS,
@@ -353,15 +358,28 @@ __ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
353358
count = PARTITION_COUNT(partition_info.a2);
354359
if (!buffer || !num_parts) /* count only */
355360
return count;
361+
if (count > num_parts)
362+
return -EINVAL;
356363

357364
cur_idx = CURRENT_INDEX(partition_info.a2);
365+
if (cur_idx < start_idx || cur_idx >= count)
366+
return -EINVAL;
367+
368+
nr_desc = cur_idx - start_idx + 1;
369+
if (nr_desc > FFA_PART_INFO_GET_REGS_MAX_DESC)
370+
return -EINVAL;
371+
372+
buf_idx = buf - buffer;
373+
if (buf_idx + nr_desc > num_parts)
374+
return -EINVAL;
375+
358376
tag = UUID_INFO_TAG(partition_info.a2);
359377
buf_sz = PARTITION_INFO_SZ(partition_info.a2);
360378
if (buf_sz > sizeof(*buffer))
361379
buf_sz = sizeof(*buffer);
362380

363381
regs = (void *)&partition_info.a3;
364-
for (idx = 0; idx < cur_idx - start_idx + 1; idx++, buf++) {
382+
for (idx = 0; idx < nr_desc; idx++, buf++) {
365383
union {
366384
uuid_t uuid;
367385
u64 regs[2];
@@ -379,7 +397,7 @@ __ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
379397
uuid_copy(&buf->uuid, &uuid_regs.uuid);
380398
regs += 3;
381399
}
382-
prev_idx = cur_idx;
400+
start_idx = cur_idx + 1;
383401

384402
} while (cur_idx < (count - 1));
385403

@@ -1189,7 +1207,7 @@ static int
11891207
ffa_sched_recv_cb_update(struct ffa_device *dev, ffa_sched_recv_cb callback,
11901208
void *cb_data, bool is_registration)
11911209
{
1192-
struct ffa_dev_part_info *partition = NULL, *tmp;
1210+
struct ffa_dev_part_info *partition = NULL;
11931211
struct list_head *phead;
11941212
bool cb_valid;
11951213

@@ -1202,11 +1220,11 @@ ffa_sched_recv_cb_update(struct ffa_device *dev, ffa_sched_recv_cb callback,
12021220
return -EINVAL;
12031221
}
12041222

1205-
list_for_each_entry_safe(partition, tmp, phead, node)
1223+
list_for_each_entry(partition, phead, node)
12061224
if (partition->dev == dev)
12071225
break;
12081226

1209-
if (!partition) {
1227+
if (&partition->node == phead) {
12101228
pr_err("%s: No such partition ID 0x%x\n", __func__, dev->vm_id);
12111229
return -EINVAL;
12121230
}
@@ -1445,60 +1463,82 @@ static int ffa_notify_send(struct ffa_device *dev, int notify_id,
14451463

14461464
static void handle_notif_callbacks(u64 bitmap, enum notify_type type)
14471465
{
1466+
ffa_notifier_cb cb;
1467+
void *cb_data;
14481468
int notify_id;
1449-
struct notifier_cb_info *cb_info = NULL;
14501469

14511470
for (notify_id = 0; notify_id <= FFA_MAX_NOTIFICATIONS && bitmap;
14521471
notify_id++, bitmap >>= 1) {
14531472
if (!(bitmap & 1))
14541473
continue;
14551474

1456-
read_lock(&drv_info->notify_lock);
1457-
cb_info = notifier_hnode_get_by_type(notify_id, type);
1458-
read_unlock(&drv_info->notify_lock);
1475+
scoped_guard(read_lock, &drv_info->notify_lock) {
1476+
struct notifier_cb_info *cb_info;
14591477

1460-
if (cb_info && cb_info->cb)
1461-
cb_info->cb(notify_id, cb_info->cb_data);
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+
}
1482+
1483+
if (cb)
1484+
cb(notify_id, cb_data);
14621485
}
14631486
}
14641487

14651488
static void handle_fwk_notif_callbacks(u32 bitmap)
14661489
{
14671490
void *buf;
14681491
uuid_t uuid;
1492+
void *fwk_cb_data;
14691493
int notify_id = 0, target;
1494+
ffa_fwk_notifier_cb fwk_cb;
14701495
struct ffa_indirect_msg_hdr *msg;
1471-
struct notifier_cb_info *cb_info = NULL;
1496+
size_t min_offset = offsetof(struct ffa_indirect_msg_hdr, uuid);
14721497

14731498
/* Only one framework notification defined and supported for now */
14741499
if (!(bitmap & FRAMEWORK_NOTIFY_RX_BUFFER_FULL))
14751500
return;
14761501

1477-
mutex_lock(&drv_info->rx_lock);
1502+
scoped_guard(mutex, &drv_info->rx_lock) {
1503+
u32 offset, size;
14781504

1479-
msg = drv_info->rx_buffer;
1480-
buf = kmemdup((void *)msg + msg->offset, msg->size, GFP_KERNEL);
1481-
if (!buf) {
1482-
mutex_unlock(&drv_info->rx_lock);
1483-
return;
1484-
}
1505+
msg = drv_info->rx_buffer;
1506+
offset = msg->offset;
1507+
size = msg->size;
14851508

1486-
target = SENDER_ID(msg->send_recv_id);
1487-
if (msg->offset >= sizeof(*msg))
1488-
uuid_copy(&uuid, &msg->uuid);
1489-
else
1490-
uuid_copy(&uuid, &uuid_null);
1509+
if (!size || (offset != min_offset && offset < sizeof(*msg)) ||
1510+
offset > drv_info->rxtx_bufsz ||
1511+
size > drv_info->rxtx_bufsz - offset) {
1512+
pr_err("invalid framework notification message\n");
1513+
ffa_rx_release();
1514+
return;
1515+
}
14911516

1492-
mutex_unlock(&drv_info->rx_lock);
1517+
buf = kmemdup((void *)msg + offset, size, GFP_KERNEL);
1518+
if (!buf) {
1519+
ffa_rx_release();
1520+
return;
1521+
}
1522+
1523+
target = SENDER_ID(msg->send_recv_id);
1524+
if (offset >= sizeof(*msg))
1525+
uuid_copy(&uuid, &msg->uuid);
1526+
else
1527+
uuid_copy(&uuid, &uuid_null);
1528+
ffa_rx_release();
1529+
}
14931530

1494-
ffa_rx_release();
1531+
scoped_guard(read_lock, &drv_info->notify_lock) {
1532+
struct notifier_cb_info *cb_info;
14951533

1496-
read_lock(&drv_info->notify_lock);
1497-
cb_info = notifier_hnode_get_by_vmid_uuid(notify_id, target, &uuid);
1498-
read_unlock(&drv_info->notify_lock);
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+
}
14991539

1500-
if (cb_info && cb_info->fwk_cb)
1501-
cb_info->fwk_cb(notify_id, cb_info->cb_data, buf);
1540+
if (fwk_cb)
1541+
fwk_cb(notify_id, fwk_cb_data, buf);
15021542
kfree(buf);
15031543
}
15041544

@@ -1539,10 +1579,11 @@ ffa_self_notif_handle(u16 vcpu, bool is_per_vcpu, void *cb_data)
15391579

15401580
static void notif_pcpu_irq_work_fn(struct work_struct *work)
15411581
{
1542-
struct ffa_drv_info *info = container_of(work, struct ffa_drv_info,
1582+
struct ffa_pcpu_irq *pcpu = container_of(work, struct ffa_pcpu_irq,
15431583
notif_pcpu_work);
1584+
struct ffa_drv_info *info = pcpu->info;
15441585

1545-
ffa_self_notif_handle(smp_processor_id(), true, info);
1586+
notif_get_and_handle(info);
15461587
}
15471588

15481589
static const struct ffa_info_ops ffa_drv_info_ops = {
@@ -1629,6 +1670,15 @@ static struct notifier_block ffa_bus_nb = {
16291670
.notifier_call = ffa_bus_notifier,
16301671
};
16311672

1673+
static void ffa_bus_notifier_unregister(void)
1674+
{
1675+
if (!drv_info->bus_notifier_registered)
1676+
return;
1677+
1678+
bus_unregister_notifier(&ffa_bus_type, &ffa_bus_nb);
1679+
drv_info->bus_notifier_registered = false;
1680+
}
1681+
16321682
static int ffa_xa_add_partition_info(struct ffa_device *dev)
16331683
{
16341684
struct ffa_dev_part_info *info;
@@ -1712,6 +1762,8 @@ static void ffa_partitions_cleanup(void)
17121762
struct list_head *phead;
17131763
unsigned long idx;
17141764

1765+
ffa_bus_notifier_unregister();
1766+
17151767
/* Clean up/free all registered devices */
17161768
ffa_devices_unregister();
17171769

@@ -1739,11 +1791,14 @@ static int ffa_setup_partitions(void)
17391791
ret = bus_register_notifier(&ffa_bus_type, &ffa_bus_nb);
17401792
if (ret)
17411793
pr_err("Failed to register FF-A bus notifiers\n");
1794+
else
1795+
drv_info->bus_notifier_registered = true;
17421796
}
17431797

17441798
count = ffa_partition_probe(&uuid_null, &pbuf);
17451799
if (count <= 0) {
17461800
pr_info("%s: No partitions found, error %d\n", __func__, count);
1801+
ffa_bus_notifier_unregister();
17471802
return -EINVAL;
17481803
}
17491804

@@ -1811,7 +1866,7 @@ static irqreturn_t notif_pend_irq_handler(int irq, void *irq_data)
18111866
struct ffa_drv_info *info = pcpu->info;
18121867

18131868
queue_work_on(smp_processor_id(), info->notif_pcpu_wq,
1814-
&info->notif_pcpu_work);
1869+
&pcpu->notif_pcpu_work);
18151870

18161871
return IRQ_HANDLED;
18171872
}
@@ -1928,8 +1983,11 @@ static int ffa_init_pcpu_irq(void)
19281983
if (!irq_pcpu)
19291984
return -ENOMEM;
19301985

1931-
for_each_present_cpu(cpu)
1986+
for_each_present_cpu(cpu) {
19321987
per_cpu_ptr(irq_pcpu, cpu)->info = drv_info;
1988+
INIT_WORK(&per_cpu_ptr(irq_pcpu, cpu)->notif_pcpu_work,
1989+
notif_pcpu_irq_work_fn);
1990+
}
19331991

19341992
drv_info->irq_pcpu = irq_pcpu;
19351993

@@ -1958,7 +2016,6 @@ static int ffa_init_pcpu_irq(void)
19582016
}
19592017

19602018
INIT_WORK(&drv_info->sched_recv_irq_work, ffa_sched_recv_irq_work_fn);
1961-
INIT_WORK(&drv_info->notif_pcpu_work, notif_pcpu_irq_work_fn);
19622019
drv_info->notif_pcpu_wq = create_workqueue("ffa_pcpu_irq_notification");
19632020
if (!drv_info->notif_pcpu_wq)
19642021
return -EINVAL;
@@ -2063,11 +2120,12 @@ static int __init ffa_init(void)
20632120
rxtx_bufsz = SZ_4K;
20642121
}
20652122

2123+
rxtx_bufsz = PAGE_ALIGN(rxtx_bufsz);
20662124
drv_info->rxtx_bufsz = rxtx_bufsz;
20672125
drv_info->rx_buffer = alloc_pages_exact(rxtx_bufsz, GFP_KERNEL);
20682126
if (!drv_info->rx_buffer) {
20692127
ret = -ENOMEM;
2070-
goto free_pages;
2128+
goto free_drv_info;
20712129
}
20722130

20732131
drv_info->tx_buffer = alloc_pages_exact(rxtx_bufsz, GFP_KERNEL);
@@ -2078,7 +2136,7 @@ static int __init ffa_init(void)
20782136

20792137
ret = ffa_rxtx_map(virt_to_phys(drv_info->tx_buffer),
20802138
virt_to_phys(drv_info->rx_buffer),
2081-
PAGE_ALIGN(rxtx_bufsz) / FFA_PAGE_SIZE);
2139+
rxtx_bufsz / FFA_PAGE_SIZE);
20822140
if (ret) {
20832141
pr_err("failed to register FFA RxTx buffers\n");
20842142
goto free_pages;

0 commit comments

Comments
 (0)