Skip to content

Commit

Permalink
Enable 64 bit processes to use compat input syscalls
Browse files Browse the repository at this point in the history
The compat variant of input syscalls is only enabled for 32 bit
tasks, but in some cases, such as userspace emulation, it's useful to
enable that variant for 64 bit processes.

Here we introduce the PR_[GET|SET]_COMPAT_INPUT prctl to allow 64 bit
tasks to opt-in for compat input syscalls.

Signed-off-by: Sergio Lopez <[email protected]>
  • Loading branch information
slp committed Oct 8, 2024
1 parent 95ae01a commit 897560f
Show file tree
Hide file tree
Showing 5 changed files with 29 additions and 4 deletions.
6 changes: 3 additions & 3 deletions drivers/input/input-compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
int input_event_from_user(const char __user *buffer,
struct input_event *event)
{
if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
if (current->compat_input || (in_compat_syscall() && !COMPAT_USE_64BIT_TIME)) {
struct input_event_compat compat_event;

if (copy_from_user(&compat_event, buffer,
Expand All @@ -38,7 +38,7 @@ int input_event_from_user(const char __user *buffer,
int input_event_to_user(char __user *buffer,
const struct input_event *event)
{
if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
if (current->compat_input || (in_compat_syscall() && !COMPAT_USE_64BIT_TIME)) {
struct input_event_compat compat_event;

compat_event.sec = event->input_event_sec;
Expand All @@ -62,7 +62,7 @@ int input_event_to_user(char __user *buffer,
int input_ff_effect_from_user(const char __user *buffer, size_t size,
struct ff_effect *effect)
{
if (in_compat_syscall()) {
if (current->compat_input || (in_compat_syscall() && !COMPAT_USE_64BIT_TIME)) {
struct ff_effect_compat *compat_effect;

if (size != sizeof(struct ff_effect_compat))
Expand Down
2 changes: 1 addition & 1 deletion drivers/input/input-compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ struct ff_effect_compat {

static inline size_t input_event_size(void)
{
return (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) ?
return (current->compat_input || (in_compat_syscall() && !COMPAT_USE_64BIT_TIME)) ?
sizeof(struct input_event_compat) : sizeof(struct input_event);
}

Expand Down
5 changes: 5 additions & 0 deletions include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -1535,6 +1535,11 @@ struct task_struct {
#ifdef CONFIG_USER_EVENTS
struct user_event_mm *user_event_mm;
#endif
/*
* Whether the task wants to use compat input syscalls even if it's
* a 64-bit process.
*/
bool compat_input;

/*
* New fields for task_struct should be added above here, so that
Expand Down
5 changes: 5 additions & 0 deletions include/uapi/linux/prctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -311,4 +311,9 @@ struct prctl_mm_map {
# define PR_SET_MEM_MODEL_DEFAULT 0
# define PR_SET_MEM_MODEL_TSO 1

#define PR_GET_COMPAT_INPUT 0x63494e50
#define PR_SET_COMPAT_INPUT 0x43494e50
# define PR_SET_COMPAT_INPUT_DISABLE 0
# define PR_SET_COMPAT_INPUT_ENABLE 1

#endif /* _LINUX_PRCTL_H */
15 changes: 15 additions & 0 deletions kernel/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -2768,6 +2768,21 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
return -EINVAL;
error = arch_prctl_mem_model_set(me, arg2);
break;
case PR_GET_COMPAT_INPUT:
if (arg2 || arg3 || arg4 || arg5)
return -EINVAL;
error = current->compat_input;
break;
case PR_SET_COMPAT_INPUT:
if (arg3 || arg4 || arg5)
return -EINVAL;
if (arg2 == PR_SET_COMPAT_INPUT_DISABLE)
current->compat_input = false;
else if (arg2 == PR_SET_COMPAT_INPUT_ENABLE)
current->compat_input = true;
else
return -EINVAL;
break;
default:
error = -EINVAL;
break;
Expand Down

0 comments on commit 897560f

Please sign in to comment.