| From: Takashi Iwai <tiwai@suse.de> |
| Date: Tue, 24 Apr 2018 08:03:14 +0200 |
| Subject: ALSA: hdspm: Hardening for potential Spectre v1 |
| |
| commit 10513142a7114d251670361ad40cba2c61403406 upstream. |
| |
| As recently Smatch suggested, a couple of places in HDSP MADI driver |
| may expand the array directly from the user-space value with |
| speculation: |
| sound/pci/rme9652/hdspm.c:5717 snd_hdspm_channel_info() warn: potential spectre issue 'hdspm->channel_map_out' (local cap) |
| sound/pci/rme9652/hdspm.c:5734 snd_hdspm_channel_info() warn: potential spectre issue 'hdspm->channel_map_in' (local cap) |
| |
| This patch puts array_index_nospec() for hardening against them. |
| |
| BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 |
| Reported-by: Dan Carpenter <dan.carpenter@oracle.com> |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| [bwh: Backported to 3.16: adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| sound/pci/rme9652/hdspm.c | 24 ++++++++++++++---------- |
| 1 file changed, 14 insertions(+), 10 deletions(-) |
| |
| --- a/sound/pci/rme9652/hdspm.c |
| +++ b/sound/pci/rme9652/hdspm.c |
| @@ -137,6 +137,7 @@ |
| #include <linux/pci.h> |
| #include <linux/math64.h> |
| #include <asm/io.h> |
| +#include <linux/nospec.h> |
| |
| #include <sound/core.h> |
| #include <sound/control.h> |
| @@ -5724,40 +5725,43 @@ static int snd_hdspm_channel_info(struct |
| struct snd_pcm_channel_info *info) |
| { |
| struct hdspm *hdspm = snd_pcm_substream_chip(substream); |
| + unsigned int channel = info->channel; |
| |
| if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
| - if (snd_BUG_ON(info->channel >= hdspm->max_channels_out)) { |
| + if (snd_BUG_ON(channel >= hdspm->max_channels_out)) { |
| dev_info(hdspm->card->dev, |
| "snd_hdspm_channel_info: output channel out of range (%d)\n", |
| - info->channel); |
| + channel); |
| return -EINVAL; |
| } |
| |
| - if (hdspm->channel_map_out[info->channel] < 0) { |
| + channel = array_index_nospec(channel, hdspm->max_channels_out); |
| + if (hdspm->channel_map_out[channel] < 0) { |
| dev_info(hdspm->card->dev, |
| "snd_hdspm_channel_info: output channel %d mapped out\n", |
| - info->channel); |
| + channel); |
| return -EINVAL; |
| } |
| |
| - info->offset = hdspm->channel_map_out[info->channel] * |
| + info->offset = hdspm->channel_map_out[channel] * |
| HDSPM_CHANNEL_BUFFER_BYTES; |
| } else { |
| - if (snd_BUG_ON(info->channel >= hdspm->max_channels_in)) { |
| + if (snd_BUG_ON(channel >= hdspm->max_channels_in)) { |
| dev_info(hdspm->card->dev, |
| "snd_hdspm_channel_info: input channel out of range (%d)\n", |
| - info->channel); |
| + channel); |
| return -EINVAL; |
| } |
| |
| - if (hdspm->channel_map_in[info->channel] < 0) { |
| + channel = array_index_nospec(channel, hdspm->max_channels_in); |
| + if (hdspm->channel_map_in[channel] < 0) { |
| dev_info(hdspm->card->dev, |
| "snd_hdspm_channel_info: input channel %d mapped out\n", |
| - info->channel); |
| + channel); |
| return -EINVAL; |
| } |
| |
| - info->offset = hdspm->channel_map_in[info->channel] * |
| + info->offset = hdspm->channel_map_in[channel] * |
| HDSPM_CHANNEL_BUFFER_BYTES; |
| } |
| |