History

kernel/sysctl-test: Add null pointer test for sysctl.c:proc_dointvec()

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.

Iurii Zaikin committed 7 years ago

Commit 2cb80db1 parent 804ec793 files · +405 −0Browse files

Unified · Split

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