Skip to content

Commit 87805c3

Browse files
djbwdavejiang
authored andcommitted
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>
1 parent e4de6b9 commit 87805c3

2 files changed

Lines changed: 57 additions & 3 deletions

File tree

drivers/cxl/core/region.c

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1064,6 +1064,14 @@ static int cxl_rr_ep_add(struct cxl_region_ref *cxl_rr,
10641064

10651065
if (!cxld->region) {
10661066
cxld->region = cxlr;
1067+
1068+
/*
1069+
* Now that cxld->region is set the intermediate staging state
1070+
* can be cleared.
1071+
*/
1072+
if (cxld == &cxled->cxld &&
1073+
cxled->state == CXL_DECODER_STATE_AUTO_STAGED)
1074+
cxled->state = CXL_DECODER_STATE_AUTO;
10671075
get_device(&cxlr->dev);
10681076
}
10691077

@@ -1805,6 +1813,7 @@ static int cxl_region_attach_auto(struct cxl_region *cxlr,
18051813
pos = p->nr_targets;
18061814
p->targets[pos] = cxled;
18071815
cxled->pos = pos;
1816+
cxled->state = CXL_DECODER_STATE_AUTO_STAGED;
18081817
p->nr_targets++;
18091818

18101819
return 0;
@@ -2154,6 +2163,47 @@ static int cxl_region_attach(struct cxl_region *cxlr,
21542163
return 0;
21552164
}
21562165

2166+
static int cxl_region_by_target(struct device *dev, const void *data)
2167+
{
2168+
const struct cxl_endpoint_decoder *cxled = data;
2169+
struct cxl_region_params *p;
2170+
struct cxl_region *cxlr;
2171+
2172+
if (!is_cxl_region(dev))
2173+
return 0;
2174+
2175+
cxlr = to_cxl_region(dev);
2176+
p = &cxlr->params;
2177+
return p->targets[cxled->pos] == cxled;
2178+
}
2179+
2180+
/*
2181+
* When an auto-region fails to assemble the decoder may be listed as a target,
2182+
* but not fully attached.
2183+
*/
2184+
static void cxl_cancel_auto_attach(struct cxl_endpoint_decoder *cxled)
2185+
{
2186+
struct cxl_region_params *p;
2187+
struct cxl_region *cxlr;
2188+
int pos = cxled->pos;
2189+
2190+
if (cxled->state != CXL_DECODER_STATE_AUTO_STAGED)
2191+
return;
2192+
2193+
struct device *dev __free(put_device) =
2194+
bus_find_device(&cxl_bus_type, NULL, cxled, cxl_region_by_target);
2195+
if (!dev)
2196+
return;
2197+
2198+
cxlr = to_cxl_region(dev);
2199+
p = &cxlr->params;
2200+
2201+
p->nr_targets--;
2202+
cxled->state = CXL_DECODER_STATE_AUTO;
2203+
cxled->pos = -1;
2204+
p->targets[pos] = NULL;
2205+
}
2206+
21572207
static struct cxl_region *
21582208
__cxl_decoder_detach(struct cxl_region *cxlr,
21592209
struct cxl_endpoint_decoder *cxled, int pos,
@@ -2177,8 +2227,10 @@ __cxl_decoder_detach(struct cxl_region *cxlr,
21772227
cxled = p->targets[pos];
21782228
} else {
21792229
cxlr = cxled->cxld.region;
2180-
if (!cxlr)
2230+
if (!cxlr) {
2231+
cxl_cancel_auto_attach(cxled);
21812232
return NULL;
2233+
}
21822234
p = &cxlr->params;
21832235
}
21842236

drivers/cxl/cxl.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,12 +378,14 @@ struct cxl_decoder {
378378
};
379379

380380
/*
381-
* Track whether this decoder is reserved for region autodiscovery, or
382-
* free for userspace provisioning.
381+
* Track whether this decoder is free for userspace provisioning, reserved for
382+
* region autodiscovery, whether it is started connecting (awaiting other
383+
* peers), or has completed auto assembly.
383384
*/
384385
enum cxl_decoder_state {
385386
CXL_DECODER_STATE_MANUAL,
386387
CXL_DECODER_STATE_AUTO,
388+
CXL_DECODER_STATE_AUTO_STAGED,
387389
};
388390

389391
/**

0 commit comments

Comments
 (0)