The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Kees Cook <keescook@chromium.org>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: linux-kernel@vger.kernel.org, Kees Cook <keescook@chromium.org>,
	David Howells <dhowells@redhat.com>,
	Randy Dunlap <rdunlap@infradead.org>,
	Ingo Molnar <mingo@kernel.org>,
	Peter Zijlstra <peterz@infradead.org>,
	Rik van Riel <riel@redhat.com>, Mel Gorman <mgorman@suse.de>,
	Li Zefan <lizefan@huawei.com>,
	Dave Hansen <dave@linux.vnet.ibm.com>,
	Aaron Tomlin <atomlin@redhat.com>,
	Dario Faggioli <raistlin@linux.it>,
	Andrew Shewmaker <agshew@gmail.com>,
	Andi Kleen <ak@linux.intel.com>, Jens Axboe <axboe@fb.com>,
	Wanpeng Li <liwanp@linux.vnet.ibm.com>,
	Benjamin Herrenschmidt <benh@kernel.crashing.org>,
	Frederic Weisbecker <fweisbec@gmail.com>,
	Pavel Emelyanov <xemul@parallels.com>,
	Andrey Vagin <avagin@openvz.org>,
	Michael Ellerman <michael@ellerman.id.au>
Subject: [PATCH v2 3/4] sysctl: allow for strict write position handling
Date: Thu, 17 Apr 2014 17:16:22 -0700	[thread overview]
Message-ID: <1397780183-24633-4-git-send-email-keescook@chromium.org> (raw)
In-Reply-To: <1397780183-24633-1-git-send-email-keescook@chromium.org>

When writing to a sysctl string, each write, regardless of VFS position,
begins writing the string from the start. This means the contents of
the last write to the sysctl controls the string contents instead of
the first:

open("/proc/sys/kernel/modprobe", O_WRONLY)   = 1
write(1, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"..., 4096) = 4096
write(1, "/bin/true", 9)                = 9
close(1)                                = 0

$ cat /proc/sys/kernel/modprobe
/bin/true

Expected behaviour would be to have the sysctl be "AAAA..." capped at
maxlen (in this case KMOD_PATH_LEN: 256), instead of truncating to the
contents of the second write. Similarly, multiple short writes would not
append to the sysctl.

This provides CONFIG_PROC_SYSCTL_STRICT_WRITES as a way to make this
behavior act in a less surprising manner for strings, and disallows
non-zero file position when writing numeric sysctls (similar to what is
already done when reading from non-zero file positions).

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 fs/proc/Kconfig |   17 +++++++++++++++++
 kernel/sysctl.c |   17 +++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig
index 2183fcf41d59..4a93cf8b7b9f 100644
--- a/fs/proc/Kconfig
+++ b/fs/proc/Kconfig
@@ -62,6 +62,23 @@ config PROC_SYSCTL
 	  building a kernel for install/rescue disks or your system is very
 	  limited in memory.
 
+config PROC_SYSCTL_STRICT_WRITES
+	bool "Perform strict writes to /proc/sys entries" if EXPERT
+	depends on PROC_SYSCTL
+	default n
+	---help---
+	  When writing to sysctl entries in /proc, each write syscall
+	  is expected to contain the entire sysctl value. For strings
+	  this means that writes do not append, and the contents of the
+	  buffer will be whatever was written last, regardless of the
+	  file position.
+
+	  When PROC_SYSCTL_STRICT_WRITES is enabled, writes to numeric
+	  sysctl entries must always be at file position 0 and the value
+	  must be fully contained in the buffer sent to the write syscall.
+	  For strings, file position is respected, though anything past
+	  the max length of the sysctl buffer will be ignored.
+
 config PROC_PAGE_MONITOR
  	default y
 	depends on PROC_FS && MMU
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 0e08103a69c8..83902ae3e4e6 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1712,8 +1712,19 @@ static int _proc_do_string(char *data, int maxlen, int write,
 	}
 
 	if (write) {
+#ifdef CONFIG_PROC_SYSCTL_STRICT_WRITES
+		/* Only continue writes not past the end of buffer. */
+		len = strlen(data);
+		if (len > maxlen - 1)
+			len = maxlen - 1;
+
+		if (*ppos > len)
+			return 0;
+		len = *ppos;
+#else
 		/* Start writing from beginning of buffer. */
 		len = 0;
+#endif
 		*ppos += *lenp;
 		p = buffer;
 		while ((p - buffer) < *lenp && len < maxlen - 1) {
@@ -1948,6 +1959,8 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
 		conv = do_proc_dointvec_conv;
 
 	if (write) {
+		if (IS_ENABLED(CONFIG_PROC_SYSCTL_STRICT_WRITES) && *ppos)
+			goto out;
 		if (left > PAGE_SIZE - 1)
 			left = PAGE_SIZE - 1;
 		page = __get_free_page(GFP_TEMPORARY);
@@ -2005,6 +2018,7 @@ free:
 			return err ? : -EINVAL;
 	}
 	*lenp -= left;
+out:
 	*ppos += *lenp;
 	return err;
 }
@@ -2197,6 +2211,8 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
 	left = *lenp;
 
 	if (write) {
+		if (IS_ENABLED(CONFIG_PROC_SYSCTL_STRICT_WRITES) && *ppos)
+			goto out;
 		if (left > PAGE_SIZE - 1)
 			left = PAGE_SIZE - 1;
 		page = __get_free_page(GFP_TEMPORARY);
@@ -2252,6 +2268,7 @@ free:
 			return err ? : -EINVAL;
 	}
 	*lenp -= left;
+out:
 	*ppos += *lenp;
 	return err;
 }
-- 
1.7.9.5


  parent reply	other threads:[~2014-04-18  0:18 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-04-18  0:16 [PATCH v2 0/4] sysctl: fix incorrect write position handling Kees Cook
2014-04-18  0:16 ` [PATCH v2 1/4] sysctl: clean up char buffer arguments Kees Cook
2014-04-18  0:28   ` Andi Kleen
2014-04-18  6:24     ` Kees Cook
2014-04-18  0:16 ` [PATCH v2 2/4] sysctl: refactor sysctl string writing logic Kees Cook
2014-04-18  0:16 ` Kees Cook [this message]
2014-04-21 22:45   ` [PATCH v2 3/4] sysctl: allow for strict write position handling Andrew Morton
2014-04-22  4:52     ` Kees Cook
2014-04-22 18:11       ` Andrew Morton
2014-04-22 18:37         ` Kees Cook
2014-04-18  0:16 ` [PATCH v2 4/4] test: validate CONFIG_PROC_SYSCTL_STRICT_WRITES Kees Cook

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1397780183-24633-4-git-send-email-keescook@chromium.org \
    --to=keescook@chromium.org \
    --cc=agshew@gmail.com \
    --cc=ak@linux.intel.com \
    --cc=akpm@linux-foundation.org \
    --cc=atomlin@redhat.com \
    --cc=avagin@openvz.org \
    --cc=axboe@fb.com \
    --cc=benh@kernel.crashing.org \
    --cc=dave@linux.vnet.ibm.com \
    --cc=dhowells@redhat.com \
    --cc=fweisbec@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=liwanp@linux.vnet.ibm.com \
    --cc=lizefan@huawei.com \
    --cc=mgorman@suse.de \
    --cc=michael@ellerman.id.au \
    --cc=mingo@kernel.org \
    --cc=peterz@infradead.org \
    --cc=raistlin@linux.it \
    --cc=rdunlap@infradead.org \
    --cc=riel@redhat.com \
    --cc=xemul@parallels.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox