~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/kernel/sysctl-test.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php