media: lirc: validate scancode for transmit
authorSean Young <sean@mess.org>
Wed, 27 Sep 2017 20:00:49 +0000 (16:00 -0400)
committerMauro Carvalho Chehab <mchehab@s-opensource.com>
Thu, 14 Dec 2017 15:35:17 +0000 (10:35 -0500)
Ensure we reject an attempt to transmit invalid scancodes.

Signed-off-by: Sean Young <sean@mess.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
drivers/media/rc/ir-lirc-codec.c
drivers/media/rc/rc-core-priv.h
drivers/media/rc/rc-main.c

index aec0109..1ed69c9 100644 (file)
@@ -126,6 +126,16 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
                if (scan.flags || scan.keycode || scan.timestamp)
                        return -EINVAL;
 
+               /*
+                * The scancode field in lirc_scancode is 64-bit simply
+                * to future-proof it, since there are IR protocols encode
+                * use more than 32 bits. For now only 32-bit protocols
+                * are supported.
+                */
+               if (scan.scancode > U32_MAX ||
+                   !rc_validate_scancode(scan.rc_proto, scan.scancode))
+                       return -EINVAL;
+
                raw = kmalloc_array(LIRCBUF_SIZE, sizeof(*raw), GFP_KERNEL);
                if (!raw)
                        return -ENOMEM;
index face39c..6d5a36b 100644 (file)
@@ -150,6 +150,7 @@ static inline bool is_timing_event(struct ir_raw_event ev)
 #define TO_STR(is_pulse)               ((is_pulse) ? "pulse" : "space")
 
 /* functions for IR encoders */
+bool rc_validate_scancode(enum rc_proto proto, u32 scancode);
 
 static inline void init_ir_raw_event_duration(struct ir_raw_event *ev,
                                              unsigned int pulse,
index 56b322b..ce8837b 100644 (file)
@@ -776,6 +776,37 @@ void rc_keydown_notimeout(struct rc_dev *dev, enum rc_proto protocol,
 EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
 
 /**
+ * rc_validate_scancode() - checks that a scancode is valid for a protocol
+ * @proto:     protocol
+ * @scancode:  scancode
+ */
+bool rc_validate_scancode(enum rc_proto proto, u32 scancode)
+{
+       switch (proto) {
+       case RC_PROTO_NECX:
+               if ((((scancode >> 16) ^ ~(scancode >> 8)) & 0xff) == 0)
+                       return false;
+               break;
+       case RC_PROTO_NEC32:
+               if ((((scancode >> 24) ^ ~(scancode >> 16)) & 0xff) == 0)
+                       return false;
+               break;
+       case RC_PROTO_RC6_MCE:
+               if ((scancode & 0xffff0000) != 0x800f0000)
+                       return false;
+               break;
+       case RC_PROTO_RC6_6A_32:
+               if ((scancode & 0xffff0000) == 0x800f0000)
+                       return false;
+               break;
+       default:
+               break;
+       }
+
+       return true;
+}
+
+/**
  * rc_validate_filter() - checks that the scancode and mask are valid and
  *                       provides sensible defaults
  * @dev:       the struct rc_dev descriptor of the device
@@ -794,26 +825,8 @@ static int rc_validate_filter(struct rc_dev *dev,
 
        mask = protocols[protocol].scancode_bits;
 
-       switch (protocol) {
-       case RC_PROTO_NECX:
-               if ((((s >> 16) ^ ~(s >> 8)) & 0xff) == 0)
-                       return -EINVAL;
-               break;
-       case RC_PROTO_NEC32:
-               if ((((s >> 24) ^ ~(s >> 16)) & 0xff) == 0)
-                       return -EINVAL;
-               break;
-       case RC_PROTO_RC6_MCE:
-               if ((s & 0xffff0000) != 0x800f0000)
-                       return -EINVAL;
-               break;
-       case RC_PROTO_RC6_6A_32:
-               if ((s & 0xffff0000) == 0x800f0000)
-                       return -EINVAL;
-               break;
-       default:
-               break;
-       }
+       if (!rc_validate_scancode(protocol, s))
+               return -EINVAL;
 
        filter->data &= mask;
        filter->mask &= mask;