media: lirc: validate scancode for transmit

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>
This commit is contained in:
Sean Young 2017-09-27 16:00:49 -04:00 committed by Mauro Carvalho Chehab
parent a60d64b15c
commit 49a4b36ada
3 changed files with 44 additions and 20 deletions

View 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;

View 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,

View File

@ -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;