vfs, security: Fix automount superblock LSM init problem, preventing NFS sb sharing
[platform/kernel/linux-rpi.git] / lib / test_sysctl.c
1 // SPDX-License-Identifier: GPL-2.0-or-later OR copyleft-next-0.3.1
2 /*
3  * proc sysctl test driver
4  *
5  * Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org>
6  */
7
8 /*
9  * This module provides an interface to the proc sysctl interfaces.  This
10  * driver requires CONFIG_PROC_SYSCTL. It will not normally be loaded by the
11  * system unless explicitly requested by name. You can also build this driver
12  * into your kernel.
13  */
14
15 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16
17 #include <linux/init.h>
18 #include <linux/list.h>
19 #include <linux/module.h>
20 #include <linux/printk.h>
21 #include <linux/fs.h>
22 #include <linux/miscdevice.h>
23 #include <linux/slab.h>
24 #include <linux/uaccess.h>
25 #include <linux/async.h>
26 #include <linux/delay.h>
27 #include <linux/vmalloc.h>
28
29 static int i_zero;
30 static int i_one_hundred = 100;
31 static int match_int_ok = 1;
32
33
34 static struct {
35         struct ctl_table_header *test_h_setup_node;
36         struct ctl_table_header *test_h_mnt;
37         struct ctl_table_header *test_h_mnterror;
38 } sysctl_test_headers;
39
40 struct test_sysctl_data {
41         int int_0001;
42         int int_0002;
43         int int_0003[4];
44
45         int boot_int;
46
47         unsigned int uint_0001;
48
49         char string_0001[65];
50
51 #define SYSCTL_TEST_BITMAP_SIZE 65536
52         unsigned long *bitmap_0001;
53 };
54
55 static struct test_sysctl_data test_data = {
56         .int_0001 = 60,
57         .int_0002 = 1,
58
59         .int_0003[0] = 0,
60         .int_0003[1] = 1,
61         .int_0003[2] = 2,
62         .int_0003[3] = 3,
63
64         .boot_int = 0,
65
66         .uint_0001 = 314,
67
68         .string_0001 = "(none)",
69 };
70
71 /* These are all under /proc/sys/debug/test_sysctl/ */
72 static struct ctl_table test_table[] = {
73         {
74                 .procname       = "int_0001",
75                 .data           = &test_data.int_0001,
76                 .maxlen         = sizeof(int),
77                 .mode           = 0644,
78                 .proc_handler   = proc_dointvec_minmax,
79                 .extra1         = &i_zero,
80                 .extra2         = &i_one_hundred,
81         },
82         {
83                 .procname       = "int_0002",
84                 .data           = &test_data.int_0002,
85                 .maxlen         = sizeof(int),
86                 .mode           = 0644,
87                 .proc_handler   = proc_dointvec,
88         },
89         {
90                 .procname       = "int_0003",
91                 .data           = &test_data.int_0003,
92                 .maxlen         = sizeof(test_data.int_0003),
93                 .mode           = 0644,
94                 .proc_handler   = proc_dointvec,
95         },
96         {
97                 .procname       = "match_int",
98                 .data           = &match_int_ok,
99                 .maxlen         = sizeof(match_int_ok),
100                 .mode           = 0444,
101                 .proc_handler   = proc_dointvec,
102         },
103         {
104                 .procname       = "boot_int",
105                 .data           = &test_data.boot_int,
106                 .maxlen         = sizeof(test_data.boot_int),
107                 .mode           = 0644,
108                 .proc_handler   = proc_dointvec,
109                 .extra1         = SYSCTL_ZERO,
110                 .extra2         = SYSCTL_ONE,
111         },
112         {
113                 .procname       = "uint_0001",
114                 .data           = &test_data.uint_0001,
115                 .maxlen         = sizeof(unsigned int),
116                 .mode           = 0644,
117                 .proc_handler   = proc_douintvec,
118         },
119         {
120                 .procname       = "string_0001",
121                 .data           = &test_data.string_0001,
122                 .maxlen         = sizeof(test_data.string_0001),
123                 .mode           = 0644,
124                 .proc_handler   = proc_dostring,
125         },
126         {
127                 .procname       = "bitmap_0001",
128                 .data           = &test_data.bitmap_0001,
129                 .maxlen         = SYSCTL_TEST_BITMAP_SIZE,
130                 .mode           = 0644,
131                 .proc_handler   = proc_do_large_bitmap,
132         },
133         { }
134 };
135
136 static void test_sysctl_calc_match_int_ok(void)
137 {
138         int i;
139
140         struct {
141                 int defined;
142                 int wanted;
143         } match_int[] = {
144                 {.defined = *(int *)SYSCTL_ZERO,        .wanted = 0},
145                 {.defined = *(int *)SYSCTL_ONE,         .wanted = 1},
146                 {.defined = *(int *)SYSCTL_TWO,         .wanted = 2},
147                 {.defined = *(int *)SYSCTL_THREE,       .wanted = 3},
148                 {.defined = *(int *)SYSCTL_FOUR,        .wanted = 4},
149                 {.defined = *(int *)SYSCTL_ONE_HUNDRED, .wanted = 100},
150                 {.defined = *(int *)SYSCTL_TWO_HUNDRED, .wanted = 200},
151                 {.defined = *(int *)SYSCTL_ONE_THOUSAND, .wanted = 1000},
152                 {.defined = *(int *)SYSCTL_THREE_THOUSAND, .wanted = 3000},
153                 {.defined = *(int *)SYSCTL_INT_MAX,     .wanted = INT_MAX},
154                 {.defined = *(int *)SYSCTL_MAXOLDUID,   .wanted = 65535},
155                 {.defined = *(int *)SYSCTL_NEG_ONE,     .wanted = -1},
156         };
157
158         for (i = 0; i < ARRAY_SIZE(match_int); i++)
159                 if (match_int[i].defined != match_int[i].wanted)
160                         match_int_ok = 0;
161 }
162
163 static int test_sysctl_setup_node_tests(void)
164 {
165         test_sysctl_calc_match_int_ok();
166         test_data.bitmap_0001 = kzalloc(SYSCTL_TEST_BITMAP_SIZE/8, GFP_KERNEL);
167         if (!test_data.bitmap_0001)
168                 return -ENOMEM;
169         sysctl_test_headers.test_h_setup_node = register_sysctl("debug/test_sysctl", test_table);
170         if (!sysctl_test_headers.test_h_setup_node) {
171                 kfree(test_data.bitmap_0001);
172                 return -ENOMEM;
173         }
174
175         return 0;
176 }
177
178 /* Used to test that unregister actually removes the directory */
179 static struct ctl_table test_table_unregister[] = {
180         {
181                 .procname       = "unregister_error",
182                 .data           = &test_data.int_0001,
183                 .maxlen         = sizeof(int),
184                 .mode           = 0644,
185                 .proc_handler   = proc_dointvec_minmax,
186         },
187         {}
188 };
189
190 static int test_sysctl_run_unregister_nested(void)
191 {
192         struct ctl_table_header *unregister;
193
194         unregister = register_sysctl("debug/test_sysctl/unregister_error",
195                                    test_table_unregister);
196         if (!unregister)
197                 return -ENOMEM;
198
199         unregister_sysctl_table(unregister);
200         return 0;
201 }
202
203 static int test_sysctl_run_register_mount_point(void)
204 {
205         sysctl_test_headers.test_h_mnt
206                 = register_sysctl_mount_point("debug/test_sysctl/mnt");
207         if (!sysctl_test_headers.test_h_mnt)
208                 return -ENOMEM;
209
210         sysctl_test_headers.test_h_mnterror
211                 = register_sysctl("debug/test_sysctl/mnt/mnt_error",
212                                   test_table_unregister);
213         /*
214          * Don't check the result.:
215          * If it fails (expected behavior), return 0.
216          * If successful (missbehavior of register mount point), we want to see
217          * mnt_error when we run the sysctl test script
218          */
219
220         return 0;
221 }
222
223 static int __init test_sysctl_init(void)
224 {
225         int err;
226
227         err = test_sysctl_setup_node_tests();
228         if (err)
229                 goto out;
230
231         err = test_sysctl_run_unregister_nested();
232         if (err)
233                 goto out;
234
235         err = test_sysctl_run_register_mount_point();
236
237 out:
238         return err;
239 }
240 module_init(test_sysctl_init);
241
242 static void __exit test_sysctl_exit(void)
243 {
244         kfree(test_data.bitmap_0001);
245         if (sysctl_test_headers.test_h_setup_node)
246                 unregister_sysctl_table(sysctl_test_headers.test_h_setup_node);
247         if (sysctl_test_headers.test_h_mnt)
248                 unregister_sysctl_table(sysctl_test_headers.test_h_mnt);
249         if (sysctl_test_headers.test_h_mnterror)
250                 unregister_sysctl_table(sysctl_test_headers.test_h_mnterror);
251 }
252
253 module_exit(test_sysctl_exit);
254
255 MODULE_AUTHOR("Luis R. Rodriguez <mcgrof@kernel.org>");
256 MODULE_LICENSE("GPL");