summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Young <sean@mess.org>2016-12-06 00:24:59 +0300
committerMauro Carvalho Chehab <mchehab@s-opensource.com>2017-01-30 17:15:52 +0300
commitb590c0bfaee6a3edb6bcaaab68dfe9e2f6db9eb9 (patch)
treebfe339d0cbdba1d71d87e0aa0618d1fc2fc83a43
parent0751d33c27eacfcd4e15a3425a9e035614ab9713 (diff)
downloadlinux-b590c0bfaee6a3edb6bcaaab68dfe9e2f6db9eb9.tar.xz
[media] rc: Add scancode validation
We need to valdiate that scancodes are valid for their protocol; an incorrect necx scancode could actually be a nec scancode, for example. Signed-off-by: Sean Young <sean@mess.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
-rw-r--r--drivers/media/rc/rc-main.c71
1 files changed, 68 insertions, 3 deletions
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index a4b12d261eb5..21a385074ec1 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -724,6 +724,64 @@ void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
}
EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
+/**
+ * rc_validate_filter() - checks that the scancode and mask are valid and
+ * provides sensible defaults
+ * @protocol: the protocol for the filter
+ * @filter: the scancode and mask
+ * @return: 0 or -EINVAL if the filter is not valid
+ */
+static int rc_validate_filter(enum rc_type protocol,
+ struct rc_scancode_filter *filter)
+{
+ static u32 masks[] = {
+ [RC_TYPE_RC5] = 0x1f7f,
+ [RC_TYPE_RC5X_20] = 0x1f7f3f,
+ [RC_TYPE_RC5_SZ] = 0x2fff,
+ [RC_TYPE_SONY12] = 0x1f007f,
+ [RC_TYPE_SONY15] = 0xff007f,
+ [RC_TYPE_SONY20] = 0x1fff7f,
+ [RC_TYPE_JVC] = 0xffff,
+ [RC_TYPE_NEC] = 0xffff,
+ [RC_TYPE_NECX] = 0xffffff,
+ [RC_TYPE_NEC32] = 0xffffffff,
+ [RC_TYPE_SANYO] = 0x1fffff,
+ [RC_TYPE_RC6_0] = 0xffff,
+ [RC_TYPE_RC6_6A_20] = 0xfffff,
+ [RC_TYPE_RC6_6A_24] = 0xffffff,
+ [RC_TYPE_RC6_6A_32] = 0xffffffff,
+ [RC_TYPE_RC6_MCE] = 0xffff7fff,
+ [RC_TYPE_SHARP] = 0x1fff,
+ };
+ u32 s = filter->data;
+
+ switch (protocol) {
+ case RC_TYPE_NECX:
+ if ((((s >> 16) ^ ~(s >> 8)) & 0xff) == 0)
+ return -EINVAL;
+ break;
+ case RC_TYPE_NEC32:
+ if ((((s >> 24) ^ ~(s >> 16)) & 0xff) == 0)
+ return -EINVAL;
+ break;
+ case RC_TYPE_RC6_MCE:
+ if ((s & 0xffff0000) != 0x800f0000)
+ return -EINVAL;
+ break;
+ case RC_TYPE_RC6_6A_32:
+ if ((s & 0xffff0000) == 0x800f0000)
+ return -EINVAL;
+ break;
+ default:
+ break;
+ }
+
+ filter->data &= masks[protocol];
+ filter->mask &= masks[protocol];
+
+ return 0;
+}
+
int rc_open(struct rc_dev *rdev)
{
int rval = 0;
@@ -1229,11 +1287,18 @@ static ssize_t store_filter(struct device *device,
new_filter.data = val;
if (fattr->type == RC_FILTER_WAKEUP) {
- /* refuse to set a filter unless a protocol is enabled */
- if (dev->wakeup_protocol == RC_TYPE_UNKNOWN) {
+ /*
+ * Refuse to set a filter unless a protocol is enabled
+ * and the filter is valid for that protocol
+ */
+ if (dev->wakeup_protocol != RC_TYPE_UNKNOWN)
+ ret = rc_validate_filter(dev->wakeup_protocol,
+ &new_filter);
+ else
ret = -EINVAL;
+
+ if (ret != 0)
goto unlock;
- }
}
if (fattr->type == RC_FILTER_NORMAL && !dev->enabled_protocols &&