Skip to content

Commit 4e60131

Browse files
He Zhegregkh
authored andcommitted
hpet: Support 32-bit userspace
hpet_compat_ioctl and read file operations failed to handle parameters from 32-bit userspace and thus samples/timers/hpet_example.c fails as below. root@intel-x86-64:~# ./hpet_example-32.out poll /dev/hpet 1 2 -hpet: executing poll hpet_poll: HPET_IRQFREQ failed This patch fixes cmd and arg handling in hpet_compat_ioctl and adds compat handling for 32-bit userspace in hpet_read. hpet_example now shows that it works for both 64-bit and 32-bit. root@intel-x86-64:~# ./hpet_example-32.out poll /dev/hpet 1 2 -hpet: executing poll hpet_poll: info.hi_flags 0x0 hpet_poll: expired time = 0xf4298 hpet_poll: revents = 0x1 hpet_poll: data 0x1 hpet_poll: expired time = 0xf4235 hpet_poll: revents = 0x1 hpet_poll: data 0x1 root@intel-x86-64:~# ./hpet_example-64.out poll /dev/hpet 1 2 -hpet: executing poll hpet_poll: info.hi_flags 0x0 hpet_poll: expired time = 0xf42a1 hpet_poll: revents = 0x1 hpet_poll: data 0x1 hpet_poll: expired time = 0xf4232 hpet_poll: revents = 0x1 hpet_poll: data 0x1 Cc: [email protected] Signed-off-by: He Zhe <[email protected]> Fixes: 54066a5 ("hpet: kill BKL, add compat_ioctl") Reviewed-by: Arnd Bergmann <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent bab2f5e commit 4e60131

File tree

1 file changed

+29
-5
lines changed

1 file changed

+29
-5
lines changed

drivers/char/hpet.c

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,13 @@ hpet_read(struct file *file, char __user *buf, size_t count, loff_t * ppos)
269269
if (!devp->hd_ireqfreq)
270270
return -EIO;
271271

272-
if (count < sizeof(unsigned long))
273-
return -EINVAL;
272+
if (in_compat_syscall()) {
273+
if (count < sizeof(compat_ulong_t))
274+
return -EINVAL;
275+
} else {
276+
if (count < sizeof(unsigned long))
277+
return -EINVAL;
278+
}
274279

275280
add_wait_queue(&devp->hd_waitqueue, &wait);
276281

@@ -294,9 +299,16 @@ hpet_read(struct file *file, char __user *buf, size_t count, loff_t * ppos)
294299
schedule();
295300
}
296301

297-
retval = put_user(data, (unsigned long __user *)buf);
298-
if (!retval)
299-
retval = sizeof(unsigned long);
302+
if (in_compat_syscall()) {
303+
retval = put_user(data, (compat_ulong_t __user *)buf);
304+
if (!retval)
305+
retval = sizeof(compat_ulong_t);
306+
} else {
307+
retval = put_user(data, (unsigned long __user *)buf);
308+
if (!retval)
309+
retval = sizeof(unsigned long);
310+
}
311+
300312
out:
301313
__set_current_state(TASK_RUNNING);
302314
remove_wait_queue(&devp->hd_waitqueue, &wait);
@@ -651,12 +663,24 @@ struct compat_hpet_info {
651663
unsigned short hi_timer;
652664
};
653665

666+
/* 32-bit types would lead to different command codes which should be
667+
* translated into 64-bit ones before passed to hpet_ioctl_common
668+
*/
669+
#define COMPAT_HPET_INFO _IOR('h', 0x03, struct compat_hpet_info)
670+
#define COMPAT_HPET_IRQFREQ _IOW('h', 0x6, compat_ulong_t)
671+
654672
static long
655673
hpet_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
656674
{
657675
struct hpet_info info;
658676
int err;
659677

678+
if (cmd == COMPAT_HPET_INFO)
679+
cmd = HPET_INFO;
680+
681+
if (cmd == COMPAT_HPET_IRQFREQ)
682+
cmd = HPET_IRQFREQ;
683+
660684
mutex_lock(&hpet_mutex);
661685
err = hpet_ioctl_common(file->private_data, cmd, arg, &info);
662686
mutex_unlock(&hpet_mutex);

0 commit comments

Comments
 (0)