All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] module: Correctly truncate sysfs sections output
@ 2020-08-07  6:35 Kees Cook
  2020-08-07  6:35 ` [PATCH 1/2] " Kees Cook
  2020-08-07  6:35 ` [PATCH 2/2] selftests: splice: Check behavior of full and short splices Kees Cook
  0 siblings, 2 replies; 5+ messages in thread
From: Kees Cook @ 2020-08-07  6:35 UTC (permalink / raw)
  To: linux-kernel
  Cc: Kees Cook, Jessica Yu, Shuah Khan, Greg Kroah-Hartman,
	Masahiro Yamada, linux-kselftest

Hi,

This fixes my sysfs module sections refactoring to take into account
the case where the output buffer is not PAGE_SIZE. :( Thanks to 0day
and trinity for noticing.

I'll let this sit in -next for a few days and then send it to Linus.

-Kees

Kees Cook (2):
  module: Correctly truncate sysfs sections output
  selftests: splice: Check behavior of full and short splices

 kernel/module.c                               | 22 ++++++-
 tools/testing/selftests/splice/.gitignore     |  1 +
 tools/testing/selftests/splice/Makefile       |  4 +-
 tools/testing/selftests/splice/config         |  1 +
 tools/testing/selftests/splice/settings       |  1 +
 .../selftests/splice/short_splice_read.sh     | 56 ++++++++++++++++++
 tools/testing/selftests/splice/splice_read.c  | 57 +++++++++++++++++++
 7 files changed, 137 insertions(+), 5 deletions(-)
 create mode 100644 tools/testing/selftests/splice/config
 create mode 100644 tools/testing/selftests/splice/settings
 create mode 100755 tools/testing/selftests/splice/short_splice_read.sh
 create mode 100644 tools/testing/selftests/splice/splice_read.c

-- 
2.25.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] module: Correctly truncate sysfs sections output
  2020-08-07  6:35 [PATCH 0/2] module: Correctly truncate sysfs sections output Kees Cook
@ 2020-08-07  6:35 ` Kees Cook
  2020-08-07  6:47   ` Greg Kroah-Hartman
  2020-08-07 13:18   ` Jessica Yu
  2020-08-07  6:35 ` [PATCH 2/2] selftests: splice: Check behavior of full and short splices Kees Cook
  1 sibling, 2 replies; 5+ messages in thread
From: Kees Cook @ 2020-08-07  6:35 UTC (permalink / raw)
  To: linux-kernel
  Cc: Kees Cook, kernel test robot, stable, Jessica Yu, Shuah Khan,
	Greg Kroah-Hartman, Masahiro Yamada, linux-kselftest

The only-root-readable /sys/module/$module/sections/$section files
did not truncate their output to the available buffer size. While most
paths into the kernfs read handlers end up using PAGE_SIZE buffers,
it's possible to get there through other paths (e.g. splice, sendfile).
Actually limit the output to the "count" passed into the read function,
and report it back correctly. *sigh*

Reported-by: kernel test robot <lkp@intel.com>
Link: https://lore.kernel.org/lkml/20200805002015.GE23458@shao2-debian
Fixes: ed66f991bb19 ("module: Refactor section attr into bin attribute")
Cc: stable@vger.kernel.org
Cc: Jessica Yu <jeyu@kernel.org>
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 kernel/module.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/kernel/module.c b/kernel/module.c
index aa183c9ac0a2..08c46084d8cc 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1520,18 +1520,34 @@ struct module_sect_attrs {
 	struct module_sect_attr attrs[];
 };
 
+#define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4))
 static ssize_t module_sect_read(struct file *file, struct kobject *kobj,
 				struct bin_attribute *battr,
 				char *buf, loff_t pos, size_t count)
 {
 	struct module_sect_attr *sattr =
 		container_of(battr, struct module_sect_attr, battr);
+	char bounce[MODULE_SECT_READ_SIZE + 1];
+	size_t wrote;
 
 	if (pos != 0)
 		return -EINVAL;
 
-	return sprintf(buf, "0x%px\n",
-		       kallsyms_show_value(file->f_cred) ? (void *)sattr->address : NULL);
+	/*
+	 * Since we're a binary read handler, we must account for the
+	 * trailing NUL byte that sprintf will write: if "buf" is
+	 * too small to hold the NUL, or the NUL is exactly the last
+	 * byte, the read will look like it got truncated by one byte.
+	 * Since there is no way to ask sprintf nicely to not write
+	 * the NUL, we have to use a bounce buffer.
+	 */
+	wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n",
+			 kallsyms_show_value(file->f_cred)
+				? (void *)sattr->address : NULL);
+	count = min(count, wrote);
+	memcpy(buf, bounce, count);
+
+	return count;
 }
 
 static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
@@ -1580,7 +1596,7 @@ static void add_sect_attrs(struct module *mod, const struct load_info *info)
 			goto out;
 		sect_attrs->nsections++;
 		sattr->battr.read = module_sect_read;
-		sattr->battr.size = 3 /* "0x", "\n" */ + (BITS_PER_LONG / 4);
+		sattr->battr.size = MODULE_SECT_READ_SIZE;
 		sattr->battr.attr.mode = 0400;
 		*(gattr++) = &(sattr++)->battr;
 	}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] selftests: splice: Check behavior of full and short splices
  2020-08-07  6:35 [PATCH 0/2] module: Correctly truncate sysfs sections output Kees Cook
  2020-08-07  6:35 ` [PATCH 1/2] " Kees Cook
@ 2020-08-07  6:35 ` Kees Cook
  1 sibling, 0 replies; 5+ messages in thread
From: Kees Cook @ 2020-08-07  6:35 UTC (permalink / raw)
  To: linux-kernel
  Cc: Kees Cook, Shuah Khan, Jessica Yu, Greg Kroah-Hartman,
	Masahiro Yamada, linux-kselftest

In order to help catch regressions in splice vs read behavior in certain
special files, test a few with various different kinds of internal
kernel helpers.

Cc: Shuah Khan <shuah@kernel.org>
Signed-off-by: Kees Cook <keescook@chromium.org>
---
 tools/testing/selftests/splice/.gitignore     |  1 +
 tools/testing/selftests/splice/Makefile       |  4 +-
 tools/testing/selftests/splice/config         |  1 +
 tools/testing/selftests/splice/settings       |  1 +
 .../selftests/splice/short_splice_read.sh     | 56 ++++++++++++++++++
 tools/testing/selftests/splice/splice_read.c  | 57 +++++++++++++++++++
 6 files changed, 118 insertions(+), 2 deletions(-)
 create mode 100644 tools/testing/selftests/splice/config
 create mode 100644 tools/testing/selftests/splice/settings
 create mode 100755 tools/testing/selftests/splice/short_splice_read.sh
 create mode 100644 tools/testing/selftests/splice/splice_read.c

diff --git a/tools/testing/selftests/splice/.gitignore b/tools/testing/selftests/splice/.gitignore
index d5a2da428752..be8266f5d04c 100644
--- a/tools/testing/selftests/splice/.gitignore
+++ b/tools/testing/selftests/splice/.gitignore
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
 default_file_splice_read
+splice_read
diff --git a/tools/testing/selftests/splice/Makefile b/tools/testing/selftests/splice/Makefile
index e519b159b60d..541cd826d5a5 100644
--- a/tools/testing/selftests/splice/Makefile
+++ b/tools/testing/selftests/splice/Makefile
@@ -1,5 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
-TEST_PROGS := default_file_splice_read.sh
-TEST_GEN_PROGS_EXTENDED := default_file_splice_read
+TEST_PROGS := default_file_splice_read.sh short_splice_read.sh
+TEST_GEN_PROGS_EXTENDED := default_file_splice_read splice_read
 
 include ../lib.mk
diff --git a/tools/testing/selftests/splice/config b/tools/testing/selftests/splice/config
new file mode 100644
index 000000000000..058c928368b8
--- /dev/null
+++ b/tools/testing/selftests/splice/config
@@ -0,0 +1 @@
+CONFIG_TEST_LKM=m
diff --git a/tools/testing/selftests/splice/settings b/tools/testing/selftests/splice/settings
new file mode 100644
index 000000000000..89cedfc0d12b
--- /dev/null
+++ b/tools/testing/selftests/splice/settings
@@ -0,0 +1 @@
+timeout=5
diff --git a/tools/testing/selftests/splice/short_splice_read.sh b/tools/testing/selftests/splice/short_splice_read.sh
new file mode 100755
index 000000000000..7810d3589d9a
--- /dev/null
+++ b/tools/testing/selftests/splice/short_splice_read.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+set -e
+
+ret=0
+
+do_splice()
+{
+	filename="$1"
+	bytes="$2"
+	expected="$3"
+
+	out=$(./splice_read "$filename" "$bytes" | cat)
+	if [ "$out" = "$expected" ] ; then
+		echo "ok: $filename $bytes"
+	else
+		echo "FAIL: $filename $bytes"
+		ret=1
+	fi
+}
+
+test_splice()
+{
+	filename="$1"
+
+	full=$(cat "$filename")
+	two=$(echo "$full" | grep -m1 . | cut -c-2)
+
+	# Make sure full splice has the same contents as a standard read.
+	do_splice "$filename" 4096 "$full"
+
+	# Make sure a partial splice see the first two characters.
+	do_splice "$filename" 2 "$two"
+}
+
+# proc_single_open(), seq_read()
+test_splice /proc/$$/limits
+# special open, seq_read()
+test_splice /proc/$$/comm
+
+# proc_handler, proc_dointvec_minmax
+test_splice /proc/sys/fs/nr_open
+# proc_handler, proc_dostring
+test_splice /proc/sys/kernel/modprobe
+# proc_handler, special read
+test_splice /proc/sys/kernel/version
+
+if ! [ -d /sys/module/test_module/sections ] ; then
+	modprobe test_module
+fi
+# kernfs, attr
+test_splice /sys/module/test_module/coresize
+# kernfs, binattr
+test_splice /sys/module/test_module/sections/.init.text
+
+exit $ret
diff --git a/tools/testing/selftests/splice/splice_read.c b/tools/testing/selftests/splice/splice_read.c
new file mode 100644
index 000000000000..46dae6a25cfb
--- /dev/null
+++ b/tools/testing/selftests/splice/splice_read.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+int main(int argc, char *argv[])
+{
+	int fd;
+	size_t size;
+	ssize_t spliced;
+
+	if (argc < 2) {
+		fprintf(stderr, "Usage: %s INPUT [BYTES]\n", argv[0]);
+		return EXIT_FAILURE;
+	}
+
+	fd = open(argv[1], O_RDONLY);
+	if (fd < 0) {
+		perror(argv[1]);
+		return EXIT_FAILURE;
+	}
+
+	if (argc == 3)
+		size = atol(argv[2]);
+	else {
+		struct stat statbuf;
+
+		if (fstat(fd, &statbuf) < 0) {
+			perror(argv[1]);
+			return EXIT_FAILURE;
+		}
+
+		if (statbuf.st_size > INT_MAX) {
+			fprintf(stderr, "%s: Too big\n", argv[1]);
+			return EXIT_FAILURE;
+		}
+
+		size = statbuf.st_size;
+	}
+
+	/* splice(2) file to stdout. */
+	spliced = splice(fd, NULL, STDOUT_FILENO, NULL,
+		      size, SPLICE_F_MOVE);
+	if (spliced < 0) {
+		perror("splice");
+		return EXIT_FAILURE;
+	}
+
+	close(fd);
+	return EXIT_SUCCESS;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] module: Correctly truncate sysfs sections output
  2020-08-07  6:35 ` [PATCH 1/2] " Kees Cook
@ 2020-08-07  6:47   ` Greg Kroah-Hartman
  2020-08-07 13:18   ` Jessica Yu
  1 sibling, 0 replies; 5+ messages in thread
From: Greg Kroah-Hartman @ 2020-08-07  6:47 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-kernel, kernel test robot, stable, Jessica Yu, Shuah Khan,
	Masahiro Yamada, linux-kselftest

On Thu, Aug 06, 2020 at 11:35:38PM -0700, Kees Cook wrote:
> The only-root-readable /sys/module/$module/sections/$section files
> did not truncate their output to the available buffer size. While most
> paths into the kernfs read handlers end up using PAGE_SIZE buffers,
> it's possible to get there through other paths (e.g. splice, sendfile).
> Actually limit the output to the "count" passed into the read function,
> and report it back correctly. *sigh*

Ugh, never thought about that...

Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] module: Correctly truncate sysfs sections output
  2020-08-07  6:35 ` [PATCH 1/2] " Kees Cook
  2020-08-07  6:47   ` Greg Kroah-Hartman
@ 2020-08-07 13:18   ` Jessica Yu
  1 sibling, 0 replies; 5+ messages in thread
From: Jessica Yu @ 2020-08-07 13:18 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-kernel, kernel test robot, stable, Shuah Khan,
	Greg Kroah-Hartman, Masahiro Yamada, linux-kselftest

+++ Kees Cook [06/08/20 23:35 -0700]:
>The only-root-readable /sys/module/$module/sections/$section files
>did not truncate their output to the available buffer size. While most
>paths into the kernfs read handlers end up using PAGE_SIZE buffers,
>it's possible to get there through other paths (e.g. splice, sendfile).
>Actually limit the output to the "count" passed into the read function,
>and report it back correctly. *sigh*
>
>Reported-by: kernel test robot <lkp@intel.com>
>Link: https://lore.kernel.org/lkml/20200805002015.GE23458@shao2-debian
>Fixes: ed66f991bb19 ("module: Refactor section attr into bin attribute")
>Cc: stable@vger.kernel.org
>Cc: Jessica Yu <jeyu@kernel.org>
>Signed-off-by: Kees Cook <keescook@chromium.org>

Oof, thanks for fixing this!

Acked-by: Jessica Yu <jeyu@kernel.org>

>---
> kernel/module.c | 22 +++++++++++++++++++---
> 1 file changed, 19 insertions(+), 3 deletions(-)
>
>diff --git a/kernel/module.c b/kernel/module.c
>index aa183c9ac0a2..08c46084d8cc 100644
>--- a/kernel/module.c
>+++ b/kernel/module.c
>@@ -1520,18 +1520,34 @@ struct module_sect_attrs {
> 	struct module_sect_attr attrs[];
> };
>
>+#define MODULE_SECT_READ_SIZE (3 /* "0x", "\n" */ + (BITS_PER_LONG / 4))
> static ssize_t module_sect_read(struct file *file, struct kobject *kobj,
> 				struct bin_attribute *battr,
> 				char *buf, loff_t pos, size_t count)
> {
> 	struct module_sect_attr *sattr =
> 		container_of(battr, struct module_sect_attr, battr);
>+	char bounce[MODULE_SECT_READ_SIZE + 1];
>+	size_t wrote;
>
> 	if (pos != 0)
> 		return -EINVAL;
>
>-	return sprintf(buf, "0x%px\n",
>-		       kallsyms_show_value(file->f_cred) ? (void *)sattr->address : NULL);
>+	/*
>+	 * Since we're a binary read handler, we must account for the
>+	 * trailing NUL byte that sprintf will write: if "buf" is
>+	 * too small to hold the NUL, or the NUL is exactly the last
>+	 * byte, the read will look like it got truncated by one byte.
>+	 * Since there is no way to ask sprintf nicely to not write
>+	 * the NUL, we have to use a bounce buffer.
>+	 */
>+	wrote = scnprintf(bounce, sizeof(bounce), "0x%px\n",
>+			 kallsyms_show_value(file->f_cred)
>+				? (void *)sattr->address : NULL);
>+	count = min(count, wrote);
>+	memcpy(buf, bounce, count);
>+
>+	return count;
> }
>
> static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
>@@ -1580,7 +1596,7 @@ static void add_sect_attrs(struct module *mod, const struct load_info *info)
> 			goto out;
> 		sect_attrs->nsections++;
> 		sattr->battr.read = module_sect_read;
>-		sattr->battr.size = 3 /* "0x", "\n" */ + (BITS_PER_LONG / 4);
>+		sattr->battr.size = MODULE_SECT_READ_SIZE;
> 		sattr->battr.attr.mode = 0400;
> 		*(gattr++) = &(sattr++)->battr;
> 	}
>-- 
>2.25.1
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-08-07 13:18 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-07  6:35 [PATCH 0/2] module: Correctly truncate sysfs sections output Kees Cook
2020-08-07  6:35 ` [PATCH 1/2] " Kees Cook
2020-08-07  6:47   ` Greg Kroah-Hartman
2020-08-07 13:18   ` Jessica Yu
2020-08-07  6:35 ` [PATCH 2/2] selftests: splice: Check behavior of full and short splices Kees Cook

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.