1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-18 15:30:21 +00:00

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
This commit is contained in:
Mark Johnston 2019-07-03 00:10:01 +00:00
parent ce5ec2c559
commit fc795c25d4
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=349627
3 changed files with 17 additions and 24 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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_ */