1 // SPDX-License-Identifier: GPL-2.0 1 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 14 * length is non-zero. 15 */ 16 static void sysctl_test_api_dointvec_null_tbl_ 17 { 18 struct ctl_table null_data_table = { 19 .procname = "foo", 20 /* 21 * Here we are testing that pr 22 * we give it a NULL .data fie 23 * piece of memory where the v 24 */ 25 .data = NULL, 26 .maxlen = sizeof(int), 27 .mode = 0644, 28 .proc_handler = proc_dointve 29 .extra1 = SYSCTL_ZERO, 30 .extra2 = SYSCTL_ONE_H 31 }; 32 /* 33 * proc_dointvec expects a buffer in u 34 * also need to cast it to __user so s 35 */ 36 void __user *buffer = (void __user *)k 37 38 size_t len; 39 loff_t pos; 40 41 /* 42 * We don't care what the starting len 43 * not try to read because .data is NU 44 */ 45 len = 1234; 46 KUNIT_EXPECT_EQ(test, 0, proc_dointvec 47 48 49 KUNIT_EXPECT_EQ(test, 0, len); 50 51 /* 52 * See above. 53 */ 54 len = 1234; 55 KUNIT_EXPECT_EQ(test, 0, proc_dointvec 56 57 58 KUNIT_EXPECT_EQ(test, 0, len); 59 } 60 61 /* 62 * Similar to the previous test, we create a s 63 * field that proc_dointvec cannot do anything 64 * because we tell proc_dointvec that the size 65 */ 66 static void sysctl_test_api_dointvec_table_max 67 { 68 int data = 0; 69 struct ctl_table data_maxlen_unset_tab 70 .procname = "foo", 71 .data = &data, 72 /* 73 * So .data is no longer NULL, 74 * length is 0, so it still sh 75 */ 76 .maxlen = 0, 77 .mode = 0644, 78 .proc_handler = proc_dointve 79 .extra1 = SYSCTL_ZERO, 80 .extra2 = SYSCTL_ONE_H 81 }; 82 void __user *buffer = (void __user *)k 83 84 size_t len; 85 loff_t pos; 86 87 /* 88 * As before, we don't care what buffe 89 * cannot do anything because its inte 90 */ 91 len = 1234; 92 KUNIT_EXPECT_EQ(test, 0, proc_dointvec 93 94 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 102 103 104 KUNIT_EXPECT_EQ(test, 0, len); 105 } 106 107 /* 108 * Here we provide a valid struct ctl_table, b 109 * it using a buffer of zero length, so it sho 110 * before. 111 */ 112 static void sysctl_test_api_dointvec_table_len 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_dointve 122 .extra1 = SYSCTL_ZERO, 123 .extra2 = SYSCTL_ONE_H 124 }; 125 void __user *buffer = (void __user *)k 126 127 /* 128 * However, now our read/write buffer 129 */ 130 size_t len = 0; 131 loff_t pos; 132 133 KUNIT_EXPECT_EQ(test, 0, proc_dointvec 134 135 KUNIT_EXPECT_EQ(test, 0, len); 136 137 KUNIT_EXPECT_EQ(test, 0, proc_dointvec 138 139 KUNIT_EXPECT_EQ(test, 0, len); 140 } 141 142 /* 143 * Test that proc_dointvec refuses to read whe 144 */ 145 static void sysctl_test_api_dointvec_table_rea 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_dointve 156 .extra1 = SYSCTL_ZERO, 157 .extra2 = SYSCTL_ONE_H 158 }; 159 void __user *buffer = (void __user *)k 160 161 /* 162 * We don't care about our buffer leng 163 * non-zero file position. 164 */ 165 size_t len = 1234; 166 /* 167 * proc_dointvec should refuse to read 168 * pos is non-zero. 169 */ 170 loff_t pos = 1; 171 172 KUNIT_EXPECT_EQ(test, 0, proc_dointvec 173 174 KUNIT_EXPECT_EQ(test, 0, len); 175 } 176 177 /* 178 * Test that we can read a two digit number in 179 * Nothing fancy. 180 */ 181 static void sysctl_test_dointvec_read_happy_si 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_dointve 191 .extra1 = SYSCTL_ZERO, 192 .extra2 = SYSCTL_ONE_H 193 }; 194 size_t len = 4; 195 loff_t pos = 0; 196 char *buffer = kunit_kzalloc(test, len 197 char __user *user_buffer = (char __use 198 /* Store 13 in the data field. */ 199 *((int *)table.data) = 13; 200 201 KUNIT_EXPECT_EQ(test, 0, proc_dointvec 202 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", buffe 207 } 208 209 /* 210 * Same as previous test, just now with negati 211 */ 212 static void sysctl_test_dointvec_read_happy_si 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_dointve 222 .extra1 = SYSCTL_ZERO, 223 .extra2 = SYSCTL_ONE_H 224 }; 225 size_t len = 5; 226 loff_t pos = 0; 227 char *buffer = kunit_kzalloc(test, len 228 char __user *user_buffer = (char __use 229 *((int *)table.data) = -16; 230 231 KUNIT_EXPECT_EQ(test, 0, proc_dointvec 232 233 KUNIT_ASSERT_EQ(test, 4, len); 234 buffer[len] = '\0'; 235 KUNIT_EXPECT_STREQ(test, "-16\n", buff 236 } 237 238 /* 239 * Test that a simple positive write works. 240 */ 241 static void sysctl_test_dointvec_write_happy_s 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_dointve 251 .extra1 = SYSCTL_ZERO, 252 .extra2 = SYSCTL_ONE_H 253 }; 254 char input[] = "9"; 255 size_t len = sizeof(input) - 1; 256 loff_t pos = 0; 257 char *buffer = kunit_kzalloc(test, len 258 char __user *user_buffer = (char __use 259 260 memcpy(buffer, input, len); 261 262 KUNIT_EXPECT_EQ(test, 0, proc_dointvec 263 264 KUNIT_EXPECT_EQ(test, sizeof(input) - 265 KUNIT_EXPECT_EQ(test, sizeof(input) - 266 KUNIT_EXPECT_EQ(test, 9, *((int *)tabl 267 } 268 269 /* 270 * Same as previous test, but now with negativ 271 */ 272 static void sysctl_test_dointvec_write_happy_s 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_dointve 281 .extra1 = SYSCTL_ZERO, 282 .extra2 = SYSCTL_ONE_H 283 }; 284 char input[] = "-9"; 285 size_t len = sizeof(input) - 1; 286 loff_t pos = 0; 287 char *buffer = kunit_kzalloc(test, len 288 char __user *user_buffer = (char __use 289 290 memcpy(buffer, input, len); 291 292 KUNIT_EXPECT_EQ(test, 0, proc_dointvec 293 294 KUNIT_EXPECT_EQ(test, sizeof(input) - 295 KUNIT_EXPECT_EQ(test, sizeof(input) - 296 KUNIT_EXPECT_EQ(test, -9, *((int *)tab 297 } 298 299 /* 300 * Test that writing a value smaller than the 301 * allowed. 302 */ 303 static void sysctl_test_api_dointvec_write_sin 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_dointve 313 .extra1 = SYSCTL_ZERO, 314 .extra2 = SYSCTL_ONE_H 315 }; 316 size_t max_len = 32, len = max_len; 317 loff_t pos = 0; 318 char *buffer = kunit_kzalloc(test, max 319 char __user *user_buffer = (char __use 320 unsigned long abs_of_less_than_min = ( 321 - 322 323 /* 324 * We use this rigmarole to create a s 325 * less than the minimum accepted valu 326 */ 327 KUNIT_ASSERT_LT(test, 328 (size_t)snprintf(buffe 329 abs_o 330 max_len); 331 332 KUNIT_EXPECT_EQ(test, -EINVAL, proc_do 333 334 KUNIT_EXPECT_EQ(test, max_len, len); 335 KUNIT_EXPECT_EQ(test, 0, *((int *)tabl 336 } 337 338 /* 339 * Test that writing the maximum possible valu 340 */ 341 static void sysctl_test_api_dointvec_write_sin 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_dointve 351 .extra1 = SYSCTL_ZERO, 352 .extra2 = SYSCTL_ONE_H 353 }; 354 size_t max_len = 32, len = max_len; 355 loff_t pos = 0; 356 char *buffer = kunit_kzalloc(test, max 357 char __user *user_buffer = (char __use 358 unsigned long greater_than_max = (unsi 359 360 KUNIT_ASSERT_GT(test, greater_than_max 361 KUNIT_ASSERT_LT(test, (size_t)snprintf 362 363 max_len); 364 KUNIT_EXPECT_EQ(test, -EINVAL, proc_do 365 366 KUNIT_ASSERT_EQ(test, max_len, len); 367 KUNIT_EXPECT_EQ(test, 0, *((int *)tabl 368 } 369 370 /* 371 * Test that registering an invalid extra valu 372 */ 373 static void sysctl_test_register_sysctl_sz_inv 374 struct kunit *test) 375 { 376 unsigned char data = 0; 377 struct ctl_table table_foo[] = { 378 { 379 .procname = "foo 380 .data = &dat 381 .maxlen = size 382 .mode = 0644 383 .proc_handler = proc 384 .extra1 = SYSC 385 .extra2 = SYSC 386 }, 387 }; 388 389 struct ctl_table table_bar[] = { 390 { 391 .procname = "bar 392 .data = &dat 393 .maxlen = size 394 .mode = 0644 395 .proc_handler = proc 396 .extra1 = SYSC 397 .extra2 = SYSC 398 }, 399 }; 400 401 struct ctl_table table_qux[] = { 402 { 403 .procname = "qux 404 .data = &dat 405 .maxlen = size 406 .mode = 0644 407 .proc_handler = proc 408 .extra1 = SYSC 409 .extra2 = SYSC 410 }, 411 }; 412 413 KUNIT_EXPECT_NULL(test, register_sysct 414 KUNIT_EXPECT_NULL(test, register_sysct 415 KUNIT_EXPECT_NOT_NULL(test, register_s 416 } 417 418 static struct kunit_case sysctl_test_cases[] = 419 KUNIT_CASE(sysctl_test_api_dointvec_nu 420 KUNIT_CASE(sysctl_test_api_dointvec_ta 421 KUNIT_CASE(sysctl_test_api_dointvec_ta 422 KUNIT_CASE(sysctl_test_api_dointvec_ta 423 KUNIT_CASE(sysctl_test_dointvec_read_h 424 KUNIT_CASE(sysctl_test_dointvec_read_h 425 KUNIT_CASE(sysctl_test_dointvec_write_ 426 KUNIT_CASE(sysctl_test_dointvec_write_ 427 KUNIT_CASE(sysctl_test_api_dointvec_wr 428 KUNIT_CASE(sysctl_test_api_dointvec_wr 429 KUNIT_CASE(sysctl_test_register_sysctl 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.