git: 13aa56fcd596 - main - cam(4): preserve alloc_flags when copying CCBs
Edward Tomasz Napierala
trasz at FreeBSD.org
Tue Jul 6 08:54:41 UTC 2021
The branch main has been updated by trasz:
URL: https://cgit.FreeBSD.org/src/commit/?id=13aa56fcd59674cd65afc8e9d6b0c15d32bf9f81
commit 13aa56fcd59674cd65afc8e9d6b0c15d32bf9f81
Author: Edward Tomasz Napierala <trasz at FreeBSD.org>
AuthorDate: 2021-07-06 08:23:25 +0000
Commit: Edward Tomasz Napierala <trasz at FreeBSD.org>
CommitDate: 2021-07-06 08:27:22 +0000
cam(4): preserve alloc_flags when copying CCBs
Before UMA CCBs, all CCBs were of the same size, and could
be trivially copied using bcopy(9). Now we have to preserve
alloc_flags, otherwise we might end up attempting to free
stack-allocated CCB to UMA; we also need to take CCB size
into account.
This fixes kernel panic which would occur when trying to access
a stopped (as in, SCSI START STOP, also "ctladm stop") SCSI device.
Reported By: Gary Jennejohn <gljennjohn at gmail.com>
Tested By: Gary Jennejohn <gljennjohn at gmail.com>
Reviewed By: imp
Sponsored by: NetApp, Inc.
Sponsored by: Klara, Inc.
Differential Revision: https://reviews.freebsd.org/D31054
---
sys/cam/cam_periph.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c
index 3e1a19936825..90ddf261cb12 100644
--- a/sys/cam/cam_periph.c
+++ b/sys/cam/cam_periph.c
@@ -1354,6 +1354,7 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
cam_status status;
struct scsi_start_stop_unit *scsi_cmd;
int error = 0, error_code, sense_key, asc, ascq;
+ u_int16_t done_flags;
scsi_cmd = (struct scsi_start_stop_unit *)
&done_ccb->csio.cdb_io.cdb_bytes;
@@ -1422,8 +1423,21 @@ camperiphdone(struct cam_periph *periph, union ccb *done_ccb)
* blocking by that also any new recovery attempts for this CCB,
* and the result will be the final one returned to the CCB owher.
*/
+
+ /*
+ * Copy the CCB back, preserving the alloc_flags field. Things
+ * will crash horribly if the CCBs are not of the same size.
+ */
saved_ccb = (union ccb *)done_ccb->ccb_h.saved_ccb_ptr;
- bcopy(saved_ccb, done_ccb, sizeof(*done_ccb));
+ KASSERT(saved_ccb->ccb_h.func_code == XPT_SCSI_IO,
+ ("%s: saved_ccb func_code %#x != XPT_SCSI_IO",
+ __func__, saved_ccb->ccb_h.func_code));
+ KASSERT(done_ccb->ccb_h.func_code == XPT_SCSI_IO,
+ ("%s: done_ccb func_code %#x != XPT_SCSI_IO",
+ __func__, done_ccb->ccb_h.func_code));
+ done_flags = done_ccb->ccb_h.alloc_flags;
+ bcopy(saved_ccb, done_ccb, sizeof(struct ccb_scsiio));
+ done_ccb->ccb_h.alloc_flags = done_flags;
xpt_free_ccb(saved_ccb);
if (done_ccb->ccb_h.cbfcnp != camperiphdone)
periph->flags &= ~CAM_PERIPH_RECOVERY_INPROG;
@@ -1619,6 +1633,7 @@ camperiphscsisenseerror(union ccb *ccb, union ccb **orig,
struct cam_periph *periph;
union ccb *orig_ccb = ccb;
int error, recoveryccb;
+ u_int16_t flags;
#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING)
if (ccb->ccb_h.func_code == XPT_SCSI_IO && ccb->csio.bio != NULL)
@@ -1713,7 +1728,13 @@ camperiphscsisenseerror(union ccb *ccb, union ccb **orig,
* this freeze will be dropped as part of ERESTART.
*/
ccb->ccb_h.status &= ~CAM_DEV_QFRZN;
- bcopy(ccb, orig_ccb, sizeof(*orig_ccb));
+
+ KASSERT(ccb->ccb_h.func_code == XPT_SCSI_IO,
+ ("%s: ccb func_code %#x != XPT_SCSI_IO",
+ __func__, ccb->ccb_h.func_code));
+ flags = orig_ccb->ccb_h.alloc_flags;
+ bcopy(ccb, orig_ccb, sizeof(struct ccb_scsiio));
+ orig_ccb->ccb_h.alloc_flags = flags;
}
switch (err_action & SS_MASK) {
More information about the dev-commits-src-all
mailing list