OSDN Git Service

compat_ioctl: block: add blkdev_compat_ptr_ioctl
authorArnd Bergmann <arnd@arndb.de>
Thu, 28 Nov 2019 14:48:10 +0000 (15:48 +0100)
committerArnd Bergmann <arnd@arndb.de>
Fri, 3 Jan 2020 08:32:59 +0000 (09:32 +0100)
A lot of block drivers need only a trivial .compat_ioctl callback.

Add a helper function that can be set as the callback pointer
to only convert the argument using the compat_ptr() conversion
and otherwise assume all input and output data is compatible,
or handled using in_compat_syscall() checks.

This mirrors the compat_ptr_ioctl() helper function used in
character devices.

Reviewed-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
block/ioctl.c
include/linux/blkdev.h

index 5de98b9..e728331 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/capability.h>
+#include <linux/compat.h>
 #include <linux/blkdev.h>
 #include <linux/export.h>
 #include <linux/gfp.h>
@@ -285,6 +286,26 @@ int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode,
  */
 EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl);
 
+#ifdef CONFIG_COMPAT
+/*
+ * This is the equivalent of compat_ptr_ioctl(), to be used by block
+ * drivers that implement only commands that are completely compatible
+ * between 32-bit and 64-bit user space
+ */
+int blkdev_compat_ptr_ioctl(struct block_device *bdev, fmode_t mode,
+                       unsigned cmd, unsigned long arg)
+{
+       struct gendisk *disk = bdev->bd_disk;
+
+       if (disk->fops->ioctl)
+               return disk->fops->ioctl(bdev, mode, cmd,
+                                        (unsigned long)compat_ptr(arg));
+
+       return -ENOIOCTLCMD;
+}
+EXPORT_SYMBOL(blkdev_compat_ptr_ioctl);
+#endif
+
 static int blkdev_pr_register(struct block_device *bdev,
                struct pr_registration __user *arg)
 {
index 47eb22a..3e04086 100644 (file)
@@ -1711,6 +1711,13 @@ struct block_device_operations {
        const struct pr_ops *pr_ops;
 };
 
+#ifdef CONFIG_COMPAT
+extern int blkdev_compat_ptr_ioctl(struct block_device *, fmode_t,
+                                     unsigned int, unsigned long);
+#else
+#define blkdev_compat_ptr_ioctl NULL
+#endif
+
 extern int __blkdev_driver_ioctl(struct block_device *, fmode_t, unsigned int,
                                 unsigned long);
 extern int bdev_read_page(struct block_device *, sector_t, struct page *);