Received: by 10.213.65.68 with SMTP id h4csp672458imn; Fri, 6 Apr 2018 07:06:07 -0700 (PDT) X-Google-Smtp-Source: AIpwx49uFkbJ7wMRAl57bJtP4GzO7busSnXvTrDF3X1hkYdkALrBa4LLOkLb8uRxm0dsh3omtjPo X-Received: by 2002:a17:902:566:: with SMTP id 93-v6mr26699694plf.327.1523023567535; Fri, 06 Apr 2018 07:06:07 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523023567; cv=none; d=google.com; s=arc-20160816; b=gpVT0H+pHxoPmO/CVzgoRGsF0S7zwf/KIJkVu2OtjtOTWl+2CukoVtk7dlNAnpxv4D tFiwBXBc/4eX3VwCE0hTEgyemrg+a0HAJjnnGe7UopfGvLSBtsNI+D6bnCYDElXiqrNs KDpA/ORBSKefuKA9CeQcyXxOTmq09gvvpZExCxFJx1x62LePbMx7ejEoWtrt0pIDMQkf 4XPmtrop0Mnpxa5eIRDZZxlZdbsPP5Z4fdUdqOWAQpRerTO3fC0td+FWhH5ey3RfibjU a8Y2yFO1E1+Vss0IMy3GBi/LKz4OsA12fWF8AR56AgmSVaXWDhTLeBv7vIFZbWw5+QaQ nkiQ== 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 :arc-authentication-results; bh=jl3GWYuDPISO3sGYoQu48FhGHtPUjdcJ5gWa3RjLdaI=; b=op1Z/iUi7oFGgL+bfELNm4q3Q4x5OJ5/kPEAieEXsQxtNBS1KbvHWwrN5mHYri2Yrc Q91nxvJUEdAk0OWL9KnKsT5+cLihZG91KC/IhsnNUTZ0v1lpYNasD0R5qBQGCF52/AXJ wg76tZimUCwj8a7gU0RUU6NGfS0UdgxnHYfJL09nPPTGj+MVWrnJj8EL8fyUhFJGioAj mMwO81WfDz/hBoBM6uz+YBz3qz8Gp9BhtZcS+uUcC3REl4t2k/RG9UZfufWA8vXI5hIu +xRSXIdfUguOFSmhXcScuROsI3FgW//vD1/LqtXDeKJPXiiAU8VZw/0Hmq28lnSo96q8 6TDQ== 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 x8-v6si7876644plv.420.2018.04.06.07.05.53; Fri, 06 Apr 2018 07:06:07 -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 S1754382AbeDFOEU (ORCPT + 99 others); Fri, 6 Apr 2018 10:04:20 -0400 Received: from mail.linuxfoundation.org ([140.211.169.12]:36562 "EHLO mail.linuxfoundation.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932906AbeDFNlj (ORCPT ); Fri, 6 Apr 2018 09:41:39 -0400 Received: from localhost (LFbn-1-12247-202.w90-92.abo.wanadoo.fr [90.92.61.202]) by mail.linuxfoundation.org (Postfix) with ESMTPSA id 429A6C64; Fri, 6 Apr 2018 13:41:38 +0000 (UTC) From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, syzbot+6800425d54ed3ed8135d@syzkaller.appspotmail.com, Roland Dreier , Jason Gunthorpe Subject: [PATCH 4.15 27/72] RDMA/ucma: Introduce safer rdma_addr_size() variants Date: Fri, 6 Apr 2018 15:24:02 +0200 Message-Id: <20180406084351.618621527@linuxfoundation.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180406084349.367583460@linuxfoundation.org> References: <20180406084349.367583460@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.15-stable review patch. If anyone has any objections, please let me know. ------------------ From: Roland Dreier commit 84652aefb347297aa08e91e283adf7b18f77c2d5 upstream. 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: Signed-off-by: Roland Dreier Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/addr.c | 16 ++++++++++++++++ drivers/infiniband/core/ucma.c | 34 +++++++++++++++++----------------- include/rdma/ib_addr.h | 2 ++ 3 files changed, 35 insertions(+), 17 deletions(-) --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -207,6 +207,22 @@ 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) --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -632,6 +632,9 @@ static ssize_t ucma_bind_ip(struct ucma_ 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_fil 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,22 @@ static ssize_t ucma_resolve_ip(struct uc 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 +697,23 @@ static ssize_t ucma_resolve_addr(struct 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; } @@ -1432,7 +1432,7 @@ static ssize_t ucma_join_ip_multicast(st 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; @@ -1451,7 +1451,7 @@ static ssize_t ucma_join_multicast(struc 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); --- a/include/rdma/ib_addr.h +++ b/include/rdma/ib_addr.h @@ -130,6 +130,8 @@ void rdma_copy_addr(struct rdma_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_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id); int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,