From patchwork Fri May 22 04:15:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Hubbard X-Patchwork-Id: 11564659 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E82E514C0 for ; Fri, 22 May 2020 04:15:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CF31520663 for ; Fri, 22 May 2020 04:15:17 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=nvidia.com header.i=@nvidia.com header.b="Z4x5Qx/G" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726911AbgEVEPK (ORCPT ); Fri, 22 May 2020 00:15:10 -0400 Received: from hqnvemgate24.nvidia.com ([216.228.121.143]:4058 "EHLO hqnvemgate24.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726816AbgEVEPJ (ORCPT ); Fri, 22 May 2020 00:15:09 -0400 Received: from hqpgpgate102.nvidia.com (Not Verified[216.228.121.13]) by hqnvemgate24.nvidia.com (using TLS: TLSv1.2, DES-CBC3-SHA) id ; Thu, 21 May 2020 21:12:44 -0700 Received: from hqmail.nvidia.com ([172.20.161.6]) by hqpgpgate102.nvidia.com (PGP Universal service); Thu, 21 May 2020 21:15:09 -0700 X-PGP-Universal: processed; by hqpgpgate102.nvidia.com on Thu, 21 May 2020 21:15:09 -0700 Received: from HQMAIL109.nvidia.com (172.20.187.15) by HQMAIL109.nvidia.com (172.20.187.15) with Microsoft SMTP Server (TLS) id 15.0.1473.3; Fri, 22 May 2020 04:15:09 +0000 Received: from rnnvemgw01.nvidia.com (10.128.109.123) by HQMAIL109.nvidia.com (172.20.187.15) with Microsoft SMTP Server (TLS) id 15.0.1473.3 via Frontend Transport; Fri, 22 May 2020 04:15:08 +0000 Received: from sandstorm.nvidia.com (Not Verified[10.2.48.182]) by rnnvemgw01.nvidia.com with Trustwave SEG (v7,5,8,10121) id ; Thu, 21 May 2020 21:15:08 -0700 From: John Hubbard To: LKML CC: John Hubbard , Bartlomiej Zolnierkiewicz , Arnd Bergmann , Daniel Vetter , "Gustavo A . R . Silva" , Jani Nikula , , Subject: [PATCH 1/2] video: fbdev: fix error handling for get_user_pages_fast() Date: Thu, 21 May 2020 21:15:05 -0700 Message-ID: <20200522041506.39638-2-jhubbard@nvidia.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200522041506.39638-1-jhubbard@nvidia.com> References: <20200522041506.39638-1-jhubbard@nvidia.com> MIME-Version: 1.0 X-NVConfidentiality: public DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nvidia.com; s=n1; t=1590120764; bh=lgtvms+evwCjD3x/lZ3Ysebw94Ksle/umtDMCsm3L+c=; h=X-PGP-Universal:From:To:CC:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:X-NVConfidentiality: Content-Transfer-Encoding:Content-Type; b=Z4x5Qx/GuV0Tog+KoMSLIucx2GzopLPT8awTgV0oqpYYTz5l7IXS8Dayvgwys0vkK WJ1Tp/Vgx19mTdabiGSlUgiJK8HYhoFk0NrUI6B6YBFK8/UahHC/HGCNGKUcGHNlzw xCgpmeNtJOD4zXoTeW0ZMCXbdRQQADn2c2+eZ7ITFgOttpe4KUCrExBiKlZGcqOXy6 m7GU/PkAC17Ymq5o4LbX4haeiPBJ/FZOG9B8qgeoCClFq3e4jimzfv/Etn6myKy3jh YdscZLVAGMAQt16da8HdU6N/r8QrZtHRjbc3UjbIzcG0+5Ol62LxmUIExoSe9bYKKm yuPbNSfgmaIpw== Sender: linux-fbdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fbdev@vger.kernel.org Dealing with the return value of get_user_pages*() variants has a few classic pitfalls, and this driver found one of them: the return value might be zero, positive, or -errno. And if positive, it might be fewer pages than were requested. And if fewer pages than requested, then the caller should return (via put_page()) the pages that *were* pinned. This driver was doing that *except* that it had a problem with the -errno case, which was being stored in an unsigned int, and which would case an interesting mess if it ever happened: nr_pages would be interpreted as a spectacularly huge unsigned value, rather than a small negative value. Also, it was unnecessarily overriding a potentially informative -errno, with -EINVAL, in some cases. Instead: clamp the nr_pages to zero or positive, so that the error handling works. And return the -errno value from get_user_pages*(), unchanged, if we get one. And explain this with comments, seeing as how it is error-prone. Cc: Bartlomiej Zolnierkiewicz Cc: Arnd Bergmann Cc: Daniel Vetter Cc: Gustavo A. R. Silva Cc: Jani Nikula Cc: dri-devel@lists.freedesktop.org Cc: linux-fbdev@vger.kernel.org Signed-off-by: John Hubbard --- drivers/video/fbdev/pvr2fb.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c index f18d457175d9..ceb6ef590597 100644 --- a/drivers/video/fbdev/pvr2fb.c +++ b/drivers/video/fbdev/pvr2fb.c @@ -654,8 +654,22 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf, ret = get_user_pages_fast((unsigned long)buf, nr_pages, FOLL_WRITE, pages); if (ret < nr_pages) { - nr_pages = ret; - ret = -EINVAL; + if (ret < 0) { + /* + * Clamp the unsigned nr_pages to zero so that the + * error handling works. And leave ret at whatever + * -errno value was returned from GUP. + */ + nr_pages = 0; + } else { + nr_pages = ret; + /* + * Use -EINVAL to represent a mildly desperate guess at + * why we got fewer pages (maybe even zero pages) than + * requested. + */ + ret = -EINVAL; + } goto out_unmap; }