Linux 6.0-rc1
[linux-2.6-microblaze.git] / kernel / sysctl-test.c
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 static int i_zero;
13 static 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  */
19 static 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, 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, 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  */
69 static 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, 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, 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  */
115 static 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, 0, len);
139
140         KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_WRITE, buffer,
141                                                &len, &pos));
142         KUNIT_EXPECT_EQ(test, 0, len);
143 }
144
145 /*
146  * Test that proc_dointvec refuses to read when the file position is non-zero.
147  */
148 static 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, 0, len);
178 }
179
180 /*
181  * Test that we can read a two digit number in a sufficiently size buffer.
182  * Nothing fancy.
183  */
184 static 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, 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  */
215 static 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, 4, len);
237         buffer[len] = '\0';
238         KUNIT_EXPECT_STREQ(test, "-16\n", buffer);
239 }
240
241 /*
242  * Test that a simple positive write works.
243  */
244 static 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, pos);
269         KUNIT_EXPECT_EQ(test, 9, *((int *)table.data));
270 }
271
272 /*
273  * Same as previous test, but now with negative numbers.
274  */
275 static 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, 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  */
306 static 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  */
344 static 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
373 static 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
387 static struct kunit_suite sysctl_test_suite = {
388         .name = "sysctl_test",
389         .test_cases = sysctl_test_cases,
390 };
391
392 kunit_test_suites(&sysctl_test_suite);
393
394 MODULE_LICENSE("GPL v2");