1 // SPDX-License-Identifier: GPL-2.0 2 #include <kunit/test.h> 3 #include <kunit/test-bug.h> 4 #include <linux/module.h> 5 #include <linux/miscdevice.h> 6 #include <linux/fs.h> 7 #include <linux/file.h> 8 #include <linux/init_syscalls.h> 9 10 /* static minor (LCD_MINOR) */ 11 static struct miscdevice dev_static_minor = { 12 .minor = LCD_MINOR, 13 .name = "dev_static_minor", 14 }; 15 16 /* misc dynamic minor */ 17 static struct miscdevice dev_misc_dynamic_minor = { 18 .minor = MISC_DYNAMIC_MINOR, 19 .name = "dev_misc_dynamic_minor", 20 }; 21 22 static void kunit_static_minor(struct kunit *test) 23 { 24 int ret; 25 26 ret = misc_register(&dev_static_minor); 27 KUNIT_EXPECT_EQ(test, 0, ret); 28 KUNIT_EXPECT_EQ(test, LCD_MINOR, dev_static_minor.minor); 29 misc_deregister(&dev_static_minor); 30 } 31 32 static void kunit_misc_dynamic_minor(struct kunit *test) 33 { 34 int ret; 35 36 ret = misc_register(&dev_misc_dynamic_minor); 37 KUNIT_EXPECT_EQ(test, 0, ret); 38 misc_deregister(&dev_misc_dynamic_minor); 39 } 40 41 struct miscdev_test_case { 42 const char *str; 43 int minor; 44 }; 45 46 static struct miscdev_test_case miscdev_test_ranges[] = { 47 { 48 .str = "lower static range, top", 49 .minor = 15, 50 }, 51 { 52 .str = "upper static range, bottom", 53 .minor = 130, 54 }, 55 { 56 .str = "lower static range, bottom", 57 .minor = 0, 58 }, 59 { 60 .str = "upper static range, top", 61 .minor = MISC_DYNAMIC_MINOR - 1, 62 }, 63 }; 64 65 KUNIT_ARRAY_PARAM_DESC(miscdev, miscdev_test_ranges, str); 66 67 static int miscdev_find_minors(struct kunit_suite *suite) 68 { 69 int ret; 70 struct miscdevice miscstat = { 71 .name = "miscstat", 72 }; 73 int i; 74 75 for (i = 15; i >= 0; i--) { 76 miscstat.minor = i; 77 ret = misc_register(&miscstat); 78 if (ret == 0) 79 break; 80 } 81 82 if (ret == 0) { 83 kunit_info(suite, "found misc device minor %d available\n", 84 miscstat.minor); 85 miscdev_test_ranges[0].minor = miscstat.minor; 86 misc_deregister(&miscstat); 87 } else { 88 return ret; 89 } 90 91 for (i = 128; i < MISC_DYNAMIC_MINOR; i++) { 92 miscstat.minor = i; 93 ret = misc_register(&miscstat); 94 if (ret == 0) 95 break; 96 } 97 98 if (ret == 0) { 99 kunit_info(suite, "found misc device minor %d available\n", 100 miscstat.minor); 101 miscdev_test_ranges[1].minor = miscstat.minor; 102 misc_deregister(&miscstat); 103 } else { 104 return ret; 105 } 106 107 for (i = 0; i < miscdev_test_ranges[0].minor; i++) { 108 miscstat.minor = i; 109 ret = misc_register(&miscstat); 110 if (ret == 0) 111 break; 112 } 113 114 if (ret == 0) { 115 kunit_info(suite, "found misc device minor %d available\n", 116 miscstat.minor); 117 miscdev_test_ranges[2].minor = miscstat.minor; 118 misc_deregister(&miscstat); 119 } else { 120 return ret; 121 } 122 123 for (i = MISC_DYNAMIC_MINOR - 1; i > miscdev_test_ranges[1].minor; i--) { 124 miscstat.minor = i; 125 ret = misc_register(&miscstat); 126 if (ret == 0) 127 break; 128 } 129 130 if (ret == 0) { 131 kunit_info(suite, "found misc device minor %d available\n", 132 miscstat.minor); 133 miscdev_test_ranges[3].minor = miscstat.minor; 134 misc_deregister(&miscstat); 135 } 136 137 return ret; 138 } 139 140 static bool is_valid_dynamic_minor(int minor) 141 { 142 if (minor < 0) 143 return false; 144 return minor > MISC_DYNAMIC_MINOR; 145 } 146 147 static int miscdev_test_open(struct inode *inode, struct file *file) 148 { 149 return 0; 150 } 151 152 static const struct file_operations miscdev_test_fops = { 153 .open = miscdev_test_open, 154 }; 155 156 static void __init miscdev_test_can_open(struct kunit *test, struct miscdevice *misc) 157 { 158 int ret; 159 struct file *filp; 160 char *devname; 161 162 devname = kasprintf(GFP_KERNEL, "/dev/%s", misc->name); 163 ret = init_mknod(devname, S_IFCHR | 0600, 164 new_encode_dev(MKDEV(MISC_MAJOR, misc->minor))); 165 if (ret != 0) 166 KUNIT_FAIL(test, "failed to create node\n"); 167 168 filp = filp_open(devname, O_RDONLY, 0); 169 if (IS_ERR_OR_NULL(filp)) 170 KUNIT_FAIL(test, "failed to open misc device: %ld\n", PTR_ERR(filp)); 171 else 172 fput(filp); 173 174 init_unlink(devname); 175 kfree(devname); 176 } 177 178 static void __init miscdev_test_static_basic(struct kunit *test) 179 { 180 struct miscdevice misc_test = { 181 .name = "misc_test", 182 .fops = &miscdev_test_fops, 183 }; 184 int ret; 185 const struct miscdev_test_case *params = test->param_value; 186 187 misc_test.minor = params->minor; 188 189 ret = misc_register(&misc_test); 190 KUNIT_EXPECT_EQ(test, ret, 0); 191 KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor); 192 193 if (ret == 0) { 194 miscdev_test_can_open(test, &misc_test); 195 misc_deregister(&misc_test); 196 } 197 } 198 199 static void __init miscdev_test_dynamic_basic(struct kunit *test) 200 { 201 struct miscdevice misc_test = { 202 .minor = MISC_DYNAMIC_MINOR, 203 .name = "misc_test", 204 .fops = &miscdev_test_fops, 205 }; 206 int ret; 207 208 ret = misc_register(&misc_test); 209 KUNIT_EXPECT_EQ(test, ret, 0); 210 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc_test.minor)); 211 212 if (ret == 0) { 213 miscdev_test_can_open(test, &misc_test); 214 misc_deregister(&misc_test); 215 } 216 } 217 218 static void miscdev_test_twice(struct kunit *test) 219 { 220 struct miscdevice misc_test = { 221 .name = "misc_test", 222 .fops = &miscdev_test_fops, 223 }; 224 int ret; 225 const struct miscdev_test_case *params = test->param_value; 226 227 misc_test.minor = params->minor; 228 229 ret = misc_register(&misc_test); 230 KUNIT_EXPECT_EQ(test, ret, 0); 231 KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor); 232 if (ret == 0) 233 misc_deregister(&misc_test); 234 235 ret = misc_register(&misc_test); 236 KUNIT_EXPECT_EQ(test, ret, 0); 237 KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor); 238 if (ret == 0) 239 misc_deregister(&misc_test); 240 } 241 242 static void miscdev_test_duplicate_minor(struct kunit *test) 243 { 244 struct miscdevice misc1 = { 245 .name = "misc1", 246 .fops = &miscdev_test_fops, 247 }; 248 struct miscdevice misc2 = { 249 .name = "misc2", 250 .fops = &miscdev_test_fops, 251 }; 252 int ret; 253 const struct miscdev_test_case *params = test->param_value; 254 255 misc1.minor = params->minor; 256 misc2.minor = params->minor; 257 258 ret = misc_register(&misc1); 259 KUNIT_EXPECT_EQ(test, ret, 0); 260 KUNIT_EXPECT_EQ(test, misc1.minor, params->minor); 261 262 ret = misc_register(&misc2); 263 KUNIT_EXPECT_EQ(test, ret, -EBUSY); 264 if (ret == 0) 265 misc_deregister(&misc2); 266 267 misc_deregister(&misc1); 268 } 269 270 static void miscdev_test_duplicate_name(struct kunit *test) 271 { 272 struct miscdevice misc1 = { 273 .minor = MISC_DYNAMIC_MINOR, 274 .name = "misc1", 275 .fops = &miscdev_test_fops, 276 }; 277 struct miscdevice misc2 = { 278 .minor = MISC_DYNAMIC_MINOR, 279 .name = "misc1", 280 .fops = &miscdev_test_fops, 281 }; 282 int ret; 283 284 ret = misc_register(&misc1); 285 KUNIT_EXPECT_EQ(test, ret, 0); 286 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc1.minor)); 287 288 ret = misc_register(&misc2); 289 KUNIT_EXPECT_EQ(test, ret, -EEXIST); 290 if (ret == 0) 291 misc_deregister(&misc2); 292 293 misc_deregister(&misc1); 294 } 295 296 /* 297 * Test that after a duplicate name failure, the reserved minor number is 298 * freed to be allocated next. 299 */ 300 static void miscdev_test_duplicate_name_leak(struct kunit *test) 301 { 302 struct miscdevice misc1 = { 303 .minor = MISC_DYNAMIC_MINOR, 304 .name = "misc1", 305 .fops = &miscdev_test_fops, 306 }; 307 struct miscdevice misc2 = { 308 .minor = MISC_DYNAMIC_MINOR, 309 .name = "misc1", 310 .fops = &miscdev_test_fops, 311 }; 312 struct miscdevice misc3 = { 313 .minor = MISC_DYNAMIC_MINOR, 314 .name = "misc3", 315 .fops = &miscdev_test_fops, 316 }; 317 int ret; 318 int dyn_minor; 319 320 ret = misc_register(&misc1); 321 KUNIT_EXPECT_EQ(test, ret, 0); 322 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc1.minor)); 323 324 /* 325 * Find out what is the next minor number available. 326 */ 327 ret = misc_register(&misc3); 328 KUNIT_EXPECT_EQ(test, ret, 0); 329 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc3.minor)); 330 dyn_minor = misc3.minor; 331 misc_deregister(&misc3); 332 misc3.minor = MISC_DYNAMIC_MINOR; 333 334 ret = misc_register(&misc2); 335 KUNIT_EXPECT_EQ(test, ret, -EEXIST); 336 if (ret == 0) 337 misc_deregister(&misc2); 338 339 /* 340 * Now check that we can still get the same minor we found before. 341 */ 342 ret = misc_register(&misc3); 343 KUNIT_EXPECT_EQ(test, ret, 0); 344 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc3.minor)); 345 KUNIT_EXPECT_EQ(test, misc3.minor, dyn_minor); 346 misc_deregister(&misc3); 347 348 misc_deregister(&misc1); 349 } 350 351 /* 352 * Try to register a static minor with a duplicate name. That might not 353 * deallocate the minor, preventing it from being used again. 354 */ 355 static void miscdev_test_duplicate_error(struct kunit *test) 356 { 357 struct miscdevice miscdyn = { 358 .minor = MISC_DYNAMIC_MINOR, 359 .name = "name1", 360 .fops = &miscdev_test_fops, 361 }; 362 struct miscdevice miscstat = { 363 .name = "name1", 364 .fops = &miscdev_test_fops, 365 }; 366 struct miscdevice miscnew = { 367 .name = "name2", 368 .fops = &miscdev_test_fops, 369 }; 370 int ret; 371 const struct miscdev_test_case *params = test->param_value; 372 373 miscstat.minor = params->minor; 374 miscnew.minor = params->minor; 375 376 ret = misc_register(&miscdyn); 377 KUNIT_EXPECT_EQ(test, ret, 0); 378 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor)); 379 380 ret = misc_register(&miscstat); 381 KUNIT_EXPECT_EQ(test, ret, -EEXIST); 382 if (ret == 0) 383 misc_deregister(&miscstat); 384 385 ret = misc_register(&miscnew); 386 KUNIT_EXPECT_EQ(test, ret, 0); 387 KUNIT_EXPECT_EQ(test, miscnew.minor, params->minor); 388 if (ret == 0) 389 misc_deregister(&miscnew); 390 391 misc_deregister(&miscdyn); 392 } 393 394 static void __init miscdev_test_dynamic_only_range(struct kunit *test) 395 { 396 int ret; 397 struct miscdevice *miscdev; 398 const int dynamic_minors = 256; 399 int i; 400 401 miscdev = kunit_kmalloc_array(test, dynamic_minors, 402 sizeof(struct miscdevice), 403 GFP_KERNEL | __GFP_ZERO); 404 405 for (i = 0; i < dynamic_minors; i++) { 406 miscdev[i].minor = MISC_DYNAMIC_MINOR; 407 miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i); 408 miscdev[i].fops = &miscdev_test_fops; 409 ret = misc_register(&miscdev[i]); 410 if (ret != 0) 411 break; 412 /* 413 * This is the bug we are looking for! 414 * We asked for a dynamic minor and got a minor in the static range space. 415 */ 416 if (miscdev[i].minor >= 0 && miscdev[i].minor <= 15) { 417 KUNIT_FAIL(test, "misc_register allocated minor %d\n", miscdev[i].minor); 418 i++; 419 break; 420 } 421 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor)); 422 } 423 424 for (i--; i >= 0; i--) { 425 miscdev_test_can_open(test, &miscdev[i]); 426 misc_deregister(&miscdev[i]); 427 kfree_const(miscdev[i].name); 428 } 429 430 KUNIT_EXPECT_EQ(test, ret, 0); 431 } 432 433 static void __init miscdev_test_collision(struct kunit *test) 434 { 435 int ret; 436 struct miscdevice *miscdev; 437 struct miscdevice miscstat = { 438 .name = "miscstat", 439 .fops = &miscdev_test_fops, 440 }; 441 const int dynamic_minors = 256; 442 int i; 443 444 miscdev = kunit_kmalloc_array(test, dynamic_minors, 445 sizeof(struct miscdevice), 446 GFP_KERNEL | __GFP_ZERO); 447 448 miscstat.minor = miscdev_test_ranges[0].minor; 449 ret = misc_register(&miscstat); 450 KUNIT_ASSERT_EQ(test, ret, 0); 451 KUNIT_EXPECT_EQ(test, miscstat.minor, miscdev_test_ranges[0].minor); 452 453 for (i = 0; i < dynamic_minors; i++) { 454 miscdev[i].minor = MISC_DYNAMIC_MINOR; 455 miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i); 456 miscdev[i].fops = &miscdev_test_fops; 457 ret = misc_register(&miscdev[i]); 458 if (ret != 0) 459 break; 460 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor)); 461 } 462 463 for (i--; i >= 0; i--) { 464 miscdev_test_can_open(test, &miscdev[i]); 465 misc_deregister(&miscdev[i]); 466 kfree_const(miscdev[i].name); 467 } 468 469 misc_deregister(&miscstat); 470 471 KUNIT_EXPECT_EQ(test, ret, 0); 472 } 473 474 static void __init miscdev_test_collision_reverse(struct kunit *test) 475 { 476 int ret; 477 struct miscdevice *miscdev; 478 struct miscdevice miscstat = { 479 .name = "miscstat", 480 .fops = &miscdev_test_fops, 481 }; 482 const int dynamic_minors = 256; 483 int i; 484 485 miscdev = kunit_kmalloc_array(test, dynamic_minors, 486 sizeof(struct miscdevice), 487 GFP_KERNEL | __GFP_ZERO); 488 489 for (i = 0; i < dynamic_minors; i++) { 490 miscdev[i].minor = MISC_DYNAMIC_MINOR; 491 miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i); 492 miscdev[i].fops = &miscdev_test_fops; 493 ret = misc_register(&miscdev[i]); 494 if (ret != 0) 495 break; 496 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor)); 497 } 498 499 KUNIT_EXPECT_EQ(test, ret, 0); 500 501 miscstat.minor = miscdev_test_ranges[0].minor; 502 ret = misc_register(&miscstat); 503 KUNIT_EXPECT_EQ(test, ret, 0); 504 KUNIT_EXPECT_EQ(test, miscstat.minor, miscdev_test_ranges[0].minor); 505 if (ret == 0) 506 misc_deregister(&miscstat); 507 508 for (i--; i >= 0; i--) { 509 miscdev_test_can_open(test, &miscdev[i]); 510 misc_deregister(&miscdev[i]); 511 kfree_const(miscdev[i].name); 512 } 513 } 514 515 static void __init miscdev_test_conflict(struct kunit *test) 516 { 517 int ret; 518 struct miscdevice miscdyn = { 519 .name = "miscdyn", 520 .minor = MISC_DYNAMIC_MINOR, 521 .fops = &miscdev_test_fops, 522 }; 523 struct miscdevice miscstat = { 524 .name = "miscstat", 525 .fops = &miscdev_test_fops, 526 }; 527 528 ret = misc_register(&miscdyn); 529 KUNIT_ASSERT_EQ(test, ret, 0); 530 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor)); 531 532 /* 533 * Try to register a static minor with the same minor as the 534 * dynamic one. 535 */ 536 miscstat.minor = miscdyn.minor; 537 ret = misc_register(&miscstat); 538 KUNIT_EXPECT_EQ(test, ret, -EINVAL); 539 if (ret == 0) 540 misc_deregister(&miscstat); 541 542 miscdev_test_can_open(test, &miscdyn); 543 544 misc_deregister(&miscdyn); 545 } 546 547 static void __init miscdev_test_conflict_reverse(struct kunit *test) 548 { 549 int ret; 550 struct miscdevice miscdyn = { 551 .name = "miscdyn", 552 .minor = MISC_DYNAMIC_MINOR, 553 .fops = &miscdev_test_fops, 554 }; 555 struct miscdevice miscstat = { 556 .name = "miscstat", 557 .fops = &miscdev_test_fops, 558 }; 559 560 /* 561 * Find the first available dynamic minor to use it as a static 562 * minor later on. 563 */ 564 ret = misc_register(&miscdyn); 565 KUNIT_ASSERT_EQ(test, ret, 0); 566 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor)); 567 miscstat.minor = miscdyn.minor; 568 misc_deregister(&miscdyn); 569 570 ret = misc_register(&miscstat); 571 KUNIT_EXPECT_EQ(test, ret, -EINVAL); 572 if (ret == 0) 573 misc_deregister(&miscstat); 574 575 /* 576 * Try to register a dynamic minor after registering a static minor 577 * within the dynamic range. It should work but get a different 578 * minor. 579 */ 580 miscdyn.minor = MISC_DYNAMIC_MINOR; 581 ret = misc_register(&miscdyn); 582 KUNIT_EXPECT_EQ(test, ret, 0); 583 KUNIT_EXPECT_EQ(test, miscdyn.minor, miscstat.minor); 584 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor)); 585 if (ret == 0) 586 misc_deregister(&miscdyn); 587 } 588 589 /* Take minor(> MISC_DYNAMIC_MINOR) as invalid when register miscdevice */ 590 static void miscdev_test_invalid_input(struct kunit *test) 591 { 592 struct miscdevice misc_test = { 593 .minor = MISC_DYNAMIC_MINOR + 1, 594 .name = "misc_test", 595 .fops = &miscdev_test_fops, 596 }; 597 int ret; 598 599 ret = misc_register(&misc_test); 600 KUNIT_EXPECT_EQ(test, ret, -EINVAL); 601 if (ret == 0) 602 misc_deregister(&misc_test); 603 } 604 605 /* 606 * Verify if @miscdyn_a can still be registered successfully without 607 * reinitialization even if its minor ever owned was requested by 608 * another miscdevice such as @miscdyn_b. 609 */ 610 static void miscdev_test_dynamic_reentry(struct kunit *test) 611 { 612 struct miscdevice miscdyn_a = { 613 .name = "miscdyn_a", 614 .minor = MISC_DYNAMIC_MINOR, 615 .fops = &miscdev_test_fops, 616 }; 617 struct miscdevice miscdyn_b = { 618 .name = "miscdyn_b", 619 .minor = MISC_DYNAMIC_MINOR, 620 .fops = &miscdev_test_fops, 621 }; 622 int ret, minor_a; 623 624 ret = misc_register(&miscdyn_a); 625 KUNIT_ASSERT_EQ(test, ret, 0); 626 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn_a.minor)); 627 minor_a = miscdyn_a.minor; 628 if (ret != 0) 629 return; 630 misc_deregister(&miscdyn_a); 631 632 ret = misc_register(&miscdyn_b); 633 KUNIT_ASSERT_EQ(test, ret, 0); 634 KUNIT_EXPECT_EQ(test, miscdyn_b.minor, minor_a); 635 if (ret != 0) 636 return; 637 638 ret = misc_register(&miscdyn_a); 639 KUNIT_ASSERT_EQ(test, ret, 0); 640 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn_a.minor)); 641 KUNIT_EXPECT_NE(test, miscdyn_a.minor, miscdyn_b.minor); 642 if (ret == 0) 643 misc_deregister(&miscdyn_a); 644 645 misc_deregister(&miscdyn_b); 646 } 647 648 static struct kunit_case test_cases[] = { 649 KUNIT_CASE(kunit_static_minor), 650 KUNIT_CASE(kunit_misc_dynamic_minor), 651 KUNIT_CASE(miscdev_test_invalid_input), 652 KUNIT_CASE_PARAM(miscdev_test_twice, miscdev_gen_params), 653 KUNIT_CASE_PARAM(miscdev_test_duplicate_minor, miscdev_gen_params), 654 KUNIT_CASE(miscdev_test_duplicate_name), 655 KUNIT_CASE(miscdev_test_duplicate_name_leak), 656 KUNIT_CASE_PARAM(miscdev_test_duplicate_error, miscdev_gen_params), 657 KUNIT_CASE(miscdev_test_dynamic_reentry), 658 {} 659 }; 660 661 static struct kunit_suite test_suite = { 662 .name = "miscdev", 663 .suite_init = miscdev_find_minors, 664 .test_cases = test_cases, 665 }; 666 kunit_test_suite(test_suite); 667 668 static struct kunit_case __refdata test_init_cases[] = { 669 KUNIT_CASE_PARAM(miscdev_test_static_basic, miscdev_gen_params), 670 KUNIT_CASE(miscdev_test_dynamic_basic), 671 KUNIT_CASE(miscdev_test_dynamic_only_range), 672 KUNIT_CASE(miscdev_test_collision), 673 KUNIT_CASE(miscdev_test_collision_reverse), 674 KUNIT_CASE(miscdev_test_conflict), 675 KUNIT_CASE(miscdev_test_conflict_reverse), 676 {} 677 }; 678 679 static struct kunit_suite test_init_suite = { 680 .name = "miscdev_init", 681 .suite_init = miscdev_find_minors, 682 .test_cases = test_init_cases, 683 }; 684 kunit_test_init_section_suite(test_init_suite); 685 686 MODULE_LICENSE("GPL"); 687 MODULE_AUTHOR("Vimal Agrawal"); 688 MODULE_AUTHOR("Thadeu Lima de Souza Cascardo <cascardo@igalia.com>"); 689 MODULE_DESCRIPTION("Test module for misc character devices"); 690