From: Sean Young Date: Wed, 27 Sep 2017 20:00:49 +0000 (-0400) Subject: media: lirc: validate scancode for transmit X-Git-Tag: v4.16-rc1~57^2~247 X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=commitdiff_plain;h=49a4b36ada336270b564cabbbcb727cadebd024d;p=linux.git media: lirc: validate scancode for transmit Ensure we reject an attempt to transmit invalid scancodes. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index aec0109b1a69..1ed69c9e64bf 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -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; diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index face39c3a96c..6d5a36b8b550 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -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, diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 56b322b3d325..ce8837b1facd 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -775,6 +775,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 @@ -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;