summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsobomax <sobomax@FreeBSD.org>2005-01-30 08:12:37 +0000
committersobomax <sobomax@FreeBSD.org>2005-01-30 08:12:37 +0000
commit69aa6843efc6c9eeb6337b4d4ea4111c5ccd9ea7 (patch)
tree60c80029e1db66c753066e1ca06309b6a56d0ce6
parent357d55c30bf33ab6d5042b919803aac27999084a (diff)
downloadFreeBSD-src-69aa6843efc6c9eeb6337b4d4ea4111c5ccd9ea7.zip
FreeBSD-src-69aa6843efc6c9eeb6337b4d4ea4111c5ccd9ea7.tar.gz
Boot away another stackgap (one of the lest ones in linuxlator/i386) by
providing special version of CDIOCREADSUBCHANNEL ioctl(), which assumes that result has to be placed into kernel space not user space. In the long run more generic solution has to be designed WRT emulating various ioctl()s that operate on userspace buffers, but right now there is only one such ioctl() is emulated, so that it makes little sense. MFC after: 2 weeks
-rw-r--r--sys/cam/scsi/scsi_cd.c14
-rw-r--r--sys/compat/linux/linux_ioctl.c27
-rw-r--r--sys/dev/ata/atapi-cd.c13
-rw-r--r--sys/dev/mcd/mcd.c14
-rw-r--r--sys/dev/scd/scd.c16
-rw-r--r--sys/sys/cdio.h7
6 files changed, 63 insertions, 28 deletions
diff --git a/sys/cam/scsi/scsi_cd.c b/sys/cam/scsi/scsi_cd.c
index 012e3a2..11a64a7 100644
--- a/sys/cam/scsi/scsi_cd.c
+++ b/sys/cam/scsi/scsi_cd.c
@@ -1909,7 +1909,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
struct cam_periph *periph;
struct cd_softc *softc;
- int error;
+ int error, nocopyout;
periph = (struct cam_periph *)dp->d_drv1;
if (periph == NULL)
@@ -1940,6 +1940,7 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
}
}
+ nocopyout = 0;
switch (cmd) {
case CDIOCPLAYTRACKS:
@@ -2098,6 +2099,9 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
error = cdplay(periph, args->blk, args->len);
}
break;
+ case CDIOCREADSUBCHANNEL_SYSSPACE:
+ nocopyout = 1;
+ /* Fallthrough */
case CDIOCREADSUBCHANNEL:
{
struct ioc_read_subchannel *args
@@ -2138,8 +2142,12 @@ cdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
len = min(len, ((data->header.data_len[0] << 8) +
data->header.data_len[1] +
sizeof(struct cd_sub_channel_header)));
- if (copyout(data, args->data, len) != 0) {
- error = EFAULT;
+ if (nocopyout == 0) {
+ if (copyout(data, args->data, len) != 0) {
+ error = EFAULT;
+ }
+ } else {
+ bcopy(data, args->data, len);
}
free(data, M_TEMP);
}
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c
index beb9e0c..20a2aa9 100644
--- a/sys/compat/linux/linux_ioctl.c
+++ b/sys/compat/linux/linux_ioctl.c
@@ -1490,30 +1490,29 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
case LINUX_CDROMSUBCHNL: {
struct linux_cdrom_subchnl sc;
struct ioc_read_subchannel bsdsc;
- struct cd_sub_channel_info *bsdinfo;
- caddr_t sg = stackgap_init();
- bsdinfo = stackgap_alloc(&sg, sizeof(*bsdinfo));
+ struct cd_sub_channel_info bsdinfo;
+
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, (caddr_t)&bsdsc,
- td->td_ucred, td);
+ bsdsc.data_len = sizeof(bsdinfo);
+ bsdsc.data = &bsdinfo;
+ error = fo_ioctl(fp, CDIOCREADSUBCHANNEL_SYSSPACE,
+ (caddr_t)&bsdsc, td->td_ucred, td);
if (error)
break;
error = copyin((void *)args->arg, &sc, sizeof(sc));
if (error)
break;
- sc.cdsc_audiostatus = bsdinfo->header.audio_status;
- sc.cdsc_adr = bsdinfo->what.position.addr_type;
- sc.cdsc_ctrl = bsdinfo->what.position.control;
- sc.cdsc_trk = bsdinfo->what.position.track_number;
- sc.cdsc_ind = bsdinfo->what.position.index_number;
+ sc.cdsc_audiostatus = bsdinfo.header.audio_status;
+ sc.cdsc_adr = bsdinfo.what.position.addr_type;
+ sc.cdsc_ctrl = bsdinfo.what.position.control;
+ sc.cdsc_trk = bsdinfo.what.position.track_number;
+ sc.cdsc_ind = bsdinfo.what.position.index_number;
set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format,
- bsdinfo->what.position.absaddr.lba);
+ bsdinfo.what.position.absaddr.lba);
set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format,
- bsdinfo->what.position.reladdr.lba);
+ bsdinfo.what.position.reladdr.lba);
error = copyout(&sc, (void *)args->arg, sizeof(sc));
break;
}
diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c
index 9b86948..4a7df80 100644
--- a/sys/dev/ata/atapi-cd.c
+++ b/sys/dev/ata/atapi-cd.c
@@ -553,7 +553,7 @@ static int
acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct thread *td)
{
struct acd_softc *cdp = pp->geom->softc;
- int error = 0;
+ int error = 0, nocopyout;
if (!cdp)
return ENXIO;
@@ -574,6 +574,7 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct
cdp->flags |= F_LOCKED;
break;
}
+ nocopyout = 0;
switch (cmd) {
case CDIOCRESUME:
@@ -738,6 +739,9 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct
}
break;
+ case CDIOCREADSUBCHANNEL_SYSSPACE:
+ nocopyout = 1;
+ /* Fallthrough */
case CDIOCREADSUBCHANNEL:
{
struct ioc_read_subchannel *args =
@@ -782,7 +786,12 @@ acd_geom_ioctl(struct g_provider *pp, u_long cmd, void *addr, int fflag, struct
break;
}
}
- error = copyout(&cdp->subchan, args->data, args->data_len);
+ if (nocopyout == 0) {
+ error = copyout(&cdp->subchan, args->data, args->data_len);
+ } else {
+ error = 0;
+ bcopy(&cdp->subchan, args->data, args->data_len);
+ }
}
break;
diff --git a/sys/dev/mcd/mcd.c b/sys/dev/mcd/mcd.c
index db35190..e9cc575 100644
--- a/sys/dev/mcd/mcd.c
+++ b/sys/dev/mcd/mcd.c
@@ -135,7 +135,8 @@ static void mcd_soft_reset(struct mcd_softc *);
static int mcd_hard_reset(struct mcd_softc *);
static int mcd_setmode(struct mcd_softc *, int mode);
static int mcd_getqchan(struct mcd_softc *, struct mcd_qchninfo *q);
-static int mcd_subchan(struct mcd_softc *, struct ioc_read_subchannel *sc);
+static int mcd_subchan(struct mcd_softc *, struct ioc_read_subchannel *sc,
+ int nocopyout);
static int mcd_toc_header(struct mcd_softc *, struct ioc_toc_header *th);
static int mcd_read_toc(struct mcd_softc *);
static int mcd_toc_entrys(struct mcd_softc *, struct ioc_read_toc_entry *te);
@@ -440,8 +441,10 @@ MCD_TRACE("ioctl called 0x%lx\n", cmd);
return mcd_playblocks(sc, (struct ioc_play_blocks *) addr);
case CDIOCPLAYMSF:
return mcd_playmsf(sc, (struct ioc_play_msf *) addr);
+ case CDIOCREADSUBCHANNEL_SYSSPACE:
+ return mcd_subchan(sc, (struct ioc_read_subchannel *) addr, 1);
case CDIOCREADSUBCHANNEL:
- return mcd_subchan(sc, (struct ioc_read_subchannel *) addr);
+ return mcd_subchan(sc, (struct ioc_read_subchannel *) addr, 0);
case CDIOREADTOCHEADER:
return mcd_toc_header(sc, (struct ioc_toc_header *) addr);
case CDIOREADTOCENTRYS:
@@ -1357,7 +1360,7 @@ mcd_getqchan(struct mcd_softc *sc, struct mcd_qchninfo *q)
}
static int
-mcd_subchan(struct mcd_softc *sc, struct ioc_read_subchannel *sch)
+mcd_subchan(struct mcd_softc *sc, struct ioc_read_subchannel *sch, int nocopyout)
{
struct mcd_qchninfo q;
struct cd_sub_channel_info data;
@@ -1423,7 +1426,10 @@ mcd_subchan(struct mcd_softc *sc, struct ioc_read_subchannel *sch)
break;
}
- return copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len));
+ if (nocopyout == 0)
+ return copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len));
+ bcopy(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len));
+ return (0)
}
static int
diff --git a/sys/dev/scd/scd.c b/sys/dev/scd/scd.c
index 1b00e02..2c5f796 100644
--- a/sys/dev/scd/scd.c
+++ b/sys/dev/scd/scd.c
@@ -131,7 +131,7 @@ static int scd_resume(struct scd_softc *);
static int scd_playtracks(struct scd_softc *, struct ioc_play_track *pt);
static int scd_playmsf(struct scd_softc *, struct ioc_play_msf *msf);
static int scd_play(struct scd_softc *, struct ioc_play_msf *msf);
-static int scd_subchan(struct scd_softc *, struct ioc_read_subchannel *sch);
+static int scd_subchan(struct scd_softc *, struct ioc_read_subchannel *sch, int nocopyout);
static int read_subcode(struct scd_softc *, struct sony_subchannel_position_data *sch);
/* for xcdplayer */
@@ -350,8 +350,10 @@ scdioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *t
return (EINVAL);
case CDIOCPLAYMSF:
return scd_playmsf(sc, (struct ioc_play_msf *) addr);
+ case CDIOCREADSUBCHANNEL_SYSSPACE:
+ return scd_subchan(sc, (struct ioc_read_subchannel *) addr, 1);
case CDIOCREADSUBCHANNEL:
- return scd_subchan(sc, (struct ioc_read_subchannel *) addr);
+ return scd_subchan(sc, (struct ioc_read_subchannel *) addr, 0);
case CDIOREADTOCHEADER:
return scd_toc_header (sc, (struct ioc_toc_header *) addr);
case CDIOREADTOCENTRYS:
@@ -544,7 +546,7 @@ scd_eject(struct scd_softc *sc)
}
static int
-scd_subchan(struct scd_softc *sc, struct ioc_read_subchannel *sch)
+scd_subchan(struct scd_softc *sc, struct ioc_read_subchannel *sch, int nocopyout)
{
struct sony_subchannel_position_data q;
struct cd_sub_channel_info data;
@@ -573,8 +575,12 @@ scd_subchan(struct scd_softc *sc, struct ioc_read_subchannel *sch)
data.what.position.absaddr.msf.second = bcd2bin(q.abs_msf[1]);
data.what.position.absaddr.msf.frame = bcd2bin(q.abs_msf[2]);
- if (copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len))!=0)
- return (EFAULT);
+ if (nocopyout == 0) {
+ if (copyout(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len))!=0)
+ return (EFAULT);
+ } else {
+ bcopy(&data, sch->data, min(sizeof(struct cd_sub_channel_info), sch->data_len));
+ }
return (0);
}
diff --git a/sys/sys/cdio.h b/sys/sys/cdio.h
index a3eb271..3614d19 100644
--- a/sys/sys/cdio.h
+++ b/sys/sys/cdio.h
@@ -274,4 +274,11 @@ 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_ */
OpenPOWER on IntegriCloud