[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20190617082613.109131-18-brendanhiggins@google.com>
Date: Mon, 17 Jun 2019 01:26:12 -0700
From: Brendan Higgins <brendanhiggins@...gle.com>
To: frowand.list@...il.com, gregkh@...uxfoundation.org,
jpoimboe@...hat.com, keescook@...gle.com,
kieran.bingham@...asonboard.com, mcgrof@...nel.org,
peterz@...radead.org, robh@...nel.org, sboyd@...nel.org,
shuah@...nel.org, tytso@....edu, yamada.masahiro@...ionext.com
Cc: devicetree@...r.kernel.org, dri-devel@...ts.freedesktop.org,
kunit-dev@...glegroups.com, linux-doc@...r.kernel.org,
linux-fsdevel@...r.kernel.org, linux-kbuild@...r.kernel.org,
linux-kernel@...r.kernel.org, linux-kselftest@...r.kernel.org,
linux-nvdimm@...ts.01.org, linux-um@...ts.infradead.org,
Alexander.Levin@...rosoft.com, Tim.Bird@...y.com,
amir73il@...il.com, dan.carpenter@...cle.com, daniel@...ll.ch,
jdike@...toit.com, joel@....id.au, julia.lawall@...6.fr,
khilman@...libre.com, knut.omang@...cle.com, logang@...tatee.com,
mpe@...erman.id.au, pmladek@...e.com, rdunlap@...radead.org,
richard@....at, rientjes@...gle.com, rostedt@...dmis.org,
wfg@...ux.intel.com, Iurii Zaikin <yzaikin@...gle.com>,
Brendan Higgins <brendanhiggins@...gle.com>
Subject: [PATCH v5 17/18] kernel/sysctl-test: Add null pointer test for sysctl.c:proc_dointvec()
From: Iurii Zaikin <yzaikin@...gle.com>
KUnit tests for initialized data behavior of proc_dointvec that is
explicitly checked in the code. Includes basic parsing tests including
int min/max overflow.
Signed-off-by: Iurii Zaikin <yzaikin@...gle.com>
Signed-off-by: Brendan Higgins <brendanhiggins@...gle.com>
Reviewed-by: Greg Kroah-Hartman <gregkh@...uxfoundation.org>
Reviewed-by: Logan Gunthorpe <logang@...tatee.com>
---
Changes Since Last Revision:
- Iurii did some clean up (thanks Iurii!) as suggested by Stephen Boyd.
---
kernel/Makefile | 2 +
kernel/sysctl-test.c | 242 +++++++++++++++++++++++++++++++++++++++++++
lib/Kconfig.debug | 10 ++
3 files changed, 254 insertions(+)
create mode 100644 kernel/sysctl-test.c
diff --git a/kernel/Makefile b/kernel/Makefile
index a8d923b5481ba..50fd511cd0ee0 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -114,6 +114,8 @@ obj-$(CONFIG_HAS_IOMEM) += iomem.o
obj-$(CONFIG_ZONE_DEVICE) += memremap.o
obj-$(CONFIG_RSEQ) += rseq.o
+obj-$(CONFIG_SYSCTL_KUNIT_TEST) += sysctl-test.o
+
obj-$(CONFIG_GCC_PLUGIN_STACKLEAK) += stackleak.o
KASAN_SANITIZE_stackleak.o := n
KCOV_INSTRUMENT_stackleak.o := n
diff --git a/kernel/sysctl-test.c b/kernel/sysctl-test.c
new file mode 100644
index 0000000000000..cb61ad3c7db63
--- /dev/null
+++ b/kernel/sysctl-test.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit test of proc sysctl.
+ */
+
+#include <kunit/test.h>
+#include <linux/sysctl.h>
+
+static int i_zero;
+static int i_one_hundred = 100;
+
+struct test_sysctl_data {
+ int int_0001;
+ int int_0002;
+ int int_0003[4];
+
+ unsigned int uint_0001;
+
+ char string_0001[65];
+};
+
+static struct test_sysctl_data test_data = {
+ .int_0001 = 60,
+ .int_0002 = 1,
+
+ .int_0003[0] = 0,
+ .int_0003[1] = 1,
+ .int_0003[2] = 2,
+ .int_0003[3] = 3,
+
+ .uint_0001 = 314,
+
+ .string_0001 = "(none)",
+};
+
+static void sysctl_test_dointvec_null_tbl_data(struct kunit *test)
+{
+ struct ctl_table table = {
+ .procname = "foo",
+ .data = NULL,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ .extra1 = &i_zero,
+ .extra2 = &i_one_hundred,
+ };
+ void *buffer = kunit_kzalloc(test, sizeof(int), GFP_USER);
+ size_t len;
+ loff_t pos;
+
+ len = 1234;
+ KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, 0, buffer, &len, &pos));
+ KUNIT_EXPECT_EQ(test, (size_t)0, len);
+ len = 1234;
+ KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, 1, buffer, &len, &pos));
+ KUNIT_EXPECT_EQ(test, (size_t)0, len);
+}
+
+static void sysctl_test_dointvec_table_maxlen_unset(struct kunit *test)
+{
+ struct ctl_table table = {
+ .procname = "foo",
+ .data = &test_data.int_0001,
+ .maxlen = 0,
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ .extra1 = &i_zero,
+ .extra2 = &i_one_hundred,
+ };
+ void *buffer = kunit_kzalloc(test, sizeof(int), GFP_USER);
+ size_t len;
+ loff_t pos;
+
+ len = 1234;
+ KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, 0, buffer, &len, &pos));
+ KUNIT_EXPECT_EQ(test, (size_t)0, len);
+ len = 1234;
+ KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, 1, buffer, &len, &pos));
+ KUNIT_EXPECT_EQ(test, (size_t)0, len);
+}
+
+static void sysctl_test_dointvec_table_len_is_zero(struct kunit *test)
+{
+ struct ctl_table table = {
+ .procname = "foo",
+ .data = &test_data.int_0001,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ .extra1 = &i_zero,
+ .extra2 = &i_one_hundred,
+ };
+ void *buffer = kunit_kzalloc(test, sizeof(int), GFP_USER);
+ size_t len;
+ loff_t pos;
+
+ len = 0;
+ KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, 0, buffer, &len, &pos));
+ KUNIT_EXPECT_EQ(test, (size_t)0, len);
+ KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, 1, buffer, &len, &pos));
+ KUNIT_EXPECT_EQ(test, (size_t)0, len);
+}
+
+static void sysctl_test_dointvec_table_read_but_position_set(struct kunit *test)
+{
+ struct ctl_table table = {
+ .procname = "foo",
+ .data = &test_data.int_0001,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ .extra1 = &i_zero,
+ .extra2 = &i_one_hundred,
+ };
+ void *buffer = kunit_kzalloc(test, sizeof(int), GFP_USER);
+ size_t len;
+ loff_t pos;
+
+ len = 1234;
+ pos = 1;
+ KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, 0, buffer, &len, &pos));
+ KUNIT_EXPECT_EQ(test, (size_t)0, len);
+}
+
+static void sysctl_test_dointvec_happy_single_positive(struct kunit *test)
+{
+ struct ctl_table table = {
+ .procname = "foo",
+ .data = &test_data.int_0001,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ .extra1 = &i_zero,
+ .extra2 = &i_one_hundred,
+ };
+ char input[] = "9";
+ size_t len = sizeof(input) - 1;
+ loff_t pos = 0;
+
+ table.data = kunit_kzalloc(test, sizeof(int), GFP_USER);
+ KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, 1, input, &len, &pos));
+ KUNIT_EXPECT_EQ(test, sizeof(input) - 1, len);
+ KUNIT_EXPECT_EQ(test, sizeof(input) - 1, (size_t)pos);
+ KUNIT_EXPECT_EQ(test, 9, ((int *)table.data)[0]);
+}
+
+static void sysctl_test_dointvec_happy_single_negative(struct kunit *test)
+{
+ struct ctl_table table = {
+ .procname = "foo",
+ .data = &test_data.int_0001,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ .extra1 = &i_zero,
+ .extra2 = &i_one_hundred,
+ };
+ char input[] = "-9";
+ size_t len = sizeof(input) - 1;
+ loff_t pos = 0;
+
+ table.data = kunit_kzalloc(test, sizeof(int), GFP_USER);
+ KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, 1, input, &len, &pos));
+ KUNIT_EXPECT_EQ(test, sizeof(input) - 1, len);
+ KUNIT_EXPECT_EQ(test, sizeof(input) - 1, (size_t)pos);
+ KUNIT_EXPECT_EQ(test, -9, ((int *)table.data)[0]);
+}
+
+static void sysctl_test_dointvec_single_less_int_min(struct kunit *test)
+{
+ struct ctl_table table = {
+ .procname = "foo",
+ .data = &test_data.int_0001,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ .extra1 = &i_zero,
+ .extra2 = &i_one_hundred,
+ };
+ char input[32];
+ size_t len = sizeof(input) - 1;
+ loff_t pos = 0;
+ unsigned long abs_of_less_than_min = (unsigned long)INT_MAX
+ - (INT_MAX + INT_MIN) + 1;
+
+ KUNIT_EXPECT_LT(test,
+ (size_t)snprintf(input, sizeof(input), "-%lu",
+ abs_of_less_than_min),
+ sizeof(input));
+
+ table.data = kunit_kzalloc(test, sizeof(int), GFP_USER);
+ KUNIT_EXPECT_EQ(test, -EINVAL,
+ proc_dointvec(&table, 1, input, &len, &pos));
+ KUNIT_EXPECT_EQ(test, sizeof(input) - 1, len);
+ KUNIT_EXPECT_EQ(test, 0, ((int *)table.data)[0]);
+}
+
+static void sysctl_test_dointvec_single_greater_int_max(struct kunit *test)
+{
+ struct ctl_table table = {
+ .procname = "foo",
+ .data = &test_data.int_0001,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ .extra1 = &i_zero,
+ .extra2 = &i_one_hundred,
+ };
+ char input[32];
+ size_t len = sizeof(input) - 1;
+ loff_t pos = 0;
+ unsigned long greater_than_max = (unsigned long)INT_MAX + 1;
+
+ KUNIT_EXPECT_GT(test, greater_than_max, (unsigned long)INT_MAX);
+ KUNIT_EXPECT_LT(test, (size_t)snprintf(input, sizeof(input), "%lu",
+ greater_than_max),
+ sizeof(input));
+ table.data = kunit_kzalloc(test, sizeof(int), GFP_USER);
+ KUNIT_EXPECT_EQ(test, -EINVAL,
+ proc_dointvec(&table, 1, input, &len, &pos));
+ KUNIT_EXPECT_EQ(test, sizeof(input) - 1, len);
+ KUNIT_EXPECT_EQ(test, 0, ((int *)table.data)[0]);
+}
+
+static struct kunit_case sysctl_test_cases[] = {
+ KUNIT_CASE(sysctl_test_dointvec_null_tbl_data),
+ KUNIT_CASE(sysctl_test_dointvec_table_maxlen_unset),
+ KUNIT_CASE(sysctl_test_dointvec_table_len_is_zero),
+ KUNIT_CASE(sysctl_test_dointvec_table_read_but_position_set),
+ KUNIT_CASE(sysctl_test_dointvec_happy_single_positive),
+ KUNIT_CASE(sysctl_test_dointvec_happy_single_negative),
+ KUNIT_CASE(sysctl_test_dointvec_single_less_int_min),
+ KUNIT_CASE(sysctl_test_dointvec_single_greater_int_max),
+ {}
+};
+
+static struct kunit_module sysctl_test_module = {
+ .name = "sysctl_test",
+ .test_cases = sysctl_test_cases,
+};
+
+module_test(sysctl_test_module);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index cbdfae3798965..389b8986f5b77 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1939,6 +1939,16 @@ config TEST_SYSCTL
If unsure, say N.
+config SYSCTL_KUNIT_TEST
+ bool "KUnit test for sysctl"
+ depends on KUNIT
+ help
+ This builds the proc sysctl unit test, which runs on boot. For more
+ information on KUnit and unit tests in general please refer to the
+ KUnit documentation in Documentation/dev-tools/kunit/.
+
+ If unsure, say N.
+
config TEST_UDELAY
tristate "udelay test driver"
help
--
2.22.0.410.gd8fdbe21b5-goog
Powered by blists - more mailing lists