test_sysctl.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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. * This module provides an interface to the proc sysctl interfaces. This
  9. * driver requires CONFIG_PROC_SYSCTL. It will not normally be loaded by the
  10. * system unless explicitly requested by name. You can also build this driver
  11. * into your kernel.
  12. */
  13. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  14. #include <linux/init.h>
  15. #include <linux/list.h>
  16. #include <linux/module.h>
  17. #include <linux/printk.h>
  18. #include <linux/fs.h>
  19. #include <linux/miscdevice.h>
  20. #include <linux/slab.h>
  21. #include <linux/uaccess.h>
  22. #include <linux/async.h>
  23. #include <linux/delay.h>
  24. #include <linux/vmalloc.h>
  25. static int i_zero;
  26. static int i_one_hundred = 100;
  27. static int match_int_ok = 1;
  28. enum {
  29. TEST_H_SETUP_NODE,
  30. TEST_H_MNT,
  31. TEST_H_MNTERROR,
  32. TEST_H_EMPTY_ADD,
  33. TEST_H_EMPTY,
  34. TEST_H_U8,
  35. TEST_H_SIZE /* Always at the end */
  36. };
  37. static struct ctl_table_header *ctl_headers[TEST_H_SIZE] = {};
  38. struct test_sysctl_data {
  39. int int_0001;
  40. int int_0002;
  41. int int_0003[4];
  42. int boot_int;
  43. unsigned int uint_0001;
  44. char string_0001[65];
  45. #define SYSCTL_TEST_BITMAP_SIZE 65536
  46. unsigned long *bitmap_0001;
  47. };
  48. static struct test_sysctl_data test_data = {
  49. .int_0001 = 60,
  50. .int_0002 = 1,
  51. .int_0003[0] = 0,
  52. .int_0003[1] = 1,
  53. .int_0003[2] = 2,
  54. .int_0003[3] = 3,
  55. .boot_int = 0,
  56. .uint_0001 = 314,
  57. .string_0001 = "(none)",
  58. };
  59. /* These are all under /proc/sys/debug/test_sysctl/ */
  60. static const struct ctl_table test_table[] = {
  61. {
  62. .procname = "int_0001",
  63. .data = &test_data.int_0001,
  64. .maxlen = sizeof(int),
  65. .mode = 0644,
  66. .proc_handler = proc_dointvec_minmax,
  67. .extra1 = &i_zero,
  68. .extra2 = &i_one_hundred,
  69. },
  70. {
  71. .procname = "int_0002",
  72. .data = &test_data.int_0002,
  73. .maxlen = sizeof(int),
  74. .mode = 0644,
  75. .proc_handler = proc_dointvec,
  76. },
  77. {
  78. .procname = "int_0003",
  79. .data = &test_data.int_0003,
  80. .maxlen = sizeof(test_data.int_0003),
  81. .mode = 0644,
  82. .proc_handler = proc_dointvec,
  83. },
  84. {
  85. .procname = "match_int",
  86. .data = &match_int_ok,
  87. .maxlen = sizeof(match_int_ok),
  88. .mode = 0444,
  89. .proc_handler = proc_dointvec,
  90. },
  91. {
  92. .procname = "boot_int",
  93. .data = &test_data.boot_int,
  94. .maxlen = sizeof(test_data.boot_int),
  95. .mode = 0644,
  96. .proc_handler = proc_dointvec,
  97. .extra1 = SYSCTL_ZERO,
  98. .extra2 = SYSCTL_ONE,
  99. },
  100. {
  101. .procname = "uint_0001",
  102. .data = &test_data.uint_0001,
  103. .maxlen = sizeof(unsigned int),
  104. .mode = 0644,
  105. .proc_handler = proc_douintvec,
  106. },
  107. {
  108. .procname = "string_0001",
  109. .data = &test_data.string_0001,
  110. .maxlen = sizeof(test_data.string_0001),
  111. .mode = 0644,
  112. .proc_handler = proc_dostring,
  113. },
  114. {
  115. .procname = "bitmap_0001",
  116. .data = &test_data.bitmap_0001,
  117. .maxlen = SYSCTL_TEST_BITMAP_SIZE,
  118. .mode = 0644,
  119. .proc_handler = proc_do_large_bitmap,
  120. },
  121. };
  122. static void test_sysctl_calc_match_int_ok(void)
  123. {
  124. int i;
  125. struct {
  126. int defined;
  127. int wanted;
  128. } match_int[] = {
  129. {.defined = *(int *)SYSCTL_ZERO, .wanted = 0},
  130. {.defined = *(int *)SYSCTL_ONE, .wanted = 1},
  131. {.defined = *(int *)SYSCTL_TWO, .wanted = 2},
  132. {.defined = *(int *)SYSCTL_THREE, .wanted = 3},
  133. {.defined = *(int *)SYSCTL_FOUR, .wanted = 4},
  134. {.defined = *(int *)SYSCTL_ONE_HUNDRED, .wanted = 100},
  135. {.defined = *(int *)SYSCTL_TWO_HUNDRED, .wanted = 200},
  136. {.defined = *(int *)SYSCTL_ONE_THOUSAND, .wanted = 1000},
  137. {.defined = *(int *)SYSCTL_THREE_THOUSAND, .wanted = 3000},
  138. {.defined = *(int *)SYSCTL_INT_MAX, .wanted = INT_MAX},
  139. {.defined = *(int *)SYSCTL_MAXOLDUID, .wanted = 65535},
  140. {.defined = *(int *)SYSCTL_NEG_ONE, .wanted = -1},
  141. };
  142. for (i = 0; i < ARRAY_SIZE(match_int); i++)
  143. if (match_int[i].defined != match_int[i].wanted)
  144. match_int_ok = 0;
  145. }
  146. static int test_sysctl_setup_node_tests(void)
  147. {
  148. test_sysctl_calc_match_int_ok();
  149. test_data.bitmap_0001 = kzalloc(SYSCTL_TEST_BITMAP_SIZE/8, GFP_KERNEL);
  150. if (!test_data.bitmap_0001)
  151. return -ENOMEM;
  152. ctl_headers[TEST_H_SETUP_NODE] = register_sysctl("debug/test_sysctl", test_table);
  153. if (!ctl_headers[TEST_H_SETUP_NODE]) {
  154. kfree(test_data.bitmap_0001);
  155. return -ENOMEM;
  156. }
  157. return 0;
  158. }
  159. /* Used to test that unregister actually removes the directory */
  160. static const struct ctl_table test_table_unregister[] = {
  161. {
  162. .procname = "unregister_error",
  163. .data = &test_data.int_0001,
  164. .maxlen = sizeof(int),
  165. .mode = 0644,
  166. .proc_handler = proc_dointvec_minmax,
  167. },
  168. };
  169. static int test_sysctl_run_unregister_nested(void)
  170. {
  171. struct ctl_table_header *unregister;
  172. unregister = register_sysctl("debug/test_sysctl/unregister_error",
  173. test_table_unregister);
  174. if (!unregister)
  175. return -ENOMEM;
  176. unregister_sysctl_table(unregister);
  177. return 0;
  178. }
  179. static int test_sysctl_run_register_mount_point(void)
  180. {
  181. ctl_headers[TEST_H_MNT]
  182. = register_sysctl_mount_point("debug/test_sysctl/mnt");
  183. if (!ctl_headers[TEST_H_MNT])
  184. return -ENOMEM;
  185. ctl_headers[TEST_H_MNTERROR]
  186. = register_sysctl("debug/test_sysctl/mnt/mnt_error",
  187. test_table_unregister);
  188. /*
  189. * Don't check the result.:
  190. * If it fails (expected behavior), return 0.
  191. * If successful (missbehavior of register mount point), we want to see
  192. * mnt_error when we run the sysctl test script
  193. */
  194. return 0;
  195. }
  196. static const struct ctl_table test_table_empty[] = { };
  197. static int test_sysctl_run_register_empty(void)
  198. {
  199. /* Tets that an empty dir can be created */
  200. ctl_headers[TEST_H_EMPTY_ADD]
  201. = register_sysctl("debug/test_sysctl/empty_add", test_table_empty);
  202. if (!ctl_headers[TEST_H_EMPTY_ADD])
  203. return -ENOMEM;
  204. /* Test that register on top of an empty dir works */
  205. ctl_headers[TEST_H_EMPTY]
  206. = register_sysctl("debug/test_sysctl/empty_add/empty", test_table_empty);
  207. if (!ctl_headers[TEST_H_EMPTY])
  208. return -ENOMEM;
  209. return 0;
  210. }
  211. static const struct ctl_table table_u8_over[] = {
  212. {
  213. .procname = "u8_over",
  214. .data = &test_data.uint_0001,
  215. .maxlen = sizeof(u8),
  216. .mode = 0644,
  217. .proc_handler = proc_dou8vec_minmax,
  218. .extra1 = SYSCTL_FOUR,
  219. .extra2 = SYSCTL_ONE_THOUSAND,
  220. },
  221. };
  222. static const struct ctl_table table_u8_under[] = {
  223. {
  224. .procname = "u8_under",
  225. .data = &test_data.uint_0001,
  226. .maxlen = sizeof(u8),
  227. .mode = 0644,
  228. .proc_handler = proc_dou8vec_minmax,
  229. .extra1 = SYSCTL_NEG_ONE,
  230. .extra2 = SYSCTL_ONE_HUNDRED,
  231. },
  232. };
  233. static const struct ctl_table table_u8_valid[] = {
  234. {
  235. .procname = "u8_valid",
  236. .data = &test_data.uint_0001,
  237. .maxlen = sizeof(u8),
  238. .mode = 0644,
  239. .proc_handler = proc_dou8vec_minmax,
  240. .extra1 = SYSCTL_ZERO,
  241. .extra2 = SYSCTL_TWO_HUNDRED,
  242. },
  243. };
  244. static int test_sysctl_register_u8_extra(void)
  245. {
  246. /* should fail because it's over */
  247. ctl_headers[TEST_H_U8]
  248. = register_sysctl("debug/test_sysctl", table_u8_over);
  249. if (ctl_headers[TEST_H_U8])
  250. return -ENOMEM;
  251. /* should fail because it's under */
  252. ctl_headers[TEST_H_U8]
  253. = register_sysctl("debug/test_sysctl", table_u8_under);
  254. if (ctl_headers[TEST_H_U8])
  255. return -ENOMEM;
  256. /* should not fail because it's valid */
  257. ctl_headers[TEST_H_U8]
  258. = register_sysctl("debug/test_sysctl", table_u8_valid);
  259. if (!ctl_headers[TEST_H_U8])
  260. return -ENOMEM;
  261. return 0;
  262. }
  263. static int __init test_sysctl_init(void)
  264. {
  265. int err = 0;
  266. int (*func_array[])(void) = {
  267. test_sysctl_setup_node_tests,
  268. test_sysctl_run_unregister_nested,
  269. test_sysctl_run_register_mount_point,
  270. test_sysctl_run_register_empty,
  271. test_sysctl_register_u8_extra
  272. };
  273. for (int i = 0; !err && i < ARRAY_SIZE(func_array); i++)
  274. err = func_array[i]();
  275. return err;
  276. }
  277. module_init(test_sysctl_init);
  278. static void __exit test_sysctl_exit(void)
  279. {
  280. kfree(test_data.bitmap_0001);
  281. for (int i = 0; i < TEST_H_SIZE; i++) {
  282. if (ctl_headers[i])
  283. unregister_sysctl_table(ctl_headers[i]);
  284. }
  285. }
  286. module_exit(test_sysctl_exit);
  287. MODULE_AUTHOR("Luis R. Rodriguez <mcgrof@kernel.org>");
  288. MODULE_DESCRIPTION("proc sysctl test driver");
  289. MODULE_LICENSE("GPL");