summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2020-04-21 23:38:54 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2020-04-21 23:38:54 +0000
commit81b62a766393215461b8439ff96ba1de57a28e62 (patch)
tree934a28ea2c156f895c7400c0a85a7e7a79288ad4 /sys
parent24c2e17d2b5ac2c4450732e0f14f5de84025b981 (diff)
downloadsrc-test2-81b62a766393215461b8439ff96ba1de57a28e62.tar.gz
src-test2-81b62a766393215461b8439ff96ba1de57a28e62.zip
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
Notes
Notes: svn path=/head/; revision=360179
Diffstat (limited to 'sys')
-rw-r--r--sys/cam/scsi/scsi_sg.c27
1 files changed, 25 insertions, 2 deletions
diff --git a/sys/cam/scsi/scsi_sg.c b/sys/cam/scsi/scsi_sg.c
index 96a66cab1a6a..ebf40853649a 100644
--- a/sys/cam/scsi/scsi_sg.c
+++ b/sys/cam/scsi/scsi_sg.c
@@ -508,6 +508,7 @@ sgioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
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 flag, struct thread *td)
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 flag, struct thread *td)
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 flag, struct thread *td)
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 flag, struct thread *td)
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 flag, struct thread *td)
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;