diff --git a/sys/bus/cam/cam_xpt.c b/sys/bus/cam/cam_xpt.c --- a/sys/bus/cam/cam_xpt.c +++ b/sys/bus/cam/cam_xpt.c @@ -2435,17 +2435,33 @@ * needs to reset everything and start over. */ if ((cdm->pos.position_type & CAM_DEV_POS_BUS) - && (cdm->pos.generations[CAM_BUS_GENERATION] != 0) - && (cdm->pos.generations[CAM_BUS_GENERATION] != xsoftc.bus_generation)) { - cdm->status = CAM_DEV_MATCH_LIST_CHANGED; - return(0); - } - - if ((cdm->pos.position_type & CAM_DEV_POS_BUS) - && (cdm->pos.cookie.bus != NULL)) + && (cdm->pos.cookie.bus != NULL)) { + /* + * A non-NULL resume cookie is dereferenced verbatim by + * xptbustraverse(). Refuse to honour it unless the caller also + * supplied a current bus generation: the old test allowed a + * malicious caller to bypass the generation check simply by + * setting generations[CAM_BUS_GENERATION]=0 and then supply an + * arbitrary kernel pointer as cookie.bus -> controlled-deref + * panic / potential UAF. (Full hardening would additionally + * re-validate that cookie.bus names a live cam_eb; this closes + * the trivial bypass.) + */ + if ((cdm->pos.generations[CAM_BUS_GENERATION] == 0) + || (cdm->pos.generations[CAM_BUS_GENERATION] != + xsoftc.bus_generation)) { + cdm->status = CAM_DEV_MATCH_LIST_CHANGED; + return(0); + } ret = xptbustraverse((struct cam_eb *)cdm->pos.cookie.bus, xptedtbusfunc, cdm); - else + } else if ((cdm->pos.position_type & CAM_DEV_POS_BUS) + && (cdm->pos.generations[CAM_BUS_GENERATION] != 0) + && (cdm->pos.generations[CAM_BUS_GENERATION] != + xsoftc.bus_generation)) { + cdm->status = CAM_DEV_MATCH_LIST_CHANGED; + return(0); + } else ret = xptbustraverse(NULL, xptedtbusfunc, cdm); /*