The mmc_ioc_cmd and mmc_ioc_multi_cmd structs are used to hold information and data about an MMC ioctl.
The PCuABI uses 129-bit capabilities as user pointers, which means that the __u64 type must be replaced with the __kernel_uintptr_t type, which is large enough to hold capabilities, yet will remain 64-bit on other architectures. Additional modifications have been made the copy routines.
The command value for an ioctl is inferred from the size of the struct that is provided to it; this patch increases the size of struct mmc_ioc_cmd with the use of __kernel_uintptr_t, which in turn modifies the calculated value for the ioctl. In order to prevent this value changing, it is necessary to hard-code the definition of the MMC_IOC_CMD ioctl value, as compat structs are not defined in this uAPI header.
Signed-off-by: Akram Ahmad Akram.Ahmad@arm.com --- drivers/mmc/core/block.c | 8 ++++---- include/uapi/linux/mmc/ioctl.h | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 7 deletions(-)
diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index 3333c4917028..547941096c0e 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -454,7 +454,7 @@ static int get_mmc_ioc_cmd_from_compat64(struct mmc_ioc_cmd *native_cmd, native_cmd->data_timeout_ns = compat_cmd.data_timeout_ns; native_cmd->cmd_timeout_ms = compat_cmd.cmd_timeout_ms; native_cmd->__pad = compat_cmd.__pad; - native_cmd->data_ptr = compat_cmd.data_ptr; + native_cmd->data_ptr = (__kernel_uintptr_t)compat_ptr(compat_cmd.data_ptr);
return 0; } @@ -464,7 +464,7 @@ static int copy_mmc_ioc_cmd_from_user(struct mmc_ioc_cmd *to, void * __user src) if (in_compat64()) return get_mmc_ioc_cmd_from_compat64(to, src);
- if (copy_from_user(to, src, sizeof(*to))) + if (copy_from_user_with_ptr(to, src, sizeof(*to))) return -EFAULT; return 0; } @@ -497,7 +497,7 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( return idata; }
- idata->buf = memdup_user(uaddr_to_user_ptr(idata->ic.data_ptr), + idata->buf = memdup_user((void __user *)idata->ic.data_ptr, idata->buf_bytes); if (IS_ERR(idata->buf)) { err = PTR_ERR(idata->buf); @@ -525,7 +525,7 @@ static int mmc_blk_ioctl_copy_to_user(struct mmc_ioc_cmd __user *ic_ptr, return -EFAULT;
if (!idata->ic.write_flag) { - if (copy_to_user(uaddr_to_user_ptr(ic->data_ptr), + if (copy_to_user((void __user *)ic->data_ptr, idata->buf, idata->buf_bytes)) return -EFAULT; } diff --git a/include/uapi/linux/mmc/ioctl.h b/include/uapi/linux/mmc/ioctl.h index e7401ade6822..ce411b555d03 100644 --- a/include/uapi/linux/mmc/ioctl.h +++ b/include/uapi/linux/mmc/ioctl.h @@ -2,6 +2,9 @@ #ifndef LINUX_MMC_IOCTL_H #define LINUX_MMC_IOCTL_H
+#ifndef __KERNEL__ +#include <stdint.h> +#endif #include <linux/types.h> #include <linux/major.h>
@@ -46,9 +49,9 @@ struct mmc_ioc_cmd { __u32 __pad;
/* DAT buffer */ - __u64 data_ptr; + __kernel_uintptr_t data_ptr; }; -#define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (__u64)(unsigned long) ptr +#define mmc_ioc_cmd_set_data(ic, ptr) ic.data_ptr = (uintptr_t) ptr
/** * struct mmc_ioc_multi_cmd - multi command information @@ -61,7 +64,17 @@ struct mmc_ioc_multi_cmd { struct mmc_ioc_cmd cmds[]; };
-#define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd) +/* + * The size of struct mmc_ioc_cmd has changed in PCuABI due to the use of + * __kernel_uintptr_t, which in turn modifies the command value for this + * ioctl. It is therefore necessary to hard-code the value for the ioctl + * using the size of the struct that is expected in any ABI other than + * PCuABI, to ensure that the value for MMC_IOC_CMD is unchanged. The + * original definition is as follows: + * + * #define MMC_IOC_CMD _IOWR(MMC_BLOCK_MAJOR, 0, struct mmc_ioc_cmd) + */ +#define MMC_IOC_CMD _IOC(_IOC_READ|_IOC_WRITE, MMC_BLOCK_MAJOR, 0, 72) /* * MMC_IOC_MULTI_CMD: Used to send an array of MMC commands described by * the structure mmc_ioc_multi_cmd. The MMC driver will issue all