From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: David Herrmann <dh.herrmann@gmail.com>
Cc: linux-input@vger.kernel.org,
Benjamin Tissoires <benjamin.tissoires@gmail.com>,
Peter Hutterer <peter.hutterer@who-t.net>
Subject: Re: [PATCH] Input: evdev - add event-mask API
Date: Sat, 24 Oct 2015 17:17:09 -0700 [thread overview]
Message-ID: <20151025001709.GA27533@dtor-pixel> (raw)
In-Reply-To: <1441296841-16894-1-git-send-email-dh.herrmann@gmail.com>
Hi David,
On Thu, Sep 03, 2015 at 06:14:01PM +0200, David Herrmann wrote:
> +static int bits_from_user(unsigned long *bits, unsigned int maxbit,
> + unsigned int maxlen, const void __user *p, int compat)
> +{
> + int len;
> +
> +#if IS_ENABLED(CONFIG_COMPAT)
> + if (compat) {
> + if (maxlen % sizeof(compat_long_t))
> + return -EINVAL;
> + len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t);
> + } else
> +#endif
> + {
> + if (maxlen % sizeof(long))
> + return -EINVAL;
> + len = BITS_TO_LONGS(maxbit) * sizeof(long);
> + }
> +
> + if (len > maxlen)
> + len = maxlen;
> +
> +#if IS_ENABLED(CONFIG_COMPAT) && defined(__BIG_ENDIAN)
> + if (compat) {
> + int i;
> +
> + for (i = 0; i < len / sizeof(compat_long_t); i++)
> + if (copy_from_user((compat_long_t *) bits +
> + i + 1 - ((i % 2) << 1),
> + (compat_long_t __user *) p + i,
> + sizeof(compat_long_t)))
> + return -EFAULT;
> + if (i % 2)
> + *((compat_long_t *) bits + i - 1) = 0;
> + } else
> +#endif
> + if (copy_from_user(bits, p, len))
> + return -EFAULT;
> +
> + return len;
> +}
I do not quite like how we sprinkle ifdefs throughout, I prefer the way
we have bits_to_user defined, even if it is more verbose.
> +
> static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
> {
> int len;
> @@ -854,6 +953,86 @@ static int evdev_revoke(struct evdev *evdev, struct evdev_client *client,
> return 0;
> }
>
> +/* must be called with evdev-mutex held */
> +static int evdev_set_mask(struct evdev_client *client,
> + unsigned int type,
> + const void __user *codes,
> + u32 codes_size,
> + int compat)
> +{
> + unsigned long flags, *mask, *oldmask;
> + size_t cnt, size, min;
> + int error;
> +
> + /* we allow unknown types and 'codes_size > size' for forward-compat */
> + cnt = evdev_get_mask_cnt(type);
> + if (!cnt)
> + return 0;
> +
> + size = sizeof(unsigned long) * BITS_TO_LONGS(cnt);
> + min = min_t(size_t, codes_size, size);
> +
> + mask = kzalloc(size, GFP_KERNEL);
> + if (!mask)
> + return -ENOMEM;
> +
> + error = bits_from_user(mask, cnt - 1, min, codes, compat);
I do not think we need to calculate and pass min here: bits_from_user()
will limit the output for us already.
Does it still work if you apply the patch below?
Thanks!
--
Dmitry
Input: evdev - mask api misc changes
From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/evdev.c | 148 +++++++++++++++++++++++++++++--------------------
1 file changed, 88 insertions(+), 60 deletions(-)
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 83d699f..ce35ea3 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -685,7 +685,46 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit,
return len;
}
+
+static int bits_from_user(unsigned long *bits, unsigned int maxbit,
+ unsigned int maxlen, const void __user *p, int compat)
+{
+ int len, i;
+
+ if (compat) {
+ if (maxlen % sizeof(compat_long_t))
+ return -EINVAL;
+
+ len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t);
+ if (len > maxlen)
+ len = maxlen;
+
+ for (i = 0; i < len / sizeof(compat_long_t); i++)
+ if (copy_from_user((compat_long_t *) bits +
+ i + 1 - ((i % 2) << 1),
+ (compat_long_t __user *) p + i,
+ sizeof(compat_long_t)))
+ return -EFAULT;
+ if (i % 2)
+ *((compat_long_t *) bits + i - 1) = 0;
+
+ } else {
+ if (maxlen % sizeof(long))
+ return -EINVAL;
+
+ len = BITS_TO_LONGS(maxbit) * sizeof(long);
+ if (len > maxlen)
+ len = maxlen;
+
+ if (copy_from_user(p, bits, len))
+ return -EFAULT;
+ }
+
+ return len;
+}
+
#else
+
static int bits_to_user(unsigned long *bits, unsigned int maxbit,
unsigned int maxlen, void __user *p, int compat)
{
@@ -698,6 +737,24 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit,
return copy_to_user(p, bits, len) ? -EFAULT : len;
}
+
+static int bits_from_user(unsigned long *bits, unsigned int maxbit,
+ unsigned int maxlen, const void __user *p, int compat)
+{
+ size_t chunk_size = compat ? sizeof(compat_long_t) : sizeof(long);
+ int len;
+
+ if (maxlen % chunk_size)
+ return -EINVAL;
+
+ len = compat ? BITS_TO_LONGS_COMPAT(maxbit) : BITS_TO_LONGS(maxbit);
+ len *= chunk_size;
+ if (len > maxlen)
+ len = maxlen;
+
+ return copy_from_user(bits, p, len) ? -EFAULT : len;
+}
+
#endif /* __BIG_ENDIAN */
#else
@@ -713,49 +770,23 @@ static int bits_to_user(unsigned long *bits, unsigned int maxbit,
return copy_to_user(p, bits, len) ? -EFAULT : len;
}
-#endif /* CONFIG_COMPAT */
-
static int bits_from_user(unsigned long *bits, unsigned int maxbit,
unsigned int maxlen, const void __user *p, int compat)
{
int len;
-#if IS_ENABLED(CONFIG_COMPAT)
- if (compat) {
- if (maxlen % sizeof(compat_long_t))
- return -EINVAL;
- len = BITS_TO_LONGS_COMPAT(maxbit) * sizeof(compat_long_t);
- } else
-#endif
- {
- if (maxlen % sizeof(long))
- return -EINVAL;
- len = BITS_TO_LONGS(maxbit) * sizeof(long);
- }
+ if (maxlen % sizeof(long))
+ return -EINVAL;
+ len = BITS_TO_LONGS(maxbit) * sizeof(long);
if (len > maxlen)
len = maxlen;
-#if IS_ENABLED(CONFIG_COMPAT) && defined(__BIG_ENDIAN)
- if (compat) {
- int i;
-
- for (i = 0; i < len / sizeof(compat_long_t); i++)
- if (copy_from_user((compat_long_t *) bits +
- i + 1 - ((i % 2) << 1),
- (compat_long_t __user *) p + i,
- sizeof(compat_long_t)))
- return -EFAULT;
- if (i % 2)
- *((compat_long_t *) bits + i - 1) = 0;
- } else
-#endif
- if (copy_from_user(bits, p, len))
- return -EFAULT;
-
- return len;
+ return copy_from_user(bits, p, len) ? -EFAULT : len;
}
+#endif /* CONFIG_COMPAT */
+
static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
{
int len;
@@ -956,7 +987,7 @@ static int evdev_set_mask(struct evdev_client *client,
int compat)
{
unsigned long flags, *mask, *oldmask;
- size_t cnt, size, min;
+ size_t cnt;
int error;
/* we allow unknown types and 'codes_size > size' for forward-compat */
@@ -964,14 +995,11 @@ static int evdev_set_mask(struct evdev_client *client,
if (!cnt)
return 0;
- size = sizeof(unsigned long) * BITS_TO_LONGS(cnt);
- min = min_t(size_t, codes_size, size);
-
- mask = kzalloc(size, GFP_KERNEL);
+ mask = kcalloc(sizeof(unsigned long), BITS_TO_LONGS(cnt), GFP_KERNEL);
if (!mask)
return -ENOMEM;
- error = bits_from_user(mask, cnt - 1, min, codes, compat);
+ error = bits_from_user(mask, cnt - 1, codes_size, codes, compat);
if (error < 0) {
kfree(mask);
return error;
@@ -995,35 +1023,33 @@ static int evdev_get_mask(struct evdev_client *client,
int compat)
{
unsigned long *mask;
- size_t cnt, size, min, i;
- u8 __user *out;
+ size_t cnt, size, xfer_size;
+ int i;
int error;
/* we allow unknown types and 'codes_size > size' for forward-compat */
cnt = evdev_get_mask_cnt(type);
size = sizeof(unsigned long) * BITS_TO_LONGS(cnt);
- min = min_t(size_t, codes_size, size);
+ xfer_size = min_t(size_t, codes_size, size);
if (cnt > 0) {
mask = client->evmasks[type];
if (mask) {
- error = bits_to_user(mask, cnt - 1, min, codes, compat);
+ error = bits_to_user(mask, cnt - 1,
+ xfer_size, codes, compat);
if (error < 0)
return error;
} else {
/* fake mask with all bits set */
- out = (u8 __user*)codes;
- for (i = 0; i < min; ++i)
- if (put_user((u8)0xff, out + i))
+ for (i = 0; i < xfer_size; i++)
+ if (put_user(0xffU, (u8 __user *)codes + i))
return -EFAULT;
}
}
- codes = (u8*)codes + min;
- codes_size -= min;
-
- if (codes_size > 0 && clear_user(codes, codes_size))
- return -EFAULT;
+ if (xfer_size < codes_size)
+ if (clear_user(codes + xfer_size, codes_size - xfer_size))
+ return -EFAULT;
return 0;
}
@@ -1097,27 +1123,29 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
else
return evdev_revoke(evdev, client, file);
- case EVIOCGMASK:
+ case EVIOCGMASK: {
+ void __user *codes_ptr;
+
if (copy_from_user(&mask, p, sizeof(mask)))
return -EFAULT;
+ codes_ptr = (void __user *)(unsigned long)mask.codes_ptr;
return evdev_get_mask(client,
- mask.type,
- (void __user*)
- (unsigned long)mask.codes_ptr,
- mask.codes_size,
+ mask.type, codes_ptr, mask.codes_size,
compat_mode);
+ }
+
+ case EVIOCSMASK: {
+ const void __user *codes_ptr;
- case EVIOCSMASK:
if (copy_from_user(&mask, p, sizeof(mask)))
return -EFAULT;
+ codes_ptr = (const void __user *)(unsigned long)mask.codes_ptr;
return evdev_set_mask(client,
- mask.type,
- (const void __user*)
- (unsigned long)mask.codes_ptr,
- mask.codes_size,
+ mask.type, codes_ptr, mask.codes_size,
compat_mode);
+ }
case EVIOCSCLOCKID:
if (copy_from_user(&i, p, sizeof(unsigned int)))
next prev parent reply other threads:[~2015-10-25 3:10 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-09-03 16:14 [PATCH] Input: evdev - add event-mask API David Herrmann
2015-10-08 15:27 ` David Herrmann
2015-10-25 0:17 ` Dmitry Torokhov [this message]
2015-10-25 9:00 ` David Herrmann
2015-10-25 21:01 ` Dmitry Torokhov
-- strict thread matches above, loose matches on Subject: below --
2014-04-15 22:31 David Herrmann
2014-04-19 21:16 ` Dmitry Torokhov
2014-04-22 6:25 ` David Herrmann
2014-04-22 4:29 ` Peter Hutterer
2014-04-22 6:31 ` David Herrmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20151025001709.GA27533@dtor-pixel \
--to=dmitry.torokhov@gmail.com \
--cc=benjamin.tissoires@gmail.com \
--cc=dh.herrmann@gmail.com \
--cc=linux-input@vger.kernel.org \
--cc=peter.hutterer@who-t.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.