From patchwork Tue Dec 17 09:58:58 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yann Droneaud X-Patchwork-Id: 3360421 Return-Path: X-Original-To: patchwork-linux-rdma@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 3969D9F314 for ; Tue, 17 Dec 2013 10:00:17 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 1E55220398 for ; Tue, 17 Dec 2013 10:00:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 64928203A7 for ; Tue, 17 Dec 2013 10:00:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751430Ab3LQKAI (ORCPT ); Tue, 17 Dec 2013 05:00:08 -0500 Received: from smtp5-g21.free.fr ([212.27.42.5]:52559 "EHLO smtp5-g21.free.fr" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753125Ab3LQKAH (ORCPT ); Tue, 17 Dec 2013 05:00:07 -0500 Received: from localhost.localdomain (unknown [37.163.161.54]) by smtp5-g21.free.fr (Postfix) with ESMTP id B81D7D481BA; Tue, 17 Dec 2013 10:59:59 +0100 (CET) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by localhost.localdomain (8.14.7/8.14.7) with ESMTP id rBH9xv79002086; Tue, 17 Dec 2013 10:59:57 +0100 Received: (from ydroneaud@localhost) by localhost.localdomain (8.14.7/8.14.7/Submit) id rBH9xvFh002085; Tue, 17 Dec 2013 10:59:57 +0100 From: Yann Droneaud To: Roland Dreier , Roland Dreier Cc: linux-rdma@vger.kernel.org, Yann Droneaud Subject: [PATCHv4 for-3.13 09/10] IB/uverbs: check access to userspace response buffer in extended command Date: Tue, 17 Dec 2013 10:58:58 +0100 Message-Id: <16ed474c560fe771e49d1cf0f0ee2b6c84e12234.1387273677.git.ydroneaud@opteya.com> X-Mailer: git-send-email 1.8.4.2 In-Reply-To: References: In-Reply-To: References: Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Spam-Status: No, score=-7.4 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds a check on the output buffer with access_ok(VERIFY_WRITE, ...) to ensure the whole buffer is in userspace memory before using the pointer in uverbs functions. If the buffer or a subset of it is not valid, returns -EFAULT to the caller. This will also catch invalid buffer before the final call to copy_to_user() which happen late in most uverb functions. Just like the check in read(2) syscall, it's a sanity check to detect invalid parameters provided by userspace. This particular check was added in vfs_read() by Linus Torvalds for v2.6.12 with following commit message: https://git.kernel.org/cgit/linux/kernel/git/tglx/history.git/commit/?id=fd770e66c9a65b14ce114e171266cf6f393df502 Make read/write always do the full "access_ok()" tests. The actual user copy will do them too, but only for the range that ends up being actually copied. That hides bugs when the range has been clamped by file size or other issues. Note: there's no need to check input buffer since vfs_write() already does access_ok(VERIFY_READ, ...) as part of write() syscall. Link: http://marc.info/?i=cover.1387273677.git.ydroneaud@opteya.com Signed-off-by: Yann Droneaud --- drivers/infiniband/core/uverbs_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 8652c13f6ea2..0be1dd86f768 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -677,6 +677,11 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, if (response) { if (!hdr.out_words && !ex_hdr.provider_out_words) return -EINVAL; + + if (!access_ok(VERIFY_WRITE, + response, + (hdr.out_words + ex_hdr.provider_out_words) * 8)) + return -EFAULT; } else { if (hdr.out_words || ex_hdr.provider_out_words) return -EINVAL;