From patchwork Wed Mar 28 18:27:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roland Dreier X-Patchwork-Id: 10313857 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 A69E4600F6 for ; Wed, 28 Mar 2018 18:27:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 94F8A28B1A for ; Wed, 28 Mar 2018 18:27:35 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 88AE828B61; Wed, 28 Mar 2018 18:27:35 +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=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, 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 6A7D428B1A for ; Wed, 28 Mar 2018 18:27:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752732AbeC1S1d (ORCPT ); Wed, 28 Mar 2018 14:27:33 -0400 Received: from mail-pg0-f65.google.com ([74.125.83.65]:37763 "EHLO mail-pg0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752462AbeC1S1c (ORCPT ); Wed, 28 Mar 2018 14:27:32 -0400 Received: by mail-pg0-f65.google.com with SMTP id n11so1311137pgp.4 for ; Wed, 28 Mar 2018 11:27:32 -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=iw3ByzJb/vInIVEvch6Tm63afLFel2InB2YbaXeaObY=; b=JRf9tbWLj7lfDJhSD74s7CYasMADJYi6sYnxybI5uiXw7/5v4r9qdlFI9bseZW5MhI Ld0I0zKJLPm2d/noDYK26c2XkhwhIUVb2cCO1rcgExbEYlg4X6Lkeko/eortTHNt9BWP DkV9Y8ouk1s7hLZsYmxNB8JRU1WxwQOhF6BWI= 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=iw3ByzJb/vInIVEvch6Tm63afLFel2InB2YbaXeaObY=; b=kfiXV0AARynDoKcqjrLGQ3TTJO5Hf8mSORti+60NNxhaCm+xJOhTfAuDhGtQgUi77W SmZrM2wz6paHADlaO7DSNm1Ungie2Ya1lXEC+uRVSLcau0PrfD+wAhoagLo3q98bmkqM +GHw1eDZ1jQ7lKAZQHi/cfuPof5dtOXXArMWoqOzLqJsOENLOHQvQjt/YZ0pyDEwj/gx JztqBIezQnfymCHgJC+dL0dCMLb3yMSmNboARvYJGvRyFyihl6RDVnNl9rPzXsgtHMXl znDUGJ9f+8RLYiFbqG15xHS/+/+5/aSH+2Yc6Do2qUUSChJf0yat5/0rlgQKWb67+hZf uHTQ== X-Gm-Message-State: AElRT7GnDTVZFjkstTgmhbN6tsGUyjLl1XaOexCpJBhEeaSlHyvgMOAf r+bIwEUAnJJpxqFUu1zeGL81NA== X-Google-Smtp-Source: AIpwx4+ZZ1rdnfcxYx5Fu1KC8YwUKtGZYZYPouMKoo1Yi4lAb4Qf02MVvjtuUx6WiK7uzSESOJWI/w== X-Received: by 10.101.98.151 with SMTP id f23mr3293632pgv.98.1522261647403; Wed, 28 Mar 2018 11:27:27 -0700 (PDT) Received: from roland-x1-yoga.purestorage.com ([64.84.68.252]) by smtp.gmail.com with ESMTPSA id a4sm10920903pfj.107.2018.03.28.11.27.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 28 Mar 2018 11:27:26 -0700 (PDT) From: Roland Dreier To: Doug Ledford , Jason Gunthorpe , Leon Romanovsky , Sean Hefty , syzbot Cc: linux-rdma@vger.kernel.org Subject: [PATCH] RDMA/ucma: Introduce safer rdma_addr_size() variants Date: Wed, 28 Mar 2018 11:27:22 -0700 Message-Id: <20180328182722.26354-1-roland@kernel.org> X-Mailer: git-send-email 2.15.1 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 are several places in the ucma ABI where userspace can pass in a sockaddr but set the address family to AF_IB. When that happens, rdma_addr_size() will return a size bigger than sizeof struct sockaddr_in6, and the ucma kernel code might end up copying past the end of a buffer not sized for a struct sockaddr_ib. Fix this by introducing new variants int rdma_addr_size_in6(struct sockaddr_in6 *addr); int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr); that are type-safe for the types used in the ucma ABI and return 0 if the size computed is bigger than the size of the type passed in. We can use these new variants to check what size userspace has passed in before copying any addresses. Reported-by: syzbot+6800425d54ed3ed8135d@syzkaller.appspotmail.com Signed-off-by: Roland Dreier --- #syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git master drivers/infiniband/core/addr.c | 14 ++++++++++++++ drivers/infiniband/core/ucma.c | 33 ++++++++++++++++----------------- include/rdma/ib_addr.h | 2 ++ 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 9183d148d644..97edaf12172e 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -207,6 +207,20 @@ int rdma_addr_size(struct sockaddr *addr) } EXPORT_SYMBOL(rdma_addr_size); +int rdma_addr_size_in6(struct sockaddr_in6 *addr) +{ + int ret = rdma_addr_size((struct sockaddr *) addr); + return ret <= sizeof(*addr) ? ret : 0; +} +EXPORT_SYMBOL(rdma_addr_size_in6); + +int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr) +{ + int ret = rdma_addr_size((struct sockaddr *) addr); + return ret <= sizeof(*addr) ? ret : 0; +} +EXPORT_SYMBOL(rdma_addr_size_kss); + static struct rdma_addr_client self; void rdma_addr_register_client(struct rdma_addr_client *client) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index e5a1e7d81326..0176d31431a7 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -632,6 +632,9 @@ static ssize_t ucma_bind_ip(struct ucma_file *file, const char __user *inbuf, if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; + if (!rdma_addr_size_in6(&cmd.addr)) + return -EINVAL; + ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); @@ -645,22 +648,21 @@ static ssize_t ucma_bind(struct ucma_file *file, const char __user *inbuf, int in_len, int out_len) { struct rdma_ucm_bind cmd; - struct sockaddr *addr; struct ucma_context *ctx; int ret; if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - addr = (struct sockaddr *) &cmd.addr; - if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr))) + if (cmd.reserved || !cmd.addr_size || + cmd.addr_size != rdma_addr_size_kss(&cmd.addr)) return -EINVAL; ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = rdma_bind_addr(ctx->cm_id, addr); + ret = rdma_bind_addr(ctx->cm_id, (struct sockaddr *) &cmd.addr); ucma_put_ctx(ctx); return ret; } @@ -670,23 +672,21 @@ static ssize_t ucma_resolve_ip(struct ucma_file *file, int in_len, int out_len) { struct rdma_ucm_resolve_ip cmd; - struct sockaddr *src, *dst; struct ucma_context *ctx; int ret; if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - src = (struct sockaddr *) &cmd.src_addr; - dst = (struct sockaddr *) &cmd.dst_addr; - if (!rdma_addr_size(src) || !rdma_addr_size(dst)) + if (!rdma_addr_size_in6(&cmd.src_addr) || !rdma_addr_size_in6(&cmd.dst_addr)) return -EINVAL; ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms); + ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr, + (struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms); ucma_put_ctx(ctx); return ret; } @@ -696,24 +696,23 @@ static ssize_t ucma_resolve_addr(struct ucma_file *file, int in_len, int out_len) { struct rdma_ucm_resolve_addr cmd; - struct sockaddr *src, *dst; struct ucma_context *ctx; int ret; if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - src = (struct sockaddr *) &cmd.src_addr; - dst = (struct sockaddr *) &cmd.dst_addr; - if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) || - !cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst))) + if (cmd.reserved || + (cmd.src_size && (cmd.src_size != rdma_addr_size_kss(&cmd.src_addr))) || + !cmd.dst_size || (cmd.dst_size != rdma_addr_size_kss(&cmd.dst_addr))) return -EINVAL; ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms); + ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr, + (struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms); ucma_put_ctx(ctx); return ret; } @@ -1426,7 +1425,7 @@ static ssize_t ucma_join_ip_multicast(struct ucma_file *file, join_cmd.response = cmd.response; join_cmd.uid = cmd.uid; join_cmd.id = cmd.id; - join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr); + join_cmd.addr_size = rdma_addr_size_in6(&cmd.addr); if (!join_cmd.addr_size) return -EINVAL; @@ -1445,7 +1444,7 @@ static ssize_t ucma_join_multicast(struct ucma_file *file, if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - if (!rdma_addr_size((struct sockaddr *)&cmd.addr)) + if (!rdma_addr_size_kss(&cmd.addr)) return -EINVAL; return ucma_process_join(file, &cmd, out_len); diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h index d656809f1217..415e09960017 100644 --- a/include/rdma/ib_addr.h +++ b/include/rdma/ib_addr.h @@ -130,6 +130,8 @@ void rdma_copy_addr(struct rdma_dev_addr *dev_addr, const unsigned char *dst_dev_addr); int rdma_addr_size(struct sockaddr *addr); +int rdma_addr_size_in6(struct sockaddr_in6 *addr); +int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr); int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid, const union ib_gid *dgid,