diff options
author | Dan Rosenberg <drosenberg@vsecurity.com> | 2011-03-23 10:53:41 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-03-23 17:47:46 -0400 |
commit | b769f49463711205d57286e64cf535ed4daf59e9 (patch) | |
tree | 1c674fdbed533434d2ba9b7b1b3646243160e55c /sound/oss/midi_synth.c | |
parent | ce24f58a1187ca3058d72c3f897e3b574209ab20 (diff) |
sound/oss: remove offset from load_patch callbacks
Was: [PATCH] sound/oss/midi_synth: prevent underflow, use of
uninitialized value, and signedness issue
The offset passed to midi_synth_load_patch() can be essentially
arbitrary. If it's greater than the header length, this will result in
a copy_from_user(dst, src, negative_val). While this will just return
-EFAULT on x86, on other architectures this may cause memory corruption.
Additionally, the length field of the sysex_info structure may not be
initialized prior to its use. Finally, a signed comparison may result
in an unintentionally large loop.
On suggestion by Takashi Iwai, version two removes the offset argument
from the load_patch callbacks entirely, which also resolves similar
issues in opl3. Compile tested only.
v3 adjusts comments and hopefully gets copy offsets right.
Signed-off-by: Dan Rosenberg <drosenberg@vsecurity.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/oss/midi_synth.c')
-rw-r--r-- | sound/oss/midi_synth.c | 30 |
1 files changed, 13 insertions, 17 deletions
diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c index 3c09374ea5bf..2292c230d7e6 100644 --- a/sound/oss/midi_synth.c +++ b/sound/oss/midi_synth.c | |||
@@ -476,7 +476,7 @@ EXPORT_SYMBOL(midi_synth_hw_control); | |||
476 | 476 | ||
477 | int | 477 | int |
478 | midi_synth_load_patch(int dev, int format, const char __user *addr, | 478 | midi_synth_load_patch(int dev, int format, const char __user *addr, |
479 | int offs, int count, int pmgr_flag) | 479 | int count, int pmgr_flag) |
480 | { | 480 | { |
481 | int orig_dev = synth_devs[dev]->midi_dev; | 481 | int orig_dev = synth_devs[dev]->midi_dev; |
482 | 482 | ||
@@ -491,33 +491,29 @@ midi_synth_load_patch(int dev, int format, const char __user *addr, | |||
491 | if (!prefix_cmd(orig_dev, 0xf0)) | 491 | if (!prefix_cmd(orig_dev, 0xf0)) |
492 | return 0; | 492 | return 0; |
493 | 493 | ||
494 | /* Invalid patch format */ | ||
494 | if (format != SYSEX_PATCH) | 495 | if (format != SYSEX_PATCH) |
495 | { | ||
496 | /* printk("MIDI Error: Invalid patch format (key) 0x%x\n", format);*/ | ||
497 | return -EINVAL; | 496 | return -EINVAL; |
498 | } | 497 | |
498 | /* Patch header too short */ | ||
499 | if (count < hdr_size) | 499 | if (count < hdr_size) |
500 | { | ||
501 | /* printk("MIDI Error: Patch header too short\n");*/ | ||
502 | return -EINVAL; | 500 | return -EINVAL; |
503 | } | 501 | |
504 | count -= hdr_size; | 502 | count -= hdr_size; |
505 | 503 | ||
506 | /* | 504 | /* |
507 | * Copy the header from user space but ignore the first bytes which have | 505 | * Copy the header from user space |
508 | * been transferred already. | ||
509 | */ | 506 | */ |
510 | 507 | ||
511 | if(copy_from_user(&((char *) &sysex)[offs], &(addr)[offs], hdr_size - offs)) | 508 | if (copy_from_user(&sysex, addr, hdr_size)) |
512 | return -EFAULT; | 509 | return -EFAULT; |
513 | 510 | ||
514 | if (count < sysex.len) | 511 | /* Sysex record too short */ |
515 | { | 512 | if ((unsigned)count < (unsigned)sysex.len) |
516 | /* printk(KERN_WARNING "MIDI Warning: Sysex record too short (%d<%d)\n", count, (int) sysex.len);*/ | ||
517 | sysex.len = count; | 513 | sysex.len = count; |
518 | } | 514 | |
519 | left = sysex.len; | 515 | left = sysex.len; |
520 | src_offs = 0; | 516 | src_offs = 0; |
521 | 517 | ||
522 | for (i = 0; i < left && !signal_pending(current); i++) | 518 | for (i = 0; i < left && !signal_pending(current); i++) |
523 | { | 519 | { |