Messages in this thread Patch in this message | ![/](/images/icornerl.gif) | | From | wenyang.linux@foxmail ... | Subject | [PATCH v2 2/9] kernel/sysctl-test: add some kunit test cases for min/max detection | Date | Sat, 9 Mar 2024 18:31:19 +0800 |
| |
From: Wen Yang <wenyang.linux@foxmail.com>
Add some kunit test cases and explicitly check the newly added min/max initialization behavior. Including basic parsing tests, min/max overflow, and writing data, etc
Signed-off-by: Wen Yang <wenyang.linux@foxmail.com> Cc: Eric W. Biederman <ebiederm@xmission.com> Cc: Luis Chamberlain <mcgrof@kernel.org> Cc: Kees Cook <keescook@chromium.org> Cc: Joel Granados <j.granados@samsung.com> Cc: Christian Brauner <brauner@kernel.org> Cc: Iurii Zaikin <yzaikin@google.com> Cc: linux-kernel@vger.kernel.org --- kernel/sysctl-test.c | 300 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+)
diff --git a/kernel/sysctl-test.c b/kernel/sysctl-test.c index 6ef887c19c48..0a2b19ae2a8c 100644 --- a/kernel/sysctl-test.c +++ b/kernel/sysctl-test.c @@ -367,6 +367,300 @@ static void sysctl_test_api_dointvec_write_single_greater_int_max( KUNIT_EXPECT_EQ(test, 0, *((int *)table.data)); } +/* + * Test that writing the int value and check if the min/max are met + */ +static void sysctl_test_api_dointvec_write_single_with_minmax_check( + struct kunit *test) +{ + int data = 0; + struct ctl_table table = CTL_TABLE_ENTRY_MINMAX("foo", + &data, + sizeof(int), + 0644, + proc_dointvec_minmax, + SYSCTL_NUMERIC_NEG_ONE, + SYSCTL_NUMERIC_ONE_HUNDRED); + size_t max_len = 32, len; + char *buffer = kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer = (char __user *)buffer; + loff_t pos = 0; + int i; + + for (i = SYSCTL_NUMERIC_NEG_ONE; i <= SYSCTL_NUMERIC_ONE_HUNDRED; i++) { + pos = 0; + KUNIT_ASSERT_LT(test, + (size_t)snprintf(buffer, max_len, "%d", i), + max_len); + len = strlen(buffer); + KUNIT_EXPECT_EQ(test, 0, + proc_dointvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, i, data); + } + + data = 0; + for (i = -10; i < SYSCTL_NUMERIC_NEG_ONE; i++) { + pos = 0; + KUNIT_ASSERT_LT(test, + (size_t)snprintf(buffer, max_len, "%d", i), + max_len); + len = strlen(buffer); + KUNIT_EXPECT_EQ(test, -EINVAL, + proc_dointvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, data); + } + + for (i = SYSCTL_NUMERIC_ONE_HUNDRED + 1; i < 110; i++) { + pos = 0; + KUNIT_ASSERT_LT(test, + (size_t)snprintf(buffer, max_len, "%d", i), + max_len); + len = strlen(buffer); + KUNIT_EXPECT_EQ(test, -EINVAL, + proc_dointvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, data); + } +} + +/* + * Test that writing the int value and check if the min is met + */ +static void sysctl_test_api_dointvec_write_single_with_min_check( + struct kunit *test) +{ + size_t max_len = 32, len; + char *buffer = kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer = (char __user *)buffer; + int data = 0, i; + loff_t pos = 0; + struct ctl_table table = CTL_TABLE_ENTRY_MIN("bar", + &data, + sizeof(int), + 0644, + proc_dointvec_minmax, + -10); + + for (i = -10; i <= SYSCTL_NUMERIC_ONE_HUNDRED; i++) { + pos = 0; + KUNIT_ASSERT_LT(test, + (size_t)snprintf(buffer, max_len, "%d", i), + max_len); + len = strlen(buffer); + KUNIT_EXPECT_EQ(test, 0, + proc_dointvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, i, data); + } + + data = 0; + for (i = -20; i < -10; i++) { + pos = 0; + KUNIT_ASSERT_LT(test, + (size_t)snprintf(buffer, max_len, "%d", i), + max_len); + len = strlen(buffer); + KUNIT_EXPECT_EQ(test, -EINVAL, + proc_dointvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, data); + } +} + +/* + * Test that writing the int value and check if the max is met + */ +static void sysctl_test_api_dointvec_write_single_with_max_check( + struct kunit *test) +{ + size_t max_len = 32, len; + char *buffer = kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer = (char __user *)buffer; + loff_t pos = 0; + int data = 0, i; + struct ctl_table table = CTL_TABLE_ENTRY_MAX("qux", + &data, + sizeof(int), + 0644, + proc_dointvec_minmax, + SYSCTL_NUMERIC_ONE_HUNDRED); + + for (i = -20; i <= SYSCTL_NUMERIC_ONE_HUNDRED; i++) { + pos = 0; + KUNIT_ASSERT_LT(test, + (size_t)snprintf(buffer, max_len, "%d", i), + max_len); + len = strlen(buffer); + KUNIT_EXPECT_EQ(test, 0, + proc_dointvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, i, data); + } + + data = 0; + for (i = SYSCTL_NUMERIC_ONE_HUNDRED + 1; i < SYSCTL_NUMERIC_TWO_HUNDRED; i++) { + pos = 0; + KUNIT_ASSERT_LT(test, + (size_t)snprintf(buffer, max_len, "%d", i), + max_len); + len = strlen(buffer); + KUNIT_EXPECT_EQ(test, -EINVAL, + proc_dointvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, data); + } +} + +/* + * Test that writing the unsigned int value and check if the min/max are met + */ +static void sysctl_test_api_douintvec_write_single_with_minmax_check( + struct kunit *test) +{ + unsigned int data = 0; + struct ctl_table table1 = CTL_TABLE_ENTRY_MINMAX("foo", + &data, + sizeof(unsigned int), + 0644, + proc_douintvec_minmax, + SYSCTL_NUMERIC_ZERO, + SYSCTL_NUMERIC_ONE_THOUSAND); + size_t max_len = 32, len; + char *buffer = kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer = (char __user *)buffer; + loff_t pos = 0; + int i; + + for (i = SYSCTL_NUMERIC_ZERO; i <= SYSCTL_NUMERIC_ONE_THOUSAND; i++) { + pos = 0; + KUNIT_ASSERT_LT(test, + (size_t)snprintf(buffer, max_len, "%d", i), + max_len); + len = strlen(buffer); + KUNIT_EXPECT_EQ(test, 0, proc_douintvec_minmax(&table1, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, i, data); + } + + data = 0; + for (i = -10; i < 0; i++) { + pos = 0; + KUNIT_ASSERT_LT(test, + (size_t)snprintf(buffer, max_len, "%d", i), + max_len); + len = strlen(buffer); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_douintvec_minmax(&table1, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, data); + } + + for (i = SYSCTL_NUMERIC_ONE_THOUSAND + 1; i < SYSCTL_NUMERIC_ONE_THOUSAND + 10; i++) { + pos = 0; + KUNIT_ASSERT_LT(test, + (size_t)snprintf(buffer, max_len, "%d", i), + max_len); + len = strlen(buffer); + KUNIT_EXPECT_EQ(test, -EINVAL, proc_douintvec_minmax(&table1, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, data); + } +} + +/* + * Test that writing the unsigned int value and check if the min is met + */ +static void sysctl_test_api_douintvec_write_single_with_min_check( + struct kunit *test) +{ + size_t max_len = 32, len; + char *buffer = kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer = (char __user *)buffer; + loff_t pos = 0; + unsigned int data = 0, i; + struct ctl_table table = CTL_TABLE_ENTRY_MIN("bar", + &data, + sizeof(unsigned int), + 0644, + proc_douintvec_minmax, + SYSCTL_NUMERIC_FOUR); + + for (i = SYSCTL_NUMERIC_FOUR; i <= SYSCTL_NUMERIC_ONE_THOUSAND; i++) { + pos = 0; + KUNIT_ASSERT_LT(test, + (size_t)snprintf(buffer, max_len, "%u", i), + max_len); + len = strlen(buffer); + KUNIT_EXPECT_EQ(test, 0, + proc_douintvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, i, data); + } + + data = 0; + for (i = SYSCTL_NUMERIC_ZERO; i < SYSCTL_NUMERIC_FOUR; i++) { + pos = 0; + KUNIT_ASSERT_LT(test, + (size_t)snprintf(buffer, max_len, "%u", i), + max_len); + len = strlen(buffer); + + KUNIT_EXPECT_EQ(test, -EINVAL, + proc_douintvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, data); + } +} + +/* + * Test that writing the unsigned int value and check if the max is met + */ +static void sysctl_test_api_douintvec_write_single_with_max_check( + struct kunit *test) +{ + size_t max_len = 32, len; + char *buffer = kunit_kzalloc(test, max_len, GFP_USER); + char __user *user_buffer = (char __user *)buffer; + loff_t pos = 0; + unsigned int data = 0, i; + struct ctl_table table = CTL_TABLE_ENTRY_MAX("bar", + &data, + sizeof(unsigned int), + 0644, + proc_douintvec_minmax, + SYSCTL_NUMERIC_TWO_THOUSAND); + + for (i = SYSCTL_NUMERIC_ONE_THOUSAND; i <= SYSCTL_NUMERIC_TWO_THOUSAND; + i++) { + pos = 0; + KUNIT_ASSERT_LT(test, + (size_t)snprintf(buffer, max_len, "%u", i), + max_len); + len = strlen(buffer); + KUNIT_EXPECT_EQ(test, 0, + proc_douintvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, i, data); + } + + data = 0; + for (i = SYSCTL_NUMERIC_TWO_THOUSAND + 1; + i < SYSCTL_NUMERIC_THREE_THOUSAND; + i++) { + pos = 0; + KUNIT_ASSERT_LT(test, + (size_t)snprintf(buffer, max_len, "%u", i), + max_len); + len = strlen(buffer); + + KUNIT_EXPECT_EQ(test, -EINVAL, + proc_douintvec_minmax(&table, KUNIT_PROC_WRITE, + user_buffer, &len, &pos)); + KUNIT_EXPECT_EQ(test, 0, data); + } +} + static struct kunit_case sysctl_test_cases[] = { KUNIT_CASE(sysctl_test_api_dointvec_null_tbl_data), KUNIT_CASE(sysctl_test_api_dointvec_table_maxlen_unset), @@ -378,6 +672,12 @@ static struct kunit_case sysctl_test_cases[] = { KUNIT_CASE(sysctl_test_dointvec_write_happy_single_negative), KUNIT_CASE(sysctl_test_api_dointvec_write_single_less_int_min), KUNIT_CASE(sysctl_test_api_dointvec_write_single_greater_int_max), + KUNIT_CASE(sysctl_test_api_dointvec_write_single_with_minmax_check), + KUNIT_CASE(sysctl_test_api_dointvec_write_single_with_min_check), + KUNIT_CASE(sysctl_test_api_dointvec_write_single_with_max_check), + KUNIT_CASE(sysctl_test_api_douintvec_write_single_with_minmax_check), + KUNIT_CASE(sysctl_test_api_douintvec_write_single_with_min_check), + KUNIT_CASE(sysctl_test_api_douintvec_write_single_with_max_check), {} }; -- 2.25.1
| ![\](/images/icornerr.gif) |