^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * KUnit test of proc sysctl.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <kunit/test.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/sysctl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #define KUNIT_PROC_READ 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #define KUNIT_PROC_WRITE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) static int i_zero;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) static int i_one_hundred = 100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Test that proc_dointvec will not try to use a NULL .data field even when the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * length is non-zero.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) static void sysctl_test_api_dointvec_null_tbl_data(struct kunit *test)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct ctl_table null_data_table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) .procname = "foo",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * Here we are testing that proc_dointvec behaves correctly when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * we give it a NULL .data field. Normally this would point to a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * piece of memory where the value would be stored.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) .data = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) .maxlen = sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) .mode = 0644,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) .proc_handler = proc_dointvec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) .extra1 = &i_zero,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) .extra2 = &i_one_hundred,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * proc_dointvec expects a buffer in user space, so we allocate one. We
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * also need to cast it to __user so sparse doesn't get mad.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) size_t len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) loff_t pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * We don't care what the starting length is since proc_dointvec should
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * not try to read because .data is NULL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) len = 1234;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&null_data_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) KUNIT_PROC_READ, buffer, &len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) &pos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) KUNIT_EXPECT_EQ(test, (size_t)0, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * See above.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) len = 1234;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&null_data_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) KUNIT_PROC_WRITE, buffer, &len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) &pos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) KUNIT_EXPECT_EQ(test, (size_t)0, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * Similar to the previous test, we create a struct ctrl_table that has a .data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * field that proc_dointvec cannot do anything with; however, this time it is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * because we tell proc_dointvec that the size is 0.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static void sysctl_test_api_dointvec_table_maxlen_unset(struct kunit *test)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) int data = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct ctl_table data_maxlen_unset_table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) .procname = "foo",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) .data = &data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * So .data is no longer NULL, but we tell proc_dointvec its
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * length is 0, so it still shouldn't try to use it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) .maxlen = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) .mode = 0644,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) .proc_handler = proc_dointvec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) .extra1 = &i_zero,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) .extra2 = &i_one_hundred,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) size_t len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) loff_t pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * As before, we don't care what buffer length is because proc_dointvec
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * cannot do anything because its internal .data buffer has zero length.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) len = 1234;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&data_maxlen_unset_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) KUNIT_PROC_READ, buffer, &len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) &pos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) KUNIT_EXPECT_EQ(test, (size_t)0, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * See previous comment.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) len = 1234;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&data_maxlen_unset_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) KUNIT_PROC_WRITE, buffer, &len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) &pos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) KUNIT_EXPECT_EQ(test, (size_t)0, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * Here we provide a valid struct ctl_table, but we try to read and write from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * it using a buffer of zero length, so it should still fail in a similar way as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * before.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static void sysctl_test_api_dointvec_table_len_is_zero(struct kunit *test)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) int data = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) /* Good table. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct ctl_table table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .procname = "foo",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) .data = &data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) .maxlen = sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) .mode = 0644,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .proc_handler = proc_dointvec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) .extra1 = &i_zero,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .extra2 = &i_one_hundred,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * However, now our read/write buffer has zero length.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) size_t len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) loff_t pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_READ, buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) &len, &pos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) KUNIT_EXPECT_EQ(test, (size_t)0, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_WRITE, buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) &len, &pos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) KUNIT_EXPECT_EQ(test, (size_t)0, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * Test that proc_dointvec refuses to read when the file position is non-zero.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static void sysctl_test_api_dointvec_table_read_but_position_set(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) struct kunit *test)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) int data = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /* Good table. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) struct ctl_table table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) .procname = "foo",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) .data = &data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) .maxlen = sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) .mode = 0644,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) .proc_handler = proc_dointvec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .extra1 = &i_zero,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .extra2 = &i_one_hundred,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * We don't care about our buffer length because we start off with a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * non-zero file position.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) size_t len = 1234;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) * proc_dointvec should refuse to read into the buffer since the file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * pos is non-zero.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) loff_t pos = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_READ, buffer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) &len, &pos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) KUNIT_EXPECT_EQ(test, (size_t)0, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * Test that we can read a two digit number in a sufficiently size buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * Nothing fancy.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) static void sysctl_test_dointvec_read_happy_single_positive(struct kunit *test)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) int data = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /* Good table. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) struct ctl_table table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) .procname = "foo",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .data = &data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) .maxlen = sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .mode = 0644,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) .proc_handler = proc_dointvec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) .extra1 = &i_zero,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) .extra2 = &i_one_hundred,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) size_t len = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) loff_t pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) char *buffer = kunit_kzalloc(test, len, GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) char __user *user_buffer = (char __user *)buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) /* Store 13 in the data field. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) *((int *)table.data) = 13;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_READ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) user_buffer, &len, &pos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) KUNIT_ASSERT_EQ(test, (size_t)3, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) buffer[len] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) /* And we read 13 back out. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) KUNIT_EXPECT_STREQ(test, "13\n", buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) * Same as previous test, just now with negative numbers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) static void sysctl_test_dointvec_read_happy_single_negative(struct kunit *test)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) int data = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) /* Good table. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) struct ctl_table table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) .procname = "foo",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) .data = &data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .maxlen = sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) .mode = 0644,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) .proc_handler = proc_dointvec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) .extra1 = &i_zero,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) .extra2 = &i_one_hundred,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) size_t len = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) loff_t pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) char *buffer = kunit_kzalloc(test, len, GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) char __user *user_buffer = (char __user *)buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) *((int *)table.data) = -16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_READ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) user_buffer, &len, &pos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) KUNIT_ASSERT_EQ(test, (size_t)4, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) buffer[len] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) KUNIT_EXPECT_STREQ(test, "-16\n", (char *)buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * Test that a simple positive write works.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) static void sysctl_test_dointvec_write_happy_single_positive(struct kunit *test)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) int data = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /* Good table. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) struct ctl_table table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) .procname = "foo",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) .data = &data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) .maxlen = sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) .mode = 0644,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) .proc_handler = proc_dointvec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) .extra1 = &i_zero,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) .extra2 = &i_one_hundred,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) char input[] = "9";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) size_t len = sizeof(input) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) loff_t pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) char *buffer = kunit_kzalloc(test, len, GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) char __user *user_buffer = (char __user *)buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) memcpy(buffer, input, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_WRITE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) user_buffer, &len, &pos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) KUNIT_EXPECT_EQ(test, sizeof(input) - 1, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) KUNIT_EXPECT_EQ(test, sizeof(input) - 1, (size_t)pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) KUNIT_EXPECT_EQ(test, 9, *((int *)table.data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * Same as previous test, but now with negative numbers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static void sysctl_test_dointvec_write_happy_single_negative(struct kunit *test)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) int data = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) struct ctl_table table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) .procname = "foo",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) .data = &data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) .maxlen = sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) .mode = 0644,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) .proc_handler = proc_dointvec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) .extra1 = &i_zero,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) .extra2 = &i_one_hundred,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) char input[] = "-9";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) size_t len = sizeof(input) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) loff_t pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) char *buffer = kunit_kzalloc(test, len, GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) char __user *user_buffer = (char __user *)buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) memcpy(buffer, input, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_WRITE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) user_buffer, &len, &pos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) KUNIT_EXPECT_EQ(test, sizeof(input) - 1, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) KUNIT_EXPECT_EQ(test, sizeof(input) - 1, (size_t)pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) KUNIT_EXPECT_EQ(test, -9, *((int *)table.data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) * Test that writing a value smaller than the minimum possible value is not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) * allowed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) static void sysctl_test_api_dointvec_write_single_less_int_min(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) struct kunit *test)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) int data = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) struct ctl_table table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) .procname = "foo",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) .data = &data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) .maxlen = sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) .mode = 0644,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) .proc_handler = proc_dointvec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) .extra1 = &i_zero,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) .extra2 = &i_one_hundred,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) size_t max_len = 32, len = max_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) loff_t pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) char *buffer = kunit_kzalloc(test, max_len, GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) char __user *user_buffer = (char __user *)buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) unsigned long abs_of_less_than_min = (unsigned long)INT_MAX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) - (INT_MAX + INT_MIN) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) * We use this rigmarole to create a string that contains a value one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) * less than the minimum accepted value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) KUNIT_ASSERT_LT(test,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) (size_t)snprintf(buffer, max_len, "-%lu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) abs_of_less_than_min),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) max_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) KUNIT_EXPECT_EQ(test, -EINVAL, proc_dointvec(&table, KUNIT_PROC_WRITE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) user_buffer, &len, &pos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) KUNIT_EXPECT_EQ(test, max_len, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) KUNIT_EXPECT_EQ(test, 0, *((int *)table.data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) * Test that writing the maximum possible value works.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) static void sysctl_test_api_dointvec_write_single_greater_int_max(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) struct kunit *test)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) int data = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) struct ctl_table table = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) .procname = "foo",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) .data = &data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) .maxlen = sizeof(int),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) .mode = 0644,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) .proc_handler = proc_dointvec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) .extra1 = &i_zero,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) .extra2 = &i_one_hundred,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) size_t max_len = 32, len = max_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) loff_t pos = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) char *buffer = kunit_kzalloc(test, max_len, GFP_USER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) char __user *user_buffer = (char __user *)buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) unsigned long greater_than_max = (unsigned long)INT_MAX + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) KUNIT_ASSERT_GT(test, greater_than_max, (unsigned long)INT_MAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) KUNIT_ASSERT_LT(test, (size_t)snprintf(buffer, max_len, "%lu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) greater_than_max),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) max_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) KUNIT_EXPECT_EQ(test, -EINVAL, proc_dointvec(&table, KUNIT_PROC_WRITE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) user_buffer, &len, &pos));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) KUNIT_ASSERT_EQ(test, max_len, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) KUNIT_EXPECT_EQ(test, 0, *((int *)table.data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) static struct kunit_case sysctl_test_cases[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) KUNIT_CASE(sysctl_test_api_dointvec_null_tbl_data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) KUNIT_CASE(sysctl_test_api_dointvec_table_maxlen_unset),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) KUNIT_CASE(sysctl_test_api_dointvec_table_len_is_zero),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) KUNIT_CASE(sysctl_test_api_dointvec_table_read_but_position_set),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) KUNIT_CASE(sysctl_test_dointvec_read_happy_single_positive),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) KUNIT_CASE(sysctl_test_dointvec_read_happy_single_negative),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) KUNIT_CASE(sysctl_test_dointvec_write_happy_single_positive),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) KUNIT_CASE(sysctl_test_dointvec_write_happy_single_negative),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) KUNIT_CASE(sysctl_test_api_dointvec_write_single_less_int_min),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) KUNIT_CASE(sysctl_test_api_dointvec_write_single_greater_int_max),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) static struct kunit_suite sysctl_test_suite = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) .name = "sysctl_test",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) .test_cases = sysctl_test_cases,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) kunit_test_suites(&sysctl_test_suite);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) MODULE_LICENSE("GPL v2");