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

HID: roccat: add bounds checking in kone_sysfs_write_settings()

This code doesn't check if "settings->startup_profile" is within bounds
and that could result in an out of bounds array access. What the code
does do is it checks if the settings can be written to the firmware, so
it's possible that the firmware has a bounds check? It's safer and
easier to verify when the bounds checking is done in the kernel.

Fixes: 14bf62cde794 ("HID: add driver for Roccat Kone gaming mouse")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

authored by

Dan Carpenter and committed by
Jiri Kosina
d4f98dbf 35556bed

+16 -7
+16 -7
drivers/hid/hid-roccat-kone.c
··· 294 294 struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev)); 295 295 struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); 296 296 int retval = 0, difference, old_profile; 297 + struct kone_settings *settings = (struct kone_settings *)buf; 297 298 298 299 /* I need to get my data in one piece */ 299 300 if (off != 0 || count != sizeof(struct kone_settings)) 300 301 return -EINVAL; 301 302 302 303 mutex_lock(&kone->kone_lock); 303 - difference = memcmp(buf, &kone->settings, sizeof(struct kone_settings)); 304 + difference = memcmp(settings, &kone->settings, 305 + sizeof(struct kone_settings)); 304 306 if (difference) { 305 - retval = kone_set_settings(usb_dev, 306 - (struct kone_settings const *)buf); 307 - if (retval) { 308 - mutex_unlock(&kone->kone_lock); 309 - return retval; 307 + if (settings->startup_profile < 1 || 308 + settings->startup_profile > 5) { 309 + retval = -EINVAL; 310 + goto unlock; 310 311 } 311 312 313 + retval = kone_set_settings(usb_dev, settings); 314 + if (retval) 315 + goto unlock; 316 + 312 317 old_profile = kone->settings.startup_profile; 313 - memcpy(&kone->settings, buf, sizeof(struct kone_settings)); 318 + memcpy(&kone->settings, settings, sizeof(struct kone_settings)); 314 319 315 320 kone_profile_activated(kone, kone->settings.startup_profile); 316 321 317 322 if (kone->settings.startup_profile != old_profile) 318 323 kone_profile_report(kone, kone->settings.startup_profile); 319 324 } 325 + unlock: 320 326 mutex_unlock(&kone->kone_lock); 327 + 328 + if (retval) 329 + return retval; 321 330 322 331 return sizeof(struct kone_settings); 323 332 }