svn commit: r360179 - head/sys/cam/scsi

John Baldwin jhb at FreeBSD.org
Tue Apr 21 23:38:55 UTC 2020


Author: jhb
Date: Tue Apr 21 23:38:54 2020
New Revision: 360179
URL: https://svnweb.freebsd.org/changeset/base/360179

Log:
  Don't pass a user buffer pointer as the data pointer in a CCB.
  
  Allocate a temporary buffer in the kernel to serve as the CCB data
  pointer for a pass-through transaction and use copyin/copyout to
  shuffle the data to/from the user buffer.
  
  Reviewed by:	scottl, brooks
  Obtained from:	CheriBSD
  MFC after:	2 weeks
  Sponsored by:	DARPA
  Differential Revision:	https://reviews.freebsd.org/D24489

Modified:
  head/sys/cam/scsi/scsi_sg.c

Modified: head/sys/cam/scsi/scsi_sg.c
==============================================================================
--- head/sys/cam/scsi/scsi_sg.c	Tue Apr 21 21:48:35 2020	(r360178)
+++ head/sys/cam/scsi/scsi_sg.c	Tue Apr 21 23:38:54 2020	(r360179)
@@ -508,6 +508,7 @@ sgioctl(struct cdev *dev, u_long cmd, caddr_t arg, int
 	struct cam_periph *periph;
 	struct sg_softc *softc;
 	struct sg_io_hdr *req;
+	void *data_ptr;
 	int dir, error;
 
 	periph = (struct cam_periph *)dev->si_drv1;
@@ -552,12 +553,20 @@ sgioctl(struct cdev *dev, u_long cmd, caddr_t arg, int
 			break;
 		}
 
+		if (req->dxfer_len > MAXPHYS) {
+			error = EINVAL;
+			break;
+		}
+
+		data_ptr = malloc(req->dxfer_len, M_DEVBUF, M_WAITOK);
+
 		ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL);
 		csio = &ccb->csio;
 
 		error = copyin(req->cmdp, &csio->cdb_io.cdb_bytes,
 		    req->cmd_len);
 		if (error) {
+			free(data_ptr, M_DEVBUF);
 			xpt_release_ccb(ccb);
 			break;
 		}
@@ -570,7 +579,7 @@ sgioctl(struct cdev *dev, u_long cmd, caddr_t arg, int
 			dir = CAM_DIR_IN;
 			break;
 		case SG_DXFER_TO_FROM_DEV:
-			dir = CAM_DIR_IN | CAM_DIR_OUT;
+			dir = CAM_DIR_BOTH;
 			break;
 		case SG_DXFER_NONE:
 		default:
@@ -578,12 +587,21 @@ sgioctl(struct cdev *dev, u_long cmd, caddr_t arg, int
 			break;
 		}
 
+		if (dir == CAM_DIR_IN || dir == CAM_DIR_BOTH) {
+			error = copyin(req->dxferp, data_ptr, req->dxfer_len);
+			if (error) {
+				free(data_ptr, M_DEVBUF);
+				xpt_release_ccb(ccb);
+				break;
+			}
+		}
+
 		cam_fill_csio(csio,
 			      /*retries*/1,
 			      /*cbfcnp*/NULL,
 			      dir|CAM_DEV_QFRZDIS,
 			      MSG_SIMPLE_Q_TAG,
-			      req->dxferp,
+			      data_ptr,
 			      req->dxfer_len,
 			      req->mx_sb_len,
 			      req->cmd_len,
@@ -593,6 +611,7 @@ sgioctl(struct cdev *dev, u_long cmd, caddr_t arg, int
 		if (error) {
 			req->host_status = DID_ERROR;
 			req->driver_status = DRIVER_INVALID;
+			free(data_ptr, M_DEVBUF);
 			xpt_release_ccb(ccb);
 			break;
 		}
@@ -611,6 +630,10 @@ sgioctl(struct cdev *dev, u_long cmd, caddr_t arg, int
 					req->sb_len_wr);
 		}
 
+		if ((dir == CAM_DIR_OUT || dir == CAM_DIR_BOTH) && error == 0)
+			error = copyout(data_ptr, req->dxferp, req->dxfer_len);
+
+		free(data_ptr, M_DEVBUF);
 		xpt_release_ccb(ccb);
 		break;
 		


More information about the svn-src-head mailing list