Received: by 10.192.165.148 with SMTP id m20csp4173159imm; Mon, 30 Apr 2018 13:10:15 -0700 (PDT) X-Google-Smtp-Source: AB8JxZqd4I4O+F5CDSes01mhHLe1mjvmTZnRYnLRlFEcceJPDoSeUDFcsjjpKzv8CTwe/YMv8H08 X-Received: by 2002:a17:902:290a:: with SMTP id g10-v6mr13632405plb.155.1525119015083; Mon, 30 Apr 2018 13:10:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525119015; cv=none; d=google.com; s=arc-20160816; b=eR847sQT5rNsEnqpHN0mBVKpjCt17fQSYTVkm+DgEWTcMkMSVoEVpvGTZNNcsFE8rI wTqNKEhDInBfVjlWiPOjy6Qyo7bU3LvLhwmQm8QeqzpDQIb7kB7OEUtw+Woy5Caop09e yDbR8XKojoLmHrfbVvy3UqNNo+CrMrRfUb+IUZw598/xgQjrOBjza4fH9mzXUq7lYidn GvcyZzSoQ/A7w7PPtSxM+i8SOgikbVDbBN64U6ozApSoXiG7UBPrkTB2khVFD45e6b0I JjDGzdhbLbgGJGO09zVW64pzj9ISHpJGynu7/+IBkezZCWESuybrvH8q0kHObhra35bf Xx1g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:message-id:date:subject:cc:to:from:dmarc-filter :arc-authentication-results; bh=W6LKyRQGuaUMVukTu7u4e2e3bzqkpSqhQ1TrGWxgXak=; b=SJgpGg8mVgxS+TDrNjYVHWv97Ev3/ychqHfr45EeLiJzCpXbISJ56duHjVrCF6tyrC tr65iAw9dS4zQd+SNybvP4PhHjHThPRDgeoS9wW6Tl+Pj+0ANioxLP5h6/imJb01nivo oIJVAoVHNHjr4PYcBmyfGaBwhjjJrKHC6G4koqj0VW4OgHMFIZ6+MFHF6AAAL5PaJLfC zJce45hy5UXimHmixckGV+yuoUcmqMnOZuxd0Me1RPaPG5JOHwt3Gycsga6BVLvqONal 1gPXttmh8QhdFqr17VJ7VJSu6d5DVMkcNm+2CImpXxSDIwTCobULEjZm6/YYAU3ghHCC 82YQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 73si7807718pfb.204.2018.04.30.13.09.59; Mon, 30 Apr 2018 13:10:15 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755943AbeD3T1V (ORCPT + 99 others); Mon, 30 Apr 2018 15:27:21 -0400 Received: from mail.kernel.org ([198.145.29.99]:33616 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753482AbeD3T1S (ORCPT ); Mon, 30 Apr 2018 15:27:18 -0400 Received: from localhost (unknown [104.132.1.102]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id BF5D722DCC; Mon, 30 Apr 2018 19:27:17 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org BF5D722DCC Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=linuxfoundation.org Authentication-Results: mail.kernel.org; spf=fail smtp.mailfrom=gregkh@linuxfoundation.org From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Dan Carpenter , Takashi Iwai Subject: [PATCH 4.14 45/91] ALSA: seq: oss: Hardening for potential Spectre v1 Date: Mon, 30 Apr 2018 12:24:27 -0700 Message-Id: <20180430184006.547893224@linuxfoundation.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180430184004.216234025@linuxfoundation.org> References: <20180430184004.216234025@linuxfoundation.org> User-Agent: quilt/0.65 X-stable: review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 4.14-stable review patch. If anyone has any objections, please let me know. ------------------ From: Takashi Iwai commit 8d218dd8116695ecda7164f97631c069938aa22e upstream. As Smatch recently suggested, a few places in OSS sequencer codes may expand the array directly from the user-space value with speculation, namely there are a significant amount of references to either info->ch[] or dp->synths[] array: sound/core/seq/oss/seq_oss_event.c:315 note_on_event() warn: potential spectre issue 'info->ch' (local cap) sound/core/seq/oss/seq_oss_event.c:362 note_off_event() warn: potential spectre issue 'info->ch' (local cap) sound/core/seq/oss/seq_oss_synth.c:470 snd_seq_oss_synth_load_patch() warn: potential spectre issue 'dp->synths' (local cap) sound/core/seq/oss/seq_oss_event.c:293 note_on_event() warn: potential spectre issue 'dp->synths' sound/core/seq/oss/seq_oss_event.c:353 note_off_event() warn: potential spectre issue 'dp->synths' sound/core/seq/oss/seq_oss_synth.c:506 snd_seq_oss_synth_sysex() warn: potential spectre issue 'dp->synths' sound/core/seq/oss/seq_oss_synth.c:580 snd_seq_oss_synth_ioctl() warn: potential spectre issue 'dp->synths' 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. We may put array_index_nospec() at each place, but here we take a different approach: - For dp->synths[], change the helpers to retrieve seq_oss_synthinfo pointer directly instead of the array expansion at each place - For info->ch[], harden in a normal way, as there are only a couple of places As a result, the existing helper, snd_seq_oss_synth_is_valid() is replaced with snd_seq_oss_synth_info(). Also, we cover MIDI device where a similar array expansion is done, too, although it wasn't reported by Smatch. BugLink: https://marc.info/?l=linux-kernel&m=152411496503418&w=2 Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/oss/seq_oss_event.c | 15 ++++--- sound/core/seq/oss/seq_oss_midi.c | 2 sound/core/seq/oss/seq_oss_synth.c | 75 ++++++++++++++++++++----------------- sound/core/seq/oss/seq_oss_synth.h | 3 - 4 files changed, 55 insertions(+), 40 deletions(-) --- a/sound/core/seq/oss/seq_oss_event.c +++ b/sound/core/seq/oss/seq_oss_event.c @@ -26,6 +26,7 @@ #include #include "seq_oss_readq.h" #include "seq_oss_writeq.h" +#include /* @@ -287,10 +288,10 @@ note_on_event(struct seq_oss_devinfo *dp { struct seq_oss_synthinfo *info; - if (!snd_seq_oss_synth_is_valid(dp, dev)) + info = snd_seq_oss_synth_info(dp, dev); + if (!info) return -ENXIO; - info = &dp->synths[dev]; switch (info->arg.event_passing) { case SNDRV_SEQ_OSS_PROCESS_EVENTS: if (! info->ch || ch < 0 || ch >= info->nr_voices) { @@ -298,6 +299,7 @@ note_on_event(struct seq_oss_devinfo *dp return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); } + ch = array_index_nospec(ch, info->nr_voices); if (note == 255 && info->ch[ch].note >= 0) { /* volume control */ int type; @@ -347,10 +349,10 @@ note_off_event(struct seq_oss_devinfo *d { struct seq_oss_synthinfo *info; - if (!snd_seq_oss_synth_is_valid(dp, dev)) + info = snd_seq_oss_synth_info(dp, dev); + if (!info) return -ENXIO; - info = &dp->synths[dev]; switch (info->arg.event_passing) { case SNDRV_SEQ_OSS_PROCESS_EVENTS: if (! info->ch || ch < 0 || ch >= info->nr_voices) { @@ -358,6 +360,7 @@ note_off_event(struct seq_oss_devinfo *d return set_note_event(dp, dev, SNDRV_SEQ_EVENT_NOTEON, ch, note, vel, ev); } + ch = array_index_nospec(ch, info->nr_voices); if (info->ch[ch].note >= 0) { note = info->ch[ch].note; info->ch[ch].vel = 0; @@ -381,7 +384,7 @@ note_off_event(struct seq_oss_devinfo *d static int set_note_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int note, int vel, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev)) + if (!snd_seq_oss_synth_info(dp, dev)) return -ENXIO; ev->type = type; @@ -399,7 +402,7 @@ set_note_event(struct seq_oss_devinfo *d static int set_control_event(struct seq_oss_devinfo *dp, int dev, int type, int ch, int param, int val, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev)) + if (!snd_seq_oss_synth_info(dp, dev)) return -ENXIO; ev->type = type; --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -29,6 +29,7 @@ #include "../seq_lock.h" #include #include +#include /* @@ -315,6 +316,7 @@ get_mididev(struct seq_oss_devinfo *dp, { if (dev < 0 || dev >= dp->max_mididev) return NULL; + dev = array_index_nospec(dev, dp->max_mididev); return get_mdev(dev); } --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -26,6 +26,7 @@ #include #include #include +#include /* * constants @@ -339,17 +340,13 @@ snd_seq_oss_synth_cleanup(struct seq_oss dp->max_synthdev = 0; } -/* - * check if the specified device is MIDI mapped device - */ -static int -is_midi_dev(struct seq_oss_devinfo *dp, int dev) +static struct seq_oss_synthinfo * +get_synthinfo_nospec(struct seq_oss_devinfo *dp, int dev) { if (dev < 0 || dev >= dp->max_synthdev) - return 0; - if (dp->synths[dev].is_midi) - return 1; - return 0; + return NULL; + dev = array_index_nospec(dev, SNDRV_SEQ_OSS_MAX_SYNTH_DEVS); + return &dp->synths[dev]; } /* @@ -359,11 +356,13 @@ static struct seq_oss_synth * get_synthdev(struct seq_oss_devinfo *dp, int dev) { struct seq_oss_synth *rec; - if (dev < 0 || dev >= dp->max_synthdev) + struct seq_oss_synthinfo *info = get_synthinfo_nospec(dp, dev); + + if (!info) return NULL; - if (! dp->synths[dev].opened) + if (!info->opened) return NULL; - if (dp->synths[dev].is_midi) { + if (info->is_midi) { rec = &midi_synth_dev; snd_use_lock_use(&rec->use_lock); } else { @@ -406,10 +405,8 @@ snd_seq_oss_synth_reset(struct seq_oss_d struct seq_oss_synth *rec; struct seq_oss_synthinfo *info; - if (snd_BUG_ON(dev < 0 || dev >= dp->max_synthdev)) - return; - info = &dp->synths[dev]; - if (! info->opened) + info = get_synthinfo_nospec(dp, dev); + if (!info || !info->opened) return; if (info->sysex) info->sysex->len = 0; /* reset sysex */ @@ -458,12 +455,14 @@ snd_seq_oss_synth_load_patch(struct seq_ const char __user *buf, int p, int c) { struct seq_oss_synth *rec; + struct seq_oss_synthinfo *info; int rc; - if (dev < 0 || dev >= dp->max_synthdev) + info = get_synthinfo_nospec(dp, dev); + if (!info) return -ENXIO; - if (is_midi_dev(dp, dev)) + if (info->is_midi) return 0; if ((rec = get_synthdev(dp, dev)) == NULL) return -ENXIO; @@ -471,24 +470,25 @@ snd_seq_oss_synth_load_patch(struct seq_ if (rec->oper.load_patch == NULL) rc = -ENXIO; else - rc = rec->oper.load_patch(&dp->synths[dev].arg, fmt, buf, p, c); + rc = rec->oper.load_patch(&info->arg, fmt, buf, p, c); snd_use_lock_free(&rec->use_lock); return rc; } /* - * check if the device is valid synth device + * check if the device is valid synth device and return the synth info */ -int -snd_seq_oss_synth_is_valid(struct seq_oss_devinfo *dp, int dev) +struct seq_oss_synthinfo * +snd_seq_oss_synth_info(struct seq_oss_devinfo *dp, int dev) { struct seq_oss_synth *rec; + rec = get_synthdev(dp, dev); if (rec) { snd_use_lock_free(&rec->use_lock); - return 1; + return get_synthinfo_nospec(dp, dev); } - return 0; + return NULL; } @@ -503,16 +503,18 @@ snd_seq_oss_synth_sysex(struct seq_oss_d int i, send; unsigned char *dest; struct seq_oss_synth_sysex *sysex; + struct seq_oss_synthinfo *info; - if (! snd_seq_oss_synth_is_valid(dp, dev)) + info = snd_seq_oss_synth_info(dp, dev); + if (!info) return -ENXIO; - sysex = dp->synths[dev].sysex; + sysex = info->sysex; if (sysex == NULL) { sysex = kzalloc(sizeof(*sysex), GFP_KERNEL); if (sysex == NULL) return -ENOMEM; - dp->synths[dev].sysex = sysex; + info->sysex = sysex; } send = 0; @@ -557,10 +559,12 @@ snd_seq_oss_synth_sysex(struct seq_oss_d int snd_seq_oss_synth_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev)) + struct seq_oss_synthinfo *info = snd_seq_oss_synth_info(dp, dev); + + if (!info) return -EINVAL; - snd_seq_oss_fill_addr(dp, ev, dp->synths[dev].arg.addr.client, - dp->synths[dev].arg.addr.port); + snd_seq_oss_fill_addr(dp, ev, info->arg.addr.client, + info->arg.addr.port); return 0; } @@ -572,16 +576,18 @@ int snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, unsigned long addr) { struct seq_oss_synth *rec; + struct seq_oss_synthinfo *info; int rc; - if (is_midi_dev(dp, dev)) + info = get_synthinfo_nospec(dp, dev); + if (!info || info->is_midi) return -ENXIO; if ((rec = get_synthdev(dp, dev)) == NULL) return -ENXIO; if (rec->oper.ioctl == NULL) rc = -ENXIO; else - rc = rec->oper.ioctl(&dp->synths[dev].arg, cmd, addr); + rc = rec->oper.ioctl(&info->arg, cmd, addr); snd_use_lock_free(&rec->use_lock); return rc; } @@ -593,7 +599,10 @@ snd_seq_oss_synth_ioctl(struct seq_oss_d int snd_seq_oss_synth_raw_event(struct seq_oss_devinfo *dp, int dev, unsigned char *data, struct snd_seq_event *ev) { - if (! snd_seq_oss_synth_is_valid(dp, dev) || is_midi_dev(dp, dev)) + struct seq_oss_synthinfo *info; + + info = snd_seq_oss_synth_info(dp, dev); + if (!info || info->is_midi) return -ENXIO; ev->type = SNDRV_SEQ_EVENT_OSS; memcpy(ev->data.raw8.d, data, 8); --- a/sound/core/seq/oss/seq_oss_synth.h +++ b/sound/core/seq/oss/seq_oss_synth.h @@ -37,7 +37,8 @@ void snd_seq_oss_synth_cleanup(struct se void snd_seq_oss_synth_reset(struct seq_oss_devinfo *dp, int dev); int snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt, const char __user *buf, int p, int c); -int snd_seq_oss_synth_is_valid(struct seq_oss_devinfo *dp, int dev); +struct seq_oss_synthinfo *snd_seq_oss_synth_info(struct seq_oss_devinfo *dp, + int dev); int snd_seq_oss_synth_sysex(struct seq_oss_devinfo *dp, int dev, unsigned char *buf, struct snd_seq_event *ev); int snd_seq_oss_synth_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_event *ev);