2019-10-09 19:13:35

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 00/43] compat_ioctl: remove most of fs/compat_ioctl.c

As part of the cleanup of some remaining y2038 issues, I came to
fs/compat_ioctl.c, which still has a couple of commands that need support
for time64_t.

In completely unrelated work, I spent time on cleaning up parts of this
file in the past, moving things out into drivers instead.

After Al Viro reviewed an earlier version of this series and did a lot
more of that cleanup, I decided to try to completely eliminate the rest
of it and move it all into drivers.

This series incorporates some of Al's work and many patches of my own,
but in the end stops short of actually removing the last part, which is
the scsi ioctl handlers. I have patches for those as well, but they need
more testing or possibly a rewrite.

Signed-off-by: Arnd Bergmann <[email protected]>
---

Everything in here was posted one or more times already, sending
the whole series again for review, I hope to get some input on those
patches that have not already been reviewed.

The entire series is also part of linux-next through
https://git.kernel.org/pub/scm/linux/kernel/git/arnd/playground.git/commit/?h=y2038


Al Viro (8):
fix compat handling of FICLONERANGE, FIDEDUPERANGE and FS_IOC_FIEMAP
FIGETBSZ: fix compat
compat: itanic doesn't have one
do_vfs_ioctl(): use saner types
compat: move FS_IOC_RESVSP_32 handling to fs/ioctl.c
compat_sys_ioctl(): make parallel to do_vfs_ioctl()
compat_ioctl: unify copy-in of ppp filters
compat_ioctl: move PPPIOCSCOMPRESS to ppp_generic

Arnd Bergmann (35):
ceph: fix compat_ioctl for ceph_dir_operations
compat_ioctl: drop FIOQSIZE table entry
compat_ioctl: add compat_ptr_ioctl()
compat_ioctl: move rtc handling into rtc-dev.c
compat_ioctl: move drivers to compat_ptr_ioctl
compat_ioctl: move more drivers to compat_ptr_ioctl
compat_ioctl: use correct compat_ptr() translation in drivers
compat_ioctl: move tape handling into drivers
compat_ioctl: move ATYFB_CLK handling to atyfb driver
compat_ioctl: move isdn/capi ioctl translation into driver
compat_ioctl: move rfcomm handlers into driver
compat_ioctl: move hci_sock handlers into driver
compat_ioctl: remove HCIUART handling
compat_ioctl: remove HIDIO translation
compat_ioctl: remove translation for sound ioctls
compat_ioctl: remove IGNORE_IOCTL()
compat_ioctl: remove /dev/random commands
compat_ioctl: remove joystick ioctl translation
compat_ioctl: remove PCI ioctl translation
compat_ioctl: remove /dev/raw ioctl translation
compat_ioctl: remove last RAID handling code
compat_ioctl: remove unused convert_in_user macro
gfs2: add compat_ioctl support
fs: compat_ioctl: move FITRIM emulation into file systems
compat_ioctl: move WDIOC handling into wdt drivers
compat_ioctl: reimplement SG_IO handling
af_unix: add compat_ioctl support
compat_ioctl: handle SIOCOUTQNSD
compat_ioctl: move SIOCOUTQ out of compat_ioctl.c
tty: handle compat PPP ioctls
compat_ioctl: handle PPPIOCGIDLE for 64-bit time_t
compat_ioctl: ppp: move simple commands into ppp_generic.c
compat_ioctl: move SG_GET_REQUEST_TABLE handling
pktcdvd: add compat_ioctl handler
scsi: sd: enable compat ioctls for sed-opal

Documentation/networking/ppp_generic.txt | 2 +
arch/powerpc/platforms/52xx/mpc52xx_gpt.c | 1 +
arch/um/drivers/harddog_kern.c | 1 +
arch/um/drivers/hostaudio_kern.c | 1 +
block/scsi_ioctl.c | 132 ++-
drivers/android/binder.c | 2 +-
drivers/block/pktcdvd.c | 25 +
drivers/char/ipmi/ipmi_watchdog.c | 1 +
drivers/char/ppdev.c | 12 +-
drivers/char/random.c | 1 +
drivers/char/tpm/tpm_vtpm_proxy.c | 12 +-
drivers/crypto/qat/qat_common/adf_ctl_drv.c | 2 +-
drivers/dma-buf/dma-buf.c | 4 +-
drivers/dma-buf/sw_sync.c | 2 +-
drivers/dma-buf/sync_file.c | 2 +-
drivers/firewire/core-cdev.c | 12 +-
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 2 +-
drivers/hid/hidraw.c | 4 +-
drivers/hid/usbhid/hiddev.c | 11 +-
drivers/hwmon/fschmd.c | 1 +
drivers/hwtracing/stm/core.c | 12 +-
drivers/ide/ide-tape.c | 27 +-
drivers/iio/industrialio-core.c | 2 +-
drivers/infiniband/core/uverbs_main.c | 4 +-
drivers/isdn/capi/capi.c | 31 +
drivers/media/rc/lirc_dev.c | 4 +-
drivers/misc/cxl/flash.c | 8 +-
drivers/misc/genwqe/card_dev.c | 23 +-
drivers/misc/mei/main.c | 22 +-
drivers/misc/vmw_vmci/vmci_host.c | 2 +-
drivers/mtd/ubi/cdev.c | 36 +-
drivers/net/ppp/ppp_generic.c | 245 ++++--
drivers/net/tap.c | 12 +-
drivers/nvdimm/bus.c | 4 +-
drivers/nvme/host/core.c | 2 +-
drivers/pci/switch/switchtec.c | 2 +-
drivers/platform/x86/wmi.c | 2 +-
drivers/rpmsg/rpmsg_char.c | 4 +-
drivers/rtc/dev.c | 13 +-
drivers/rtc/rtc-ds1374.c | 1 +
drivers/rtc/rtc-vr41xx.c | 10 +
drivers/s390/char/tape_char.c | 41 +-
drivers/sbus/char/display7seg.c | 2 +-
drivers/sbus/char/envctrl.c | 4 +-
drivers/scsi/3w-xxxx.c | 4 +-
drivers/scsi/cxlflash/main.c | 2 +-
drivers/scsi/esas2r/esas2r_main.c | 2 +-
drivers/scsi/megaraid/megaraid_mm.c | 28 +-
drivers/scsi/pmcraid.c | 4 +-
drivers/scsi/sd.c | 14 +-
drivers/scsi/sg.c | 59 +-
drivers/scsi/st.c | 28 +-
drivers/staging/android/ion/ion.c | 4 +-
drivers/staging/pi433/pi433_if.c | 12 +-
drivers/staging/vme/devices/vme_user.c | 2 +-
drivers/tee/tee_core.c | 2 +-
drivers/tty/tty_io.c | 5 +
drivers/usb/class/cdc-wdm.c | 2 +-
drivers/usb/class/usbtmc.c | 4 +-
drivers/usb/core/devio.c | 16 +-
drivers/usb/gadget/function/f_fs.c | 12 +-
drivers/vfio/vfio.c | 39 +-
drivers/vhost/net.c | 12 +-
drivers/vhost/scsi.c | 12 +-
drivers/vhost/test.c | 12 +-
drivers/vhost/vsock.c | 12 +-
drivers/video/fbdev/aty/atyfb_base.c | 12 +-
drivers/virt/fsl_hypervisor.c | 2 +-
drivers/watchdog/acquirewdt.c | 1 +
drivers/watchdog/advantechwdt.c | 1 +
drivers/watchdog/alim1535_wdt.c | 1 +
drivers/watchdog/alim7101_wdt.c | 1 +
drivers/watchdog/ar7_wdt.c | 1 +
drivers/watchdog/at91rm9200_wdt.c | 1 +
drivers/watchdog/ath79_wdt.c | 1 +
drivers/watchdog/bcm63xx_wdt.c | 1 +
drivers/watchdog/cpu5wdt.c | 1 +
drivers/watchdog/eurotechwdt.c | 1 +
drivers/watchdog/f71808e_wdt.c | 1 +
drivers/watchdog/gef_wdt.c | 1 +
drivers/watchdog/geodewdt.c | 1 +
drivers/watchdog/ib700wdt.c | 1 +
drivers/watchdog/ibmasr.c | 1 +
drivers/watchdog/indydog.c | 1 +
drivers/watchdog/intel_scu_watchdog.c | 1 +
drivers/watchdog/iop_wdt.c | 1 +
drivers/watchdog/it8712f_wdt.c | 1 +
drivers/watchdog/ixp4xx_wdt.c | 1 +
drivers/watchdog/m54xx_wdt.c | 1 +
drivers/watchdog/machzwd.c | 1 +
drivers/watchdog/mixcomwd.c | 1 +
drivers/watchdog/mtx-1_wdt.c | 1 +
drivers/watchdog/mv64x60_wdt.c | 1 +
drivers/watchdog/nv_tco.c | 1 +
drivers/watchdog/pc87413_wdt.c | 1 +
drivers/watchdog/pcwd.c | 1 +
drivers/watchdog/pcwd_pci.c | 1 +
drivers/watchdog/pcwd_usb.c | 1 +
drivers/watchdog/pika_wdt.c | 1 +
drivers/watchdog/pnx833x_wdt.c | 1 +
drivers/watchdog/rc32434_wdt.c | 1 +
drivers/watchdog/rdc321x_wdt.c | 1 +
drivers/watchdog/riowd.c | 1 +
drivers/watchdog/sa1100_wdt.c | 1 +
drivers/watchdog/sb_wdog.c | 1 +
drivers/watchdog/sbc60xxwdt.c | 1 +
drivers/watchdog/sbc7240_wdt.c | 1 +
drivers/watchdog/sbc_epx_c3.c | 1 +
drivers/watchdog/sbc_fitpc2_wdt.c | 1 +
drivers/watchdog/sc1200wdt.c | 1 +
drivers/watchdog/sc520_wdt.c | 1 +
drivers/watchdog/sch311x_wdt.c | 1 +
drivers/watchdog/scx200_wdt.c | 1 +
drivers/watchdog/smsc37b787_wdt.c | 1 +
drivers/watchdog/w83877f_wdt.c | 1 +
drivers/watchdog/w83977f_wdt.c | 1 +
drivers/watchdog/wafer5823wdt.c | 1 +
drivers/watchdog/watchdog_dev.c | 1 +
drivers/watchdog/wdrtas.c | 1 +
drivers/watchdog/wdt.c | 1 +
drivers/watchdog/wdt285.c | 1 +
drivers/watchdog/wdt977.c | 1 +
drivers/watchdog/wdt_pci.c | 1 +
fs/btrfs/super.c | 2 +-
fs/ceph/dir.c | 1 +
fs/ceph/file.c | 2 +-
fs/ceph/super.h | 1 +
fs/compat_ioctl.c | 917 +-------------------
fs/ecryptfs/file.c | 1 +
fs/ext4/ioctl.c | 1 +
fs/f2fs/file.c | 1 +
fs/fat/file.c | 13 +-
fs/fuse/dev.c | 2 +-
fs/gfs2/file.c | 30 +
fs/hpfs/dir.c | 1 +
fs/hpfs/file.c | 1 +
fs/ioctl.c | 80 +-
fs/nilfs2/ioctl.c | 1 +
fs/notify/fanotify/fanotify_user.c | 2 +-
fs/ocfs2/ioctl.c | 1 +
fs/userfaultfd.c | 2 +-
include/linux/blkdev.h | 2 +
include/linux/falloc.h | 20 +
include/linux/fs.h | 7 +
include/linux/mtio.h | 60 ++
include/uapi/linux/ppp-ioctl.h | 2 +
include/uapi/linux/ppp_defs.h | 14 +
lib/iov_iter.c | 1 +
net/bluetooth/hci_sock.c | 21 +-
net/bluetooth/rfcomm/sock.c | 14 +-
net/rfkill/core.c | 2 +-
net/socket.c | 3 +
net/unix/af_unix.c | 19 +
sound/core/oss/pcm_oss.c | 4 +
sound/oss/dmasound/dmasound_core.c | 2 +
155 files changed, 935 insertions(+), 1394 deletions(-)
create mode 100644 include/linux/mtio.h

--
2.20.0


2019-10-09 19:14:03

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 30/43] fs: compat_ioctl: move FITRIM emulation into file systems

Remove the special case for FITRIM, and make file systems
handle that like all other ioctl commands with their own
handlers.

Cc: [email protected]
Cc: [email protected]
Cc: Mikulas Patocka <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/compat_ioctl.c | 2 --
fs/ecryptfs/file.c | 1 +
fs/ext4/ioctl.c | 1 +
fs/f2fs/file.c | 1 +
fs/hpfs/dir.c | 1 +
fs/hpfs/file.c | 1 +
fs/nilfs2/ioctl.c | 1 +
fs/ocfs2/ioctl.c | 1 +
8 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 1e740f4406d3..b20228c19ccd 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -345,8 +345,6 @@ static int ppp_scompress(struct file *file, unsigned int cmd,
static unsigned int ioctl_pointer[] = {
/* Little t */
COMPATIBLE_IOCTL(TIOCOUTQ)
-/* 'X' - originally XFS but some now in the VFS */
-COMPATIBLE_IOCTL(FITRIM)
#ifdef CONFIG_BLOCK
/* Big S */
COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index feecb57defa7..5fb45d865ce5 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -378,6 +378,7 @@ ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return rc;

switch (cmd) {
+ case FITRIM:
case FS_IOC32_GETFLAGS:
case FS_IOC32_SETFLAGS:
case FS_IOC32_GETVERSION:
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 0b7f316fd30f..e8870fff8224 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -1360,6 +1360,7 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
case EXT4_IOC_MOVE_EXT:
case EXT4_IOC_RESIZE_FS:
+ case FITRIM:
case EXT4_IOC_PRECACHE_EXTENTS:
case EXT4_IOC_SET_ENCRYPTION_POLICY:
case EXT4_IOC_GET_ENCRYPTION_PWSALT:
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 29bc0a542759..57d82f2d2ebd 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -3403,6 +3403,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case F2FS_IOC_RELEASE_VOLATILE_WRITE:
case F2FS_IOC_ABORT_VOLATILE_WRITE:
case F2FS_IOC_SHUTDOWN:
+ case FITRIM:
case F2FS_IOC_SET_ENCRYPTION_POLICY:
case F2FS_IOC_GET_ENCRYPTION_PWSALT:
case F2FS_IOC_GET_ENCRYPTION_POLICY:
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c
index d85230c84ef2..f32f15669996 100644
--- a/fs/hpfs/dir.c
+++ b/fs/hpfs/dir.c
@@ -325,4 +325,5 @@ const struct file_operations hpfs_dir_ops =
.release = hpfs_dir_release,
.fsync = hpfs_file_fsync,
.unlocked_ioctl = hpfs_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
};
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index 1ecec124e76f..b36abf9cb345 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -215,6 +215,7 @@ const struct file_operations hpfs_file_ops =
.fsync = hpfs_file_fsync,
.splice_read = generic_file_splice_read,
.unlocked_ioctl = hpfs_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
};

const struct inode_operations hpfs_file_iops =
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
index 91b9dac6b2cc..4ba73dbf3e8d 100644
--- a/fs/nilfs2/ioctl.c
+++ b/fs/nilfs2/ioctl.c
@@ -1354,6 +1354,7 @@ long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
case NILFS_IOCTL_SYNC:
case NILFS_IOCTL_RESIZE:
case NILFS_IOCTL_SET_ALLOC_RANGE:
+ case FITRIM:
break;
default:
return -ENOIOCTLCMD;
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
index d6f7b299eb23..2d517b5ec6ac 100644
--- a/fs/ocfs2/ioctl.c
+++ b/fs/ocfs2/ioctl.c
@@ -985,6 +985,7 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
return -EFAULT;

return ocfs2_info_handle(inode, &info, 1);
+ case FITRIM:
case OCFS2_IOC_MOVE_EXT:
break;
default:
--
2.20.0

2019-10-09 19:14:19

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 43/43] scsi: sd: enable compat ioctls for sed-opal

The sed_ioctl() function is written to be compatible between
32-bit and 64-bit processes, however compat mode is only
wired up for nvme, not for sd.

Add the missing call to sed_ioctl() in sd_compat_ioctl().

Fixes: d80210f25ff0 ("sd: add support for TCG OPAL self encrypting disks")
Cc: [email protected]
Cc: "James E.J. Bottomley" <[email protected]>
Cc: "Martin K. Petersen" <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
drivers/scsi/sd.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 50928bc266eb..5abdf03083ae 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1692,20 +1692,30 @@ static void sd_rescan(struct device *dev)
static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
- struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device;
+ struct gendisk *disk = bdev->bd_disk;
+ struct scsi_disk *sdkp = scsi_disk(disk);
+ struct scsi_device *sdev = sdkp->device;
+ void __user *p = compat_ptr(arg);
int error;

+ error = scsi_verify_blk_ioctl(bdev, cmd);
+ if (error < 0)
+ return error;
+
error = scsi_ioctl_block_when_processing_errors(sdev, cmd,
(mode & FMODE_NDELAY) != 0);
if (error)
return error;
+
+ if (is_sed_ioctl(cmd))
+ return sed_ioctl(sdkp->opal_dev, cmd, p);

/*
* Let the static ioctl translation table take care of it.
*/
if (!sdev->host->hostt->compat_ioctl)
return -ENOIOCTLCMD;
- return sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);
+ return sdev->host->hostt->compat_ioctl(sdev, cmd, p);
}
#endif

--
2.20.0

2019-10-09 19:14:23

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 33/43] af_unix: add compat_ioctl support

The af_unix protocol family has a custom ioctl command (inexplicibly
based on SIOCPROTOPRIVATE), but never had a compat_ioctl handler for
32-bit applications.

Since all commands are compatible here, add a trivial wrapper that
performs the compat_ptr() conversion for SIOCOUTQ/SIOCINQ. SIOCUNIXFILE
does not use the argument, but it doesn't hurt to also use compat_ptr()
here.

Fixes: ba94f3088b79 ("unix: add ioctl to open a unix socket file with O_PATH")
Cc: [email protected]
Cc: "David S. Miller" <[email protected]>
Cc: Eric Dumazet <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
net/unix/af_unix.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)

diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 67e87db5877f..e18ca6d9f3d4 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -646,6 +646,9 @@ static __poll_t unix_poll(struct file *, struct socket *, poll_table *);
static __poll_t unix_dgram_poll(struct file *, struct socket *,
poll_table *);
static int unix_ioctl(struct socket *, unsigned int, unsigned long);
+#ifdef CONFIG_COMPAT
+static int unix_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
+#endif
static int unix_shutdown(struct socket *, int);
static int unix_stream_sendmsg(struct socket *, struct msghdr *, size_t);
static int unix_stream_recvmsg(struct socket *, struct msghdr *, size_t, int);
@@ -687,6 +690,9 @@ static const struct proto_ops unix_stream_ops = {
.getname = unix_getname,
.poll = unix_poll,
.ioctl = unix_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = unix_compat_ioctl,
+#endif
.listen = unix_listen,
.shutdown = unix_shutdown,
.setsockopt = sock_no_setsockopt,
@@ -710,6 +716,9 @@ static const struct proto_ops unix_dgram_ops = {
.getname = unix_getname,
.poll = unix_dgram_poll,
.ioctl = unix_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = unix_compat_ioctl,
+#endif
.listen = sock_no_listen,
.shutdown = unix_shutdown,
.setsockopt = sock_no_setsockopt,
@@ -732,6 +741,9 @@ static const struct proto_ops unix_seqpacket_ops = {
.getname = unix_getname,
.poll = unix_dgram_poll,
.ioctl = unix_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = unix_compat_ioctl,
+#endif
.listen = unix_listen,
.shutdown = unix_shutdown,
.setsockopt = sock_no_setsockopt,
@@ -2582,6 +2594,13 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
return err;
}

+#ifdef CONFIG_COMPAT
+static int unix_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ return unix_ioctl(sock, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
static __poll_t unix_poll(struct file *file, struct socket *sock, poll_table *wait)
{
struct sock *sk = sock->sk;
--
2.20.0

2019-10-09 19:14:33

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 27/43] compat_ioctl: remove last RAID handling code

Commit aa98aa31987a ("md: move compat_ioctl handling into md.c")
already removed the COMPATIBLE_IOCTL() table entries and added
a complete implementation, but a few lines got left behind and
should also be removed here.

Cc: [email protected]
Cc: Song Liu <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/compat_ioctl.c | 13 -------------
1 file changed, 13 deletions(-)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 6070481f2b6a..1ed32cca2176 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -462,19 +462,6 @@ static long do_ioctl_trans(unsigned int cmd,
#endif
}

- /*
- * These take an integer instead of a pointer as 'arg',
- * so we must not do a compat_ptr() translation.
- */
- switch (cmd) {
- /* RAID */
- case HOT_REMOVE_DISK:
- case HOT_ADD_DISK:
- case SET_DISK_FAULTY:
- case SET_BITMAP_FILE:
- return vfs_ioctl(file, cmd, arg);
- }
-
return -ENOIOCTLCMD;
}

--
2.20.0

2019-10-09 19:14:36

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 37/43] compat_ioctl: unify copy-in of ppp filters

From: Al Viro <[email protected]>

Now that isdn4linux is gone, the is only one implementation of PPPIOCSPASS
and PPPIOCSACTIVE in ppp_generic.c, so this is where the compat_ioctl
support should be implemented.

The two commands are implemented in very similar ways, so introduce
new helpers to allow sharing between the two and between native and
compat mode.

Signed-off-by: Al Viro <[email protected]>
[arnd: rebased, and added changelog text]
Cc: [email protected]
Cc: [email protected]
Cc: Paul Mackerras <[email protected]>
Cc: "David S. Miller" <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
drivers/net/ppp/ppp_generic.c | 169 ++++++++++++++++++++++------------
fs/compat_ioctl.c | 37 --------
2 files changed, 108 insertions(+), 98 deletions(-)

diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 9a1b006904a7..7f8430e6b137 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -554,29 +554,58 @@ static __poll_t ppp_poll(struct file *file, poll_table *wait)
}

#ifdef CONFIG_PPP_FILTER
-static int get_filter(void __user *arg, struct sock_filter **p)
+static struct bpf_prog *get_filter(struct sock_fprog *uprog)
+{
+ struct sock_fprog_kern fprog;
+ struct bpf_prog *res = NULL;
+ int err;
+
+ if (!uprog->len)
+ return NULL;
+
+ /* uprog->len is unsigned short, so no overflow here */
+ fprog.len = uprog->len * sizeof(struct sock_filter);
+ fprog.filter = memdup_user(uprog->filter, fprog.len);
+ if (IS_ERR(fprog.filter))
+ return ERR_CAST(fprog.filter);
+
+ err = bpf_prog_create(&res, &fprog);
+ kfree(fprog.filter);
+
+ return err ? ERR_PTR(err) : res;
+}
+
+static struct bpf_prog *ppp_get_filter(struct sock_fprog __user *p)
{
struct sock_fprog uprog;
- struct sock_filter *code = NULL;
- int len;

- if (copy_from_user(&uprog, arg, sizeof(uprog)))
- return -EFAULT;
+ if (copy_from_user(&uprog, p, sizeof(struct sock_fprog)))
+ return ERR_PTR(-EFAULT);
+ return get_filter(&uprog);
+}

- if (!uprog.len) {
- *p = NULL;
- return 0;
- }
+#ifdef CONFIG_COMPAT
+struct sock_fprog32 {
+ unsigned short len;
+ compat_caddr_t filter;
+};

- len = uprog.len * sizeof(struct sock_filter);
- code = memdup_user(uprog.filter, len);
- if (IS_ERR(code))
- return PTR_ERR(code);
+#define PPPIOCSPASS32 _IOW('t', 71, struct sock_fprog32)
+#define PPPIOCSACTIVE32 _IOW('t', 70, struct sock_fprog32)

- *p = code;
- return uprog.len;
+static struct bpf_prog *compat_ppp_get_filter(struct sock_fprog32 __user *p)
+{
+ struct sock_fprog32 uprog32;
+ struct sock_fprog uprog;
+
+ if (copy_from_user(&uprog32, p, sizeof(struct sock_fprog32)))
+ return ERR_PTR(-EFAULT);
+ uprog.len = uprog32.len;
+ uprog.filter = compat_ptr(uprog32.filter);
+ return get_filter(&uprog);
}
-#endif /* CONFIG_PPP_FILTER */
+#endif
+#endif

static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
@@ -753,55 +782,25 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

#ifdef CONFIG_PPP_FILTER
case PPPIOCSPASS:
- {
- struct sock_filter *code;
-
- err = get_filter(argp, &code);
- if (err >= 0) {
- struct bpf_prog *pass_filter = NULL;
- struct sock_fprog_kern fprog = {
- .len = err,
- .filter = code,
- };
-
- err = 0;
- if (fprog.filter)
- err = bpf_prog_create(&pass_filter, &fprog);
- if (!err) {
- ppp_lock(ppp);
- if (ppp->pass_filter)
- bpf_prog_destroy(ppp->pass_filter);
- ppp->pass_filter = pass_filter;
- ppp_unlock(ppp);
- }
- kfree(code);
- }
- break;
- }
case PPPIOCSACTIVE:
{
- struct sock_filter *code;
+ struct bpf_prog *filter = ppp_get_filter(argp);
+ struct bpf_prog **which;

- err = get_filter(argp, &code);
- if (err >= 0) {
- struct bpf_prog *active_filter = NULL;
- struct sock_fprog_kern fprog = {
- .len = err,
- .filter = code,
- };
-
- err = 0;
- if (fprog.filter)
- err = bpf_prog_create(&active_filter, &fprog);
- if (!err) {
- ppp_lock(ppp);
- if (ppp->active_filter)
- bpf_prog_destroy(ppp->active_filter);
- ppp->active_filter = active_filter;
- ppp_unlock(ppp);
- }
- kfree(code);
+ if (IS_ERR(filter)) {
+ err = PTR_ERR(filter);
+ break;
}
+ if (cmd == PPPIOCSPASS)
+ which = &ppp->pass_filter;
+ else
+ which = &ppp->active_filter;
+ ppp_lock(ppp);
+ if (*which)
+ bpf_prog_destroy(*which);
+ *which = filter;
+ ppp_unlock(ppp);
+ err = 0;
break;
}
#endif /* CONFIG_PPP_FILTER */
@@ -827,6 +826,51 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return err;
}

+#ifdef CONFIG_COMPAT
+static long ppp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct ppp_file *pf;
+ int err = -ENOIOCTLCMD;
+ void __user *argp = (void __user *)arg;
+
+ mutex_lock(&ppp_mutex);
+
+ pf = file->private_data;
+ if (pf && pf->kind == INTERFACE) {
+ struct ppp *ppp = PF_TO_PPP(pf);
+ switch (cmd) {
+#ifdef CONFIG_PPP_FILTER
+ case PPPIOCSPASS32:
+ case PPPIOCSACTIVE32:
+ {
+ struct bpf_prog *filter = compat_ppp_get_filter(argp);
+ struct bpf_prog **which;
+
+ if (IS_ERR(filter)) {
+ err = PTR_ERR(filter);
+ break;
+ }
+ if (cmd == PPPIOCSPASS32)
+ which = &ppp->pass_filter;
+ else
+ which = &ppp->active_filter;
+ ppp_lock(ppp);
+ if (*which)
+ bpf_prog_destroy(*which);
+ *which = filter;
+ ppp_unlock(ppp);
+ err = 0;
+ break;
+ }
+#endif /* CONFIG_PPP_FILTER */
+ }
+ }
+ mutex_unlock(&ppp_mutex);
+
+ return err;
+}
+#endif
+
static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
struct file *file, unsigned int cmd, unsigned long arg)
{
@@ -895,6 +939,9 @@ static const struct file_operations ppp_device_fops = {
.write = ppp_write,
.poll = ppp_poll,
.unlocked_ioctl = ppp_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ppp_compat_ioctl,
+#endif
.open = ppp_open,
.release = ppp_release,
.llseek = noop_llseek,
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index d537888f3660..eda41b2537f0 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -99,40 +99,6 @@ static int sg_grt_trans(struct file *file,
}
#endif /* CONFIG_BLOCK */

-struct sock_fprog32 {
- unsigned short len;
- compat_caddr_t filter;
-};
-
-#define PPPIOCSPASS32 _IOW('t', 71, struct sock_fprog32)
-#define PPPIOCSACTIVE32 _IOW('t', 70, struct sock_fprog32)
-
-static int ppp_sock_fprog_ioctl_trans(struct file *file,
- unsigned int cmd, struct sock_fprog32 __user *u_fprog32)
-{
- struct sock_fprog __user *u_fprog64 = compat_alloc_user_space(sizeof(struct sock_fprog));
- void __user *fptr64;
- u32 fptr32;
- u16 flen;
-
- if (get_user(flen, &u_fprog32->len) ||
- get_user(fptr32, &u_fprog32->filter))
- return -EFAULT;
-
- fptr64 = compat_ptr(fptr32);
-
- if (put_user(flen, &u_fprog64->len) ||
- put_user(fptr64, &u_fprog64->filter))
- return -EFAULT;
-
- if (cmd == PPPIOCSPASS32)
- cmd = PPPIOCSPASS;
- else
- cmd = PPPIOCSACTIVE;
-
- return do_ioctl(file, cmd, (unsigned long) u_fprog64);
-}
-
struct ppp_option_data32 {
compat_caddr_t ptr;
u32 length;
@@ -285,9 +251,6 @@ static long do_ioctl_trans(unsigned int cmd,
return ppp_gidle(file, cmd, argp);
case PPPIOCSCOMPRESS32:
return ppp_scompress(file, cmd, argp);
- case PPPIOCSPASS32:
- case PPPIOCSACTIVE32:
- return ppp_sock_fprog_ioctl_trans(file, cmd, argp);
#ifdef CONFIG_BLOCK
case SG_GET_REQUEST_TABLE:
return sg_grt_trans(file, cmd, argp);
--
2.20.0

2019-10-09 19:14:48

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 40/43] compat_ioctl: ppp: move simple commands into ppp_generic.c

All ppp commands that are not already handled in ppp_compat_ioctl()
are compatible, so they can now handled by calling the native
ppp_ioctl() directly.

Without CONFIG_BLOCK, the generic compat_ioctl table is now empty,
so add a check to avoid a build failure in the looking function for
that configuration.

Cc: [email protected]
Cc: [email protected]
Cc: Paul Mackerras <[email protected]>
Cc: "David S. Miller" <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
drivers/net/ppp/ppp_generic.c | 4 ++++
fs/compat_ioctl.c | 36 ++++-------------------------------
2 files changed, 8 insertions(+), 32 deletions(-)

diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index ce4dd45c541d..267fe2c58087 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -903,6 +903,10 @@ static long ppp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long
}
mutex_unlock(&ppp_mutex);

+ /* all other commands have compatible arguments */
+ if (err == -ENOIOCTLCMD)
+ err = ppp_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+
return err;
}
#endif
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 5e59101ef981..3cf8b6d113c3 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -144,38 +144,6 @@ COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
#endif
-/* PPP stuff */
-COMPATIBLE_IOCTL(PPPIOCGFLAGS)
-COMPATIBLE_IOCTL(PPPIOCSFLAGS)
-COMPATIBLE_IOCTL(PPPIOCGASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCSASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCGUNIT)
-COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCGMRU)
-COMPATIBLE_IOCTL(PPPIOCSMRU)
-COMPATIBLE_IOCTL(PPPIOCSMAXCID)
-COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
-/* PPPIOCSCOMPRESS is translated */
-COMPATIBLE_IOCTL(PPPIOCGNPMODE)
-COMPATIBLE_IOCTL(PPPIOCSNPMODE)
-COMPATIBLE_IOCTL(PPPIOCGDEBUG)
-COMPATIBLE_IOCTL(PPPIOCSDEBUG)
-/* PPPIOCSPASS is translated */
-/* PPPIOCSACTIVE is translated */
-COMPATIBLE_IOCTL(PPPIOCGIDLE32)
-COMPATIBLE_IOCTL(PPPIOCGIDLE64)
-COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
-COMPATIBLE_IOCTL(PPPIOCATTACH)
-COMPATIBLE_IOCTL(PPPIOCDETACH)
-COMPATIBLE_IOCTL(PPPIOCSMRRU)
-COMPATIBLE_IOCTL(PPPIOCCONNECT)
-COMPATIBLE_IOCTL(PPPIOCDISCONN)
-COMPATIBLE_IOCTL(PPPIOCATTCHAN)
-COMPATIBLE_IOCTL(PPPIOCGCHAN)
-COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS)
};

/*
@@ -202,6 +170,7 @@ static long do_ioctl_trans(unsigned int cmd,

static int compat_ioctl_check_table(unsigned int xcmd)
{
+#ifdef CONFIG_BLOCK
int i;
const int max = ARRAY_SIZE(ioctl_pointer) - 1;

@@ -220,6 +189,9 @@ static int compat_ioctl_check_table(unsigned int xcmd)
i--;

return ioctl_pointer[i] == xcmd;
+#else
+ return 0;
+#endif
}

COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
--
2.20.0

2019-10-09 19:15:00

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 14/43] compat_ioctl: move tape handling into drivers

MTIOCPOS and MTIOCGET are incompatible between 32-bit and 64-bit user
space, and traditionally have been translated in fs/compat_ioctl.c.

To get rid of that translation handler, move a corresponding
implementation into each of the four drivers implementing those commands.

The interesting part of that is now in a new linux/mtio.h header that
wraps the existing uapi/linux/mtio.h header and provides an abstraction
to let drivers handle both cases easily. Using an in_compat_syscall()
check, the caller does not have to keep track of whether this was
called through .unlocked_ioctl() or .compat_ioctl().

Acked-by: Heiko Carstens <[email protected]>
Cc: "Kai Mäkisara" <[email protected]>
Cc: [email protected]
Cc: "James E.J. Bottomley" <[email protected]>
Cc: "Martin K. Petersen" <[email protected]>
Cc: "David S. Miller" <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
drivers/ide/ide-tape.c | 27 ++++++++++---
drivers/s390/char/tape_char.c | 41 +++++++-------------
drivers/scsi/st.c | 28 +++++++++-----
fs/compat_ioctl.c | 73 -----------------------------------
include/linux/mtio.h | 60 ++++++++++++++++++++++++++++
5 files changed, 114 insertions(+), 115 deletions(-)
create mode 100644 include/linux/mtio.h

diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index db1a65f4b490..3e7482695f77 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -19,6 +19,7 @@

#define IDETAPE_VERSION "1.20"

+#include <linux/compat.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -1407,14 +1408,10 @@ static long do_idetape_chrdev_ioctl(struct file *file,
if (tape->drv_write_prot)
mtget.mt_gstat |= GMT_WR_PROT(0xffffffff);

- if (copy_to_user(argp, &mtget, sizeof(struct mtget)))
- return -EFAULT;
- return 0;
+ return put_user_mtget(argp, &mtget);
case MTIOCPOS:
mtpos.mt_blkno = position / tape->user_bs_factor - block_offset;
- if (copy_to_user(argp, &mtpos, sizeof(struct mtpos)))
- return -EFAULT;
- return 0;
+ return put_user_mtpos(argp, &mtpos);
default:
if (tape->chrdev_dir == IDETAPE_DIR_READ)
ide_tape_discard_merge_buffer(drive, 1);
@@ -1432,6 +1429,22 @@ static long idetape_chrdev_ioctl(struct file *file,
return ret;
}

+static long idetape_chrdev_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ long ret;
+
+ if (cmd == MTIOCPOS32)
+ cmd = MTIOCPOS;
+ else if (cmd == MTIOCGET32)
+ cmd = MTIOCGET;
+
+ mutex_lock(&ide_tape_mutex);
+ ret = do_idetape_chrdev_ioctl(file, cmd, arg);
+ mutex_unlock(&ide_tape_mutex);
+ return ret;
+}
+
/*
* Do a mode sense page 0 with block descriptor and if it succeeds set the tape
* block size with the reported value.
@@ -1886,6 +1899,8 @@ static const struct file_operations idetape_fops = {
.read = idetape_chrdev_read,
.write = idetape_chrdev_write,
.unlocked_ioctl = idetape_chrdev_ioctl,
+ .compat_ioctl = IS_ENABLED(CONFIG_COMPAT) ?
+ idetape_chrdev_compat_ioctl : NULL,
.open = idetape_chrdev_open,
.release = idetape_chrdev_release,
.llseek = noop_llseek,
diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
index ea4253939555..8abb42923307 100644
--- a/drivers/s390/char/tape_char.c
+++ b/drivers/s390/char/tape_char.c
@@ -341,14 +341,14 @@ tapechar_release(struct inode *inode, struct file *filp)
*/
static int
__tapechar_ioctl(struct tape_device *device,
- unsigned int no, unsigned long data)
+ unsigned int no, void __user *data)
{
int rc;

if (no == MTIOCTOP) {
struct mtop op;

- if (copy_from_user(&op, (char __user *) data, sizeof(op)) != 0)
+ if (copy_from_user(&op, data, sizeof(op)) != 0)
return -EFAULT;
if (op.mt_count < 0)
return -EINVAL;
@@ -392,9 +392,7 @@ __tapechar_ioctl(struct tape_device *device,
if (rc < 0)
return rc;
pos.mt_blkno = rc;
- if (copy_to_user((char __user *) data, &pos, sizeof(pos)) != 0)
- return -EFAULT;
- return 0;
+ return put_user_mtpos(data, &pos);
}
if (no == MTIOCGET) {
/* MTIOCGET: query the tape drive status. */
@@ -424,15 +422,12 @@ __tapechar_ioctl(struct tape_device *device,
get.mt_blkno = rc;
}

- if (copy_to_user((char __user *) data, &get, sizeof(get)) != 0)
- return -EFAULT;
-
- return 0;
+ return put_user_mtget(data, &get);
}
/* Try the discipline ioctl function. */
if (device->discipline->ioctl_fn == NULL)
return -EINVAL;
- return device->discipline->ioctl_fn(device, no, data);
+ return device->discipline->ioctl_fn(device, no, (unsigned long)data);
}

static long
@@ -445,7 +440,7 @@ tapechar_ioctl(struct file *filp, unsigned int no, unsigned long data)

device = (struct tape_device *) filp->private_data;
mutex_lock(&device->mutex);
- rc = __tapechar_ioctl(device, no, data);
+ rc = __tapechar_ioctl(device, no, (void __user *)data);
mutex_unlock(&device->mutex);
return rc;
}
@@ -455,23 +450,17 @@ static long
tapechar_compat_ioctl(struct file *filp, unsigned int no, unsigned long data)
{
struct tape_device *device = filp->private_data;
- int rval = -ENOIOCTLCMD;
- unsigned long argp;
+ long rc;

- /* The 'arg' argument of any ioctl function may only be used for
- * pointers because of the compat pointer conversion.
- * Consider this when adding new ioctls.
- */
- argp = (unsigned long) compat_ptr(data);
- if (device->discipline->ioctl_fn) {
- mutex_lock(&device->mutex);
- rval = device->discipline->ioctl_fn(device, no, argp);
- mutex_unlock(&device->mutex);
- if (rval == -EINVAL)
- rval = -ENOIOCTLCMD;
- }
+ if (no == MTIOCPOS32)
+ no = MTIOCPOS;
+ else if (no == MTIOCGET32)
+ no = MTIOCGET;

- return rval;
+ mutex_lock(&device->mutex);
+ rc = __tapechar_ioctl(device, no, compat_ptr(data));
+ mutex_unlock(&device->mutex);
+ return rc;
}
#endif /* CONFIG_COMPAT */

diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index e3266a64a477..9e3fff2de83e 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -22,6 +22,7 @@ static const char *verstr = "20160209";

#include <linux/module.h>

+#include <linux/compat.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/sched/signal.h>
@@ -3800,14 +3801,11 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
if (STp->cleaning_req)
mt_status.mt_gstat |= GMT_CLN(0xffffffff);

- i = copy_to_user(p, &mt_status, sizeof(struct mtget));
- if (i) {
- retval = (-EFAULT);
+ retval = put_user_mtget(p, &mt_status);
+ if (retval)
goto out;
- }

STp->recover_reg = 0; /* Clear after read */
- retval = 0;
goto out;
} /* End of MTIOCGET */
if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
@@ -3821,9 +3819,7 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
goto out;
}
mt_pos.mt_blkno = blk;
- i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));
- if (i)
- retval = (-EFAULT);
+ retval = put_user_mtpos(p, &mt_pos);
goto out;
}
mutex_unlock(&STp->lock);
@@ -3857,14 +3853,26 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
}

#ifdef CONFIG_COMPAT
-static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
{
+ void __user *p = compat_ptr(arg);
struct scsi_tape *STp = file->private_data;
struct scsi_device *sdev = STp->device;
int ret = -ENOIOCTLCMD;
+
+ /* argument conversion is handled using put_user_mtpos/put_user_mtget */
+ switch (cmd_in) {
+ case MTIOCTOP:
+ return st_ioctl(file, MTIOCTOP, (unsigned long)p);
+ case MTIOCPOS32:
+ return st_ioctl(file, MTIOCPOS, (unsigned long)p);
+ case MTIOCGET32:
+ return st_ioctl(file, MTIOCGET, (unsigned long)p);
+ }
+
if (sdev->host->hostt->compat_ioctl) {

- ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);
+ ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);

}
return ret;
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 47da220f95b1..b65eef3d4787 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -27,7 +27,6 @@
#include <linux/file.h>
#include <linux/ppp-ioctl.h>
#include <linux/if_pppox.h>
-#include <linux/mtio.h>
#include <linux/tty.h>
#include <linux/vt_kern.h>
#include <linux/raw.h>
@@ -361,73 +360,6 @@ static int ppp_scompress(struct file *file, unsigned int cmd,
return do_ioctl(file, PPPIOCSCOMPRESS, (unsigned long) odata);
}

-#ifdef CONFIG_BLOCK
-struct mtget32 {
- compat_long_t mt_type;
- compat_long_t mt_resid;
- compat_long_t mt_dsreg;
- compat_long_t mt_gstat;
- compat_long_t mt_erreg;
- compat_daddr_t mt_fileno;
- compat_daddr_t mt_blkno;
-};
-#define MTIOCGET32 _IOR('m', 2, struct mtget32)
-
-struct mtpos32 {
- compat_long_t mt_blkno;
-};
-#define MTIOCPOS32 _IOR('m', 3, struct mtpos32)
-
-static int mt_ioctl_trans(struct file *file,
- unsigned int cmd, void __user *argp)
-{
- /* NULL initialization to make gcc shut up */
- struct mtget __user *get = NULL;
- struct mtget32 __user *umget32;
- struct mtpos __user *pos = NULL;
- struct mtpos32 __user *upos32;
- unsigned long kcmd;
- void *karg;
- int err = 0;
-
- switch(cmd) {
- case MTIOCPOS32:
- kcmd = MTIOCPOS;
- pos = compat_alloc_user_space(sizeof(*pos));
- karg = pos;
- break;
- default: /* MTIOCGET32 */
- kcmd = MTIOCGET;
- get = compat_alloc_user_space(sizeof(*get));
- karg = get;
- break;
- }
- if (karg == NULL)
- return -EFAULT;
- err = do_ioctl(file, kcmd, (unsigned long)karg);
- if (err)
- return err;
- switch (cmd) {
- case MTIOCPOS32:
- upos32 = argp;
- err = convert_in_user(&pos->mt_blkno, &upos32->mt_blkno);
- break;
- case MTIOCGET32:
- umget32 = argp;
- err = convert_in_user(&get->mt_type, &umget32->mt_type);
- err |= convert_in_user(&get->mt_resid, &umget32->mt_resid);
- err |= convert_in_user(&get->mt_dsreg, &umget32->mt_dsreg);
- err |= convert_in_user(&get->mt_gstat, &umget32->mt_gstat);
- err |= convert_in_user(&get->mt_erreg, &umget32->mt_erreg);
- err |= convert_in_user(&get->mt_fileno, &umget32->mt_fileno);
- err |= convert_in_user(&get->mt_blkno, &umget32->mt_blkno);
- break;
- }
- return err ? -EFAULT: 0;
-}
-
-#endif /* CONFIG_BLOCK */
-
/* Bluetooth ioctls */
#define HCIUARTSETPROTO _IOW('U', 200, int)
#define HCIUARTGETPROTO _IOR('U', 201, int)
@@ -479,8 +411,6 @@ IGNORE_IOCTL(VT_GETMODE)
*/
COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */
COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */
-/* Little m */
-COMPATIBLE_IOCTL(MTIOCTOP)
#ifdef CONFIG_BLOCK
/* md calls this on random blockdevs */
IGNORE_IOCTL(RAID_VERSION)
@@ -846,9 +776,6 @@ static long do_ioctl_trans(unsigned int cmd,
return sg_ioctl_trans(file, cmd, argp);
case SG_GET_REQUEST_TABLE:
return sg_grt_trans(file, cmd, argp);
- case MTIOCGET32:
- case MTIOCPOS32:
- return mt_ioctl_trans(file, cmd, argp);
#endif
}

diff --git a/include/linux/mtio.h b/include/linux/mtio.h
new file mode 100644
index 000000000000..67d03156f2c2
--- /dev/null
+++ b/include/linux/mtio.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MTIO_COMPAT_H
+#define _LINUX_MTIO_COMPAT_H
+
+#include <linux/compat.h>
+#include <uapi/linux/mtio.h>
+#include <linux/uaccess.h>
+
+/*
+ * helper functions for implementing compat ioctls on the four tape
+ * drivers: we define the 32-bit layout of each incompatible structure,
+ * plus a wrapper function to copy it to user space in either format.
+ */
+
+struct mtget32 {
+ s32 mt_type;
+ s32 mt_resid;
+ s32 mt_dsreg;
+ s32 mt_gstat;
+ s32 mt_erreg;
+ s32 mt_fileno;
+ s32 mt_blkno;
+};
+#define MTIOCGET32 _IOR('m', 2, struct mtget32)
+
+struct mtpos32 {
+ s32 mt_blkno;
+};
+#define MTIOCPOS32 _IOR('m', 3, struct mtpos32)
+
+static inline int put_user_mtget(void __user *u, struct mtget *k)
+{
+ struct mtget32 k32 = {
+ .mt_type = k->mt_type,
+ .mt_resid = k->mt_resid,
+ .mt_dsreg = k->mt_dsreg,
+ .mt_gstat = k->mt_gstat,
+ .mt_erreg = k->mt_erreg,
+ .mt_fileno = k->mt_fileno,
+ .mt_blkno = k->mt_blkno,
+ };
+ int ret;
+
+ if (in_compat_syscall())
+ ret = copy_to_user(u, &k32, sizeof(k32));
+ else
+ ret = copy_to_user(u, k, sizeof(*k));
+
+ return ret ? -EFAULT : 0;
+}
+
+static inline int put_user_mtpos(void __user *u, struct mtpos *k)
+{
+ if (in_compat_syscall())
+ return put_user(k->mt_blkno, (u32 __user *)u);
+ else
+ return put_user(k->mt_blkno, (long __user *)u);
+}
+
+#endif
--
2.20.0

2019-10-09 19:15:21

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 35/43] compat_ioctl: move SIOCOUTQ out of compat_ioctl.c

All users of this call are in socket or tty code, so handling
it there means we can avoid the table entry in fs/compat_ioctl.c.

Reviewed-by: Greg Kroah-Hartman <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: [email protected]
Cc: "David S. Miller" <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
drivers/tty/tty_io.c | 1 +
fs/compat_ioctl.c | 2 --
net/socket.c | 2 ++
3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 802c1210558f..c09691b20a25 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2755,6 +2755,7 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
int retval = -ENOIOCTLCMD;

switch (cmd) {
+ case TIOCOUTQ:
case TIOCSTI:
case TIOCGWINSZ:
case TIOCSWINSZ:
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index f279e77df256..d537888f3660 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -198,8 +198,6 @@ static int ppp_scompress(struct file *file, unsigned int cmd,

#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd),
static unsigned int ioctl_pointer[] = {
-/* Little t */
-COMPATIBLE_IOCTL(TIOCOUTQ)
#ifdef CONFIG_BLOCK
/* Big S */
COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
diff --git a/net/socket.c b/net/socket.c
index a60f48ab2130..371999a024fa 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -100,6 +100,7 @@
#include <linux/if_tun.h>
#include <linux/ipv6_route.h>
#include <linux/route.h>
+#include <linux/termios.h>
#include <linux/sockios.h>
#include <net/busy_poll.h>
#include <linux/errqueue.h>
@@ -3452,6 +3453,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
case SIOCSARP:
case SIOCGARP:
case SIOCDARP:
+ case SIOCOUTQ:
case SIOCOUTQNSD:
case SIOCATMARK:
return sock_do_ioctl(net, sock, cmd, arg);
--
2.20.0

2019-10-09 19:15:27

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 29/43] gfs2: add compat_ioctl support

Out of the four ioctl commands supported on gfs2, only FITRIM
works in compat mode.

Add a proper handler based on the ext4 implementation.

Fixes: 6ddc5c3ddf25 ("gfs2: getlabel support")
Reviewed-by: Bob Peterson <[email protected]>
Cc: Andreas Gruenbacher <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/gfs2/file.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)

diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index 997b326247e2..e073050c1f2a 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -6,6 +6,7 @@

#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/compat.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/pagemap.h>
@@ -354,6 +355,31 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return -ENOTTY;
}

+#ifdef CONFIG_COMPAT
+static long gfs2_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ switch(cmd) {
+ /* These are just misnamed, they actually get/put from/to user an int */
+ case FS_IOC32_GETFLAGS:
+ cmd = FS_IOC_GETFLAGS;
+ break;
+ case FS_IOC32_SETFLAGS:
+ cmd = FS_IOC_SETFLAGS;
+ break;
+ /* Keep this list in sync with gfs2_ioctl */
+ case FITRIM:
+ case FS_IOC_GETFSLABEL:
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return gfs2_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#else
+#define gfs2_compat_ioctl NULL
+#endif
+
/**
* gfs2_size_hint - Give a hint to the size of a write request
* @filep: The struct file
@@ -1293,6 +1319,7 @@ const struct file_operations gfs2_file_fops = {
.write_iter = gfs2_file_write_iter,
.iopoll = iomap_dio_iopoll,
.unlocked_ioctl = gfs2_ioctl,
+ .compat_ioctl = gfs2_compat_ioctl,
.mmap = gfs2_mmap,
.open = gfs2_open,
.release = gfs2_release,
@@ -1308,6 +1335,7 @@ const struct file_operations gfs2_file_fops = {
const struct file_operations gfs2_dir_fops = {
.iterate_shared = gfs2_readdir,
.unlocked_ioctl = gfs2_ioctl,
+ .compat_ioctl = gfs2_compat_ioctl,
.open = gfs2_open,
.release = gfs2_release,
.fsync = gfs2_fsync,
@@ -1324,6 +1352,7 @@ const struct file_operations gfs2_file_fops_nolock = {
.write_iter = gfs2_file_write_iter,
.iopoll = iomap_dio_iopoll,
.unlocked_ioctl = gfs2_ioctl,
+ .compat_ioctl = gfs2_compat_ioctl,
.mmap = gfs2_mmap,
.open = gfs2_open,
.release = gfs2_release,
@@ -1337,6 +1366,7 @@ const struct file_operations gfs2_file_fops_nolock = {
const struct file_operations gfs2_dir_fops_nolock = {
.iterate_shared = gfs2_readdir,
.unlocked_ioctl = gfs2_ioctl,
+ .compat_ioctl = gfs2_compat_ioctl,
.open = gfs2_open,
.release = gfs2_release,
.fsync = gfs2_fsync,
--
2.20.0

2019-10-09 19:15:38

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 15/43] compat_ioctl: move ATYFB_CLK handling to atyfb driver

These are two obscure ioctl commands, in a driver that only
has compatible commands, so just let the driver handle this
itself.

Acked-by: Bartlomiej Zolnierkiewicz <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
drivers/video/fbdev/aty/atyfb_base.c | 12 +++++++++++-
fs/compat_ioctl.c | 2 --
2 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c
index 6dda5d885a03..79d548746efd 100644
--- a/drivers/video/fbdev/aty/atyfb_base.c
+++ b/drivers/video/fbdev/aty/atyfb_base.c
@@ -48,7 +48,7 @@

******************************************************************************/

-
+#include <linux/compat.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -235,6 +235,13 @@ static int atyfb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info);
static int atyfb_blank(int blank, struct fb_info *info);
static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
+#ifdef CONFIG_COMPAT
+static int atyfb_compat_ioctl(struct fb_info *info, u_int cmd, u_long arg)
+{
+ return atyfb_ioctl(info, cmd, (u_long)compat_ptr(arg));
+}
+#endif
+
#ifdef __sparc__
static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma);
#endif
@@ -290,6 +297,9 @@ static struct fb_ops atyfb_ops = {
.fb_pan_display = atyfb_pan_display,
.fb_blank = atyfb_blank,
.fb_ioctl = atyfb_ioctl,
+#ifdef CONFIG_COMPAT
+ .fb_compat_ioctl = atyfb_compat_ioctl,
+#endif
.fb_fillrect = atyfb_fillrect,
.fb_copyarea = atyfb_copyarea,
.fb_imageblit = atyfb_imageblit,
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index b65eef3d4787..a4e8fb7da968 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -696,8 +696,6 @@ COMPATIBLE_IOCTL(CAPI_CLR_FLAGS)
COMPATIBLE_IOCTL(CAPI_NCCI_OPENCOUNT)
COMPATIBLE_IOCTL(CAPI_NCCI_GETUNIT)
/* Misc. */
-COMPATIBLE_IOCTL(0x41545900) /* ATYIO_CLKR */
-COMPATIBLE_IOCTL(0x41545901) /* ATYIO_CLKW */
COMPATIBLE_IOCTL(PCIIOC_CONTROLLER)
COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
--
2.20.0

2019-10-09 19:15:43

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 28/43] compat_ioctl: remove unused convert_in_user macro

The last users are all gone, so let's remove the macro as well.

Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/compat_ioctl.c | 7 -------
1 file changed, 7 deletions(-)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 1ed32cca2176..1e740f4406d3 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -52,13 +52,6 @@

#include <linux/sort.h>

-#define convert_in_user(srcptr, dstptr) \
-({ \
- typeof(*srcptr) val; \
- \
- get_user(val, srcptr) || put_user(val, dstptr); \
-})
-
static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int err;
--
2.20.0

2019-10-09 19:15:43

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 21/43] compat_ioctl: remove translation for sound ioctls

The SNDCTL_* and SOUND_* commands are the old OSS user interface.

I checked all the sound ioctl commands listed in fs/compat_ioctl.c
to see if we still need the translation handlers. Here is what I
found:

- sound/oss/ is (almost) gone from the kernel, this is what actually
needed all the translations
- The ALSA emulation for OSS correctly handles all compat_ioctl
commands already.
- sound/oss/dmasound/ is the last holdout of the original OSS code,
this is only used on arch/m68k, which has no 64-bit mode and
hence needs no compat handlers
- arch/um/drivers/hostaudio_kern.c may run in 64-bit mode with
32-bit x86 user space underneath it. This rare corner case is
the only one that still needs the compat handlers.

By adding a simple redirect of .compat_ioctl to .unlocked_ioctl in the
UML driver, we can remove all the COMPATIBLE_IOCTL() annotations without
a change in functionality. For completeness, I'm adding the same thing
to the dmasound file, knowing that it makes no difference.

The compat_ioctl list contains one comment about SNDCTL_DSP_MAPINBUF and
SNDCTL_DSP_MAPOUTBUF, which actually would need a translation handler
if implemented. However, the native implementation just returns -EINVAL,
so we don't care.

Reviewed-by: Takashi Iwai <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
arch/um/drivers/hostaudio_kern.c | 1 +
fs/compat_ioctl.c | 158 -----------------------------
sound/core/oss/pcm_oss.c | 4 +
sound/oss/dmasound/dmasound_core.c | 2 +
4 files changed, 7 insertions(+), 158 deletions(-)

diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index bf75b1ceac47..d35d3f305a31 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -298,6 +298,7 @@ static const struct file_operations hostaudio_fops = {
.write = hostaudio_write,
.poll = hostaudio_poll,
.unlocked_ioctl = hostaudio_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
.mmap = NULL,
.open = hostaudio_open,
.release = hostaudio_release,
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 03da7934a351..33f732979f45 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -51,8 +51,6 @@
#include <linux/uaccess.h>
#include <linux/watchdog.h>

-#include <linux/soundcard.h>
-
#include <linux/hiddev.h>


@@ -458,162 +456,6 @@ COMPATIBLE_IOCTL(PPPIOCDISCONN)
COMPATIBLE_IOCTL(PPPIOCATTCHAN)
COMPATIBLE_IOCTL(PPPIOCGCHAN)
COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS)
-/* Big A */
-/* sparc only */
-/* Big Q for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_INFO)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_CTRLRATE)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_GETOUTCOUNT)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_GETINCOUNT)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_PERCMODE)
-COMPATIBLE_IOCTL(SNDCTL_FM_LOAD_INSTR)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_TESTMIDI)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_RESETSAMPLES)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_NRSYNTHS)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_NRMIDIS)
-COMPATIBLE_IOCTL(SNDCTL_MIDI_INFO)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_THRESHOLD)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_MEMAVL)
-COMPATIBLE_IOCTL(SNDCTL_FM_4OP_ENABLE)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_PANIC)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_OUTOFBAND)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_GETTIME)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_ID)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_CONTROL)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_REMOVESAMPLE)
-/* Big T for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_TMR_TIMEBASE)
-COMPATIBLE_IOCTL(SNDCTL_TMR_START)
-COMPATIBLE_IOCTL(SNDCTL_TMR_STOP)
-COMPATIBLE_IOCTL(SNDCTL_TMR_CONTINUE)
-COMPATIBLE_IOCTL(SNDCTL_TMR_TEMPO)
-COMPATIBLE_IOCTL(SNDCTL_TMR_SOURCE)
-COMPATIBLE_IOCTL(SNDCTL_TMR_METRONOME)
-COMPATIBLE_IOCTL(SNDCTL_TMR_SELECT)
-/* Little m for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_MIDI_PRETIME)
-COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUMODE)
-COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUCMD)
-/* Big P for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_DSP_RESET)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SYNC)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SPEED)
-COMPATIBLE_IOCTL(SNDCTL_DSP_STEREO)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETBLKSIZE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_CHANNELS)
-COMPATIBLE_IOCTL(SOUND_PCM_WRITE_FILTER)
-COMPATIBLE_IOCTL(SNDCTL_DSP_POST)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SUBDIVIDE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETFRAGMENT)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETFMTS)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETFMT)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETOSPACE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETISPACE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_NONBLOCK)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETCAPS)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETTRIGGER)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETTRIGGER)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETIPTR)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETOPTR)
-/* SNDCTL_DSP_MAPINBUF, XXX needs translation */
-/* SNDCTL_DSP_MAPOUTBUF, XXX needs translation */
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETSYNCRO)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETDUPLEX)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETODELAY)
-COMPATIBLE_IOCTL(SNDCTL_DSP_PROFILE)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_RATE)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_CHANNELS)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_BITS)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_FILTER)
-/* Big C for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_COPR_RESET)
-COMPATIBLE_IOCTL(SNDCTL_COPR_LOAD)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RDATA)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RCODE)
-COMPATIBLE_IOCTL(SNDCTL_COPR_WDATA)
-COMPATIBLE_IOCTL(SNDCTL_COPR_WCODE)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RUN)
-COMPATIBLE_IOCTL(SNDCTL_COPR_HALT)
-COMPATIBLE_IOCTL(SNDCTL_COPR_SENDMSG)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RCVMSG)
-/* Big M for sound/OSS */
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_VOLUME)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_BASS)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_TREBLE)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_SYNTH)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_PCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_SPEAKER)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_MIC)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_CD)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_IMIX)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_ALTPCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECLEV)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_IGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3)
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL1))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL2))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL3))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEIN))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEOUT))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_VIDEO))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_RADIO))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_MONITOR))
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE)
-/* SOUND_MIXER_READ_ENHANCE, same value as READ_MUTE */
-/* SOUND_MIXER_READ_LOUD, same value as READ_MUTE */
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECSRC)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_DEVMASK)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECMASK)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_STEREODEVS)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_CAPS)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_VOLUME)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_BASS)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_TREBLE)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SYNTH)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_PCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SPEAKER)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MIC)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_CD)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IMIX)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_ALTPCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECLEV)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3)
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL1))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL2))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL3))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEIN))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEOUT))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_VIDEO))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_RADIO))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_MONITOR))
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE)
-/* SOUND_MIXER_WRITE_ENHANCE, same value as WRITE_MUTE */
-/* SOUND_MIXER_WRITE_LOUD, same value as WRITE_MUTE */
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECSRC)
-COMPATIBLE_IOCTL(SOUND_MIXER_INFO)
-COMPATIBLE_IOCTL(SOUND_OLD_MIXER_INFO)
-COMPATIBLE_IOCTL(SOUND_MIXER_ACCESS)
-COMPATIBLE_IOCTL(SOUND_MIXER_AGC)
-COMPATIBLE_IOCTL(SOUND_MIXER_3DSE)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE1)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE2)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE3)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE4)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5)
-COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS)
-COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS)
-COMPATIBLE_IOCTL(OSS_GETVERSION)
/* Raw devices */
COMPATIBLE_IOCTL(RAW_SETBIND)
COMPATIBLE_IOCTL(RAW_GETBIND)
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index f57c610d7523..13db77771f0f 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -2717,6 +2717,10 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
static long snd_pcm_oss_ioctl_compat(struct file *file, unsigned int cmd,
unsigned long arg)
{
+ /*
+ * Everything is compatbile except SNDCTL_DSP_MAPINBUF/SNDCTL_DSP_MAPOUTBUF,
+ * which are not implemented for the native case either
+ */
return snd_pcm_oss_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
}
#else
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index fc9bcd47d6a4..f802ea331e24 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -384,6 +384,7 @@ static const struct file_operations mixer_fops =
.owner = THIS_MODULE,
.llseek = no_llseek,
.unlocked_ioctl = mixer_unlocked_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
.open = mixer_open,
.release = mixer_release,
};
@@ -1167,6 +1168,7 @@ static const struct file_operations sq_fops =
.write = sq_write,
.poll = sq_poll,
.unlocked_ioctl = sq_unlocked_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
.open = sq_open,
.release = sq_release,
};
--
2.20.0

2019-10-09 19:15:49

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 25/43] compat_ioctl: remove PCI ioctl translation

The /proc/pci/ implementation already handles these just fine, so
the entries in the table are not needed any more.

Cc: [email protected]
Cc: Bjorn Helgaas <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/compat_ioctl.c | 6 ------
1 file changed, 6 deletions(-)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index a214ae052596..37f45644528a 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -29,7 +29,6 @@
#include <linux/vt_kern.h>
#include <linux/raw.h>
#include <linux/blkdev.h>
-#include <linux/pci.h>
#include <linux/serial.h>
#include <linux/ctype.h>
#include <linux/syscalls.h>
@@ -437,11 +436,6 @@ COMPATIBLE_IOCTL(WDIOC_SETTIMEOUT)
COMPATIBLE_IOCTL(WDIOC_GETTIMEOUT)
COMPATIBLE_IOCTL(WDIOC_SETPRETIMEOUT)
COMPATIBLE_IOCTL(WDIOC_GETPRETIMEOUT)
-/* Misc. */
-COMPATIBLE_IOCTL(PCIIOC_CONTROLLER)
-COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
-COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
-COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE)
};

/*
--
2.20.0

2019-10-09 19:15:55

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 16/43] compat_ioctl: move isdn/capi ioctl translation into driver

Neither the old isdn4linux interface nor the newer mISDN stack
ever had working 32-bit compat mode as far as I can tell.

However, the CAPI stack has some ioctl commands that are
correctly listed in fs/compat_ioctl.c.

We can trivially move all of those into the corresponding
file that implement the native handlers by adding a compat_ioctl
redirect to that.

I did notice that treating CAPI_MANUFACTURER_CMD() as compatible
is broken, so I'm also adding a handler for that, realizing that
in all likelyhood, nobody is ever going to call it.

Cc: Karsten Keil <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Arnd Bergmann <[email protected]>
---
drivers/isdn/capi/capi.c | 31 +++++++++++++++++++++++++++++++
fs/compat_ioctl.c | 17 -----------------
2 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index c92b405b7646..efce7532513c 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -950,6 +950,34 @@ capi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return ret;
}

+#ifdef CONFIG_COMPAT
+static long
+capi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int ret;
+
+ if (cmd == CAPI_MANUFACTURER_CMD) {
+ struct {
+ unsigned long cmd;
+ compat_uptr_t data;
+ } mcmd32;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&mcmd32, compat_ptr(arg), sizeof(mcmd32)))
+ return -EFAULT;
+
+ mutex_lock(&capi_mutex);
+ ret = capi20_manufacturer(mcmd32.cmd, compat_ptr(mcmd32.data));
+ mutex_unlock(&capi_mutex);
+
+ return ret;
+ }
+
+ return capi_unlocked_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
static int capi_open(struct inode *inode, struct file *file)
{
struct capidev *cdev;
@@ -996,6 +1024,9 @@ static const struct file_operations capi_fops =
.write = capi_write,
.poll = capi_poll,
.unlocked_ioctl = capi_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = capi_compat_ioctl,
+#endif
.open = capi_open,
.release = capi_release,
};
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index a4e8fb7da968..f3b4179d6dff 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -44,9 +44,6 @@
#include <net/bluetooth/hci_sock.h>
#include <net/bluetooth/rfcomm.h>

-#include <linux/capi.h>
-#include <linux/gigaset_dev.h>
-
#ifdef CONFIG_BLOCK
#include <linux/cdrom.h>
#include <linux/fd.h>
@@ -681,20 +678,6 @@ COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
-/* CAPI */
-COMPATIBLE_IOCTL(CAPI_REGISTER)
-COMPATIBLE_IOCTL(CAPI_GET_MANUFACTURER)
-COMPATIBLE_IOCTL(CAPI_GET_VERSION)
-COMPATIBLE_IOCTL(CAPI_GET_SERIAL)
-COMPATIBLE_IOCTL(CAPI_GET_PROFILE)
-COMPATIBLE_IOCTL(CAPI_MANUFACTURER_CMD)
-COMPATIBLE_IOCTL(CAPI_GET_ERRCODE)
-COMPATIBLE_IOCTL(CAPI_INSTALLED)
-COMPATIBLE_IOCTL(CAPI_GET_FLAGS)
-COMPATIBLE_IOCTL(CAPI_SET_FLAGS)
-COMPATIBLE_IOCTL(CAPI_CLR_FLAGS)
-COMPATIBLE_IOCTL(CAPI_NCCI_OPENCOUNT)
-COMPATIBLE_IOCTL(CAPI_NCCI_GETUNIT)
/* Misc. */
COMPATIBLE_IOCTL(PCIIOC_CONTROLLER)
COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
--
2.20.0

2019-10-09 19:16:04

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 34/43] compat_ioctl: handle SIOCOUTQNSD

Unlike the normal SIOCOUTQ, SIOCOUTQNSD was never handled in compat
mode. Add it to the common socket compat handler along with similar
ones.

Fixes: 2f4e1b397097 ("tcp: ioctl type SIOCOUTQNSD returns amount of data not sent")
Cc: Eric Dumazet <[email protected]>
Cc: [email protected]
Cc: "David S. Miller" <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
net/socket.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/net/socket.c b/net/socket.c
index 6a9ab7a8b1d2..a60f48ab2130 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -3452,6 +3452,7 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
case SIOCSARP:
case SIOCGARP:
case SIOCDARP:
+ case SIOCOUTQNSD:
case SIOCATMARK:
return sock_do_ioctl(net, sock, cmd, arg);
}
--
2.20.0

2019-10-09 19:16:06

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 26/43] compat_ioctl: remove /dev/raw ioctl translation

The /dev/rawX implementation already handles these just fine, so
the entries in the table are not needed any more.

Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/compat_ioctl.c | 4 ----
1 file changed, 4 deletions(-)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 37f45644528a..6070481f2b6a 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -27,7 +27,6 @@
#include <linux/if_pppox.h>
#include <linux/tty.h>
#include <linux/vt_kern.h>
-#include <linux/raw.h>
#include <linux/blkdev.h>
#include <linux/serial.h>
#include <linux/ctype.h>
@@ -422,9 +421,6 @@ COMPATIBLE_IOCTL(PPPIOCDISCONN)
COMPATIBLE_IOCTL(PPPIOCATTCHAN)
COMPATIBLE_IOCTL(PPPIOCGCHAN)
COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS)
-/* Raw devices */
-COMPATIBLE_IOCTL(RAW_SETBIND)
-COMPATIBLE_IOCTL(RAW_GETBIND)
/* Watchdog */
COMPATIBLE_IOCTL(WDIOC_GETSUPPORT)
COMPATIBLE_IOCTL(WDIOC_GETSTATUS)
--
2.20.0

2019-10-09 19:16:13

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 32/43] compat_ioctl: reimplement SG_IO handling

There are two code locations that implement the SG_IO ioctl: the old
sg.c driver, and the generic scsi_ioctl helper that is in turn used by
multiple drivers.

To eradicate the old compat_ioctl conversion handler for the SG_IO
command, I implement a readable pair of put_sg_io_hdr() /get_sg_io_hdr()
helper functions that can be used for both compat and native mode,
and then I call this from both drivers.

For the iovec handling, there is already a compat_import_iovec() function
that can simply be called in place of import_iovec().

To avoid having to pass the compat/native state through multiple
indirections, I mark the SG_IO command itself as compatible in
fs/compat_ioctl.c and use in_compat_syscall() to figure out where
we are called from.

As a side-effect of this, the sg.c driver now also accepts the 32-bit
sg_io_hdr format in compat mode using the read/write interface, not
just ioctl. This should improve compatiblity with old 32-bit binaries,
but it would break if any application intentionally passes the 64-bit
data structure in compat mode here.

Steffen Maier helped debug an issue in an earlier version of this patch.

Cc: Steffen Maier <[email protected]>
Cc: [email protected]
Cc: Doug Gilbert <[email protected]>
Cc: "James E.J. Bottomley" <[email protected]>
Cc: "Martin K. Petersen" <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
block/scsi_ioctl.c | 132 ++++++++++++++++++++++++++++++++++--
drivers/scsi/sg.c | 19 +++---
fs/compat_ioctl.c | 148 +----------------------------------------
include/linux/blkdev.h | 2 +
lib/iov_iter.c | 1 +
5 files changed, 143 insertions(+), 159 deletions(-)

diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index f5e0ad65e86a..650bade5ea5a 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2001 Jens Axboe <[email protected]>
*/
+#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
@@ -327,7 +328,14 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
struct iov_iter i;
struct iovec *iov = NULL;

- ret = import_iovec(rq_data_dir(rq),
+#ifdef CONFIG_COMPAT
+ if (in_compat_syscall())
+ ret = compat_import_iovec(rq_data_dir(rq),
+ hdr->dxferp, hdr->iovec_count,
+ 0, &iov, &i);
+ else
+#endif
+ ret = import_iovec(rq_data_dir(rq),
hdr->dxferp, hdr->iovec_count,
0, &iov, &i);
if (ret < 0)
@@ -542,6 +550,122 @@ static inline int blk_send_start_stop(struct request_queue *q,
return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data);
}

+#ifdef CONFIG_COMPAT
+struct compat_sg_io_hdr {
+ compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */
+ compat_int_t dxfer_direction; /* [i] data transfer direction */
+ unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */
+ unsigned char mx_sb_len; /* [i] max length to write to sbp */
+ unsigned short iovec_count; /* [i] 0 implies no scatter gather */
+ compat_uint_t dxfer_len; /* [i] byte count of data transfer */
+ compat_uint_t dxferp; /* [i], [*io] points to data transfer memory
+ or scatter gather list */
+ compat_uptr_t cmdp; /* [i], [*i] points to command to perform */
+ compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */
+ compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */
+ compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */
+ compat_int_t pack_id; /* [i->o] unused internally (normally) */
+ compat_uptr_t usr_ptr; /* [i->o] unused internally */
+ unsigned char status; /* [o] scsi status */
+ unsigned char masked_status; /* [o] shifted, masked scsi status */
+ unsigned char msg_status; /* [o] messaging level data (optional) */
+ unsigned char sb_len_wr; /* [o] byte count actually written to sbp */
+ unsigned short host_status; /* [o] errors from host adapter */
+ unsigned short driver_status; /* [o] errors from software driver */
+ compat_int_t resid; /* [o] dxfer_len - actual_transferred */
+ compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */
+ compat_uint_t info; /* [o] auxiliary information */
+};
+#endif
+
+int put_sg_io_hdr(const struct sg_io_hdr *hdr, void __user *argp)
+{
+#ifdef CONFIG_COMPAT
+ if (in_compat_syscall()) {
+ struct compat_sg_io_hdr hdr32 = {
+ .interface_id = hdr->interface_id,
+ .dxfer_direction = hdr->dxfer_direction,
+ .cmd_len = hdr->cmd_len,
+ .mx_sb_len = hdr->mx_sb_len,
+ .iovec_count = hdr->iovec_count,
+ .dxfer_len = hdr->dxfer_len,
+ .dxferp = (uintptr_t)hdr->dxferp,
+ .cmdp = (uintptr_t)hdr->cmdp,
+ .sbp = (uintptr_t)hdr->sbp,
+ .timeout = hdr->timeout,
+ .flags = hdr->flags,
+ .pack_id = hdr->pack_id,
+ .usr_ptr = (uintptr_t)hdr->usr_ptr,
+ .status = hdr->status,
+ .masked_status = hdr->masked_status,
+ .msg_status = hdr->msg_status,
+ .sb_len_wr = hdr->sb_len_wr,
+ .host_status = hdr->host_status,
+ .driver_status = hdr->driver_status,
+ .resid = hdr->resid,
+ .duration = hdr->duration,
+ .info = hdr->info,
+ };
+
+ if (copy_to_user(argp, &hdr32, sizeof(hdr32)))
+ return -EFAULT;
+
+ return 0;
+ }
+#endif
+
+ if (copy_to_user(argp, hdr, sizeof(*hdr)))
+ return -EFAULT;
+
+ return 0;
+}
+EXPORT_SYMBOL(put_sg_io_hdr);
+
+int get_sg_io_hdr(struct sg_io_hdr *hdr, const void __user *argp)
+{
+#ifdef CONFIG_COMPAT
+ struct compat_sg_io_hdr hdr32;
+
+ if (in_compat_syscall()) {
+ if (copy_from_user(&hdr32, argp, sizeof(hdr32)))
+ return -EFAULT;
+
+ *hdr = (struct sg_io_hdr) {
+ .interface_id = hdr32.interface_id,
+ .dxfer_direction = hdr32.dxfer_direction,
+ .cmd_len = hdr32.cmd_len,
+ .mx_sb_len = hdr32.mx_sb_len,
+ .iovec_count = hdr32.iovec_count,
+ .dxfer_len = hdr32.dxfer_len,
+ .dxferp = compat_ptr(hdr32.dxferp),
+ .cmdp = compat_ptr(hdr32.cmdp),
+ .sbp = compat_ptr(hdr32.sbp),
+ .timeout = hdr32.timeout,
+ .flags = hdr32.flags,
+ .pack_id = hdr32.pack_id,
+ .usr_ptr = compat_ptr(hdr32.usr_ptr),
+ .status = hdr32.status,
+ .masked_status = hdr32.masked_status,
+ .msg_status = hdr32.msg_status,
+ .sb_len_wr = hdr32.sb_len_wr,
+ .host_status = hdr32.host_status,
+ .driver_status = hdr32.driver_status,
+ .resid = hdr32.resid,
+ .duration = hdr32.duration,
+ .info = hdr32.info,
+ };
+
+ return 0;
+ }
+#endif
+
+ if (copy_from_user(hdr, argp, sizeof(*hdr)))
+ return -EFAULT;
+
+ return 0;
+}
+EXPORT_SYMBOL(get_sg_io_hdr);
+
int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mode,
unsigned int cmd, void __user *arg)
{
@@ -581,14 +705,14 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod
case SG_IO: {
struct sg_io_hdr hdr;

- err = -EFAULT;
- if (copy_from_user(&hdr, arg, sizeof(hdr)))
+ err = get_sg_io_hdr(&hdr, arg);
+ if (err)
break;
err = sg_io(q, bd_disk, &hdr, mode);
if (err == -EFAULT)
break;

- if (copy_to_user(arg, &hdr, sizeof(hdr)))
+ if (put_sg_io_hdr(&hdr, arg))
err = -EFAULT;
break;
}
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index cce757506383..8ae096af2667 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -447,8 +447,7 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
retval = -ENOMEM;
goto free_old_hdr;
}
- retval =__copy_from_user
- (new_hdr, buf, SZ_SG_IO_HDR);
+ retval = get_sg_io_hdr(new_hdr, buf);
req_pack_id = new_hdr->pack_id;
kfree(new_hdr);
if (retval) {
@@ -589,10 +588,7 @@ sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp)
}
if (hp->masked_status || hp->host_status || hp->driver_status)
hp->info |= SG_INFO_CHECK;
- if (copy_to_user(buf, hp, SZ_SG_IO_HDR)) {
- err = -EFAULT;
- goto err_out;
- }
+ err = put_sg_io_hdr(hp, buf);
err_out:
err2 = sg_finish_rem_req(srp);
sg_remove_request(sfp, srp);
@@ -735,7 +731,7 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf,
}
srp->sg_io_owned = sg_io_owned;
hp = &srp->header;
- if (__copy_from_user(hp, buf, SZ_SG_IO_HDR)) {
+ if (get_sg_io_hdr(hp, buf)) {
sg_remove_request(sfp, srp);
return -EFAULT;
}
@@ -1797,7 +1793,14 @@ sg_start_req(Sg_request *srp, unsigned char *cmd)
struct iovec *iov = NULL;
struct iov_iter i;

- res = import_iovec(rw, hp->dxferp, iov_count, 0, &iov, &i);
+#ifdef CONFIG_COMPAT
+ if (in_compat_syscall())
+ res = compat_import_iovec(rw, hp->dxferp, iov_count,
+ 0, &iov, &i);
+ else
+#endif
+ res = import_iovec(rw, hp->dxferp, iov_count,
+ 0, &iov, &i);
if (res < 0)
return res;

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 10ba2d9e20bc..f279e77df256 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -64,151 +64,6 @@ static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}

#ifdef CONFIG_BLOCK
-typedef struct sg_io_hdr32 {
- compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */
- compat_int_t dxfer_direction; /* [i] data transfer direction */
- unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */
- unsigned char mx_sb_len; /* [i] max length to write to sbp */
- unsigned short iovec_count; /* [i] 0 implies no scatter gather */
- compat_uint_t dxfer_len; /* [i] byte count of data transfer */
- compat_uint_t dxferp; /* [i], [*io] points to data transfer memory
- or scatter gather list */
- compat_uptr_t cmdp; /* [i], [*i] points to command to perform */
- compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */
- compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */
- compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */
- compat_int_t pack_id; /* [i->o] unused internally (normally) */
- compat_uptr_t usr_ptr; /* [i->o] unused internally */
- unsigned char status; /* [o] scsi status */
- unsigned char masked_status; /* [o] shifted, masked scsi status */
- unsigned char msg_status; /* [o] messaging level data (optional) */
- unsigned char sb_len_wr; /* [o] byte count actually written to sbp */
- unsigned short host_status; /* [o] errors from host adapter */
- unsigned short driver_status; /* [o] errors from software driver */
- compat_int_t resid; /* [o] dxfer_len - actual_transferred */
- compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */
- compat_uint_t info; /* [o] auxiliary information */
-} sg_io_hdr32_t; /* 64 bytes long (on sparc32) */
-
-typedef struct sg_iovec32 {
- compat_uint_t iov_base;
- compat_uint_t iov_len;
-} sg_iovec32_t;
-
-static int sg_build_iovec(sg_io_hdr_t __user *sgio, void __user *dxferp, u16 iovec_count)
-{
- sg_iovec_t __user *iov = (sg_iovec_t __user *) (sgio + 1);
- sg_iovec32_t __user *iov32 = dxferp;
- int i;
-
- for (i = 0; i < iovec_count; i++) {
- u32 base, len;
-
- if (get_user(base, &iov32[i].iov_base) ||
- get_user(len, &iov32[i].iov_len) ||
- put_user(compat_ptr(base), &iov[i].iov_base) ||
- put_user(len, &iov[i].iov_len))
- return -EFAULT;
- }
-
- if (put_user(iov, &sgio->dxferp))
- return -EFAULT;
- return 0;
-}
-
-static int sg_ioctl_trans(struct file *file, unsigned int cmd,
- sg_io_hdr32_t __user *sgio32)
-{
- sg_io_hdr_t __user *sgio;
- u16 iovec_count;
- u32 data;
- void __user *dxferp;
- int err;
- int interface_id;
-
- if (get_user(interface_id, &sgio32->interface_id))
- return -EFAULT;
- if (interface_id != 'S')
- return do_ioctl(file, cmd, (unsigned long)sgio32);
-
- if (get_user(iovec_count, &sgio32->iovec_count))
- return -EFAULT;
-
- {
- void __user *top = compat_alloc_user_space(0);
- void __user *new = compat_alloc_user_space(sizeof(sg_io_hdr_t) +
- (iovec_count * sizeof(sg_iovec_t)));
- if (new > top)
- return -EINVAL;
-
- sgio = new;
- }
-
- /* Ok, now construct. */
- if (copy_in_user(&sgio->interface_id, &sgio32->interface_id,
- (2 * sizeof(int)) +
- (2 * sizeof(unsigned char)) +
- (1 * sizeof(unsigned short)) +
- (1 * sizeof(unsigned int))))
- return -EFAULT;
-
- if (get_user(data, &sgio32->dxferp))
- return -EFAULT;
- dxferp = compat_ptr(data);
- if (iovec_count) {
- if (sg_build_iovec(sgio, dxferp, iovec_count))
- return -EFAULT;
- } else {
- if (put_user(dxferp, &sgio->dxferp))
- return -EFAULT;
- }
-
- {
- unsigned char __user *cmdp;
- unsigned char __user *sbp;
-
- if (get_user(data, &sgio32->cmdp))
- return -EFAULT;
- cmdp = compat_ptr(data);
-
- if (get_user(data, &sgio32->sbp))
- return -EFAULT;
- sbp = compat_ptr(data);
-
- if (put_user(cmdp, &sgio->cmdp) ||
- put_user(sbp, &sgio->sbp))
- return -EFAULT;
- }
-
- if (copy_in_user(&sgio->timeout, &sgio32->timeout,
- 3 * sizeof(int)))
- return -EFAULT;
-
- if (get_user(data, &sgio32->usr_ptr))
- return -EFAULT;
- if (put_user(compat_ptr(data), &sgio->usr_ptr))
- return -EFAULT;
-
- err = do_ioctl(file, cmd, (unsigned long) sgio);
-
- if (err >= 0) {
- void __user *datap;
-
- if (copy_in_user(&sgio32->pack_id, &sgio->pack_id,
- sizeof(int)) ||
- get_user(datap, &sgio->usr_ptr) ||
- put_user((u32)(unsigned long)datap,
- &sgio32->usr_ptr) ||
- copy_in_user(&sgio32->status, &sgio->status,
- (4 * sizeof(unsigned char)) +
- (2 * sizeof(unsigned short)) +
- (3 * sizeof(int))))
- err = -EFAULT;
- }
-
- return err;
-}
-
struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
char req_state;
char orphan;
@@ -358,6 +213,7 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
#endif
#ifdef CONFIG_BLOCK
/* SG stuff */
+COMPATIBLE_IOCTL(SG_IO)
COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
COMPATIBLE_IOCTL(SG_EMULATED_HOST)
@@ -435,8 +291,6 @@ static long do_ioctl_trans(unsigned int cmd,
case PPPIOCSACTIVE32:
return ppp_sock_fprog_ioctl_trans(file, cmd, argp);
#ifdef CONFIG_BLOCK
- case SG_IO:
- return sg_ioctl_trans(file, cmd, argp);
case SG_GET_REQUEST_TABLE:
return sg_grt_trans(file, cmd, argp);
#endif
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index f3ea78b0c91c..2c8cd22b176b 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -870,6 +870,8 @@ extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t,
unsigned int, void __user *);
extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t,
struct scsi_ioctl_command __user *);
+extern int get_sg_io_hdr(struct sg_io_hdr *hdr, const void __user *argp);
+extern int put_sg_io_hdr(const struct sg_io_hdr *hdr, void __user *argp);

extern int blk_queue_enter(struct request_queue *q, blk_mq_req_flags_t flags);
extern void blk_queue_exit(struct request_queue *q);
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 639d5e7014c1..ffb52f2c0ef4 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -1678,6 +1678,7 @@ ssize_t compat_import_iovec(int type,
*iov = p == *iov ? NULL : p;
return n;
}
+EXPORT_SYMBOL(compat_import_iovec);
#endif

int import_single_range(int rw, void __user *buf, size_t len,
--
2.20.0

2019-10-09 19:16:16

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 23/43] compat_ioctl: remove /dev/random commands

These are all handled by the random driver, so instead of listing
each ioctl, we can use the generic compat_ptr_ioctl() helper.

Acked-by: Greg Kroah-Hartman <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
drivers/char/random.c | 1 +
fs/compat_ioctl.c | 7 -------
2 files changed, 1 insertion(+), 7 deletions(-)

diff --git a/drivers/char/random.c b/drivers/char/random.c
index de434feb873a..46afd14facb7 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -2167,6 +2167,7 @@ const struct file_operations random_fops = {
.write = random_write,
.poll = random_poll,
.unlocked_ioctl = random_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
.fasync = random_fasync,
.llseek = noop_llseek,
};
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 10dfe4d80bbd..398268604ab7 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -439,13 +439,6 @@ COMPATIBLE_IOCTL(WDIOC_SETTIMEOUT)
COMPATIBLE_IOCTL(WDIOC_GETTIMEOUT)
COMPATIBLE_IOCTL(WDIOC_SETPRETIMEOUT)
COMPATIBLE_IOCTL(WDIOC_GETPRETIMEOUT)
-/* Big R */
-COMPATIBLE_IOCTL(RNDGETENTCNT)
-COMPATIBLE_IOCTL(RNDADDTOENTCNT)
-COMPATIBLE_IOCTL(RNDGETPOOL)
-COMPATIBLE_IOCTL(RNDADDENTROPY)
-COMPATIBLE_IOCTL(RNDZAPENTCNT)
-COMPATIBLE_IOCTL(RNDCLEARPOOL)
/* Misc. */
COMPATIBLE_IOCTL(PCIIOC_CONTROLLER)
COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
--
2.20.0

2019-10-09 19:16:24

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 20/43] compat_ioctl: remove HIDIO translation

The two drivers implementing these both gained proper compat_ioctl()
handlers a long time ago with commits bb6c8d8fa9b5 ("HID: hiddev:
Add 32bit ioctl compatibilty") and ae5e49c79c05 ("HID: hidraw: add
compatibility ioctl() for 32-bit applications."), so the lists in
fs/compat_ioctl.c are no longer used.

It appears that the lists were also incomplete, so the translation
didn't actually work correctly when it was still in use.

Remove them as cleanup.

Cc: [email protected]
Cc: Marcel Holtmann <[email protected]>
Cc: Johan Hedberg <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/compat_ioctl.c | 17 -----------------
1 file changed, 17 deletions(-)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 758b8b934b70..03da7934a351 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -640,23 +640,6 @@ COMPATIBLE_IOCTL(PCIIOC_CONTROLLER)
COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE)
-/* hiddev */
-COMPATIBLE_IOCTL(HIDIOCGVERSION)
-COMPATIBLE_IOCTL(HIDIOCAPPLICATION)
-COMPATIBLE_IOCTL(HIDIOCGDEVINFO)
-COMPATIBLE_IOCTL(HIDIOCGSTRING)
-COMPATIBLE_IOCTL(HIDIOCINITREPORT)
-COMPATIBLE_IOCTL(HIDIOCGREPORT)
-COMPATIBLE_IOCTL(HIDIOCSREPORT)
-COMPATIBLE_IOCTL(HIDIOCGREPORTINFO)
-COMPATIBLE_IOCTL(HIDIOCGFIELDINFO)
-COMPATIBLE_IOCTL(HIDIOCGUSAGE)
-COMPATIBLE_IOCTL(HIDIOCSUSAGE)
-COMPATIBLE_IOCTL(HIDIOCGUCODE)
-COMPATIBLE_IOCTL(HIDIOCGFLAG)
-COMPATIBLE_IOCTL(HIDIOCSFLAG)
-COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINDEX)
-COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINFO)
/* joystick */
COMPATIBLE_IOCTL(JSIOCGVERSION)
COMPATIBLE_IOCTL(JSIOCGAXES)
--
2.20.0

2019-10-09 19:16:39

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 39/43] compat_ioctl: handle PPPIOCGIDLE for 64-bit time_t

The ppp_idle structure is defined in terms of __kernel_time_t, which is
defined as 'long' on all architectures, and this usage is not affected
by the y2038 problem since it transports a time interval rather than an
absolute time.

However, the ppp user space defines the same structure as time_t, which
may be 64-bit wide on new libc versions even on 32-bit architectures.

It's easy enough to just handle both possible structure layouts on
all architectures, to deal with the possibility that a user space ppp
implementation comes with its own ppp_idle structure definition, as well
as to document the fact that the driver is y2038-safe.

Doing this also avoids the need for a special compat mode translation,
since 32-bit and 64-bit kernels now support the same interfaces. The old
32-bit structure is also available on native 64-bit architectures now,
but this is harmless.

Cc: [email protected]
Cc: [email protected]
Cc: Paul Mackerras <[email protected]>
Cc: "David S. Miller" <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
Documentation/networking/ppp_generic.txt | 2 ++
drivers/net/ppp/ppp_generic.c | 19 ++++++++----
fs/compat_ioctl.c | 38 ++++--------------------
include/uapi/linux/ppp-ioctl.h | 2 ++
include/uapi/linux/ppp_defs.h | 14 +++++++++
5 files changed, 37 insertions(+), 38 deletions(-)

diff --git a/Documentation/networking/ppp_generic.txt b/Documentation/networking/ppp_generic.txt
index 61daf4b39600..fd563aff5fc9 100644
--- a/Documentation/networking/ppp_generic.txt
+++ b/Documentation/networking/ppp_generic.txt
@@ -378,6 +378,8 @@ an interface unit are:
CONFIG_PPP_FILTER option is enabled, the set of packets which reset
the transmit and receive idle timers is restricted to those which
pass the `active' packet filter.
+ Two versions of this command exist, to deal with user space
+ expecting times as either 32-bit or 64-bit time_t seconds.

* PPPIOCSMAXCID sets the maximum connection-ID parameter (and thus the
number of connection slots) for the TCP header compressor and
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index fb8e0ac099b8..ce4dd45c541d 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -612,7 +612,8 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct ppp_file *pf;
struct ppp *ppp;
int err = -EFAULT, val, val2, i;
- struct ppp_idle idle;
+ struct ppp_idle32 idle32;
+ struct ppp_idle64 idle64;
struct npioctl npi;
int unit, cflags;
struct slcompress *vj;
@@ -735,10 +736,18 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
err = 0;
break;

- case PPPIOCGIDLE:
- idle.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
- idle.recv_idle = (jiffies - ppp->last_recv) / HZ;
- if (copy_to_user(argp, &idle, sizeof(idle)))
+ case PPPIOCGIDLE32:
+ idle32.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
+ idle32.recv_idle = (jiffies - ppp->last_recv) / HZ;
+ if (copy_to_user(argp, &idle32, sizeof(idle32)))
+ break;
+ err = 0;
+ break;
+
+ case PPPIOCGIDLE64:
+ idle64.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
+ idle64.recv_idle = (jiffies - ppp->last_recv) / HZ;
+ if (copy_to_user(argp, &idle64, sizeof(idle64)))
break;
err = 0;
break;
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 0b5a732d7afd..5e59101ef981 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -52,6 +52,7 @@

#include <linux/sort.h>

+#ifdef CONFIG_BLOCK
static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int err;
@@ -63,7 +64,6 @@ static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return vfs_ioctl(file, cmd, arg);
}

-#ifdef CONFIG_BLOCK
struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
char req_state;
char orphan;
@@ -99,33 +99,6 @@ static int sg_grt_trans(struct file *file,
}
#endif /* CONFIG_BLOCK */

-struct ppp_idle32 {
- compat_time_t xmit_idle;
- compat_time_t recv_idle;
-};
-#define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32)
-
-static int ppp_gidle(struct file *file, unsigned int cmd,
- struct ppp_idle32 __user *idle32)
-{
- struct ppp_idle __user *idle;
- __kernel_time_t xmit, recv;
- int err;
-
- idle = compat_alloc_user_space(sizeof(*idle));
-
- err = do_ioctl(file, PPPIOCGIDLE, (unsigned long) idle);
-
- if (!err) {
- if (get_user(xmit, &idle->xmit_idle) ||
- get_user(recv, &idle->recv_idle) ||
- put_user(xmit, &idle32->xmit_idle) ||
- put_user(recv, &idle32->recv_idle))
- err = -EFAULT;
- }
- return err;
-}
-
/*
* simple reversible transform to make our table more evenly
* distributed after sorting.
@@ -192,7 +165,8 @@ COMPATIBLE_IOCTL(PPPIOCGDEBUG)
COMPATIBLE_IOCTL(PPPIOCSDEBUG)
/* PPPIOCSPASS is translated */
/* PPPIOCSACTIVE is translated */
-/* PPPIOCGIDLE is translated */
+COMPATIBLE_IOCTL(PPPIOCGIDLE32)
+COMPATIBLE_IOCTL(PPPIOCGIDLE64)
COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
COMPATIBLE_IOCTL(PPPIOCATTACH)
COMPATIBLE_IOCTL(PPPIOCDETACH)
@@ -214,16 +188,14 @@ COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS)
static long do_ioctl_trans(unsigned int cmd,
unsigned long arg, struct file *file)
{
+#ifdef CONFIG_BLOCK
void __user *argp = compat_ptr(arg);

switch (cmd) {
- case PPPIOCGIDLE32:
- return ppp_gidle(file, cmd, argp);
-#ifdef CONFIG_BLOCK
case SG_GET_REQUEST_TABLE:
return sg_grt_trans(file, cmd, argp);
-#endif
}
+#endif

return -ENOIOCTLCMD;
}
diff --git a/include/uapi/linux/ppp-ioctl.h b/include/uapi/linux/ppp-ioctl.h
index 88b5f9990320..7bd2a5a75348 100644
--- a/include/uapi/linux/ppp-ioctl.h
+++ b/include/uapi/linux/ppp-ioctl.h
@@ -104,6 +104,8 @@ struct pppol2tp_ioc_stats {
#define PPPIOCGDEBUG _IOR('t', 65, int) /* Read debug level */
#define PPPIOCSDEBUG _IOW('t', 64, int) /* Set debug level */
#define PPPIOCGIDLE _IOR('t', 63, struct ppp_idle) /* get idle time */
+#define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32) /* 32-bit times */
+#define PPPIOCGIDLE64 _IOR('t', 63, struct ppp_idle64) /* 64-bit times */
#define PPPIOCNEWUNIT _IOWR('t', 62, int) /* create new ppp unit */
#define PPPIOCATTACH _IOW('t', 61, int) /* attach to ppp unit */
#define PPPIOCDETACH _IOW('t', 60, int) /* obsolete, do not use */
diff --git a/include/uapi/linux/ppp_defs.h b/include/uapi/linux/ppp_defs.h
index fff51b91b409..0039fa39a358 100644
--- a/include/uapi/linux/ppp_defs.h
+++ b/include/uapi/linux/ppp_defs.h
@@ -142,10 +142,24 @@ struct ppp_comp_stats {
/*
* The following structure records the time in seconds since
* the last NP packet was sent or received.
+ *
+ * Linux implements both 32-bit and 64-bit time_t versions
+ * for compatibility with user space that defines ppp_idle
+ * based on the libc time_t.
*/
struct ppp_idle {
__kernel_time_t xmit_idle; /* time since last NP packet sent */
__kernel_time_t recv_idle; /* time since last NP packet received */
};

+struct ppp_idle32 {
+ __s32 xmit_idle; /* time since last NP packet sent */
+ __s32 recv_idle; /* time since last NP packet received */
+};
+
+struct ppp_idle64 {
+ __s64 xmit_idle; /* time since last NP packet sent */
+ __s64 recv_idle; /* time since last NP packet received */
+};
+
#endif /* _UAPI_PPP_DEFS_H_ */
--
2.20.0

2019-10-09 19:16:47

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 18/43] compat_ioctl: move hci_sock handlers into driver

All these ioctl commands are compatible, so we can handle
them with a trivial wrapper in hci_sock.c and remove
the listing in fs/compat_ioctl.c.

A few of the commands pass integer arguments instead of
pointers, so for correctness skip the compat_ptr() conversion
here.

Acked-by: Marcel Holtmann <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/compat_ioctl.c | 24 ------------------------
net/bluetooth/hci_sock.c | 21 ++++++++++++++++++++-
2 files changed, 20 insertions(+), 25 deletions(-)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 8dbef92b10fd..9302157d1471 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -40,9 +40,6 @@

#include "internal.h"

-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_sock.h>
-
#ifdef CONFIG_BLOCK
#include <linux/cdrom.h>
#include <linux/fd.h>
@@ -646,27 +643,6 @@ COMPATIBLE_IOCTL(RNDADDENTROPY)
COMPATIBLE_IOCTL(RNDZAPENTCNT)
COMPATIBLE_IOCTL(RNDCLEARPOOL)
/* Bluetooth */
-COMPATIBLE_IOCTL(HCIDEVUP)
-COMPATIBLE_IOCTL(HCIDEVDOWN)
-COMPATIBLE_IOCTL(HCIDEVRESET)
-COMPATIBLE_IOCTL(HCIDEVRESTAT)
-COMPATIBLE_IOCTL(HCIGETDEVLIST)
-COMPATIBLE_IOCTL(HCIGETDEVINFO)
-COMPATIBLE_IOCTL(HCIGETCONNLIST)
-COMPATIBLE_IOCTL(HCIGETCONNINFO)
-COMPATIBLE_IOCTL(HCIGETAUTHINFO)
-COMPATIBLE_IOCTL(HCISETRAW)
-COMPATIBLE_IOCTL(HCISETSCAN)
-COMPATIBLE_IOCTL(HCISETAUTH)
-COMPATIBLE_IOCTL(HCISETENCRYPT)
-COMPATIBLE_IOCTL(HCISETPTYPE)
-COMPATIBLE_IOCTL(HCISETLINKPOL)
-COMPATIBLE_IOCTL(HCISETLINKMODE)
-COMPATIBLE_IOCTL(HCISETACLMTU)
-COMPATIBLE_IOCTL(HCISETSCOMTU)
-COMPATIBLE_IOCTL(HCIBLOCKADDR)
-COMPATIBLE_IOCTL(HCIUNBLOCKADDR)
-COMPATIBLE_IOCTL(HCIINQUIRY)
COMPATIBLE_IOCTL(HCIUARTSETPROTO)
COMPATIBLE_IOCTL(HCIUARTGETPROTO)
COMPATIBLE_IOCTL(HCIUARTGETDEVICE)
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index d32077b28433..5d0ed28c0d3a 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -23,7 +23,7 @@
*/

/* Bluetooth HCI sockets. */
-
+#include <linux/compat.h>
#include <linux/export.h>
#include <linux/utsname.h>
#include <linux/sched.h>
@@ -1054,6 +1054,22 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd,
return err;
}

+#ifdef CONFIG_COMPAT
+static int hci_sock_compat_ioctl(struct socket *sock, unsigned int cmd,
+ unsigned long arg)
+{
+ switch (cmd) {
+ case HCIDEVUP:
+ case HCIDEVDOWN:
+ case HCIDEVRESET:
+ case HCIDEVRESTAT:
+ return hci_sock_ioctl(sock, cmd, arg);
+ }
+
+ return hci_sock_ioctl(sock, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
int addr_len)
{
@@ -1974,6 +1990,9 @@ static const struct proto_ops hci_sock_ops = {
.sendmsg = hci_sock_sendmsg,
.recvmsg = hci_sock_recvmsg,
.ioctl = hci_sock_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = hci_sock_compat_ioctl,
+#endif
.poll = datagram_poll,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
--
2.20.0

2019-10-09 19:16:56

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 10/43] compat_ioctl: move rtc handling into rtc-dev.c

We no longer need the rtc compat handling to be in common code, now that
all drivers are either moved to the rtc-class framework, or (rarely)
exist in drivers/char for architectures without compat mode (m68k,
alpha and ia64, respectively).

I checked the list of ioctl commands in drivers, and the ones that are
not already handled are all compatible, again with the one exception of
m68k driver, which implements RTC_PLL_GET and RTC_PLL_SET, but has no
compat mode.

Since the ioctl commands are either compatible or differ in both structure
and command code between 32-bit and 64-bit, we can merge the compat
handler into the native one and just implement the two common compat
commands (RTC_IRQP_READ, RTC_IRQP_SET) there. The result is a slight
change in behavior, as a native 64-bit process will now also handle the
32-bit commands (RTC_IRQP_SET32/RTC_IRQP_SET).

The old conversion handler also deals with RTC_EPOCH_READ and
RTC_EPOCH_SET, which are not handled in rtc-dev.c but only in a single
device driver (rtc-vr41xx), so I'm adding the compat version in the same
place. I don't expect other drivers to need those commands in the future.

Acked-by: Alexandre Belloni <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
v2: merge compat handler into ioctl function to avoid the
compat_alloc_user_space() roundtrip, based on feedback
from Al Viro.
---
drivers/rtc/dev.c | 13 +++++++++-
drivers/rtc/rtc-vr41xx.c | 10 ++++++++
fs/compat_ioctl.c | 53 ----------------------------------------
3 files changed, 22 insertions(+), 54 deletions(-)

diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c
index 84feb2565abd..1dc5063f78c9 100644
--- a/drivers/rtc/dev.c
+++ b/drivers/rtc/dev.c
@@ -10,6 +10,7 @@

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

+#include <linux/compat.h>
#include <linux/module.h>
#include <linux/rtc.h>
#include <linux/sched/signal.h>
@@ -357,10 +358,19 @@ static long rtc_dev_ioctl(struct file *file,
mutex_unlock(&rtc->ops_lock);
return rtc_update_irq_enable(rtc, 0);

+#ifdef CONFIG_64BIT
+#define RTC_IRQP_SET32 _IOW('p', 0x0c, __u32)
+#define RTC_IRQP_READ32 _IOR('p', 0x0b, __u32)
+ case RTC_IRQP_SET32:
+ err = rtc_irq_set_freq(rtc, arg);
+ break;
+ case RTC_IRQP_READ32:
+ err = put_user(rtc->irq_freq, (unsigned int __user *)uarg);
+ break;
+#endif
case RTC_IRQP_SET:
err = rtc_irq_set_freq(rtc, arg);
break;
-
case RTC_IRQP_READ:
err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);
break;
@@ -434,6 +444,7 @@ static const struct file_operations rtc_dev_fops = {
.read = rtc_dev_read,
.poll = rtc_dev_poll,
.unlocked_ioctl = rtc_dev_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
.open = rtc_dev_open,
.release = rtc_dev_release,
.fasync = rtc_dev_fasync,
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index c75230562c0d..79f27de545af 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2003-2008 Yoichi Yuasa <[email protected]>
*/
+#include <linux/compat.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/init.h>
@@ -66,6 +67,10 @@ static void __iomem *rtc2_base;
#define rtc2_read(offset) readw(rtc2_base + (offset))
#define rtc2_write(offset, value) writew((value), rtc2_base + (offset))

+/* 32-bit compat for ioctls that nobody else uses */
+#define RTC_EPOCH_READ32 _IOR('p', 0x0d, __u32)
+#define RTC_EPOCH_SET32 _IOW('p', 0x0e, __u32)
+
static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */

static DEFINE_SPINLOCK(rtc_lock);
@@ -179,6 +184,11 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
switch (cmd) {
case RTC_EPOCH_READ:
return put_user(epoch, (unsigned long __user *)arg);
+#ifdef CONFIG_64BIT
+ case RTC_EPOCH_READ32:
+ return put_user(epoch, (unsigned int __user *)arg);
+ case RTC_EPOCH_SET32:
+#endif
case RTC_EPOCH_SET:
/* Doesn't support before 1900 */
if (arg < 1900)
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index cec3ec0a1727..47da220f95b1 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -32,7 +32,6 @@
#include <linux/vt_kern.h>
#include <linux/raw.h>
#include <linux/blkdev.h>
-#include <linux/rtc.h>
#include <linux/pci.h>
#include <linux/serial.h>
#include <linux/ctype.h>
@@ -436,37 +435,6 @@ static int mt_ioctl_trans(struct file *file,
#define HCIUARTSETFLAGS _IOW('U', 203, int)
#define HCIUARTGETFLAGS _IOR('U', 204, int)

-#define RTC_IRQP_READ32 _IOR('p', 0x0b, compat_ulong_t)
-#define RTC_IRQP_SET32 _IOW('p', 0x0c, compat_ulong_t)
-#define RTC_EPOCH_READ32 _IOR('p', 0x0d, compat_ulong_t)
-#define RTC_EPOCH_SET32 _IOW('p', 0x0e, compat_ulong_t)
-
-static int rtc_ioctl(struct file *file,
- unsigned cmd, void __user *argp)
-{
- unsigned long __user *valp = compat_alloc_user_space(sizeof(*valp));
- int ret;
-
- if (valp == NULL)
- return -EFAULT;
- switch (cmd) {
- case RTC_IRQP_READ32:
- case RTC_EPOCH_READ32:
- ret = do_ioctl(file, (cmd == RTC_IRQP_READ32) ?
- RTC_IRQP_READ : RTC_EPOCH_READ,
- (unsigned long)valp);
- if (ret)
- return ret;
- return convert_in_user(valp, (unsigned int __user *)argp);
- case RTC_IRQP_SET32:
- return do_ioctl(file, RTC_IRQP_SET, (unsigned long)argp);
- case RTC_EPOCH_SET32:
- return do_ioctl(file, RTC_EPOCH_SET, (unsigned long)argp);
- }
-
- return -ENOIOCTLCMD;
-}
-
/*
* simple reversible transform to make our table more evenly
* distributed after sorting.
@@ -503,21 +471,6 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
/* Big V (don't complain on serial console) */
IGNORE_IOCTL(VT_OPENQRY)
IGNORE_IOCTL(VT_GETMODE)
-/* Little p (/dev/rtc, /dev/envctrl, etc.) */
-COMPATIBLE_IOCTL(RTC_AIE_ON)
-COMPATIBLE_IOCTL(RTC_AIE_OFF)
-COMPATIBLE_IOCTL(RTC_UIE_ON)
-COMPATIBLE_IOCTL(RTC_UIE_OFF)
-COMPATIBLE_IOCTL(RTC_PIE_ON)
-COMPATIBLE_IOCTL(RTC_PIE_OFF)
-COMPATIBLE_IOCTL(RTC_WIE_ON)
-COMPATIBLE_IOCTL(RTC_WIE_OFF)
-COMPATIBLE_IOCTL(RTC_ALM_SET)
-COMPATIBLE_IOCTL(RTC_ALM_READ)
-COMPATIBLE_IOCTL(RTC_RD_TIME)
-COMPATIBLE_IOCTL(RTC_SET_TIME)
-COMPATIBLE_IOCTL(RTC_WKALM_SET)
-COMPATIBLE_IOCTL(RTC_WKALM_RD)
/*
* These two are only for the sbus rtc driver, but
* hwclock tries them on every rtc device first when
@@ -897,12 +850,6 @@ static long do_ioctl_trans(unsigned int cmd,
case MTIOCPOS32:
return mt_ioctl_trans(file, cmd, argp);
#endif
- /* Not implemented in the native kernel */
- case RTC_IRQP_READ32:
- case RTC_IRQP_SET32:
- case RTC_EPOCH_READ32:
- case RTC_EPOCH_SET32:
- return rtc_ioctl(file, cmd, argp);
}

/*
--
2.20.0

2019-10-09 19:17:17

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 36/43] tty: handle compat PPP ioctls

Multiple tty devices are have tty devices that handle the
PPPIOCGUNIT and PPPIOCGCHAN ioctls. To avoid adding a compat_ioctl
handler to each of those, add it directly in tty_compat_ioctl
so we can remove the calls from fs/compat_ioctl.c.

Reviewed-by: Greg Kroah-Hartman <[email protected]>
Cc: Paul Mackerras <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
drivers/tty/tty_io.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index c09691b20a25..a81807b394d1 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -87,6 +87,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/poll.h>
+#include <linux/ppp-ioctl.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -2811,6 +2812,9 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd,
#endif
case TIOCGSOFTCAR:
case TIOCSSOFTCAR:
+
+ case PPPIOCGCHAN:
+ case PPPIOCGUNIT:
return tty_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
case TIOCCONS:
case TIOCEXCL:
--
2.20.0

2019-10-09 19:17:18

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 07/43] ceph: fix compat_ioctl for ceph_dir_operations

The ceph_ioctl function is used both for files and directories, but only
the files support doing that in 32-bit compat mode.

For consistency, add the same compat handler to the dir operations
as well, and use a handler that applies the appropriate compat_ptr()
conversion.

Reviewed-by: "Yan, Zheng" <[email protected]>
Cc: [email protected]
Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/ceph/dir.c | 1 +
fs/ceph/file.c | 2 +-
fs/ceph/super.h | 10 ++++++++++
3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index 4ca0b8ff9a72..401c17d36b71 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -1808,6 +1808,7 @@ const struct file_operations ceph_dir_fops = {
.open = ceph_open,
.release = ceph_release,
.unlocked_ioctl = ceph_ioctl,
+ .compat_ioctl = ceph_compat_ioctl,
.fsync = ceph_fsync,
.lock = ceph_lock,
.flock = ceph_flock,
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index d277f71abe0b..9e8e4bfe1d50 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -2162,7 +2162,7 @@ const struct file_operations ceph_file_fops = {
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.unlocked_ioctl = ceph_ioctl,
- .compat_ioctl = ceph_ioctl,
+ .compat_ioctl = ceph_compat_ioctl,
.fallocate = ceph_fallocate,
.copy_file_range = ceph_copy_file_range,
};
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index f98d9247f9cb..87bf9db76f98 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -6,6 +6,7 @@

#include <asm/unaligned.h>
#include <linux/backing-dev.h>
+#include <linux/compat.h>
#include <linux/completion.h>
#include <linux/exportfs.h>
#include <linux/fs.h>
@@ -1123,6 +1124,15 @@ extern void ceph_readdir_cache_release(struct ceph_readdir_cache_control *ctl);

/* ioctl.c */
extern long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+static inline long
+ceph_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+#ifdef CONFIG_COMPAT
+ return ceph_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
+#else
+ return -ENOTTY;
+#endif
+}

/* export.c */
extern const struct export_operations ceph_export_ops;
--
2.20.0

2019-10-09 19:17:28

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 13/43] compat_ioctl: use correct compat_ptr() translation in drivers

A handful of drivers all have a trivial wrapper around their ioctl
handler, but don't call the compat_ptr() conversion function at the
moment. In practice this does not matter, since none of them are used
on the s390 architecture and for all other architectures, compat_ptr()
does not do anything, but using the new compat_ptr_ioctl()
helper makes it more correct in theory, and simplifies the code.

I checked that all ioctl handlers in these files are compatible
and take either pointer arguments or no argument.

Acked-by: Al Viro <[email protected]>
Acked-by: Greg Kroah-Hartman <[email protected]>
Acked-by: Andrew Donnellan <[email protected]>
Acked-by: Felipe Balbi <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
drivers/misc/cxl/flash.c | 8 +-------
drivers/misc/genwqe/card_dev.c | 23 +----------------------
drivers/scsi/megaraid/megaraid_mm.c | 28 +---------------------------
drivers/usb/gadget/function/f_fs.c | 12 +-----------
4 files changed, 4 insertions(+), 67 deletions(-)

diff --git a/drivers/misc/cxl/flash.c b/drivers/misc/cxl/flash.c
index 4d6836f19489..cb9cca35a226 100644
--- a/drivers/misc/cxl/flash.c
+++ b/drivers/misc/cxl/flash.c
@@ -473,12 +473,6 @@ static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return -EINVAL;
}

-static long device_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- return device_ioctl(file, cmd, arg);
-}
-
static int device_close(struct inode *inode, struct file *file)
{
struct cxl *adapter = file->private_data;
@@ -514,7 +508,7 @@ static const struct file_operations fops = {
.owner = THIS_MODULE,
.open = device_open,
.unlocked_ioctl = device_ioctl,
- .compat_ioctl = device_compat_ioctl,
+ .compat_ioctl = compat_ptr_ioctl,
.release = device_close,
};

diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c
index 0e34c0568fed..040a0bda3125 100644
--- a/drivers/misc/genwqe/card_dev.c
+++ b/drivers/misc/genwqe/card_dev.c
@@ -1215,34 +1215,13 @@ static long genwqe_ioctl(struct file *filp, unsigned int cmd,
return rc;
}

-#if defined(CONFIG_COMPAT)
-/**
- * genwqe_compat_ioctl() - Compatibility ioctl
- *
- * Called whenever a 32-bit process running under a 64-bit kernel
- * performs an ioctl on /dev/genwqe<n>_card.
- *
- * @filp: file pointer.
- * @cmd: command.
- * @arg: user argument.
- * Return: zero on success or negative number on failure.
- */
-static long genwqe_compat_ioctl(struct file *filp, unsigned int cmd,
- unsigned long arg)
-{
- return genwqe_ioctl(filp, cmd, arg);
-}
-#endif /* defined(CONFIG_COMPAT) */
-
static const struct file_operations genwqe_fops = {
.owner = THIS_MODULE,
.open = genwqe_open,
.fasync = genwqe_fasync,
.mmap = genwqe_mmap,
.unlocked_ioctl = genwqe_ioctl,
-#if defined(CONFIG_COMPAT)
- .compat_ioctl = genwqe_compat_ioctl,
-#endif
+ .compat_ioctl = compat_ptr_ioctl,
.release = genwqe_release,
};

diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index 59cca898f088..e83163c66884 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -41,10 +41,6 @@ static int mraid_mm_setup_dma_pools(mraid_mmadp_t *);
static void mraid_mm_free_adp_resources(mraid_mmadp_t *);
static void mraid_mm_teardown_dma_pools(mraid_mmadp_t *);

-#ifdef CONFIG_COMPAT
-static long mraid_mm_compat_ioctl(struct file *, unsigned int, unsigned long);
-#endif
-
MODULE_AUTHOR("LSI Logic Corporation");
MODULE_DESCRIPTION("LSI Logic Management Module");
MODULE_LICENSE("GPL");
@@ -68,9 +64,7 @@ static wait_queue_head_t wait_q;
static const struct file_operations lsi_fops = {
.open = mraid_mm_open,
.unlocked_ioctl = mraid_mm_unlocked_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = mraid_mm_compat_ioctl,
-#endif
+ .compat_ioctl = compat_ptr_ioctl,
.owner = THIS_MODULE,
.llseek = noop_llseek,
};
@@ -224,7 +218,6 @@ mraid_mm_unlocked_ioctl(struct file *filep, unsigned int cmd,
{
int err;

- /* inconsistent: mraid_mm_compat_ioctl doesn't take the BKL */
mutex_lock(&mraid_mm_mutex);
err = mraid_mm_ioctl(filep, cmd, arg);
mutex_unlock(&mraid_mm_mutex);
@@ -1228,25 +1221,6 @@ mraid_mm_init(void)
}


-#ifdef CONFIG_COMPAT
-/**
- * mraid_mm_compat_ioctl - 32bit to 64bit ioctl conversion routine
- * @filep : file operations pointer (ignored)
- * @cmd : ioctl command
- * @arg : user ioctl packet
- */
-static long
-mraid_mm_compat_ioctl(struct file *filep, unsigned int cmd,
- unsigned long arg)
-{
- int err;
-
- err = mraid_mm_ioctl(filep, cmd, arg);
-
- return err;
-}
-#endif
-
/**
* mraid_mm_exit - Module exit point
*/
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 59d9d512dcda..ce1d0235969c 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1352,14 +1352,6 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code,
return ret;
}

-#ifdef CONFIG_COMPAT
-static long ffs_epfile_compat_ioctl(struct file *file, unsigned code,
- unsigned long value)
-{
- return ffs_epfile_ioctl(file, code, value);
-}
-#endif
-
static const struct file_operations ffs_epfile_operations = {
.llseek = no_llseek,

@@ -1368,9 +1360,7 @@ static const struct file_operations ffs_epfile_operations = {
.read_iter = ffs_epfile_read_iter,
.release = ffs_epfile_release,
.unlocked_ioctl = ffs_epfile_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = ffs_epfile_compat_ioctl,
-#endif
+ .compat_ioctl = compat_ptr_ioctl,
};


--
2.20.0

2019-10-09 19:17:29

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 03/43] compat: itanic doesn't have one

From: Al Viro <[email protected]>

... and hadn't for a long time.

Signed-off-by: Al Viro <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/compat_ioctl.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index a979b7d1ed90..46e8a8f8b6f1 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -468,7 +468,7 @@ static int rtc_ioctl(struct file *file,
}

/* on ia32 l_start is on a 32-bit boundary */
-#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
+#if defined(CONFIG_X86_64)
struct space_resv_32 {
__s16 l_type;
__s16 l_whence;
@@ -1019,7 +1019,7 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
case FIOQSIZE:
break;

-#if defined(CONFIG_IA64) || defined(CONFIG_X86_64)
+#if defined(CONFIG_X86_64)
case FS_IOC_RESVSP_32:
case FS_IOC_RESVSP64_32:
error = compat_ioctl_preallocate(f.file, compat_ptr(arg));
--
2.20.0

2019-10-09 19:17:29

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 05/43] compat: move FS_IOC_RESVSP_32 handling to fs/ioctl.c

From: Al Viro <[email protected]>

... and lose the ridiculous games with compat_alloc_user_space()
there.

Signed-off-by: Al Viro <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/compat_ioctl.c | 35 -----------------------------------
fs/ioctl.c | 29 +++++++++++++++++++++++++++++
include/linux/falloc.h | 20 ++++++++++++++++++++
3 files changed, 49 insertions(+), 35 deletions(-)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 46e8a8f8b6f1..ce995d4fa1f4 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -467,41 +467,6 @@ static int rtc_ioctl(struct file *file,
return -ENOIOCTLCMD;
}

-/* on ia32 l_start is on a 32-bit boundary */
-#if defined(CONFIG_X86_64)
-struct space_resv_32 {
- __s16 l_type;
- __s16 l_whence;
- __s64 l_start __attribute__((packed));
- /* len == 0 means until end of file */
- __s64 l_len __attribute__((packed));
- __s32 l_sysid;
- __u32 l_pid;
- __s32 l_pad[4]; /* reserve area */
-};
-
-#define FS_IOC_RESVSP_32 _IOW ('X', 40, struct space_resv_32)
-#define FS_IOC_RESVSP64_32 _IOW ('X', 42, struct space_resv_32)
-
-/* just account for different alignment */
-static int compat_ioctl_preallocate(struct file *file,
- struct space_resv_32 __user *p32)
-{
- struct space_resv __user *p = compat_alloc_user_space(sizeof(*p));
-
- if (copy_in_user(&p->l_type, &p32->l_type, sizeof(s16)) ||
- copy_in_user(&p->l_whence, &p32->l_whence, sizeof(s16)) ||
- copy_in_user(&p->l_start, &p32->l_start, sizeof(s64)) ||
- copy_in_user(&p->l_len, &p32->l_len, sizeof(s64)) ||
- copy_in_user(&p->l_sysid, &p32->l_sysid, sizeof(s32)) ||
- copy_in_user(&p->l_pid, &p32->l_pid, sizeof(u32)) ||
- copy_in_user(&p->l_pad, &p32->l_pad, 4*sizeof(u32)))
- return -EFAULT;
-
- return ioctl_preallocate(file, p);
-}
-#endif
-
/*
* simple reversible transform to make our table more evenly
* distributed after sorting.
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 3f28b39f32f3..9d26251f34a9 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -490,6 +490,35 @@ int ioctl_preallocate(struct file *filp, void __user *argp)
return vfs_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
}

+/* on ia32 l_start is on a 32-bit boundary */
+#if defined CONFIG_COMPAT && defined(CONFIG_X86_64)
+/* just account for different alignment */
+int compat_ioctl_preallocate(struct file *file,
+ struct space_resv_32 __user *argp)
+{
+ struct inode *inode = file_inode(file);
+ struct space_resv_32 sr;
+
+ if (copy_from_user(&sr, argp, sizeof(sr)))
+ return -EFAULT;
+
+ switch (sr.l_whence) {
+ case SEEK_SET:
+ break;
+ case SEEK_CUR:
+ sr.l_start += file->f_pos;
+ break;
+ case SEEK_END:
+ sr.l_start += i_size_read(inode);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return vfs_fallocate(file, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len);
+}
+#endif
+
static int file_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
diff --git a/include/linux/falloc.h b/include/linux/falloc.h
index 674d59f4d6ce..fc61fdb9d1e9 100644
--- a/include/linux/falloc.h
+++ b/include/linux/falloc.h
@@ -29,4 +29,24 @@ struct space_resv {
FALLOC_FL_INSERT_RANGE | \
FALLOC_FL_UNSHARE_RANGE)

+/* on ia32 l_start is on a 32-bit boundary */
+#if defined(CONFIG_X86_64)
+struct space_resv_32 {
+ __s16 l_type;
+ __s16 l_whence;
+ __s64 l_start __attribute__((packed));
+ /* len == 0 means until end of file */
+ __s64 l_len __attribute__((packed));
+ __s32 l_sysid;
+ __u32 l_pid;
+ __s32 l_pad[4]; /* reserve area */
+};
+
+#define FS_IOC_RESVSP_32 _IOW ('X', 40, struct space_resv_32)
+#define FS_IOC_RESVSP64_32 _IOW ('X', 42, struct space_resv_32)
+
+int compat_ioctl_preallocate(struct file *, struct space_resv_32 __user *);
+
+#endif
+
#endif /* _FALLOC_H_ */
--
2.20.0

2019-10-09 19:17:34

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 06/43] compat_sys_ioctl(): make parallel to do_vfs_ioctl()

From: Al Viro <[email protected]>

Handle ioctls that might be handled without reaching ->ioctl() in
native case on the top level there. The counterpart of vfs_ioctl()
(i.e. calling ->unlock_ioctl(), etc.) left as-is; eventually
that would turn simply into the call of ->compat_ioctl(), but
that'll take more work. Once that is done, we can move the
remains of compat_sys_ioctl() into fs/ioctl.c and finally bury
fs/compat_ioctl.c.

Signed-off-by: Al Viro <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/compat_ioctl.c | 63 +++++++++++++++++++++--------------------------
1 file changed, 28 insertions(+), 35 deletions(-)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index ce995d4fa1f4..ecbd5254b547 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -487,19 +487,7 @@ static unsigned int ioctl_pointer[] = {
/* compatible ioctls first */
/* Little t */
COMPATIBLE_IOCTL(TIOCOUTQ)
-/* Little f */
-COMPATIBLE_IOCTL(FIOCLEX)
-COMPATIBLE_IOCTL(FIONCLEX)
-COMPATIBLE_IOCTL(FIOASYNC)
-COMPATIBLE_IOCTL(FIONBIO)
-COMPATIBLE_IOCTL(FIONREAD) /* This is also TIOCINQ */
-COMPATIBLE_IOCTL(FS_IOC_FIEMAP)
-/* 0x00 */
-COMPATIBLE_IOCTL(FIBMAP)
-COMPATIBLE_IOCTL(FIGETBSZ)
/* 'X' - originally XFS but some now in the VFS */
-COMPATIBLE_IOCTL(FIFREEZE)
-COMPATIBLE_IOCTL(FITHAW)
COMPATIBLE_IOCTL(FITRIM)
#ifdef CONFIG_BLOCK
/* Big S */
@@ -971,19 +959,39 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
if (error)
goto out_fput;

- /*
- * To allow the compat_ioctl handlers to be self contained
- * we need to check the common ioctls here first.
- * Just handle them with the standard handlers below.
- */
switch (cmd) {
+ /* these are never seen by ->ioctl(), no argument or int argument */
case FIOCLEX:
case FIONCLEX:
+ case FIFREEZE:
+ case FITHAW:
+ case FICLONE:
+ goto do_ioctl;
+ /* these are never seen by ->ioctl(), pointer argument */
case FIONBIO:
case FIOASYNC:
case FIOQSIZE:
- break;
-
+ case FS_IOC_FIEMAP:
+ case FIGETBSZ:
+ case FICLONERANGE:
+ case FIDEDUPERANGE:
+ goto found_handler;
+ /*
+ * The next group is the stuff handled inside file_ioctl().
+ * For regular files these never reach ->ioctl(); for
+ * devices, sockets, etc. they do and one (FIONREAD) is
+ * even accepted in some cases. In all those cases
+ * argument has the same type, so we can handle these
+ * here, shunting them towards do_vfs_ioctl().
+ * ->compat_ioctl() will never see any of those.
+ */
+ /* pointer argument, never actually handled by ->ioctl() */
+ case FIBMAP:
+ goto found_handler;
+ /* handled by some ->ioctl(); always a pointer to int */
+ case FIONREAD:
+ goto found_handler;
+ /* these two get messy on amd64 due to alignment differences */
#if defined(CONFIG_X86_64)
case FS_IOC_RESVSP_32:
case FS_IOC_RESVSP64_32:
@@ -992,23 +1000,8 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
#else
case FS_IOC_RESVSP:
case FS_IOC_RESVSP64:
- error = ioctl_preallocate(f.file, compat_ptr(arg));
- goto out_fput;
-#endif
-
- case FICLONE:
- goto do_ioctl;
- case FICLONERANGE:
- case FIDEDUPERANGE:
- case FS_IOC_FIEMAP:
- case FIGETBSZ:
goto found_handler;
-
- case FIBMAP:
- case FIONREAD:
- if (S_ISREG(file_inode(f.file)->i_mode))
- break;
- /*FALL THROUGH*/
+#endif

default:
if (f.file->f_op->compat_ioctl) {
--
2.20.0

2019-10-09 19:18:39

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 01/43] fix compat handling of FICLONERANGE, FIDEDUPERANGE and FS_IOC_FIEMAP

From: Al Viro <[email protected]>

Unlike FICLONE, all of those take a pointer argument; they do need
compat_ptr() applied to arg.

Fixes: d79bdd52d8be ("vfs: wire up compat ioctl for CLONE/CLONE_RANGE")
Fixes: 54dbc1517237 ("vfs: hoist the btrfs deduplication ioctl to the vfs")
Fixes: ceac204e1da9 ("fs: make fiemap work from compat_ioctl")
Signed-off-by: Al Viro <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/compat_ioctl.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index a7ec2d3dff92..e0226b2138d6 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1032,10 +1032,11 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
#endif

case FICLONE:
+ goto do_ioctl;
case FICLONERANGE:
case FIDEDUPERANGE:
case FS_IOC_FIEMAP:
- goto do_ioctl;
+ goto found_handler;

case FIBMAP:
case FIGETBSZ:
--
2.20.0

2019-10-09 19:18:40

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 22/43] compat_ioctl: remove IGNORE_IOCTL()

Since commit 07d106d0a33d ("vfs: fix up ENOIOCTLCMD error handling"),
we don't warn about unhandled compat-ioctl command code any more, but
just return the same error that a native file descriptor returns when
there is no handler.

This means the IGNORE_IOCTL() annotations are completely useless and
can all be removed. TIOCSTART/TIOCSTOP and KDGHWCLK/KDSHWCLK fall into
the same category, but for some reason were listed as COMPATIBLE_IOCTL().

Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/compat_ioctl.c | 56 -----------------------------------------------
1 file changed, 56 deletions(-)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 33f732979f45..10dfe4d80bbd 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -56,11 +56,6 @@

#include <linux/sort.h>

-#ifdef CONFIG_SPARC
-#include <linux/fb.h>
-#include <asm/fbio.h>
-#endif
-
#define convert_in_user(srcptr, dstptr) \
({ \
typeof(*srcptr) val; \
@@ -358,17 +353,7 @@ static int ppp_scompress(struct file *file, unsigned int cmd,
#define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)

#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd),
-/* ioctl should not be warned about even if it's not implemented.
- Valid reasons to use this:
- - It is implemented with ->compat_ioctl on some device, but programs
- call it on others too.
- - The ioctl is not implemented in the native kernel, but programs
- call it commonly anyways.
- Most other reasons are not valid. */
-#define IGNORE_IOCTL(cmd) COMPATIBLE_IOCTL(cmd)
-
static unsigned int ioctl_pointer[] = {
-/* compatible ioctls first */
/* Little t */
COMPATIBLE_IOCTL(TIOCOUTQ)
/* 'X' - originally XFS but some now in the VFS */
@@ -384,23 +369,7 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
#endif
-/* Big V (don't complain on serial console) */
-IGNORE_IOCTL(VT_OPENQRY)
-IGNORE_IOCTL(VT_GETMODE)
-/*
- * These two are only for the sbus rtc driver, but
- * hwclock tries them on every rtc device first when
- * running on sparc. On other architectures the entries
- * are useless but harmless.
- */
-COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */
-COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */
#ifdef CONFIG_BLOCK
-/* md calls this on random blockdevs */
-IGNORE_IOCTL(RAID_VERSION)
-/* qemu/qemu-img might call these two on plain files for probing */
-IGNORE_IOCTL(CDROM_DRIVE_STATUS)
-IGNORE_IOCTL(FDGETPRM32)
/* SG stuff */
COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
@@ -487,31 +456,6 @@ COMPATIBLE_IOCTL(JSIOCGVERSION)
COMPATIBLE_IOCTL(JSIOCGAXES)
COMPATIBLE_IOCTL(JSIOCGBUTTONS)
COMPATIBLE_IOCTL(JSIOCGNAME(0))
-
-/* fat 'r' ioctls. These are handled by fat with ->compat_ioctl,
- but we don't want warnings on other file systems. So declare
- them as compatible here. */
-#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2])
-#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2])
-
-IGNORE_IOCTL(VFAT_IOCTL_READDIR_BOTH32)
-IGNORE_IOCTL(VFAT_IOCTL_READDIR_SHORT32)
-
-#ifdef CONFIG_SPARC
-/* Sparc framebuffers, handled in sbusfb_compat_ioctl() */
-IGNORE_IOCTL(FBIOGTYPE)
-IGNORE_IOCTL(FBIOSATTR)
-IGNORE_IOCTL(FBIOGATTR)
-IGNORE_IOCTL(FBIOSVIDEO)
-IGNORE_IOCTL(FBIOGVIDEO)
-IGNORE_IOCTL(FBIOSCURPOS)
-IGNORE_IOCTL(FBIOGCURPOS)
-IGNORE_IOCTL(FBIOGCURMAX)
-IGNORE_IOCTL(FBIOPUTCMAP32)
-IGNORE_IOCTL(FBIOGETCMAP32)
-IGNORE_IOCTL(FBIOSCURSOR32)
-IGNORE_IOCTL(FBIOGCURSOR32)
-#endif
};

/*
--
2.20.0

2019-10-09 19:19:05

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 02/43] FIGETBSZ: fix compat

From: Al Viro <[email protected]>

it takes a pointer argument, regular file or no regular file

Signed-off-by: Al Viro <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/compat_ioctl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index e0226b2138d6..a979b7d1ed90 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1036,10 +1036,10 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
case FICLONERANGE:
case FIDEDUPERANGE:
case FS_IOC_FIEMAP:
+ case FIGETBSZ:
goto found_handler;

case FIBMAP:
- case FIGETBSZ:
case FIONREAD:
if (S_ISREG(file_inode(f.file)->i_mode))
break;
--
2.20.0

2019-10-09 19:19:26

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 04/43] do_vfs_ioctl(): use saner types

From: Al Viro <[email protected]>

casting to pointer to int, only to pass that to function that
takes pointer to void and uses it as pointer to structure is
really asking for trouble.

"Some pointer, I'm not sure what to" is spelled "void *",
not "int *"; use that.

And declare the functions we are passing that pointer to
as taking the pointer to what they really want to access.

Signed-off-by: Al Viro <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/ioctl.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/fs/ioctl.c b/fs/ioctl.c
index fef3a6bf7c78..3f28b39f32f3 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -174,10 +174,9 @@ static int fiemap_check_ranges(struct super_block *sb,
return 0;
}

-static int ioctl_fiemap(struct file *filp, unsigned long arg)
+static int ioctl_fiemap(struct file *filp, struct fiemap __user *ufiemap)
{
struct fiemap fiemap;
- struct fiemap __user *ufiemap = (struct fiemap __user *) arg;
struct fiemap_extent_info fieinfo = { 0, };
struct inode *inode = file_inode(filp);
struct super_block *sb = inode->i_sb;
@@ -244,7 +243,8 @@ static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd,
return ret;
}

-static long ioctl_file_clone_range(struct file *file, void __user *argp)
+static long ioctl_file_clone_range(struct file *file,
+ struct file_clone_range __user *argp)
{
struct file_clone_range args;

@@ -584,9 +584,9 @@ static int ioctl_fsthaw(struct file *filp)
return thaw_super(sb);
}

-static int ioctl_file_dedupe_range(struct file *file, void __user *arg)
+static int ioctl_file_dedupe_range(struct file *file,
+ struct file_dedupe_range __user *argp)
{
- struct file_dedupe_range __user *argp = arg;
struct file_dedupe_range *same = NULL;
int ret;
unsigned long size;
@@ -635,7 +635,7 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
unsigned long arg)
{
int error = 0;
- int __user *argp = (int __user *)arg;
+ void __user *argp = (void __user *)arg;
struct inode *inode = file_inode(filp);

switch (cmd) {
@@ -674,13 +674,13 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
break;

case FS_IOC_FIEMAP:
- return ioctl_fiemap(filp, arg);
+ return ioctl_fiemap(filp, argp);

case FIGETBSZ:
/* anon_bdev filesystems may not have a block size */
if (!inode->i_sb->s_blocksize)
return -EINVAL;
- return put_user(inode->i_sb->s_blocksize, argp);
+ return put_user(inode->i_sb->s_blocksize, (int __user *)argp);

case FICLONE:
return ioctl_file_clone(filp, arg, 0, 0, 0);
--
2.20.0

2019-10-09 19:19:28

by Arnd Bergmann

[permalink] [raw]
Subject: [PATCH v6 08/43] compat_ioctl: drop FIOQSIZE table entry

This is already handled by the compat_ioctl() function itself.

Signed-off-by: Arnd Bergmann <[email protected]>
---
fs/compat_ioctl.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index ecbd5254b547..cec3ec0a1727 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -528,8 +528,6 @@ COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */
COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */
/* Little m */
COMPATIBLE_IOCTL(MTIOCTOP)
-/* Socket level stuff */
-COMPATIBLE_IOCTL(FIOQSIZE)
#ifdef CONFIG_BLOCK
/* md calls this on random blockdevs */
IGNORE_IOCTL(RAID_VERSION)
--
2.20.0

2019-10-09 19:25:58

by Alexandre Belloni

[permalink] [raw]
Subject: Re: [PATCH v6 10/43] compat_ioctl: move rtc handling into rtc-dev.c

Hi,

If you ever have to resend, the file is now named rtc/dev.c so you could
adjust the subject.

On 09/10/2019 21:10:10+0200, Arnd Bergmann wrote:
> We no longer need the rtc compat handling to be in common code, now that
> all drivers are either moved to the rtc-class framework, or (rarely)
> exist in drivers/char for architectures without compat mode (m68k,
> alpha and ia64, respectively).
>
> I checked the list of ioctl commands in drivers, and the ones that are
> not already handled are all compatible, again with the one exception of
> m68k driver, which implements RTC_PLL_GET and RTC_PLL_SET, but has no
> compat mode.
>
> Since the ioctl commands are either compatible or differ in both structure
> and command code between 32-bit and 64-bit, we can merge the compat
> handler into the native one and just implement the two common compat
> commands (RTC_IRQP_READ, RTC_IRQP_SET) there. The result is a slight
> change in behavior, as a native 64-bit process will now also handle the
> 32-bit commands (RTC_IRQP_SET32/RTC_IRQP_SET).
>
> The old conversion handler also deals with RTC_EPOCH_READ and
> RTC_EPOCH_SET, which are not handled in rtc-dev.c but only in a single
> device driver (rtc-vr41xx), so I'm adding the compat version in the same
> place. I don't expect other drivers to need those commands in the future.
>
> Acked-by: Alexandre Belloni <[email protected]>
> Signed-off-by: Arnd Bergmann <[email protected]>
> ---
> v2: merge compat handler into ioctl function to avoid the
> compat_alloc_user_space() roundtrip, based on feedback
> from Al Viro.
> ---
> drivers/rtc/dev.c | 13 +++++++++-
> drivers/rtc/rtc-vr41xx.c | 10 ++++++++
> fs/compat_ioctl.c | 53 ----------------------------------------
> 3 files changed, 22 insertions(+), 54 deletions(-)
>
> diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c
> index 84feb2565abd..1dc5063f78c9 100644
> --- a/drivers/rtc/dev.c
> +++ b/drivers/rtc/dev.c
> @@ -10,6 +10,7 @@
>
> #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>
> +#include <linux/compat.h>
> #include <linux/module.h>
> #include <linux/rtc.h>
> #include <linux/sched/signal.h>
> @@ -357,10 +358,19 @@ static long rtc_dev_ioctl(struct file *file,
> mutex_unlock(&rtc->ops_lock);
> return rtc_update_irq_enable(rtc, 0);
>
> +#ifdef CONFIG_64BIT
> +#define RTC_IRQP_SET32 _IOW('p', 0x0c, __u32)
> +#define RTC_IRQP_READ32 _IOR('p', 0x0b, __u32)
> + case RTC_IRQP_SET32:
> + err = rtc_irq_set_freq(rtc, arg);
> + break;
> + case RTC_IRQP_READ32:
> + err = put_user(rtc->irq_freq, (unsigned int __user *)uarg);
> + break;
> +#endif
> case RTC_IRQP_SET:
> err = rtc_irq_set_freq(rtc, arg);
> break;
> -
> case RTC_IRQP_READ:
> err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);
> break;
> @@ -434,6 +444,7 @@ static const struct file_operations rtc_dev_fops = {
> .read = rtc_dev_read,
> .poll = rtc_dev_poll,
> .unlocked_ioctl = rtc_dev_ioctl,
> + .compat_ioctl = compat_ptr_ioctl,
> .open = rtc_dev_open,
> .release = rtc_dev_release,
> .fasync = rtc_dev_fasync,
> diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
> index c75230562c0d..79f27de545af 100644
> --- a/drivers/rtc/rtc-vr41xx.c
> +++ b/drivers/rtc/rtc-vr41xx.c
> @@ -4,6 +4,7 @@
> *
> * Copyright (C) 2003-2008 Yoichi Yuasa <[email protected]>
> */
> +#include <linux/compat.h>
> #include <linux/err.h>
> #include <linux/fs.h>
> #include <linux/init.h>
> @@ -66,6 +67,10 @@ static void __iomem *rtc2_base;
> #define rtc2_read(offset) readw(rtc2_base + (offset))
> #define rtc2_write(offset, value) writew((value), rtc2_base + (offset))
>
> +/* 32-bit compat for ioctls that nobody else uses */
> +#define RTC_EPOCH_READ32 _IOR('p', 0x0d, __u32)
> +#define RTC_EPOCH_SET32 _IOW('p', 0x0e, __u32)
> +
> static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */
>
> static DEFINE_SPINLOCK(rtc_lock);
> @@ -179,6 +184,11 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
> switch (cmd) {
> case RTC_EPOCH_READ:
> return put_user(epoch, (unsigned long __user *)arg);
> +#ifdef CONFIG_64BIT
> + case RTC_EPOCH_READ32:
> + return put_user(epoch, (unsigned int __user *)arg);
> + case RTC_EPOCH_SET32:
> +#endif
> case RTC_EPOCH_SET:
> /* Doesn't support before 1900 */
> if (arg < 1900)
> diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
> index cec3ec0a1727..47da220f95b1 100644
> --- a/fs/compat_ioctl.c
> +++ b/fs/compat_ioctl.c
> @@ -32,7 +32,6 @@
> #include <linux/vt_kern.h>
> #include <linux/raw.h>
> #include <linux/blkdev.h>
> -#include <linux/rtc.h>
> #include <linux/pci.h>
> #include <linux/serial.h>
> #include <linux/ctype.h>
> @@ -436,37 +435,6 @@ static int mt_ioctl_trans(struct file *file,
> #define HCIUARTSETFLAGS _IOW('U', 203, int)
> #define HCIUARTGETFLAGS _IOR('U', 204, int)
>
> -#define RTC_IRQP_READ32 _IOR('p', 0x0b, compat_ulong_t)
> -#define RTC_IRQP_SET32 _IOW('p', 0x0c, compat_ulong_t)
> -#define RTC_EPOCH_READ32 _IOR('p', 0x0d, compat_ulong_t)
> -#define RTC_EPOCH_SET32 _IOW('p', 0x0e, compat_ulong_t)
> -
> -static int rtc_ioctl(struct file *file,
> - unsigned cmd, void __user *argp)
> -{
> - unsigned long __user *valp = compat_alloc_user_space(sizeof(*valp));
> - int ret;
> -
> - if (valp == NULL)
> - return -EFAULT;
> - switch (cmd) {
> - case RTC_IRQP_READ32:
> - case RTC_EPOCH_READ32:
> - ret = do_ioctl(file, (cmd == RTC_IRQP_READ32) ?
> - RTC_IRQP_READ : RTC_EPOCH_READ,
> - (unsigned long)valp);
> - if (ret)
> - return ret;
> - return convert_in_user(valp, (unsigned int __user *)argp);
> - case RTC_IRQP_SET32:
> - return do_ioctl(file, RTC_IRQP_SET, (unsigned long)argp);
> - case RTC_EPOCH_SET32:
> - return do_ioctl(file, RTC_EPOCH_SET, (unsigned long)argp);
> - }
> -
> - return -ENOIOCTLCMD;
> -}
> -
> /*
> * simple reversible transform to make our table more evenly
> * distributed after sorting.
> @@ -503,21 +471,6 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
> /* Big V (don't complain on serial console) */
> IGNORE_IOCTL(VT_OPENQRY)
> IGNORE_IOCTL(VT_GETMODE)
> -/* Little p (/dev/rtc, /dev/envctrl, etc.) */
> -COMPATIBLE_IOCTL(RTC_AIE_ON)
> -COMPATIBLE_IOCTL(RTC_AIE_OFF)
> -COMPATIBLE_IOCTL(RTC_UIE_ON)
> -COMPATIBLE_IOCTL(RTC_UIE_OFF)
> -COMPATIBLE_IOCTL(RTC_PIE_ON)
> -COMPATIBLE_IOCTL(RTC_PIE_OFF)
> -COMPATIBLE_IOCTL(RTC_WIE_ON)
> -COMPATIBLE_IOCTL(RTC_WIE_OFF)
> -COMPATIBLE_IOCTL(RTC_ALM_SET)
> -COMPATIBLE_IOCTL(RTC_ALM_READ)
> -COMPATIBLE_IOCTL(RTC_RD_TIME)
> -COMPATIBLE_IOCTL(RTC_SET_TIME)
> -COMPATIBLE_IOCTL(RTC_WKALM_SET)
> -COMPATIBLE_IOCTL(RTC_WKALM_RD)
> /*
> * These two are only for the sbus rtc driver, but
> * hwclock tries them on every rtc device first when
> @@ -897,12 +850,6 @@ static long do_ioctl_trans(unsigned int cmd,
> case MTIOCPOS32:
> return mt_ioctl_trans(file, cmd, argp);
> #endif
> - /* Not implemented in the native kernel */
> - case RTC_IRQP_READ32:
> - case RTC_IRQP_SET32:
> - case RTC_EPOCH_READ32:
> - case RTC_EPOCH_SET32:
> - return rtc_ioctl(file, cmd, argp);
> }
>
> /*
> --
> 2.20.0
>

--
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

2019-10-09 19:33:57

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v6 10/43] compat_ioctl: move rtc handling into rtc-dev.c

On Wed, Oct 9, 2019 at 9:25 PM Alexandre Belloni
<[email protected]> wrote:
>
> If you ever have to resend, the file is now named rtc/dev.c so you could
> adjust the subject.

Ok, I fixed up my local copy.

Arnd

2019-10-18 16:12:02

by Ben Hutchings

[permalink] [raw]
Subject: Re: [Y2038] [PATCH v6 10/43] compat_ioctl: move rtc handling into rtc-dev.c

On Wed, 2019-10-09 at 21:10 +0200, Arnd Bergmann wrote:
> We no longer need the rtc compat handling to be in common code, now that
> all drivers are either moved to the rtc-class framework, or (rarely)
> exist in drivers/char for architectures without compat mode (m68k,
> alpha and ia64, respectively).
>
> I checked the list of ioctl commands in drivers, and the ones that are
> not already handled are all compatible, again with the one exception of
> m68k driver, which implements RTC_PLL_GET and RTC_PLL_SET, but has no
> compat mode.
>
> Since the ioctl commands are either compatible or differ in both structure
> and command code between 32-bit and 64-bit, we can merge the compat
> handler into the native one and just implement the two common compat
> commands (RTC_IRQP_READ, RTC_IRQP_SET) there.
[...]

I don't think this can work properly on s390, because some of them take
integers and some take pointers.

Ben.

--
Ben Hutchings, Software Developer Codethink Ltd
https://www.codethink.co.uk/ Dale House, 35 Dale Street
Manchester, M1 2HF, United Kingdom

2019-10-18 19:48:16

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [Y2038] [PATCH v6 10/43] compat_ioctl: move rtc handling into rtc-dev.c

On Thu, Oct 17, 2019 at 3:42 PM Ben Hutchings
<[email protected]> wrote:
>
> On Wed, 2019-10-09 at 21:10 +0200, Arnd Bergmann wrote:
> > We no longer need the rtc compat handling to be in common code, now that
> > all drivers are either moved to the rtc-class framework, or (rarely)
> > exist in drivers/char for architectures without compat mode (m68k,
> > alpha and ia64, respectively).
> >
> > I checked the list of ioctl commands in drivers, and the ones that are
> > not already handled are all compatible, again with the one exception of
> > m68k driver, which implements RTC_PLL_GET and RTC_PLL_SET, but has no
> > compat mode.
> >
> > Since the ioctl commands are either compatible or differ in both structure
> > and command code between 32-bit and 64-bit, we can merge the compat
> > handler into the native one and just implement the two common compat
> > commands (RTC_IRQP_READ, RTC_IRQP_SET) there.
> [...]
>
> I don't think this can work properly on s390, because some of them take
> integers and some take pointers.

Thanks a lot for taking a look at the patch and pointing this out!

I don't remember how I got to this, either I missed the problem or I
decided that it was ok, since it will still do the right thing:
On s390 only the highest bit is cleared in a pointer value, and we
ensure that the RTC_IRQP_SET argument is between 1 and 8192.

Passing a value of (0x80000000 + n) where n is in the valid range
would lead to the call succeeding unexpectedly on compat s390
(if it had an RTC, which it does not) which is clearly not good but
mostly harmless. I certainly had not considered this case.

However, looking at this again after your comment I found a rather
more serious bug in my new RTC_IRQP_SET handling: Any 64-bit
machine can now bypass the permission check for RTC_IRQP_SET by
calling RTC_IRQP_SET32 instead.

I'll fix it both issues by adding a rtc_compat_dev_ioctl() to handle
RTC_IRQP_SET32/RTC_IRQP_READ32:

diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c
index 1dc5063f78c9..9e4fd5088ead 100644
--- a/drivers/rtc/dev.c
+++ b/drivers/rtc/dev.c
@@ -358,16 +358,6 @@ static long rtc_dev_ioctl(struct file *file,
mutex_unlock(&rtc->ops_lock);
return rtc_update_irq_enable(rtc, 0);

-#ifdef CONFIG_64BIT
-#define RTC_IRQP_SET32 _IOW('p', 0x0c, __u32)
-#define RTC_IRQP_READ32 _IOR('p', 0x0b, __u32)
- case RTC_IRQP_SET32:
- err = rtc_irq_set_freq(rtc, arg);
- break;
- case RTC_IRQP_READ32:
- err = put_user(rtc->irq_freq, (unsigned int __user *)uarg);
- break;
-#endif
case RTC_IRQP_SET:
err = rtc_irq_set_freq(rtc, arg);
break;
@@ -409,6 +399,29 @@ static long rtc_dev_ioctl(struct file *file,
return err;
}

+#ifdef CONFIG_COMPAT
+#define RTC_IRQP_SET32 _IOW('p', 0x0c, __u32)
+#define RTC_IRQP_READ32 _IOR('p', 0x0b, __u32)
+
+static long rtc_dev_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct rtc_device *rtc = file->private_data;
+ void __user *uarg = compat_ptr(arg);
+
+ switch (cmd) {
+ case RTC_IRQP_READ32:
+ return put_user(rtc->irq_freq, (__u32 __user *)uarg);
+
+ case RTC_IRQP_SET32:
+ /* arg is a plain integer, not pointer */
+ return rtc_dev_ioctl(file, RTC_IRQP_SET, arg);
+ }
+
+ return rtc_dev_ioctl(file, cmd, (unsigned long)uarg);
+}
+#endif
+
static int rtc_dev_fasync(int fd, struct file *file, int on)
{
struct rtc_device *rtc = file->private_data;
@@ -444,7 +457,7 @@ static const struct file_operations rtc_dev_fops = {
.read = rtc_dev_read,
.poll = rtc_dev_poll,
.unlocked_ioctl = rtc_dev_ioctl,
- .compat_ioctl = compat_ptr_ioctl,
+ .compat_ioctl = rtc_dev_compat_ioctl,
.open = rtc_dev_open,
.release = rtc_dev_release,
.fasync = rtc_dev_fasync,

If you and Alexandre are both happy with this version, I'll fold it into
my original patch.

Arnd

2019-10-18 22:13:09

by Ben Hutchings

[permalink] [raw]
Subject: Re: [Y2038] [PATCH v6 10/43] compat_ioctl: move rtc handling into rtc-dev.c

On Thu, 2019-10-17 at 16:33 +0200, Arnd Bergmann wrote:
> On Thu, Oct 17, 2019 at 3:42 PM Ben Hutchings
> <[email protected]> wrote:
> > On Wed, 2019-10-09 at 21:10 +0200, Arnd Bergmann wrote:
> > > We no longer need the rtc compat handling to be in common code, now that
> > > all drivers are either moved to the rtc-class framework, or (rarely)
> > > exist in drivers/char for architectures without compat mode (m68k,
> > > alpha and ia64, respectively).
> > >
> > > I checked the list of ioctl commands in drivers, and the ones that are
> > > not already handled are all compatible, again with the one exception of
> > > m68k driver, which implements RTC_PLL_GET and RTC_PLL_SET, but has no
> > > compat mode.
> > >
> > > Since the ioctl commands are either compatible or differ in both structure
> > > and command code between 32-bit and 64-bit, we can merge the compat
> > > handler into the native one and just implement the two common compat
> > > commands (RTC_IRQP_READ, RTC_IRQP_SET) there.
> > [...]
> >
> > I don't think this can work properly on s390, because some of them take
> > integers and some take pointers.
>
> Thanks a lot for taking a look at the patch and pointing this out!
>
> I don't remember how I got to this, either I missed the problem or I
> decided that it was ok, since it will still do the right thing:
> On s390 only the highest bit is cleared in a pointer value, and we
> ensure that the RTC_IRQP_SET argument is between 1 and 8192.
>
> Passing a value of (0x80000000 + n) where n is in the valid range
> would lead to the call succeeding unexpectedly on compat s390
> (if it had an RTC, which it does not) which is clearly not good but
> mostly harmless. I certainly had not considered this case.
>
> However, looking at this again after your comment I found a rather
> more serious bug in my new RTC_IRQP_SET handling: Any 64-bit
> machine can now bypass the permission check for RTC_IRQP_SET by
> calling RTC_IRQP_SET32 instead.
>
> I'll fix it both issues by adding a rtc_compat_dev_ioctl() to handle
> RTC_IRQP_SET32/RTC_IRQP_READ32:

Reviewed-by: Ben Hutchings <[email protected]>

> diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c
> index 1dc5063f78c9..9e4fd5088ead 100644
> --- a/drivers/rtc/dev.c
> +++ b/drivers/rtc/dev.c
> @@ -358,16 +358,6 @@ static long rtc_dev_ioctl(struct file *file,
> mutex_unlock(&rtc->ops_lock);
> return rtc_update_irq_enable(rtc, 0);
>
> -#ifdef CONFIG_64BIT
> -#define RTC_IRQP_SET32 _IOW('p', 0x0c, __u32)
> -#define RTC_IRQP_READ32 _IOR('p', 0x0b, __u32)
> - case RTC_IRQP_SET32:
> - err = rtc_irq_set_freq(rtc, arg);
> - break;
> - case RTC_IRQP_READ32:
> - err = put_user(rtc->irq_freq, (unsigned int __user *)uarg);
> - break;
> -#endif
> case RTC_IRQP_SET:
> err = rtc_irq_set_freq(rtc, arg);
> break;
> @@ -409,6 +399,29 @@ static long rtc_dev_ioctl(struct file *file,
> return err;
> }
>
> +#ifdef CONFIG_COMPAT
> +#define RTC_IRQP_SET32 _IOW('p', 0x0c, __u32)
> +#define RTC_IRQP_READ32 _IOR('p', 0x0b, __u32)
> +
> +static long rtc_dev_compat_ioctl(struct file *file,
> + unsigned int cmd, unsigned long arg)
> +{
> + struct rtc_device *rtc = file->private_data;
> + void __user *uarg = compat_ptr(arg);
> +
> + switch (cmd) {
> + case RTC_IRQP_READ32:
> + return put_user(rtc->irq_freq, (__u32 __user *)uarg);
> +
> + case RTC_IRQP_SET32:
> + /* arg is a plain integer, not pointer */
> + return rtc_dev_ioctl(file, RTC_IRQP_SET, arg);
> + }
> +
> + return rtc_dev_ioctl(file, cmd, (unsigned long)uarg);
> +}
> +#endif
> +
> static int rtc_dev_fasync(int fd, struct file *file, int on)
> {
> struct rtc_device *rtc = file->private_data;
> @@ -444,7 +457,7 @@ static const struct file_operations rtc_dev_fops = {
> .read = rtc_dev_read,
> .poll = rtc_dev_poll,
> .unlocked_ioctl = rtc_dev_ioctl,
> - .compat_ioctl = compat_ptr_ioctl,
> + .compat_ioctl = rtc_dev_compat_ioctl,
> .open = rtc_dev_open,
> .release = rtc_dev_release,
> .fasync = rtc_dev_fasync,
>
> If you and Alexandre are both happy with this version, I'll fold it into
> my original patch.
>
> Arnd
>
--
Ben Hutchings, Software Developer Codethink Ltd
https://www.codethink.co.uk/ Dale House, 35 Dale Street
Manchester, M1 2HF, United Kingdom

2019-10-18 22:13:50

by Ben Hutchings

[permalink] [raw]
Subject: Re: [Y2038] [PATCH v6 16/43] compat_ioctl: move isdn/capi ioctl translation into driver

On Wed, 2019-10-09 at 21:10 +0200, Arnd Bergmann wrote:
[...]
> --- a/drivers/isdn/capi/capi.c
> +++ b/drivers/isdn/capi/capi.c
> @@ -950,6 +950,34 @@ capi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> return ret;
> }
>
> +#ifdef CONFIG_COMPAT
> +static long
> +capi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> +{
> + int ret;
> +
> + if (cmd == CAPI_MANUFACTURER_CMD) {
> + struct {
> + unsigned long cmd;

Should be u32?

Ben.

> + compat_uptr_t data;
> + } mcmd32;
[...]

--
Ben Hutchings, Software Developer Codethink Ltd
https://www.codethink.co.uk/ Dale House, 35 Dale Street
Manchester, M1 2HF, United Kingdom

2019-10-19 08:30:30

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [Y2038] [PATCH v6 16/43] compat_ioctl: move isdn/capi ioctl translation into driver

On Thu, Oct 17, 2019 at 8:25 PM Ben Hutchings
<[email protected]> wrote:
>
> On Wed, 2019-10-09 at 21:10 +0200, Arnd Bergmann wrote:
> [...]
> > --- a/drivers/isdn/capi/capi.c
> > +++ b/drivers/isdn/capi/capi.c
> > @@ -950,6 +950,34 @@ capi_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> > return ret;
> > }
> >
> > +#ifdef CONFIG_COMPAT
> > +static long
> > +capi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> > +{
> > + int ret;
> > +
> > + if (cmd == CAPI_MANUFACTURER_CMD) {
> > + struct {
> > + unsigned long cmd;
>
> Should be u32?

Good catch, changed to compat_ulong_t now.

Thanks,

Arnd

2019-10-22 04:57:13

by Al Viro

[permalink] [raw]
Subject: Re: [Y2038] [PATCH v6 10/43] compat_ioctl: move rtc handling into rtc-dev.c

On Thu, Oct 17, 2019 at 04:33:09PM +0200, Arnd Bergmann wrote:

> However, looking at this again after your comment I found a rather
> more serious bug in my new RTC_IRQP_SET handling: Any 64-bit
> machine can now bypass the permission check for RTC_IRQP_SET by
> calling RTC_IRQP_SET32 instead.

You've lost the check on RTC_EPOCH_SET as well.

Another potential issue is drivers/input/misc/hp_sdc_rtc.c,
provided that the hardware in question might possibly exist
on hppa64 boxen - CONFIG_GSC defaults to y and it's not
32bit-only, so that thing is at least selectable on 64bit
kernels.

2019-10-22 13:36:15

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [Y2038] [PATCH v6 10/43] compat_ioctl: move rtc handling into rtc-dev.c

On Tue, Oct 22, 2019 at 6:30 AM Al Viro <[email protected]> wrote:
>
> On Thu, Oct 17, 2019 at 04:33:09PM +0200, Arnd Bergmann wrote:
>
> > However, looking at this again after your comment I found a rather
> > more serious bug in my new RTC_IRQP_SET handling: Any 64-bit
> > machine can now bypass the permission check for RTC_IRQP_SET by
> > calling RTC_IRQP_SET32 instead.
>
> You've lost the check on RTC_EPOCH_SET as well.

Right, originally my plan was to keep the epoch handling local to
rtc-vr41xx.c as explained in the patch description. The driver is
specific to a particular very obsolete MIPS machine that was
apparently only ever used with 32-bit kernels.

I guess it can't hurt to treat it the same as RTC_IRQP_SET32
if you prefer. Folding in this change now and adapting the
changelog text:

--- a/drivers/rtc/dev.c
+++ b/drivers/rtc/dev.c
@@ -402,6 +402,7 @@ static long rtc_dev_ioctl(struct file *file,
#ifdef CONFIG_COMPAT
#define RTC_IRQP_SET32 _IOW('p', 0x0c, __u32)
#define RTC_IRQP_READ32 _IOR('p', 0x0b, __u32)
+#define RTC_EPOCH_SET32 _IOW('p', 0x0e, __u32)

static long rtc_dev_compat_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
@@ -416,6 +417,10 @@ static long rtc_dev_compat_ioctl(struct file *file,
case RTC_IRQP_SET32:
/* arg is a plain integer, not pointer */
return rtc_dev_ioctl(file, RTC_IRQP_SET, arg);
+
+ case RTC_EPOCH_SET32:
+ /* arg is a plain integer, not pointer */
+ return rtc_dev_ioctl(file, RTC_EPOCH_SET, arg);
}

return rtc_dev_ioctl(file, cmd, (unsigned long)uarg);
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index 79f27de545af..c3671043ace7 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -69,7 +69,6 @@ static void __iomem *rtc2_base;

/* 32-bit compat for ioctls that nobody else uses */
#define RTC_EPOCH_READ32 _IOR('p', 0x0d, __u32)
-#define RTC_EPOCH_SET32 _IOW('p', 0x0e, __u32)

static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */

@@ -187,7 +186,6 @@ static int vr41xx_rtc_ioctl(struct device *dev,
unsigned int cmd, unsigned long
#ifdef CONFIG_64BIT
case RTC_EPOCH_READ32:
return put_user(epoch, (unsigned int __user *)arg);
- case RTC_EPOCH_SET32:
#endif
case RTC_EPOCH_SET:
/* Doesn't support before 1900 */

> Another potential issue is drivers/input/misc/hp_sdc_rtc.c,
> provided that the hardware in question might possibly exist
> on hppa64 boxen - CONFIG_GSC defaults to y and it's not
> 32bit-only, so that thing is at least selectable on 64bit
> kernels.

I decided long ago not to care: that code has never compiled after
it was originally merged into the kernel in 2005:

static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
#if 1
return -EINVAL;
#else
...
RTC_IRQP_SET, RTC_EPOCH_SET, ...
...
#endif
}

I don't see any chance that this code is revived. If anyone wanted to
make it work, the right approach would be to use the rtc framework
and rewrite the code first.

I could send a patch to remove the dead code though if that helps.

Arnd

2019-10-23 10:32:22

by Alexandre Belloni

[permalink] [raw]
Subject: Re: [Y2038] [PATCH v6 10/43] compat_ioctl: move rtc handling into rtc-dev.c

On 22/10/2019 14:14:21+0200, Arnd Bergmann wrote:
> On Tue, Oct 22, 2019 at 6:30 AM Al Viro <[email protected]> wrote:
> >
> > On Thu, Oct 17, 2019 at 04:33:09PM +0200, Arnd Bergmann wrote:
> >
> > > However, looking at this again after your comment I found a rather
> > > more serious bug in my new RTC_IRQP_SET handling: Any 64-bit
> > > machine can now bypass the permission check for RTC_IRQP_SET by
> > > calling RTC_IRQP_SET32 instead.
> >
> > You've lost the check on RTC_EPOCH_SET as well.
>
> Right, originally my plan was to keep the epoch handling local to
> rtc-vr41xx.c as explained in the patch description. The driver is
> specific to a particular very obsolete MIPS machine that was
> apparently only ever used with 32-bit kernels.
>
> I guess it can't hurt to treat it the same as RTC_IRQP_SET32
> if you prefer. Folding in this change now and adapting the
> changelog text:
>
> --- a/drivers/rtc/dev.c
> +++ b/drivers/rtc/dev.c
> @@ -402,6 +402,7 @@ static long rtc_dev_ioctl(struct file *file,
> #ifdef CONFIG_COMPAT
> #define RTC_IRQP_SET32 _IOW('p', 0x0c, __u32)
> #define RTC_IRQP_READ32 _IOR('p', 0x0b, __u32)
> +#define RTC_EPOCH_SET32 _IOW('p', 0x0e, __u32)
>
> static long rtc_dev_compat_ioctl(struct file *file,
> unsigned int cmd, unsigned long arg)
> @@ -416,6 +417,10 @@ static long rtc_dev_compat_ioctl(struct file *file,
> case RTC_IRQP_SET32:
> /* arg is a plain integer, not pointer */
> return rtc_dev_ioctl(file, RTC_IRQP_SET, arg);
> +
> + case RTC_EPOCH_SET32:
> + /* arg is a plain integer, not pointer */
> + return rtc_dev_ioctl(file, RTC_EPOCH_SET, arg);
> }
>
> return rtc_dev_ioctl(file, cmd, (unsigned long)uarg);
> diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
> index 79f27de545af..c3671043ace7 100644
> --- a/drivers/rtc/rtc-vr41xx.c
> +++ b/drivers/rtc/rtc-vr41xx.c
> @@ -69,7 +69,6 @@ static void __iomem *rtc2_base;
>
> /* 32-bit compat for ioctls that nobody else uses */
> #define RTC_EPOCH_READ32 _IOR('p', 0x0d, __u32)
> -#define RTC_EPOCH_SET32 _IOW('p', 0x0e, __u32)
>
> static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */
>
> @@ -187,7 +186,6 @@ static int vr41xx_rtc_ioctl(struct device *dev,
> unsigned int cmd, unsigned long
> #ifdef CONFIG_64BIT
> case RTC_EPOCH_READ32:
> return put_user(epoch, (unsigned int __user *)arg);
> - case RTC_EPOCH_SET32:
> #endif
> case RTC_EPOCH_SET:
> /* Doesn't support before 1900 */
>
> > Another potential issue is drivers/input/misc/hp_sdc_rtc.c,
> > provided that the hardware in question might possibly exist
> > on hppa64 boxen - CONFIG_GSC defaults to y and it's not
> > 32bit-only, so that thing is at least selectable on 64bit
> > kernels.
>
> I decided long ago not to care: that code has never compiled after
> it was originally merged into the kernel in 2005:
>
> static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file,
> unsigned int cmd, unsigned long arg)
> {
> #if 1
> return -EINVAL;
> #else
> ...
> RTC_IRQP_SET, RTC_EPOCH_SET, ...
> ...
> #endif
> }
>
> I don't see any chance that this code is revived. If anyone wanted to
> make it work, the right approach would be to use the rtc framework
> and rewrite the code first.
>
> I could send a patch to remove the dead code though if that helps.
>

Please do.

IIUC, this doesn't affect arch/alpha/kernel/rtc.c because alpha has
always been 64bit.


--
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

2019-10-23 12:54:06

by Alexandre Belloni

[permalink] [raw]
Subject: Re: [Y2038] [PATCH v6 10/43] compat_ioctl: move rtc handling into rtc-dev.c

On 17/10/2019 16:33:09+0200, Arnd Bergmann wrote:
> On Thu, Oct 17, 2019 at 3:42 PM Ben Hutchings
> <[email protected]> wrote:
> >
> > On Wed, 2019-10-09 at 21:10 +0200, Arnd Bergmann wrote:
> > > We no longer need the rtc compat handling to be in common code, now that
> > > all drivers are either moved to the rtc-class framework, or (rarely)
> > > exist in drivers/char for architectures without compat mode (m68k,
> > > alpha and ia64, respectively).
> > >
> > > I checked the list of ioctl commands in drivers, and the ones that are
> > > not already handled are all compatible, again with the one exception of
> > > m68k driver, which implements RTC_PLL_GET and RTC_PLL_SET, but has no
> > > compat mode.
> > >
> > > Since the ioctl commands are either compatible or differ in both structure
> > > and command code between 32-bit and 64-bit, we can merge the compat
> > > handler into the native one and just implement the two common compat
> > > commands (RTC_IRQP_READ, RTC_IRQP_SET) there.
> > [...]
> >
> > I don't think this can work properly on s390, because some of them take
> > integers and some take pointers.
>
> Thanks a lot for taking a look at the patch and pointing this out!
>
> I don't remember how I got to this, either I missed the problem or I
> decided that it was ok, since it will still do the right thing:
> On s390 only the highest bit is cleared in a pointer value, and we
> ensure that the RTC_IRQP_SET argument is between 1 and 8192.
>
> Passing a value of (0x80000000 + n) where n is in the valid range
> would lead to the call succeeding unexpectedly on compat s390
> (if it had an RTC, which it does not) which is clearly not good but
> mostly harmless. I certainly had not considered this case.
>
> However, looking at this again after your comment I found a rather
> more serious bug in my new RTC_IRQP_SET handling: Any 64-bit
> machine can now bypass the permission check for RTC_IRQP_SET by
> calling RTC_IRQP_SET32 instead.
>
> I'll fix it both issues by adding a rtc_compat_dev_ioctl() to handle
> RTC_IRQP_SET32/RTC_IRQP_READ32:
>
> diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c
> index 1dc5063f78c9..9e4fd5088ead 100644
> --- a/drivers/rtc/dev.c
> +++ b/drivers/rtc/dev.c
> @@ -358,16 +358,6 @@ static long rtc_dev_ioctl(struct file *file,
> mutex_unlock(&rtc->ops_lock);
> return rtc_update_irq_enable(rtc, 0);
>
> -#ifdef CONFIG_64BIT
> -#define RTC_IRQP_SET32 _IOW('p', 0x0c, __u32)
> -#define RTC_IRQP_READ32 _IOR('p', 0x0b, __u32)
> - case RTC_IRQP_SET32:
> - err = rtc_irq_set_freq(rtc, arg);
> - break;
> - case RTC_IRQP_READ32:
> - err = put_user(rtc->irq_freq, (unsigned int __user *)uarg);
> - break;
> -#endif
> case RTC_IRQP_SET:
> err = rtc_irq_set_freq(rtc, arg);
> break;
> @@ -409,6 +399,29 @@ static long rtc_dev_ioctl(struct file *file,
> return err;
> }
>
> +#ifdef CONFIG_COMPAT
> +#define RTC_IRQP_SET32 _IOW('p', 0x0c, __u32)
> +#define RTC_IRQP_READ32 _IOR('p', 0x0b, __u32)
> +
> +static long rtc_dev_compat_ioctl(struct file *file,
> + unsigned int cmd, unsigned long arg)
> +{
> + struct rtc_device *rtc = file->private_data;
> + void __user *uarg = compat_ptr(arg);
> +
> + switch (cmd) {
> + case RTC_IRQP_READ32:
> + return put_user(rtc->irq_freq, (__u32 __user *)uarg);
> +
> + case RTC_IRQP_SET32:
> + /* arg is a plain integer, not pointer */
> + return rtc_dev_ioctl(file, RTC_IRQP_SET, arg);
> + }
> +
> + return rtc_dev_ioctl(file, cmd, (unsigned long)uarg);
> +}
> +#endif
> +
> static int rtc_dev_fasync(int fd, struct file *file, int on)
> {
> struct rtc_device *rtc = file->private_data;
> @@ -444,7 +457,7 @@ static const struct file_operations rtc_dev_fops = {
> .read = rtc_dev_read,
> .poll = rtc_dev_poll,
> .unlocked_ioctl = rtc_dev_ioctl,
> - .compat_ioctl = compat_ptr_ioctl,
> + .compat_ioctl = rtc_dev_compat_ioctl,
> .open = rtc_dev_open,
> .release = rtc_dev_release,
> .fasync = rtc_dev_fasync,
>
> If you and Alexandre are both happy with this version, I'll fold it into
> my original patch.
>

I'm OK with that version

--
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

2019-10-23 23:44:44

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [Y2038] [PATCH v6 10/43] compat_ioctl: move rtc handling into rtc-dev.c

On Wed, Oct 23, 2019 at 12:29 PM Alexandre Belloni
<[email protected]> wrote:
> On 22/10/2019 14:14:21+0200, Arnd Bergmann wrote:
> > On Tue, Oct 22, 2019 at 6:30 AM Al Viro <[email protected]> wrote:
> >
> > I don't see any chance that this code is revived. If anyone wanted to
> > make it work, the right approach would be to use the rtc framework
> > and rewrite the code first.
> >
> > I could send a patch to remove the dead code though if that helps.
> >
>
> Please do.

Ok, done. Speaking of removing rtc drivers, should we just kill off
drivers/char/rtc.c and drivers/char/efirtc.c as well? I don't remember
why we left them in the tree, but I'm fairly sure they are not actually
needed.

Arnd

2019-10-24 00:49:55

by Alexandre Belloni

[permalink] [raw]
Subject: Re: [Y2038] [PATCH v6 10/43] compat_ioctl: move rtc handling into rtc-dev.c

On 23/10/2019 16:28:40+0200, Arnd Bergmann wrote:
> On Wed, Oct 23, 2019 at 12:29 PM Alexandre Belloni
> <[email protected]> wrote:
> > On 22/10/2019 14:14:21+0200, Arnd Bergmann wrote:
> > > On Tue, Oct 22, 2019 at 6:30 AM Al Viro <[email protected]> wrote:
> > >
> > > I don't see any chance that this code is revived. If anyone wanted to
> > > make it work, the right approach would be to use the rtc framework
> > > and rewrite the code first.
> > >
> > > I could send a patch to remove the dead code though if that helps.
> > >
> >
> > Please do.
>
> Ok, done. Speaking of removing rtc drivers, should we just kill off
> drivers/char/rtc.c and drivers/char/efirtc.c as well? I don't remember
> why we left them in the tree, but I'm fairly sure they are not actually
> needed.
>

https://lore.kernel.org/lkml/CAK8P3a0QZNY+K+V1HG056xCerz=_L2jh5UfZ+2LWkDqkw5Zznw@mail.gmail.com/

That's how we left it ;)

--
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

2019-10-24 02:31:49

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [Y2038] [PATCH v6 10/43] compat_ioctl: move rtc handling into rtc-dev.c

On Wed, Oct 23, 2019 at 4:34 PM Alexandre Belloni
<[email protected]> wrote:
> On 23/10/2019 16:28:40+0200, Arnd Bergmann wrote:
> > Ok, done. Speaking of removing rtc drivers, should we just kill off
> > drivers/char/rtc.c and drivers/char/efirtc.c as well? I don't remember
> > why we left them in the tree, but I'm fairly sure they are not actually
> > needed.
> >
>
> https://lore.kernel.org/lkml/CAK8P3a0QZNY+K+V1HG056xCerz=_L2jh5UfZ+2LWkDqkw5Zznw@mail.gmail.com/
>
> That's how we left it ;)

Right, that is roughly what I remembered. Sending a patch to remove them
now, let's see if anyone cares.

Arnd