mirror of
https://github.com/torvalds/linux.git
synced 2026-05-24 15:12:13 +02:00
cxl/region: Fix use-after-free from auto assembly failure
The following crash signature results from region destruction while an endpoint decoder is staged, but not fully attached. [ dj: Moved bus_find_device( to next line. ] Signed-off-by: Dan Williams <dan.j.williams@intel.com> Reviewed-by: Ira Weiny <ira.weiny@intel.com> Reviewed-by: Alison Schofield <alison.schofield@intel.com> Reviewed-by: Dave Jiang <dave.jiang@intel.com> Link: https://patch.msgid.link/20260327052821.440749-2-dan.j.williams@intel.com Signed-off-by: Dave Jiang <dave.jiang@intel.com>
This commit is contained in:
parent
e4de6b910b
commit
87805c32e6
|
|
@ -1064,6 +1064,14 @@ static int cxl_rr_ep_add(struct cxl_region_ref *cxl_rr,
|
|||
|
||||
if (!cxld->region) {
|
||||
cxld->region = cxlr;
|
||||
|
||||
/*
|
||||
* Now that cxld->region is set the intermediate staging state
|
||||
* can be cleared.
|
||||
*/
|
||||
if (cxld == &cxled->cxld &&
|
||||
cxled->state == CXL_DECODER_STATE_AUTO_STAGED)
|
||||
cxled->state = CXL_DECODER_STATE_AUTO;
|
||||
get_device(&cxlr->dev);
|
||||
}
|
||||
|
||||
|
|
@ -1805,6 +1813,7 @@ static int cxl_region_attach_auto(struct cxl_region *cxlr,
|
|||
pos = p->nr_targets;
|
||||
p->targets[pos] = cxled;
|
||||
cxled->pos = pos;
|
||||
cxled->state = CXL_DECODER_STATE_AUTO_STAGED;
|
||||
p->nr_targets++;
|
||||
|
||||
return 0;
|
||||
|
|
@ -2154,6 +2163,47 @@ static int cxl_region_attach(struct cxl_region *cxlr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cxl_region_by_target(struct device *dev, const void *data)
|
||||
{
|
||||
const struct cxl_endpoint_decoder *cxled = data;
|
||||
struct cxl_region_params *p;
|
||||
struct cxl_region *cxlr;
|
||||
|
||||
if (!is_cxl_region(dev))
|
||||
return 0;
|
||||
|
||||
cxlr = to_cxl_region(dev);
|
||||
p = &cxlr->params;
|
||||
return p->targets[cxled->pos] == cxled;
|
||||
}
|
||||
|
||||
/*
|
||||
* When an auto-region fails to assemble the decoder may be listed as a target,
|
||||
* but not fully attached.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
static struct cxl_region *
|
||||
__cxl_decoder_detach(struct cxl_region *cxlr,
|
||||
struct cxl_endpoint_decoder *cxled, int pos,
|
||||
|
|
@ -2177,8 +2227,10 @@ __cxl_decoder_detach(struct cxl_region *cxlr,
|
|||
cxled = p->targets[pos];
|
||||
} else {
|
||||
cxlr = cxled->cxld.region;
|
||||
if (!cxlr)
|
||||
if (!cxlr) {
|
||||
cxl_cancel_auto_attach(cxled);
|
||||
return NULL;
|
||||
}
|
||||
p = &cxlr->params;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -378,12 +378,14 @@ struct cxl_decoder {
|
|||
};
|
||||
|
||||
/*
|
||||
* Track whether this decoder is reserved for region autodiscovery, or
|
||||
* free for userspace provisioning.
|
||||
* Track whether this decoder is free for userspace provisioning, reserved for
|
||||
* region autodiscovery, whether it is started connecting (awaiting other
|
||||
* peers), or has completed auto assembly.
|
||||
*/
|
||||
enum cxl_decoder_state {
|
||||
CXL_DECODER_STATE_MANUAL,
|
||||
CXL_DECODER_STATE_AUTO,
|
||||
CXL_DECODER_STATE_AUTO_STAGED,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user