Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49a4b36a authored by Sean Young's avatar Sean Young Committed by Mauro Carvalho Chehab
Browse files

media: lirc: validate scancode for transmit



Ensure we reject an attempt to transmit invalid scancodes.

Signed-off-by: default avatarSean Young <sean@mess.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent a60d64b1
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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,
+33 −20
Original line number Diff line number Diff line
@@ -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)
	if (!rc_validate_scancode(protocol, s))
		return -EINVAL;
		break;
	case RC_PROTO_RC6_6A_32:
		if ((s & 0xffff0000) == 0x800f0000)
			return -EINVAL;
		break;
	default:
		break;
	}

	filter->data &= mask;
	filter->mask &= mask;