mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
cxl/region: Fix out-of-bounds access in cxl_cancel_auto_attach()
In cxl_cancel_auto_attach(), it assumes cxled->pos is a valid index for
accessing p->targets[]. However, cxled->pos can be set to negative errno
in cxl_region_sort_targets() if cxl_calc_interleave_pos() fails. This
causes the driver to use a negative index to access p->targets[],
resulting in out-of-bounds access.
Fix it by walking p->targets[] instead of using cxled->pos directly.
Fixes: 87805c32e6 ("cxl/region: Fix use-after-free from auto assembly failure")
Signed-off-by: Li Ming <ming.li@zohomail.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Link: https://patch.msgid.link/20260606-fix_two_issues_introduced_by_cxl_cancel_auto_attach-v1-1-5d94ca06c4e4@zohomail.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
This commit is contained in:
parent
769f0b350c
commit
cbda6a2c2b
|
|
@ -2009,8 +2009,9 @@ static int cxl_region_sort_targets(struct cxl_region *cxlr)
|
|||
cxled->pos = cxl_calc_interleave_pos(cxled, &cxlr->hpa_range);
|
||||
/*
|
||||
* Record that sorting failed, but still continue to calc
|
||||
* cxled->pos so that follow-on code paths can reliably
|
||||
* do p->targets[cxled->pos] to self-reference their entry.
|
||||
* cxled->pos so that cxl_calc_interleave_pos() emits its
|
||||
* dev_dbg() for every member. which is useful for auto
|
||||
* discovery debug.
|
||||
*/
|
||||
if (cxled->pos < 0)
|
||||
rc = -ENXIO;
|
||||
|
|
@ -2200,18 +2201,30 @@ static int cxl_region_attach(struct cxl_region *cxlr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cxl_region_by_target(struct device *dev, const void *data)
|
||||
static int cxl_region_remove_target(struct device *dev, void *data)
|
||||
{
|
||||
const struct cxl_endpoint_decoder *cxled = data;
|
||||
struct cxl_endpoint_decoder *cxled = data;
|
||||
struct cxl_region_params *p;
|
||||
struct cxl_region *cxlr;
|
||||
int i;
|
||||
|
||||
if (!is_cxl_region(dev))
|
||||
return 0;
|
||||
|
||||
cxlr = to_cxl_region(dev);
|
||||
p = &cxlr->params;
|
||||
return p->targets[cxled->pos] == cxled;
|
||||
for (i = 0; i < p->interleave_ways; i++) {
|
||||
if (p->targets[i] == cxled) {
|
||||
p->nr_targets--;
|
||||
cxled->state = CXL_DECODER_STATE_AUTO;
|
||||
cxled->pos = -1;
|
||||
p->targets[i] = NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2220,25 +2233,10 @@ static int cxl_region_by_target(struct device *dev, const void *data)
|
|||
*/
|
||||
static void cxl_cancel_auto_attach(struct cxl_endpoint_decoder *cxled)
|
||||
{
|
||||
struct cxl_region_params *p;
|
||||
struct cxl_region *cxlr;
|
||||
int pos = cxled->pos;
|
||||
|
||||
if (cxled->state != CXL_DECODER_STATE_AUTO_STAGED)
|
||||
return;
|
||||
|
||||
struct device *dev __free(put_device) =
|
||||
bus_find_device(&cxl_bus_type, NULL, cxled, cxl_region_by_target);
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
cxlr = to_cxl_region(dev);
|
||||
p = &cxlr->params;
|
||||
|
||||
p->nr_targets--;
|
||||
cxled->state = CXL_DECODER_STATE_AUTO;
|
||||
cxled->pos = -1;
|
||||
p->targets[pos] = NULL;
|
||||
bus_for_each_dev(&cxl_bus_type, NULL, cxled, cxl_region_remove_target);
|
||||
}
|
||||
|
||||
static struct cxl_region *
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user