aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2016-10-17 15:02:17 +0000
committerAlexander Motin <mav@FreeBSD.org>2016-10-17 15:02:17 +0000
commita1a604ca902bbe790abd63576d5127680663f0e1 (patch)
treebacc0b57718997f86c2506c847bd0766b69aca8e /sys
parent9e621953611e11cbb2282f7b28b3796621693328 (diff)
downloadsrc-a1a604ca902bbe790abd63576d5127680663f0e1.tar.gz
src-a1a604ca902bbe790abd63576d5127680663f0e1.zip
Make pass driver better support CAM_CDB_POINTER flag.
Previously pass driver just ignored the flag, making random kernel code access user-space pointer, sometime causing crashes even for correctly written applications if user-level context was switched or swapped out. This patch tries to copyin the CDB into kernel space to avoid it. MFC after: 2 weeks
Notes
Notes: svn path=/head/; revision=307523
Diffstat (limited to 'sys')
-rw-r--r--sys/cam/scsi/scsi_pass.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/sys/cam/scsi/scsi_pass.c b/sys/cam/scsi/scsi_pass.c
index d7fa73b9fc69..68412b4a1157 100644
--- a/sys/cam/scsi/scsi_pass.c
+++ b/sys/cam/scsi/scsi_pass.c
@@ -1876,6 +1876,18 @@ passdoioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread
break;
}
+ if (ccb->ccb_h.flags & CAM_CDB_POINTER) {
+ if (ccb->csio.cdb_len > IOCDBLEN) {
+ error = EINVAL;
+ break;
+ }
+ error = copyin(ccb->csio.cdb_io.cdb_ptr,
+ ccb->csio.cdb_io.cdb_bytes, ccb->csio.cdb_len);
+ if (error)
+ break;
+ ccb->ccb_h.flags &= ~CAM_CDB_POINTER;
+ }
+
/*
* Some CCB types, like scan bus and scan lun can only go
* through the transport layer device.
@@ -2143,6 +2155,7 @@ passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
{
struct pass_softc *softc;
struct cam_periph_map_info mapinfo;
+ uint8_t *cmd;
xpt_opcode fc;
int error;
@@ -2154,6 +2167,14 @@ passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb)
*/
xpt_merge_ccb(ccb, inccb);
+ if (ccb->ccb_h.flags & CAM_CDB_POINTER) {
+ cmd = __builtin_alloca(ccb->csio.cdb_len);
+ error = copyin(ccb->csio.cdb_io.cdb_ptr, cmd, ccb->csio.cdb_len);
+ if (error)
+ return (error);
+ ccb->csio.cdb_io.cdb_ptr = cmd;
+ }
+
/*
*/
ccb->ccb_h.cbfcnp = passdone;