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