| From: Takashi Iwai <tiwai@suse.de> |
| Date: Tue, 24 Apr 2018 07:45:56 +0200 |
| Subject: ALSA: control: Hardening for potential Spectre v1 |
| |
| commit 088e861edffb84879cf0c0d1b02eda078c3a0ffe upstream. |
| |
| As recently Smatch suggested, a few places in ALSA control core codes |
| may expand the array directly from the user-space value with |
| speculation: |
| |
| sound/core/control.c:1003 snd_ctl_elem_lock() warn: potential spectre issue 'kctl->vd' |
| sound/core/control.c:1031 snd_ctl_elem_unlock() warn: potential spectre issue 'kctl->vd' |
| sound/core/control.c:844 snd_ctl_elem_info() warn: potential spectre issue 'kctl->vd' |
| sound/core/control.c:891 snd_ctl_elem_read() warn: potential spectre issue 'kctl->vd' |
| sound/core/control.c:939 snd_ctl_elem_write() warn: potential spectre issue 'kctl->vd' |
| |
| Although all these seem doing only the first load without further |
| reference, we may want to stay in a safer side, so hardening with |
| array_index_nospec() would still make sense. |
| |
| In this patch, we put array_index_nospec() to the common |
| snd_ctl_get_ioff*() helpers instead of each caller. These helpers are |
| also referred from some drivers, too, and basically all usages are to |
| calculate the array index from the user-space value, hence it's better |
| to cover there. |
| |
| 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> |
| --- |
| include/sound/control.h | 7 +++++-- |
| 1 file changed, 5 insertions(+), 2 deletions(-) |
| |
| --- a/include/sound/control.h |
| +++ b/include/sound/control.h |
| @@ -22,6 +22,7 @@ |
| * |
| */ |
| |
| +#include <linux/nospec.h> |
| #include <sound/asound.h> |
| |
| #define snd_kcontrol_chip(kcontrol) ((kcontrol)->private_data) |
| @@ -135,12 +136,14 @@ int snd_ctl_unregister_ioctl_compat(snd_ |
| |
| static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) |
| { |
| - return id->numid - kctl->id.numid; |
| + unsigned int ioff = id->numid - kctl->id.numid; |
| + return array_index_nospec(ioff, kctl->count); |
| } |
| |
| static inline unsigned int snd_ctl_get_ioffidx(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) |
| { |
| - return id->index - kctl->id.index; |
| + unsigned int ioff = id->index - kctl->id.index; |
| + return array_index_nospec(ioff, kctl->count); |
| } |
| |
| static inline unsigned int snd_ctl_get_ioff(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id) |