[PATCH RESEND v2 16/26] hwmon: (dell-smm) let procfs copy the i8k ioctl arguments
Christian Brauner
brauner at kernel.org
Wed Nov 4 11:46:09 PST 2026
Implement ->proc_ioctl_buf() so procfs copies the arguments in before
it pins the entry and back out after unpinning it. The command numbers
in <uapi/linux/i8k.h> encode the wrong sizes, so the table lists what
is really copied: an int or the 16 bytes of the machine id out, and one
or two ints in.
A NULL argument fails with -EFAULT now instead of -EINVAL, and so does
a bad pointer to SET_FAN from an unprivileged task, which got -EPERM
before, since procfs copies the argument in before the entry's own
checks run. 32-bit tasks can use the commands whose numbers don't
depend on the size of size_t.
Signed-off-by: Christian Brauner (Amutable) <brauner at kernel.org>
---
drivers/hwmon/dell-smm-hwmon.c | 48 +++++++++++++++++++++---------------------
1 file changed, 24 insertions(+), 24 deletions(-)
diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c
index 492b2b6c6d7e..67b8c6e5752f 100644
--- a/drivers/hwmon/dell-smm-hwmon.c
+++ b/drivers/hwmon/dell-smm-hwmon.c
@@ -549,16 +549,13 @@ static int i8k_get_power_status(const struct dell_smm_data *data)
* Procfs interface
*/
-static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+static long i8k_ioctl(struct file *fp, unsigned int cmd, void *arg)
{
struct dell_smm_data *data = pde_data(file_inode(fp));
- int __user *argp = (int __user *)arg;
+ int *argp = arg;
int speed, err;
int val = 0;
- if (!argp)
- return -EINVAL;
-
switch (cmd) {
case I8K_BIOS_VERSION:
if (!isdigit(data->bios_version[0]) || !isdigit(data->bios_version[1]) ||
@@ -568,17 +565,13 @@ static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
val = (data->bios_version[0] << 16) |
(data->bios_version[1] << 8) | data->bios_version[2];
- if (copy_to_user(argp, &val, sizeof(val)))
- return -EFAULT;
-
+ *argp = val;
return 0;
case I8K_MACHINE_ID:
if (restricted && !capable(CAP_SYS_ADMIN))
return -EPERM;
- if (copy_to_user(argp, data->bios_machineid, sizeof(data->bios_machineid)))
- return -EFAULT;
-
+ memcpy(argp, data->bios_machineid, sizeof(data->bios_machineid));
return 0;
case I8K_FN_STATUS:
val = i8k_get_fn_status(data);
@@ -593,8 +586,7 @@ static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
break;
case I8K_GET_SPEED:
- if (copy_from_user(&val, argp, sizeof(int)))
- return -EFAULT;
+ val = *argp;
if (val > U8_MAX || val < 0)
return -EINVAL;
@@ -603,8 +595,7 @@ static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
break;
case I8K_GET_FAN:
- if (copy_from_user(&val, argp, sizeof(int)))
- return -EFAULT;
+ val = *argp;
if (val > U8_MAX || val < 0)
return -EINVAL;
@@ -616,14 +607,11 @@ static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
if (restricted && !capable(CAP_SYS_ADMIN))
return -EPERM;
- if (copy_from_user(&val, argp, sizeof(int)))
- return -EFAULT;
-
+ val = argp[0];
if (val > U8_MAX || val < 0)
return -EINVAL;
- if (copy_from_user(&speed, argp + 1, sizeof(int)))
- return -EFAULT;
+ speed = argp[1];
speed = clamp_val(speed, 0, data->i8k_fan_max);
@@ -643,12 +631,22 @@ static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
if (val < 0)
return val;
- if (copy_to_user(argp, &val, sizeof(int)))
- return -EFAULT;
-
+ *argp = val;
return 0;
}
+/* The command numbers don't encode what is copied, see <uapi/linux/i8k.h>. */
+static const struct proc_ioctl_arg i8k_ioctl_args[] = {
+ PROC_IOCTL_ARG(I8K_BIOS_VERSION, 0, sizeof(int)),
+ PROC_IOCTL_ARG(I8K_MACHINE_ID, 0, sizeof_field(struct dell_smm_data, bios_machineid)),
+ PROC_IOCTL_ARG(I8K_FN_STATUS, 0, sizeof(int)),
+ PROC_IOCTL_ARG(I8K_POWER_STATUS, 0, sizeof(int)),
+ PROC_IOCTL_ARG(I8K_GET_TEMP, 0, sizeof(int)),
+ PROC_IOCTL_ARG(I8K_GET_SPEED, sizeof(int), sizeof(int)),
+ PROC_IOCTL_ARG(I8K_GET_FAN, sizeof(int), sizeof(int)),
+ PROC_IOCTL_ARG(I8K_SET_FAN, 2 * sizeof(int), sizeof(int)),
+};
+
/*
* Print the information for /proc/i8k.
*/
@@ -696,7 +694,9 @@ static int i8k_proc_show(struct seq_file *seq, void *offset)
static const struct proc_ops i8k_proc_ops = {
.proc_show = i8k_proc_show,
- .proc_ioctl = i8k_ioctl,
+ .proc_ioctl_buf = i8k_ioctl,
+ .proc_ioctl_args = i8k_ioctl_args,
+ .proc_nr_ioctl_args = ARRAY_SIZE(i8k_ioctl_args),
};
static void i8k_exit_procfs(void *param)
--
2.53.0
More information about the linux-um
mailing list