Merge tag 'asm-generic-fixes-6.1-1' of git://git.kernel.org/pub/scm/linux/kernel...
[platform/kernel/linux-starfive.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 /*
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 static struct kunit_case sysctl_test_cases[] = {
371         KUNIT_CASE(sysctl_test_api_dointvec_null_tbl_data),
372         KUNIT_CASE(sysctl_test_api_dointvec_table_maxlen_unset),
373         KUNIT_CASE(sysctl_test_api_dointvec_table_len_is_zero),
374         KUNIT_CASE(sysctl_test_api_dointvec_table_read_but_position_set),
375         KUNIT_CASE(sysctl_test_dointvec_read_happy_single_positive),
376         KUNIT_CASE(sysctl_test_dointvec_read_happy_single_negative),
377         KUNIT_CASE(sysctl_test_dointvec_write_happy_single_positive),
378         KUNIT_CASE(sysctl_test_dointvec_write_happy_single_negative),
379         KUNIT_CASE(sysctl_test_api_dointvec_write_single_less_int_min),
380         KUNIT_CASE(sysctl_test_api_dointvec_write_single_greater_int_max),
381         {}
382 };
383
384 static struct kunit_suite sysctl_test_suite = {
385         .name = "sysctl_test",
386         .test_cases = sysctl_test_cases,
387 };
388
389 kunit_test_suites(&sysctl_test_suite);
390
391 MODULE_LICENSE("GPL v2");