Commit 68f66feb authored by Stephen Tweedie's avatar Stephen Tweedie Committed by Greg KH

[PATCH] Fix root hole in raw device

[Patch] Fix raw device ioctl pass-through

Raw character devices are supposed to pass ioctls through to the block
devices they are bound to.  Unfortunately, they are using the wrong
function for this: ioctl_by_bdev(), instead of blkdev_ioctl().

ioctl_by_bdev() performs a set_fs(KERNEL_DS) before calling the ioctl,
redirecting the user-space buffer access to the kernel address space.
This is, needless to say, a bad thing.

This was noticed first on s390, where raw IO was non-functioning.  The
s390 driver config does not actually allow raw IO to be enabled, which
was the first part of the problem.  Secondly, the s390 kernel address
space is distinct from user, causing legal raw ioctls to fail.  I've
reproduced this on a kernel built with 4G:4G split on x86, which fails
in the same way (-EFAULT if the address does not exist kernel-side;
returns success without actually populating the user buffer if it does.)

The patch below fixes both the config and address-space problems.  It's
based closely on a patch by Jan Glauber <jang@de.ibm.com>, which has
been tested on s390 at IBM.  I've tested it on x86 4G:4G (split address
space) and x86_64 (common address space).

Kernel-address-space access has been assigned CAN-2005-1264.
Signed-off-by: default avatarStephen Tweedie <sct@redhat.com>
Signed-off-by: default avatarDave Jones <davej@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent a84a5059
...@@ -237,3 +237,5 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg) ...@@ -237,3 +237,5 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
} }
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(blkdev_ioctl);
...@@ -122,7 +122,7 @@ raw_ioctl(struct inode *inode, struct file *filp, ...@@ -122,7 +122,7 @@ raw_ioctl(struct inode *inode, struct file *filp,
{ {
struct block_device *bdev = filp->private_data; struct block_device *bdev = filp->private_data;
return ioctl_by_bdev(bdev, command, arg); return blkdev_ioctl(bdev->bd_inode, filp, command, arg);
} }
static void bind_device(struct raw_config_request *rq) static void bind_device(struct raw_config_request *rq)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment