From patchwork Tue May 15 21:33:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roland Dreier X-Patchwork-Id: 10402035 X-Patchwork-Delegate: jgg@ziepe.ca Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 88128601F7 for ; Tue, 15 May 2018 21:34:01 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 77BEF2853E for ; Tue, 15 May 2018 21:34:01 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 6C35E28653; Tue, 15 May 2018 21:34:01 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CC7BE2853E for ; Tue, 15 May 2018 21:34:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752024AbeEOVd7 (ORCPT ); Tue, 15 May 2018 17:33:59 -0400 Received: from mail-pf0-f195.google.com ([209.85.192.195]:37178 "EHLO mail-pf0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751868AbeEOVd6 (ORCPT ); Tue, 15 May 2018 17:33:58 -0400 Received: by mail-pf0-f195.google.com with SMTP id e9-v6so682008pfi.4 for ; Tue, 15 May 2018 14:33:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=purestorage.com; s=google; h=sender:from:to:cc:subject:date:message-id; bh=wfmrRhCdZfh1vsBqBLWtX6Ocj6PgHZOcv6ja6L29TQQ=; b=PZyJt1bbOqP25/E6H70u7nZniqhR9q3tAh/WRlKtA0DgBkMbw7desz8kLQS/g5feCu jzGmKgByupdT0+fAmvsl7EspuZSFpb8/2+dNpa/PxzpoudbHrtGr7MMBcN7miYsXIqSC O1pVjazTMlkX2Dl49R86ZaaI4HAA14xn4CC4c= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id; bh=wfmrRhCdZfh1vsBqBLWtX6Ocj6PgHZOcv6ja6L29TQQ=; b=oVr175sj6vXZfHTtaiGjT8GTJEurNUAkzWkVhppYiwsvPdgVh/4PSqL2Ue1ZpECdJR DIk6wUpz4D/fVF0ILgy9o/bYek7x8m5kahcxNLNT/2keKm3kgFLw05FoMJDb3e0/H+Tp d0Q/DX/GpWHkMPh34SE/v13pFew6lR8RRrxliR6JQtMBUPHwWCnU0ED+XP4bv+Sk8wDf aHGGipjdJMZoimJfZqZy0jfeuB7qDmNtz9xTN6SgLAhmIrBlYMlf/p+acXbn9e+gOu3p gkQdcYeUhVa/n6ULZzfEkFKDyhSCGzmOP8MTCMcJOFrcqzKDUyWLU3QJ3xqZUxtZBeEd wtng== X-Gm-Message-State: ALKqPweU8lm3RkKD94Svm+T0vxqUBz+QW4XcvKwXUeKcKpOOk5RkLP2l qOGYFcKMO1ghJY6GZer3ikTjp+Um X-Google-Smtp-Source: AB8JxZqpho+u22j6wqYrncYfMMNVNWZZ478xYSJK9jqoGq+MXJW6qUKR21c2bVF+y7oV3ruQ6RCYYQ== X-Received: by 2002:a65:4acd:: with SMTP id c13-v6mr13905137pgu.32.1526420038278; Tue, 15 May 2018 14:33:58 -0700 (PDT) Received: from roland-x1-yoga.purestorage.com ([64.84.68.252]) by smtp.gmail.com with ESMTPSA id y24-v6sm1266917pfn.23.2018.05.15.14.33.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 15 May 2018 14:33:56 -0700 (PDT) From: Roland Dreier To: Doug Ledford , Jason Gunthorpe , Leon Romanovsky Cc: linux-rdma@vger.kernel.org, Eric Biggers Subject: [PATCH] RDMA/cma: Avoid using invalid state during rdma_bind_addr() Date: Tue, 15 May 2018 14:33:52 -0700 Message-Id: <20180515213352.29848-1-roland@kernel.org> X-Mailer: git-send-email 2.17.0 Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Roland Dreier There is a race (which userspace can trigger through ucma) that leads to use-after free in cma: rdma_bind_addr(id, bogus address) cma_comp_exch(RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND) [succeed] copy address into id_priv struct fail to find device for address rdma_listen(id, any address); id_priv state isn't RDMA_CM_IDLE cma_comp_exch(RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN) [succeed] id->device not set, call cma_listen_on_all() add id_priv->list to listen_any_list return success cma_comp_exch(RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE) [fail] return failure Now, when the id is destroyed, cma_release_dev() won't be called because id_priv->cma_dev isn't set. And cma_cancel_operation() won't call cma_cancel_listens() because cma_src_addr(id_priv) is the bogus address passed into rdma_bind_addr(). So neither of the paths that does list_del(&id_priv->list); will be followed, but the code will go ahead and kfree(id_priv) even though it is still linked into the listen_any_list. So we end up with use-after-free when listen_any_list is traversed. We can close this race by having rdma_bind_addr() put the CM ID into an intermediate "binding" state during the time that we are modifying the state but don't know whether the bind operation will succeed yet. Reported-and-tested-by: syzbot+db1c219466daac1083df@syzkaller.appspotmail.com Reported-by: Eric Biggers Signed-off-by: Roland Dreier --- drivers/infiniband/core/cma.c | 6 ++++-- drivers/infiniband/core/cma_priv.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index a693fcd4c513..826b4ffbf259 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -3345,7 +3345,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) return -EAFNOSUPPORT; id_priv = container_of(id, struct rdma_id_private, id); - if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND)) + if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BINDING)) return -EINVAL; ret = cma_check_linklocal(&id->route.addr.dev_addr, addr); @@ -3381,6 +3381,8 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) if (ret) goto err2; + cma_comp_exch(id_priv, RDMA_CM_ADDR_BINDING, RDMA_CM_ADDR_BOUND); + return 0; err2: if (id_priv->cma_dev) { @@ -3388,7 +3390,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr) cma_release_dev(id_priv); } err1: - cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE); + cma_comp_exch(id_priv, RDMA_CM_ADDR_BINDING, RDMA_CM_IDLE); return ret; } EXPORT_SYMBOL(rdma_bind_addr); diff --git a/drivers/infiniband/core/cma_priv.h b/drivers/infiniband/core/cma_priv.h index 194cfe78c447..8d0f8715dd51 100644 --- a/drivers/infiniband/core/cma_priv.h +++ b/drivers/infiniband/core/cma_priv.h @@ -44,6 +44,7 @@ enum rdma_cm_state { RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT, RDMA_CM_DISCONNECT, + RDMA_CM_ADDR_BINDING, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN, RDMA_CM_DEVICE_REMOVAL,