media: rc: read out of bounds if bpf reports high protocol number
authorSean Young <sean@mess.org>
Sat, 28 Jul 2018 09:11:15 +0000 (05:11 -0400)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Mon, 30 Jul 2018 12:19:53 +0000 (08:19 -0400)
The repeat period is read from a static array. If a keydown event is
reported from bpf with a high protocol number, we read out of bounds. This
is unlikely to end up with a reasonable repeat period at the best of times,
in which case no timely key up event is generated.

Signed-off-by: Sean Young <sean@mess.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
drivers/media/rc/rc-main.c

index 2e222d9..ca68e1d 100644 (file)
@@ -679,6 +679,14 @@ static void ir_timer_repeat(struct timer_list *t)
        spin_unlock_irqrestore(&dev->keylock, flags);
 }
 
+static unsigned int repeat_period(int protocol)
+{
+       if (protocol >= ARRAY_SIZE(protocols))
+               return 100;
+
+       return protocols[protocol].repeat_period;
+}
+
 /**
  * rc_repeat() - signals that a key is still pressed
  * @dev:       the struct rc_dev descriptor of the device
@@ -691,7 +699,7 @@ void rc_repeat(struct rc_dev *dev)
 {
        unsigned long flags;
        unsigned int timeout = nsecs_to_jiffies(dev->timeout) +
-               msecs_to_jiffies(protocols[dev->last_protocol].repeat_period);
+               msecs_to_jiffies(repeat_period(dev->last_protocol));
        struct lirc_scancode sc = {
                .scancode = dev->last_scancode, .rc_proto = dev->last_protocol,
                .keycode = dev->keypressed ? dev->last_keycode : KEY_RESERVED,
@@ -803,7 +811,7 @@ void rc_keydown(struct rc_dev *dev, enum rc_proto protocol, u32 scancode,
 
        if (dev->keypressed) {
                dev->keyup_jiffies = jiffies + nsecs_to_jiffies(dev->timeout) +
-                       msecs_to_jiffies(protocols[protocol].repeat_period);
+                       msecs_to_jiffies(repeat_period(protocol));
                mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
        }
        spin_unlock_irqrestore(&dev->keylock, flags);