Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

sysctl: move u8 register test to lib/test_sysctl.c

If the test added in commit b5ffbd139688 ("sysctl: move the extra1/2
boundary check of u8 to sysctl_check_table_array") is run as a module, a
lingering reference to the module is left behind, and a 'sysctl -a'
leads to a panic.

To reproduce
CONFIG_KUNIT=y
CONFIG_SYSCTL_KUNIT_TEST=m

Then run these commands:
modprobe sysctl-test
rmmod sysctl-test
sysctl -a

The panic varies but generally looks something like this:

BUG: unable to handle page fault for address: ffffa4571c0c7db4
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 100000067 P4D 100000067 PUD 100351067 PMD 114f5e067 PTE 0
Oops: Oops: 0000 [#1] SMP NOPTI
... ... ...
RIP: 0010:proc_sys_readdir+0x166/0x2c0
... ... ...
Call Trace:
<TASK>
iterate_dir+0x6e/0x140
__se_sys_getdents+0x6e/0x100
do_syscall_64+0x70/0x150
entry_SYSCALL_64_after_hwframe+0x76/0x7e

Move the test to lib/test_sysctl.c where the registration reference is
handled on module exit

Fixes: b5ffbd139688 ("sysctl: move the extra1/2 boundary check of u8 to sysctl_check_table_array")

Reviewed-by: Kees Cook <kees@kernel.org>
Signed-off-by: Joel Granados <joel.granados@kernel.org>

+66 -49
-49
kernel/sysctl-test.c
··· 367 367 KUNIT_EXPECT_EQ(test, 0, *((int *)table.data)); 368 368 } 369 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 - const 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 - const 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 - const 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 370 static struct kunit_case sysctl_test_cases[] = { 419 371 KUNIT_CASE(sysctl_test_api_dointvec_null_tbl_data), 420 372 KUNIT_CASE(sysctl_test_api_dointvec_table_maxlen_unset), ··· 378 426 KUNIT_CASE(sysctl_test_dointvec_write_happy_single_negative), 379 427 KUNIT_CASE(sysctl_test_api_dointvec_write_single_less_int_min), 380 428 KUNIT_CASE(sysctl_test_api_dointvec_write_single_greater_int_max), 381 - KUNIT_CASE(sysctl_test_register_sysctl_sz_invalid_extra_value), 382 429 {} 383 430 }; 384 431
+66
lib/test_sysctl.c
··· 37 37 struct ctl_table_header *test_h_mnterror; 38 38 struct ctl_table_header *empty_add; 39 39 struct ctl_table_header *empty; 40 + struct ctl_table_header *test_u8; 40 41 } sysctl_test_headers; 41 42 42 43 struct test_sysctl_data { ··· 240 239 return 0; 241 240 } 242 241 242 + static const struct ctl_table table_u8_over[] = { 243 + { 244 + .procname = "u8_over", 245 + .data = &test_data.uint_0001, 246 + .maxlen = sizeof(u8), 247 + .mode = 0644, 248 + .proc_handler = proc_dou8vec_minmax, 249 + .extra1 = SYSCTL_FOUR, 250 + .extra2 = SYSCTL_ONE_THOUSAND, 251 + }, 252 + }; 253 + 254 + static const struct ctl_table table_u8_under[] = { 255 + { 256 + .procname = "u8_under", 257 + .data = &test_data.uint_0001, 258 + .maxlen = sizeof(u8), 259 + .mode = 0644, 260 + .proc_handler = proc_dou8vec_minmax, 261 + .extra1 = SYSCTL_NEG_ONE, 262 + .extra2 = SYSCTL_ONE_HUNDRED, 263 + }, 264 + }; 265 + 266 + static const struct ctl_table table_u8_valid[] = { 267 + { 268 + .procname = "u8_valid", 269 + .data = &test_data.uint_0001, 270 + .maxlen = sizeof(u8), 271 + .mode = 0644, 272 + .proc_handler = proc_dou8vec_minmax, 273 + .extra1 = SYSCTL_ZERO, 274 + .extra2 = SYSCTL_TWO_HUNDRED, 275 + }, 276 + }; 277 + 278 + static int test_sysctl_register_u8_extra(void) 279 + { 280 + /* should fail because it's over */ 281 + sysctl_test_headers.test_u8 282 + = register_sysctl("debug/test_sysctl", table_u8_over); 283 + if (sysctl_test_headers.test_u8) 284 + return -ENOMEM; 285 + 286 + /* should fail because it's under */ 287 + sysctl_test_headers.test_u8 288 + = register_sysctl("debug/test_sysctl", table_u8_under); 289 + if (sysctl_test_headers.test_u8) 290 + return -ENOMEM; 291 + 292 + /* should not fail because it's valid */ 293 + sysctl_test_headers.test_u8 294 + = register_sysctl("debug/test_sysctl", table_u8_valid); 295 + if (!sysctl_test_headers.test_u8) 296 + return -ENOMEM; 297 + 298 + return 0; 299 + } 300 + 243 301 static int __init test_sysctl_init(void) 244 302 { 245 303 int err; ··· 316 256 goto out; 317 257 318 258 err = test_sysctl_run_register_empty(); 259 + if (err) 260 + goto out; 261 + 262 + err = test_sysctl_register_u8_extra(); 319 263 320 264 out: 321 265 return err; ··· 339 275 unregister_sysctl_table(sysctl_test_headers.empty); 340 276 if (sysctl_test_headers.empty_add) 341 277 unregister_sysctl_table(sysctl_test_headers.empty_add); 278 + if (sysctl_test_headers.test_u8) 279 + unregister_sysctl_table(sysctl_test_headers.test_u8); 342 280 } 343 281 344 282 module_exit(test_sysctl_exit);