| // SPDX-License-Identifier: GPL-2.0 |
| |
| #include <linux/export.h> |
| #include <linux/kernel.h> |
| #include <linux/errno.h> |
| #include <linux/fs.h> |
| #include <linux/compat.h> |
| |
| #ifdef CONFIG_COMPAT |
| /** |
| * compat_ptr_ioctl - generic implementation of .compat_ioctl file operation |
| * |
| * This is not normally called as a function, but instead set in struct |
| * file_operations as |
| * |
| * .compat_ioctl = compat_ptr_ioctl, |
| * |
| * On most architectures, the compat_ptr_ioctl() just passes all arguments |
| * to the corresponding ->ioctl handler. The exception is arch/s390, where |
| * compat_ptr() clears the top bit of a 32-bit pointer value, so user space |
| * pointers to the second 2GB alias the first 2GB, as is the case for |
| * native 32-bit s390 user space. |
| * |
| * The compat_ptr_ioctl() function must therefore be used only with ioctl |
| * functions that either ignore the argument or pass a pointer to a |
| * compatible data type. |
| * |
| * If any ioctl command handled by fops->unlocked_ioctl passes a plain |
| * integer instead of a pointer, or any of the passed data types |
| * is incompatible between 32-bit and 64-bit architectures, a proper |
| * handler is required instead of compat_ptr_ioctl. |
| */ |
| long compat_ptr_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| { |
| if (!file->f_op->unlocked_ioctl) |
| return -ENOIOCTLCMD; |
| |
| return file->f_op->unlocked_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); |
| } |
| EXPORT_SYMBOL(compat_ptr_ioctl); |
| #endif |