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