Skip to content

Commit

Permalink
Input: fix force feedback upload issue in compat mode
Browse files Browse the repository at this point in the history
Force feedback upload of effects through the event device (ioctl
EVIOCSFF) is not working in 32 bit applications running on 64-bit
kernel due to the fact that struct ff_effect contains a pointer,
resulting in the structure having different sizes in 64 and 32 bit
programs and causing difference in ioctl numbers.

[dtor@mail.ru: refactor to keep all ugliness in evdev]

Signed-off-by: Adam Dawidowski <drake_ster@wp.pl>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
  • Loading branch information
Adam Dawidowski authored and Dmitry Torokhov committed Jun 30, 2008
1 parent 82547e9 commit f2278f3
Showing 1 changed file with 90 additions and 11 deletions.
101 changes: 90 additions & 11 deletions drivers/input/evdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,35 @@ struct input_event_compat {
__s32 value;
};

struct ff_periodic_effect_compat {
__u16 waveform;
__u16 period;
__s16 magnitude;
__s16 offset;
__u16 phase;

struct ff_envelope envelope;

__u32 custom_len;
compat_uptr_t custom_data;
};

struct ff_effect_compat {
__u16 type;
__s16 id;
__u16 direction;
struct ff_trigger trigger;
struct ff_replay replay;

union {
struct ff_constant_effect constant;
struct ff_ramp_effect ramp;
struct ff_periodic_effect_compat periodic;
struct ff_condition_effect condition[2]; /* One for each axis */
struct ff_rumble_effect rumble;
} u;
};

/* Note to the author of this code: did it ever occur to
you why the ifdefs are needed? Think about it again. -AK */
#ifdef CONFIG_X86_64
Expand Down Expand Up @@ -368,6 +397,42 @@ static int evdev_event_to_user(char __user *buffer,
return 0;
}

static int evdev_ff_effect_from_user(const char __user *buffer, size_t size,
struct ff_effect *effect)
{
if (COMPAT_TEST) {
struct ff_effect_compat *compat_effect;

if (size != sizeof(struct ff_effect_compat))
return -EINVAL;

/*
* It so happens that the pointer which needs to be changed
* is the last field in the structure, so we can copy the
* whole thing and replace just the pointer.
*/

compat_effect = (struct ff_effect_compat *)effect;

if (copy_from_user(compat_effect, buffer,
sizeof(struct ff_effect_compat)))
return -EFAULT;

if (compat_effect->type == FF_PERIODIC &&
compat_effect->u.periodic.waveform == FF_CUSTOM)
effect->u.periodic.custom_data =
compat_ptr(compat_effect->u.periodic.custom_data);
} else {
if (size != sizeof(struct ff_effect))
return -EINVAL;

if (copy_from_user(effect, buffer, sizeof(struct ff_effect)))
return -EFAULT;
}

return 0;
}

#else

static inline size_t evdev_event_size(void)
Expand All @@ -393,6 +458,18 @@ static int evdev_event_to_user(char __user *buffer,
return 0;
}

static int evdev_ff_effect_from_user(const char __user *buffer, size_t size,
struct ff_effect *effect)
{
if (size != sizeof(struct ff_effect))
return -EINVAL;

if (copy_from_user(effect, buffer, sizeof(struct ff_effect)))
return -EFAULT;

return 0;
}

#endif /* CONFIG_COMPAT */

static ssize_t evdev_write(struct file *file, const char __user *buffer,
Expand Down Expand Up @@ -633,17 +710,6 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,

return input_set_keycode(dev, t, v);

case EVIOCSFF:
if (copy_from_user(&effect, p, sizeof(effect)))
return -EFAULT;

error = input_ff_upload(dev, &effect, file);

if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
return -EFAULT;

return error;

case EVIOCRMFF:
return input_ff_erase(dev, (int)(unsigned long) p, file);

Expand Down Expand Up @@ -733,6 +799,19 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,

if (_IOC_DIR(cmd) == _IOC_WRITE) {

if (_IOC_NR(cmd) == _IOC_NR(EVIOCSFF)) {

if (evdev_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect))
return -EFAULT;

error = input_ff_upload(dev, &effect, file);

if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
return -EFAULT;

return error;
}

if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {

t = _IOC_NR(cmd) & ABS_MAX;
Expand Down

0 comments on commit f2278f3

Please sign in to comment.