From patchwork Thu Jun 7 23:28:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kleber Sacilotto de Souza X-Patchwork-Id: 926540 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4121vq4118z9s3q; Fri, 8 Jun 2018 09:29:11 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1fR4L1-0005jF-R3; Thu, 07 Jun 2018 23:29:03 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1fR4L0-0005it-51 for kernel-team@lists.ubuntu.com; Thu, 07 Jun 2018 23:29:02 +0000 Received: from mail-it0-f72.google.com ([209.85.214.72]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1fR4Kz-0000aL-QV for kernel-team@lists.ubuntu.com; Thu, 07 Jun 2018 23:29:01 +0000 Received: by mail-it0-f72.google.com with SMTP id v127-v6so114506ith.9 for ; Thu, 07 Jun 2018 16:29:01 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=yPGvjVPfq83duqr92KAAXZsIASBG3/HaSYAAgJaKvw8=; b=NdQDwzNJoSPDX2xKjtvGuNFZenzA+KVhyMT7lMSFSN8HbfZT1H2xHkMYYNxfWe0yXv KgNiEv8gQe6/3++SHdea3VO+XcMf3QA+eriByOiG7h7P9b4VF4dMlvrx4KWhAEryra54 rh1RcANCFXhAy4vzMPzJH1AH8/MzF1BKzzFi0UyNEumeag9h53Rdu7jK9qGEm+DqOQYP wEYoqJaqo3oETxzCNXcTovWyuJkGV4ce75isdWUkLOJCmtKyk1swh0bdl8vz3CwUCUr3 kwe7l7Gok9RnUPAronUO3fNvez18fs1LZrVhzoG+ez2IVpFP6ziUMqcN7mchkmFehzAX tZHw== X-Gm-Message-State: APt69E2GBO5hjshRr3K+a6gdH5XgRA9rSaBp1LInCsxaT4FkytAR4A9F 0rkqoM+KMVr0qtj6fo6+aBIPZMuAhuNTDuOZgWry9nf1sTTxzaLN5tY681gCtc4gWAV1JD21qm6 9OhNnujtp1oluJY5y8sMWw0e0BipOshIU3aZZONvKYQ== X-Received: by 2002:a24:d484:: with SMTP id x126-v6mr3514682itg.64.1528414140638; Thu, 07 Jun 2018 16:29:00 -0700 (PDT) X-Google-Smtp-Source: ADUXVKK4SgHusMEM0tvtw8eTPukp/LYcmYhb2Y4yQ9CzuN3el847M8kH4xMofWVgX6ZDnlRzYPD77Q== X-Received: by 2002:a24:d484:: with SMTP id x126-v6mr3514666itg.64.1528414140405; Thu, 07 Jun 2018 16:29:00 -0700 (PDT) Received: from localhost (50-201-118-110-static.hfc.comcastbusiness.net. [50.201.118.110]) by smtp.gmail.com with ESMTPSA id f14-v6sm8098487ioc.17.2018.06.07.16.28.59 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Thu, 07 Jun 2018 16:28:59 -0700 (PDT) From: Kleber Sacilotto de Souza To: kernel-team@lists.ubuntu.com Subject: [SRU][Trusty][PATCH 1/1] ALSA: seq: Fix use-after-free at creating a port Date: Thu, 7 Jun 2018 16:28:56 -0700 Message-Id: <20180607232856.28995-2-kleber.souza@canonical.com> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180607232856.28995-1-kleber.souza@canonical.com> References: <20180607232856.28995-1-kleber.souza@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Takashi Iwai There is a potential race window opened at creating and deleting a port via ioctl, as spotted by fuzzing. snd_seq_create_port() creates a port object and returns its pointer, but it doesn't take the refcount, thus it can be deleted immediately by another thread. Meanwhile, snd_seq_ioctl_create_port() still calls the function snd_seq_system_client_ev_port_start() with the created port object that is being deleted, and this triggers use-after-free like: BUG: KASAN: use-after-free in snd_seq_ioctl_create_port+0x504/0x630 [snd_seq] at addr ffff8801f2241cb1 ============================================================================= BUG kmalloc-512 (Tainted: G B ): kasan: bad access detected ----------------------------------------------------------------------------- INFO: Allocated in snd_seq_create_port+0x94/0x9b0 [snd_seq] age=1 cpu=3 pid=4511 ___slab_alloc+0x425/0x460 __slab_alloc+0x20/0x40 kmem_cache_alloc_trace+0x150/0x190 snd_seq_create_port+0x94/0x9b0 [snd_seq] snd_seq_ioctl_create_port+0xd1/0x630 [snd_seq] snd_seq_do_ioctl+0x11c/0x190 [snd_seq] snd_seq_ioctl+0x40/0x80 [snd_seq] do_vfs_ioctl+0x54b/0xda0 SyS_ioctl+0x79/0x90 entry_SYSCALL_64_fastpath+0x16/0x75 INFO: Freed in port_delete+0x136/0x1a0 [snd_seq] age=1 cpu=2 pid=4717 __slab_free+0x204/0x310 kfree+0x15f/0x180 port_delete+0x136/0x1a0 [snd_seq] snd_seq_delete_port+0x235/0x350 [snd_seq] snd_seq_ioctl_delete_port+0xc8/0x180 [snd_seq] snd_seq_do_ioctl+0x11c/0x190 [snd_seq] snd_seq_ioctl+0x40/0x80 [snd_seq] do_vfs_ioctl+0x54b/0xda0 SyS_ioctl+0x79/0x90 entry_SYSCALL_64_fastpath+0x16/0x75 Call Trace: [] dump_stack+0x63/0x82 [] print_trailer+0xfb/0x160 [] object_err+0x34/0x40 [] kasan_report.part.2+0x223/0x520 [] ? snd_seq_ioctl_create_port+0x504/0x630 [snd_seq] [] __asan_report_load1_noabort+0x2e/0x30 [] snd_seq_ioctl_create_port+0x504/0x630 [snd_seq] [] ? snd_seq_ioctl_delete_port+0x180/0x180 [snd_seq] [] ? taskstats_exit+0xbc0/0xbc0 [] snd_seq_do_ioctl+0x11c/0x190 [snd_seq] [] snd_seq_ioctl+0x40/0x80 [snd_seq] [] ? acct_account_cputime+0x63/0x80 [] do_vfs_ioctl+0x54b/0xda0 ..... We may fix this in a few different ways, and in this patch, it's fixed simply by taking the refcount properly at snd_seq_create_port() and letting the caller unref the object after use. Also, there is another potential use-after-free by sprintf() call in snd_seq_create_port(), and this is moved inside the lock. This fix covers CVE-2017-15265. Reported-and-tested-by: Michael23 Yu Suggested-by: Linus Torvalds Cc: Signed-off-by: Takashi Iwai CVE-2017-15265 (backported from commit 71105998845fb012937332fe2e806d443c09e026) Signed-off-by: Kleber Sacilotto de Souza Acked-by: Stefan Bader Acked-by: Andy Whitcroft --- sound/core/seq/seq_clientmgr.c | 6 +++++- sound/core/seq/seq_ports.c | 7 +++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 08865dcbf5f1..750e4a975379 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1248,6 +1248,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, struct snd_seq_client_port *port; struct snd_seq_port_info info; struct snd_seq_port_callback *callback; + int port_idx; if (copy_from_user(&info, arg, sizeof(info))) return -EFAULT; @@ -1261,7 +1262,9 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, return -ENOMEM; if (client->type == USER_CLIENT && info.kernel) { - snd_seq_delete_port(client, port->addr.port); + port_idx = port->addr.port; + snd_seq_port_unlock(port); + snd_seq_delete_port(client, port_idx); return -EINVAL; } if (client->type == KERNEL_CLIENT) { @@ -1283,6 +1286,7 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, snd_seq_set_port_info(port, &info); snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port); + snd_seq_port_unlock(port); if (copy_to_user(arg, &info, sizeof(info))) return -EFAULT; diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index 0cb3c28b7a3e..7960f898f37b 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -122,7 +122,9 @@ static void port_subs_info_init(struct snd_seq_port_subs_info *grp) } -/* create a port, port number is returned (-1 on failure) */ +/* create a port, port number is returned (-1 on failure); + * the caller needs to unref the port via snd_seq_port_unlock() appropriately + */ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, int port) { @@ -151,6 +153,7 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, snd_use_lock_init(&new_port->use_lock); port_subs_info_init(&new_port->c_src); port_subs_info_init(&new_port->c_dest); + snd_use_lock_use(&new_port->use_lock); num = port >= 0 ? port : 0; mutex_lock(&client->ports_mutex); @@ -165,9 +168,9 @@ struct snd_seq_client_port *snd_seq_create_port(struct snd_seq_client *client, list_add_tail(&new_port->list, &p->list); client->num_ports++; new_port->addr.port = num; /* store the port number in the port */ + sprintf(new_port->name, "port-%d", num); write_unlock_irqrestore(&client->ports_lock, flags); mutex_unlock(&client->ports_mutex); - sprintf(new_port->name, "port-%d", num); return new_port; }