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-main mailing list