Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Dan Williams and committed by
Dave Jiang
87805c32 e4de6b91

+57 -3
+53 -1
drivers/cxl/core/region.c
··· 1064 1064 1065 1065 if (!cxld->region) { 1066 1066 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; 1067 1075 get_device(&cxlr->dev); 1068 1076 } 1069 1077 ··· 1813 1805 pos = p->nr_targets; 1814 1806 p->targets[pos] = cxled; 1815 1807 cxled->pos = pos; 1808 + cxled->state = CXL_DECODER_STATE_AUTO_STAGED; 1816 1809 p->nr_targets++; 1817 1810 1818 1811 return 0; ··· 2163 2154 return 0; 2164 2155 } 2165 2156 2157 + static int cxl_region_by_target(struct device *dev, const void *data) 2158 + { 2159 + const struct cxl_endpoint_decoder *cxled = data; 2160 + struct cxl_region_params *p; 2161 + struct cxl_region *cxlr; 2162 + 2163 + if (!is_cxl_region(dev)) 2164 + return 0; 2165 + 2166 + cxlr = to_cxl_region(dev); 2167 + p = &cxlr->params; 2168 + return p->targets[cxled->pos] == cxled; 2169 + } 2170 + 2171 + /* 2172 + * When an auto-region fails to assemble the decoder may be listed as a target, 2173 + * but not fully attached. 2174 + */ 2175 + static void cxl_cancel_auto_attach(struct cxl_endpoint_decoder *cxled) 2176 + { 2177 + struct cxl_region_params *p; 2178 + struct cxl_region *cxlr; 2179 + int pos = cxled->pos; 2180 + 2181 + if (cxled->state != CXL_DECODER_STATE_AUTO_STAGED) 2182 + return; 2183 + 2184 + struct device *dev __free(put_device) = 2185 + bus_find_device(&cxl_bus_type, NULL, cxled, cxl_region_by_target); 2186 + if (!dev) 2187 + return; 2188 + 2189 + cxlr = to_cxl_region(dev); 2190 + p = &cxlr->params; 2191 + 2192 + p->nr_targets--; 2193 + cxled->state = CXL_DECODER_STATE_AUTO; 2194 + cxled->pos = -1; 2195 + p->targets[pos] = NULL; 2196 + } 2197 + 2166 2198 static struct cxl_region * 2167 2199 __cxl_decoder_detach(struct cxl_region *cxlr, 2168 2200 struct cxl_endpoint_decoder *cxled, int pos, ··· 2227 2177 cxled = p->targets[pos]; 2228 2178 } else { 2229 2179 cxlr = cxled->cxld.region; 2230 - if (!cxlr) 2180 + if (!cxlr) { 2181 + cxl_cancel_auto_attach(cxled); 2231 2182 return NULL; 2183 + } 2232 2184 p = &cxlr->params; 2233 2185 } 2234 2186
+4 -2
drivers/cxl/cxl.h
··· 378 378 }; 379 379 380 380 /* 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. 383 384 */ 384 385 enum cxl_decoder_state { 385 386 CXL_DECODER_STATE_MANUAL, 386 387 CXL_DECODER_STATE_AUTO, 388 + CXL_DECODER_STATE_AUTO_STAGED, 387 389 }; 388 390 389 391 /**