Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: streamzap: prevent processing IR data on URB failure

If streamzap_callback() receives an urb with any non-critical error
status, i.e. any error code other than -ECONNRESET, -ENOENT or -ESHUTDOWN,
it will try to process IR data, ignoring a possible transfer failure.

Make streamzap_callback() process IR data only when urb->status is 0.
Move processing logic to a separate function to make code cleaner and
more similar to the URB completion handlers in other RC drivers.

Found by Linux Verification Center (linuxtesting.org) with Syzkaller.

Fixes: 19770693c354 ("V4L/DVB: staging/lirc: add lirc_streamzap driver")
Cc: stable@vger.kernel.org
Signed-off-by: Murad Masimov <m.masimov@mt-integration.ru>
Signed-off-by: Sean Young <sean@mess.org>
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>

authored by

Murad Masimov and committed by
Hans Verkuil
549f6d34 f656cfbc

+38 -30
+38 -30
drivers/media/rc/streamzap.c
··· 138 138 sz_push_full_space(sz, value & SZ_SPACE_MASK); 139 139 } 140 140 141 - /* 142 - * streamzap_callback - usb IRQ handler callback 143 - * 144 - * This procedure is invoked on reception of data from 145 - * the usb remote. 146 - */ 147 - static void streamzap_callback(struct urb *urb) 141 + static void sz_process_ir_data(struct streamzap_ir *sz, int len) 148 142 { 149 - struct streamzap_ir *sz; 150 143 unsigned int i; 151 - int len; 152 144 153 - if (!urb) 154 - return; 155 - 156 - sz = urb->context; 157 - len = urb->actual_length; 158 - 159 - switch (urb->status) { 160 - case -ECONNRESET: 161 - case -ENOENT: 162 - case -ESHUTDOWN: 163 - /* 164 - * this urb is terminated, clean up. 165 - * sz might already be invalid at this point 166 - */ 167 - dev_err(sz->dev, "urb terminated, status: %d\n", urb->status); 168 - return; 169 - default: 170 - break; 171 - } 172 - 173 - dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len); 174 145 for (i = 0; i < len; i++) { 175 146 dev_dbg(sz->dev, "sz->buf_in[%d]: %x\n", 176 147 i, (unsigned char)sz->buf_in[i]); ··· 190 219 } 191 220 192 221 ir_raw_event_handle(sz->rdev); 222 + } 223 + 224 + /* 225 + * streamzap_callback - usb IRQ handler callback 226 + * 227 + * This procedure is invoked on reception of data from 228 + * the usb remote. 229 + */ 230 + static void streamzap_callback(struct urb *urb) 231 + { 232 + struct streamzap_ir *sz; 233 + int len; 234 + 235 + if (!urb) 236 + return; 237 + 238 + sz = urb->context; 239 + len = urb->actual_length; 240 + 241 + switch (urb->status) { 242 + case 0: 243 + dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len); 244 + sz_process_ir_data(sz, len); 245 + break; 246 + case -ECONNRESET: 247 + case -ENOENT: 248 + case -ESHUTDOWN: 249 + /* 250 + * this urb is terminated, clean up. 251 + * sz might already be invalid at this point 252 + */ 253 + dev_err(sz->dev, "urb terminated, status: %d\n", urb->status); 254 + return; 255 + default: 256 + break; 257 + } 258 + 193 259 usb_submit_urb(urb, GFP_ATOMIC); 194 260 } 195 261