--- a/sys/bus/cam/cam_periph.c 2026-10-21 08:21:37.426871402 +0000 +++ b/sys/bus/cam/cam_periph.c 2026-10-21 08:21:37.430871352 +0000 @@ -1,21 +1,5 @@ case CAMGETPASSTHRU: ccb = cam_periph_getccb(periph, /* priority */ 1); - /* - * DF-2266: the pooled CCB carries stale kernel pointers - * (cbfcnp, path, sim_priv, timeout_ch, saved_ccb_ptr) and - * old I/O bytes in the union body; the whole union is - * bcopied to userspace below. Zero it first, preserving - * only path/timeout_ch which xpt_setup_ccb needs and which - * must not be freed or re-inited here. - */ - { - struct cam_path *df_path = ccb->ccb_h.path; - struct callout *df_co = ccb->ccb_h.timeout_ch; - - bzero(ccb, sizeof(*ccb)); - ccb->ccb_h.path = df_path; - ccb->ccb_h.timeout_ch = df_co; - } xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, /*priority*/1); \ No newline at end of file --- a/sys/bus/cam/cam_periph.c 2026-10-21 08:21:37.430871352 +0000 +++ b/sys/bus/cam/cam_periph.c 2026-10-21 08:21:37.430871352 +0000 @@ -1,2 +1,29 @@ - /* copy the result back out */ - bcopy(ccb, addr, sizeof(union ccb)); \ No newline at end of file + /* + * DF-2266: copy the result back out through a SCRUBBED + * shadow CCB: the pooled kernel CCB carries live kernel + * pointers (path cam_path*, timeout_ch callout*, sim_priv + * SIM softc*) and stale bytes from prior I/O in the union + * body, none of which may be disclosed to userspace. The + * live CCB itself is left untouched (xpt_release_ccb still + * needs its state). + */ + { + union ccb df_out; + + bzero(&df_out, sizeof(df_out)); + bcopy(&ccb->ccb_h, &df_out.ccb_h, + sizeof(struct ccb_hdr)); + df_out.cgdl = ccb->cgdl; + df_out.ccb_h.cbfcnp = NULL; + df_out.ccb_h.path = NULL; + df_out.ccb_h.timeout_ch = NULL; + df_out.ccb_h.sim_priv.entries[0].ptr = NULL; + df_out.ccb_h.sim_priv.entries[1].ptr = NULL; + df_out.ccb_h.xpt_links.sle.sle_next = NULL; + df_out.ccb_h.sim_links.sle.sle_next = NULL; + df_out.ccb_h.periph_links.sle.sle_next = NULL; + df_out.ccb_h.xpt_links.tqe.tqe_next = NULL; + df_out.ccb_h.sim_links.tqe.tqe_next = NULL; + df_out.ccb_h.periph_links.tqe.tqe_next = NULL; + bcopy(&df_out, addr, sizeof(union ccb)); + } \ No newline at end of file