mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-09 06:43:09 +00:00
irqchip/gicv3-its: Don't allow devices whose ID is outside range
We are not checking whether the requested device identifier fits into the device table memory or not. The function its_create_device() assumes that enough memory has been allocated for whole DevID space (reported by ITS_TYPER.Devbits) during the ITS probe() and continues to initialize ITS hardware. This assumption is not perfect, sometimes we reduce memory size either because of its size crossing MAX_ORDER-1 or BASERn max size limit. The MAPD command fails if 'Device ID' is outside of device table range. Add a simple validation check to avoid MAPD failures since we are not handling ITS command errors. This change also helps to return an error -ENOMEM instead of success to caller. Signed-off-by: Shanker Donthineni <shankerd@codeaurora.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
This commit is contained in:
parent
8cb17b5ed0
commit
466b7d1688
@ -54,6 +54,16 @@ struct its_collection {
|
||||
u16 col_id;
|
||||
};
|
||||
|
||||
/*
|
||||
* The ITS_BASER structure - contains memory information and cached
|
||||
* value of BASER register configuration.
|
||||
*/
|
||||
struct its_baser {
|
||||
void *base;
|
||||
u64 val;
|
||||
u32 order;
|
||||
};
|
||||
|
||||
/*
|
||||
* The ITS structure - contains most of the infrastructure, with the
|
||||
* top-level MSI domain, the command queue, the collections, and the
|
||||
@ -66,14 +76,12 @@ struct its_node {
|
||||
unsigned long phys_base;
|
||||
struct its_cmd_block *cmd_base;
|
||||
struct its_cmd_block *cmd_write;
|
||||
struct {
|
||||
void *base;
|
||||
u32 order;
|
||||
} tables[GITS_BASER_NR_REGS];
|
||||
struct its_baser tables[GITS_BASER_NR_REGS];
|
||||
struct its_collection *collections;
|
||||
struct list_head its_device_list;
|
||||
u64 flags;
|
||||
u32 ite_size;
|
||||
u32 device_ids;
|
||||
};
|
||||
|
||||
#define ITS_ITT_ALIGN SZ_256
|
||||
@ -838,6 +846,8 @@ static int its_alloc_tables(const char *node_name, struct its_node *its)
|
||||
ids = GITS_TYPER_DEVBITS(typer);
|
||||
}
|
||||
|
||||
its->device_ids = ids;
|
||||
|
||||
for (i = 0; i < GITS_BASER_NR_REGS; i++) {
|
||||
u64 val = readq_relaxed(its->base + GITS_BASER + i * 8);
|
||||
u64 type = GITS_BASER_TYPE(val);
|
||||
@ -913,6 +923,7 @@ static int its_alloc_tables(const char *node_name, struct its_node *its)
|
||||
}
|
||||
|
||||
val |= alloc_pages - 1;
|
||||
its->tables[i].val = val;
|
||||
|
||||
writeq_relaxed(val, its->base + GITS_BASER + i * 8);
|
||||
tmp = readq_relaxed(its->base + GITS_BASER + i * 8);
|
||||
@ -1138,9 +1149,22 @@ static struct its_device *its_find_device(struct its_node *its, u32 dev_id)
|
||||
return its_dev;
|
||||
}
|
||||
|
||||
static struct its_baser *its_get_baser(struct its_node *its, u32 type)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GITS_BASER_NR_REGS; i++) {
|
||||
if (GITS_BASER_TYPE(its->tables[i].val) == type)
|
||||
return &its->tables[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
|
||||
int nvecs)
|
||||
{
|
||||
struct its_baser *baser;
|
||||
struct its_device *dev;
|
||||
unsigned long *lpi_map;
|
||||
unsigned long flags;
|
||||
@ -1151,6 +1175,16 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
|
||||
int nr_ites;
|
||||
int sz;
|
||||
|
||||
baser = its_get_baser(its, GITS_BASER_TYPE_DEVICE);
|
||||
|
||||
/* Don't allow 'dev_id' that exceeds single, flat table limit */
|
||||
if (baser) {
|
||||
if (dev_id >= (PAGE_ORDER_TO_SIZE(baser->order) /
|
||||
GITS_BASER_ENTRY_SIZE(baser->val)))
|
||||
return NULL;
|
||||
} else if (ilog2(dev_id) >= its->device_ids)
|
||||
return NULL;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
/*
|
||||
* At least one bit of EventID is being used, hence a minimum
|
||||
|
Loading…
Reference in New Issue
Block a user