| From 493626f2d87a74e6dbea1686499ed6e7e600484e Mon Sep 17 00:00:00 2001 |
| From: Takashi Sakamoto <o-takashi@sakamocchi.jp> |
| Date: Sun, 9 Sep 2018 22:25:12 +0900 |
| Subject: ALSA: bebob: use address returned by kmalloc() instead of kernel stack for streaming DMA mapping |
| |
| From: Takashi Sakamoto <o-takashi@sakamocchi.jp> |
| |
| commit 493626f2d87a74e6dbea1686499ed6e7e600484e upstream. |
| |
| When executing 'fw_run_transaction()' with 'TCODE_WRITE_BLOCK_REQUEST', |
| an address of 'payload' argument is used for streaming DMA mapping by |
| 'firewire_ohci' module if 'size' argument is larger than 8 byte. |
| Although in this case the address should not be on kernel stack, current |
| implementation of ALSA bebob driver uses data in kernel stack for a cue |
| to boot M-Audio devices. This often brings unexpected result, especially |
| for a case of CONFIG_VMAP_STACK=y. |
| |
| This commit fixes the bug. |
| |
| Reference: https://bugzilla.kernel.org/show_bug.cgi?id=201021 |
| Reference: https://forum.manjaro.org/t/firewire-m-audio-410-driver-wont-load-firmware/51165 |
| Fixes: a2b2a7798fb6('ALSA: bebob: Send a cue to load firmware for M-Audio Firewire series') |
| Cc: <stable@vger.kernel.org> # v3.16+ |
| Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| sound/firewire/bebob/bebob_maudio.c | 24 ++++++++++++++---------- |
| 1 file changed, 14 insertions(+), 10 deletions(-) |
| |
| --- a/sound/firewire/bebob/bebob_maudio.c |
| +++ b/sound/firewire/bebob/bebob_maudio.c |
| @@ -96,17 +96,13 @@ int snd_bebob_maudio_load_firmware(struc |
| struct fw_device *device = fw_parent_device(unit); |
| int err, rcode; |
| u64 date; |
| - __le32 cues[3] = { |
| - cpu_to_le32(MAUDIO_BOOTLOADER_CUE1), |
| - cpu_to_le32(MAUDIO_BOOTLOADER_CUE2), |
| - cpu_to_le32(MAUDIO_BOOTLOADER_CUE3) |
| - }; |
| + __le32 *cues; |
| |
| /* check date of software used to build */ |
| err = snd_bebob_read_block(unit, INFO_OFFSET_SW_DATE, |
| &date, sizeof(u64)); |
| if (err < 0) |
| - goto end; |
| + return err; |
| /* |
| * firmware version 5058 or later has date later than "20070401", but |
| * 'date' is not null-terminated. |
| @@ -114,20 +110,28 @@ int snd_bebob_maudio_load_firmware(struc |
| if (date < 0x3230303730343031LL) { |
| dev_err(&unit->device, |
| "Use firmware version 5058 or later\n"); |
| - err = -ENOSYS; |
| - goto end; |
| + return -ENXIO; |
| } |
| |
| + cues = kmalloc_array(3, sizeof(*cues), GFP_KERNEL); |
| + if (!cues) |
| + return -ENOMEM; |
| + |
| + cues[0] = cpu_to_le32(MAUDIO_BOOTLOADER_CUE1); |
| + cues[1] = cpu_to_le32(MAUDIO_BOOTLOADER_CUE2); |
| + cues[2] = cpu_to_le32(MAUDIO_BOOTLOADER_CUE3); |
| + |
| rcode = fw_run_transaction(device->card, TCODE_WRITE_BLOCK_REQUEST, |
| device->node_id, device->generation, |
| device->max_speed, BEBOB_ADDR_REG_REQ, |
| - cues, sizeof(cues)); |
| + cues, 3 * sizeof(*cues)); |
| + kfree(cues); |
| if (rcode != RCODE_COMPLETE) { |
| dev_err(&unit->device, |
| "Failed to send a cue to load firmware\n"); |
| err = -EIO; |
| } |
| -end: |
| + |
| return err; |
| } |
| |