Skip to content
Permalink
Browse files

Remove the CDIOCREADSUBCHANNEL_SYSSPACE ioctl.

This was added for emulation of Linux's CDROMSUBCHNL, but allows
users with read access to a cd(4) device to overwrite kernel memory
provided that the driver detects some media present.

Reimplement CDROMSUBCHNL by bouncing the data from CDIOCREADSUBCHANNEL
through the linux_cdrom_subchnl structure passed from userspace.

admbugs:	768
Reported by:	Alex Fortune
Security:	CVE-2019-5602
Security:	FreeBSD-SA-19:11.cd_ioctl
  • Loading branch information...
markjdb committed Jul 3, 2019
1 parent fcc8c9e commit 6bcf6e3fcb7911683307dc5d033108ed0f66e97c
Showing with 17 additions and 24 deletions.
  1. +2 −12 sys/cam/scsi/scsi_cd.c
  2. +15 −5 sys/compat/linux/linux_ioctl.c
  3. +0 −7 sys/sys/cdio.h
@@ -1314,7 +1314,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)

struct cam_periph *periph;
struct cd_softc *softc;
int nocopyout, error = 0;
int error = 0;

periph = (struct cam_periph *)dp->d_drv1;
cam_periph_lock(periph);
@@ -1356,7 +1356,6 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
*/
cam_periph_unlock(periph);

nocopyout = 0;
switch (cmd) {

case CDIOCPLAYTRACKS:
@@ -1532,9 +1531,6 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
cam_periph_unlock(periph);
}
break;
case CDIOCREADSUBCHANNEL_SYSSPACE:
nocopyout = 1;
/* Fallthrough */
case CDIOCREADSUBCHANNEL:
{
struct ioc_read_subchannel *args
@@ -1579,13 +1575,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
data->header.data_len[1] +
sizeof(struct cd_sub_channel_header)));
cam_periph_unlock(periph);
if (nocopyout == 0) {
if (copyout(data, args->data, len) != 0) {
error = EFAULT;
}
} else {
bcopy(data, args->data, len);
}
error = copyout(data, args->data, len);
free(data, M_SCSICD);
}
break;
@@ -1489,16 +1489,26 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
struct ioc_read_subchannel bsdsc;
struct cd_sub_channel_info bsdinfo;

error = copyin((void *)args->arg, &sc, sizeof(sc));
if (error)
break;

/*
* Invoke the native ioctl and bounce the returned data through
* the userspace buffer. This works because the Linux structure
* is the same size as our structures for the subchannel header
* and position data.
*/
bsdsc.address_format = CD_LBA_FORMAT;
bsdsc.data_format = CD_CURRENT_POSITION;
bsdsc.track = 0;
bsdsc.data_len = sizeof(bsdinfo);
bsdsc.data = &bsdinfo;
error = fo_ioctl(fp, CDIOCREADSUBCHANNEL_SYSSPACE,
(caddr_t)&bsdsc, td->td_ucred, td);
bsdsc.data_len = sizeof(sc);
bsdsc.data = (void *)args->arg;
error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc,
td->td_ucred, td);
if (error)
break;
error = copyin((void *)args->arg, &sc, sizeof(sc));
error = copyin((void *)args->arg, &bsdinfo, sizeof(bsdinfo));
if (error)
break;
sc.cdsc_audiostatus = bsdinfo.header.audio_status;
@@ -274,11 +274,4 @@ struct ioc_capability { /*<2>*/

#define CDIOCCAPABILITY _IOR('c',30,struct ioc_capability) /*<2>*/

/*
* Special version of CDIOCREADSUBCHANNEL which assumes that
* ioc_read_subchannel->data points to the kernel memory. For
* use in compatibility layers.
*/
#define CDIOCREADSUBCHANNEL_SYSSPACE _IOWR('c', 31, struct ioc_read_subchannel)

#endif /* !_SYS_CDIO_H_ */

0 comments on commit 6bcf6e3

Please sign in to comment.
You can’t perform that action at this time.