Received: by 2002:ac0:a679:0:0:0:0:0 with SMTP id p54csp116474imp; Wed, 20 Feb 2019 15:34:42 -0800 (PST) X-Google-Smtp-Source: AHgI3Ia6LAZLF8Nc2IUu0wees4CUpsjkBOdteAZwPSnuTZqg6yikKAm6ERDd9J75jyCkCXtEYow9 X-Received: by 2002:a63:f253:: with SMTP id d19mr31466951pgk.14.1550705682096; Wed, 20 Feb 2019 15:34:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1550705682; cv=none; d=google.com; s=arc-20160816; b=lFSAwpqo5tO2sBVO9OH1rD9fu9iK3uhxqW1YDKUr08DNMfSeiTZuW1MA0c7Z3Jg43b whAG+pYGRZinBdsgCJWsX0/bf8kJ0lQUmY915WzVY/FvN5k3gk10aLx/6cHnuqZokyEm pcxs/vZvzBiLCohnC/k4zCcKBL9t43W9YisDM0N2K4wmjnp4zhgUyVM5xoaOg1vCWrVv fUFJP5Sbmv9Y116uL/UOdp2GWdFwktuXclsMlJfFFQ3dvm2bcfglapdMmIDExPsvo4TA o5xZDxmJ39MVZ8VsyGfxccu5ju9XOPkUL62K+lrYaPga1199GfO4IDWMrqPm7hvlpl9H VDqw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:mime-version:user-agent:date:message-id:cc:to :subject:from; bh=M9Noj+DRr1BvEL/PTqvWWP1JC3jiVarPN0iqmKSNI8g=; b=XuVpVhkEDNHCgL4fUdFCKeCPBeze44GZM/4HN5vke02pr0xLGt6NPavzdMH0wVRGMp gOx4nyk1bk/lXOaqpzs4c5gQxTc8fIf/EgM2GvIdKp2w8b+x14B5i5a5IY6WE/9wCQzo VHWWp5Mn0874pnAFpgzUSfHWGyamueM5EL9xwJdEsfzqBfqd7Wc+BUDFCHfRGE/4n33b hLfDI7z7CvBiaQK/2ckRSnvxWTY8HpERgpFdL50uvXFFYxlT3wkaqakhv1Y9CN8+S6DV egClFzTO7ghj6VhxL0qPRSQoMd7aFyymAzQ14LTOmZzNjgWK6G+EfGgxqYQWczmKl2VI B3rA== 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 91si20630872ply.214.2019.02.20.15.34.25; Wed, 20 Feb 2019 15:34:42 -0800 (PST) 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726520AbfBTXcP (ORCPT + 99 others); Wed, 20 Feb 2019 18:32:15 -0500 Received: from mx1.redhat.com ([209.132.183.28]:34842 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725804AbfBTXcP (ORCPT ); Wed, 20 Feb 2019 18:32:15 -0500 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C43AF30832DC; Wed, 20 Feb 2019 23:32:14 +0000 (UTC) Received: from [IPv6:::1] (ovpn04.gateway.prod.ext.phx2.redhat.com [10.5.9.4]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 508921A837; Wed, 20 Feb 2019 23:32:14 +0000 (UTC) From: Eric Sandeen Subject: [PATCH] sysctl: Fix proc_do_large_bitmap for large input buffers To: Linux Kernel Mailing List , fsdevel , netdev@vger.kernel.org Cc: Luis Chamberlain , Kees Cook Message-ID: <53be40fc-6ec4-c714-a64e-f69c96f7058f@redhat.com> Date: Wed, 20 Feb 2019 17:32:13 -0600 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Thunderbird/60.5.0 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.44]); Wed, 20 Feb 2019 23:32:14 +0000 (UTC) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Today, proc_do_large_bitmap() truncates a large write input buffer to PAGE_SIZE - 1, which may result in misparsed numbers at the (truncated) end of the buffer. Further, it fails to notify the caller that the buffer was truncated, so it doesn't get called iteratively to finish the entire input buffer. Tell the caller if there's more work to do by adding the skipped amount back to left/*lenp before returning. To fix the misparsing, reset the position if we have completely consumed a truncated buffer (or if just one char is left, which may be a "-" in a range), and ask the caller to come back for more. Signed-off-by: Eric Sandeen --- diff --git a/kernel/sysctl.c b/kernel/sysctl.c index ba4d9e85feb8..970a96659809 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -3089,9 +3089,13 @@ int proc_do_large_bitmap(struct ctl_table *table, int write, if (write) { char *kbuf, *p; + size_t skipped = 0; - if (left > PAGE_SIZE - 1) + if (left > PAGE_SIZE - 1) { left = PAGE_SIZE - 1; + /* How much of the buffer we'll skip this pass */ + skipped = *lenp - left; + } p = kbuf = memdup_user_nul(buffer, left); if (IS_ERR(kbuf)) @@ -3108,9 +3112,22 @@ int proc_do_large_bitmap(struct ctl_table *table, int write, while (!err && left) { unsigned long val_a, val_b; bool neg; + size_t saved_left; + /* In case we stop parsing mid-number, we can reset */ + saved_left = left; err = proc_get_long(&p, &left, &val_a, &neg, tr_a, sizeof(tr_a), &c); + /* + * If we consumed the entirety of a truncated buffer or + * only one char is left (may be a "-"), then stop here, + * reset, & come back for more. + */ + if ((left <= 1) && skipped) { + left = saved_left; + break; + } + if (err) break; if (val_a >= bitmap_len || neg) { @@ -3128,6 +3145,15 @@ int proc_do_large_bitmap(struct ctl_table *table, int write, err = proc_get_long(&p, &left, &val_b, &neg, tr_b, sizeof(tr_b), &c); + /* + * If we consumed all of a truncated buffer or + * then stop here, reset, & come back for more. + */ + if (!left && skipped) { + left = saved_left; + break; + } + if (err) break; if (val_b >= bitmap_len || neg || @@ -3146,6 +3172,7 @@ int proc_do_large_bitmap(struct ctl_table *table, int write, proc_skip_char(&p, &left, '\n'); } kfree(kbuf); + left += skipped; } else { unsigned long bit_a, bit_b = 0;