0001
0002
0003
0004
0005
0006 #include <kunit/test.h>
0007 #include <linux/sysctl.h>
0008
0009 #define KUNIT_PROC_READ 0
0010 #define KUNIT_PROC_WRITE 1
0011
0012 static int i_zero;
0013 static int i_one_hundred = 100;
0014
0015
0016
0017
0018
0019 static void sysctl_test_api_dointvec_null_tbl_data(struct kunit *test)
0020 {
0021 struct ctl_table null_data_table = {
0022 .procname = "foo",
0023
0024
0025
0026
0027
0028 .data = NULL,
0029 .maxlen = sizeof(int),
0030 .mode = 0644,
0031 .proc_handler = proc_dointvec,
0032 .extra1 = &i_zero,
0033 .extra2 = &i_one_hundred,
0034 };
0035
0036
0037
0038
0039 void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
0040 GFP_USER);
0041 size_t len;
0042 loff_t pos;
0043
0044
0045
0046
0047
0048 len = 1234;
0049 KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&null_data_table,
0050 KUNIT_PROC_READ, buffer, &len,
0051 &pos));
0052 KUNIT_EXPECT_EQ(test, 0, len);
0053
0054
0055
0056
0057 len = 1234;
0058 KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&null_data_table,
0059 KUNIT_PROC_WRITE, buffer, &len,
0060 &pos));
0061 KUNIT_EXPECT_EQ(test, 0, len);
0062 }
0063
0064
0065
0066
0067
0068
0069 static void sysctl_test_api_dointvec_table_maxlen_unset(struct kunit *test)
0070 {
0071 int data = 0;
0072 struct ctl_table data_maxlen_unset_table = {
0073 .procname = "foo",
0074 .data = &data,
0075
0076
0077
0078
0079 .maxlen = 0,
0080 .mode = 0644,
0081 .proc_handler = proc_dointvec,
0082 .extra1 = &i_zero,
0083 .extra2 = &i_one_hundred,
0084 };
0085 void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
0086 GFP_USER);
0087 size_t len;
0088 loff_t pos;
0089
0090
0091
0092
0093
0094 len = 1234;
0095 KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&data_maxlen_unset_table,
0096 KUNIT_PROC_READ, buffer, &len,
0097 &pos));
0098 KUNIT_EXPECT_EQ(test, 0, len);
0099
0100
0101
0102
0103 len = 1234;
0104 KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&data_maxlen_unset_table,
0105 KUNIT_PROC_WRITE, buffer, &len,
0106 &pos));
0107 KUNIT_EXPECT_EQ(test, 0, len);
0108 }
0109
0110
0111
0112
0113
0114
0115 static void sysctl_test_api_dointvec_table_len_is_zero(struct kunit *test)
0116 {
0117 int data = 0;
0118
0119 struct ctl_table table = {
0120 .procname = "foo",
0121 .data = &data,
0122 .maxlen = sizeof(int),
0123 .mode = 0644,
0124 .proc_handler = proc_dointvec,
0125 .extra1 = &i_zero,
0126 .extra2 = &i_one_hundred,
0127 };
0128 void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
0129 GFP_USER);
0130
0131
0132
0133 size_t len = 0;
0134 loff_t pos;
0135
0136 KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_READ, buffer,
0137 &len, &pos));
0138 KUNIT_EXPECT_EQ(test, 0, len);
0139
0140 KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_WRITE, buffer,
0141 &len, &pos));
0142 KUNIT_EXPECT_EQ(test, 0, len);
0143 }
0144
0145
0146
0147
0148 static void sysctl_test_api_dointvec_table_read_but_position_set(
0149 struct kunit *test)
0150 {
0151 int data = 0;
0152
0153 struct ctl_table table = {
0154 .procname = "foo",
0155 .data = &data,
0156 .maxlen = sizeof(int),
0157 .mode = 0644,
0158 .proc_handler = proc_dointvec,
0159 .extra1 = &i_zero,
0160 .extra2 = &i_one_hundred,
0161 };
0162 void __user *buffer = (void __user *)kunit_kzalloc(test, sizeof(int),
0163 GFP_USER);
0164
0165
0166
0167
0168 size_t len = 1234;
0169
0170
0171
0172
0173 loff_t pos = 1;
0174
0175 KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_READ, buffer,
0176 &len, &pos));
0177 KUNIT_EXPECT_EQ(test, 0, len);
0178 }
0179
0180
0181
0182
0183
0184 static void sysctl_test_dointvec_read_happy_single_positive(struct kunit *test)
0185 {
0186 int data = 0;
0187
0188 struct ctl_table table = {
0189 .procname = "foo",
0190 .data = &data,
0191 .maxlen = sizeof(int),
0192 .mode = 0644,
0193 .proc_handler = proc_dointvec,
0194 .extra1 = &i_zero,
0195 .extra2 = &i_one_hundred,
0196 };
0197 size_t len = 4;
0198 loff_t pos = 0;
0199 char *buffer = kunit_kzalloc(test, len, GFP_USER);
0200 char __user *user_buffer = (char __user *)buffer;
0201
0202 *((int *)table.data) = 13;
0203
0204 KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_READ,
0205 user_buffer, &len, &pos));
0206 KUNIT_ASSERT_EQ(test, 3, len);
0207 buffer[len] = '\0';
0208
0209 KUNIT_EXPECT_STREQ(test, "13\n", buffer);
0210 }
0211
0212
0213
0214
0215 static void sysctl_test_dointvec_read_happy_single_negative(struct kunit *test)
0216 {
0217 int data = 0;
0218
0219 struct ctl_table table = {
0220 .procname = "foo",
0221 .data = &data,
0222 .maxlen = sizeof(int),
0223 .mode = 0644,
0224 .proc_handler = proc_dointvec,
0225 .extra1 = &i_zero,
0226 .extra2 = &i_one_hundred,
0227 };
0228 size_t len = 5;
0229 loff_t pos = 0;
0230 char *buffer = kunit_kzalloc(test, len, GFP_USER);
0231 char __user *user_buffer = (char __user *)buffer;
0232 *((int *)table.data) = -16;
0233
0234 KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_READ,
0235 user_buffer, &len, &pos));
0236 KUNIT_ASSERT_EQ(test, 4, len);
0237 buffer[len] = '\0';
0238 KUNIT_EXPECT_STREQ(test, "-16\n", buffer);
0239 }
0240
0241
0242
0243
0244 static void sysctl_test_dointvec_write_happy_single_positive(struct kunit *test)
0245 {
0246 int data = 0;
0247
0248 struct ctl_table table = {
0249 .procname = "foo",
0250 .data = &data,
0251 .maxlen = sizeof(int),
0252 .mode = 0644,
0253 .proc_handler = proc_dointvec,
0254 .extra1 = &i_zero,
0255 .extra2 = &i_one_hundred,
0256 };
0257 char input[] = "9";
0258 size_t len = sizeof(input) - 1;
0259 loff_t pos = 0;
0260 char *buffer = kunit_kzalloc(test, len, GFP_USER);
0261 char __user *user_buffer = (char __user *)buffer;
0262
0263 memcpy(buffer, input, len);
0264
0265 KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_WRITE,
0266 user_buffer, &len, &pos));
0267 KUNIT_EXPECT_EQ(test, sizeof(input) - 1, len);
0268 KUNIT_EXPECT_EQ(test, sizeof(input) - 1, pos);
0269 KUNIT_EXPECT_EQ(test, 9, *((int *)table.data));
0270 }
0271
0272
0273
0274
0275 static void sysctl_test_dointvec_write_happy_single_negative(struct kunit *test)
0276 {
0277 int data = 0;
0278 struct ctl_table table = {
0279 .procname = "foo",
0280 .data = &data,
0281 .maxlen = sizeof(int),
0282 .mode = 0644,
0283 .proc_handler = proc_dointvec,
0284 .extra1 = &i_zero,
0285 .extra2 = &i_one_hundred,
0286 };
0287 char input[] = "-9";
0288 size_t len = sizeof(input) - 1;
0289 loff_t pos = 0;
0290 char *buffer = kunit_kzalloc(test, len, GFP_USER);
0291 char __user *user_buffer = (char __user *)buffer;
0292
0293 memcpy(buffer, input, len);
0294
0295 KUNIT_EXPECT_EQ(test, 0, proc_dointvec(&table, KUNIT_PROC_WRITE,
0296 user_buffer, &len, &pos));
0297 KUNIT_EXPECT_EQ(test, sizeof(input) - 1, len);
0298 KUNIT_EXPECT_EQ(test, sizeof(input) - 1, pos);
0299 KUNIT_EXPECT_EQ(test, -9, *((int *)table.data));
0300 }
0301
0302
0303
0304
0305
0306 static void sysctl_test_api_dointvec_write_single_less_int_min(
0307 struct kunit *test)
0308 {
0309 int data = 0;
0310 struct ctl_table table = {
0311 .procname = "foo",
0312 .data = &data,
0313 .maxlen = sizeof(int),
0314 .mode = 0644,
0315 .proc_handler = proc_dointvec,
0316 .extra1 = &i_zero,
0317 .extra2 = &i_one_hundred,
0318 };
0319 size_t max_len = 32, len = max_len;
0320 loff_t pos = 0;
0321 char *buffer = kunit_kzalloc(test, max_len, GFP_USER);
0322 char __user *user_buffer = (char __user *)buffer;
0323 unsigned long abs_of_less_than_min = (unsigned long)INT_MAX
0324 - (INT_MAX + INT_MIN) + 1;
0325
0326
0327
0328
0329
0330 KUNIT_ASSERT_LT(test,
0331 (size_t)snprintf(buffer, max_len, "-%lu",
0332 abs_of_less_than_min),
0333 max_len);
0334
0335 KUNIT_EXPECT_EQ(test, -EINVAL, proc_dointvec(&table, KUNIT_PROC_WRITE,
0336 user_buffer, &len, &pos));
0337 KUNIT_EXPECT_EQ(test, max_len, len);
0338 KUNIT_EXPECT_EQ(test, 0, *((int *)table.data));
0339 }
0340
0341
0342
0343
0344 static void sysctl_test_api_dointvec_write_single_greater_int_max(
0345 struct kunit *test)
0346 {
0347 int data = 0;
0348 struct ctl_table table = {
0349 .procname = "foo",
0350 .data = &data,
0351 .maxlen = sizeof(int),
0352 .mode = 0644,
0353 .proc_handler = proc_dointvec,
0354 .extra1 = &i_zero,
0355 .extra2 = &i_one_hundred,
0356 };
0357 size_t max_len = 32, len = max_len;
0358 loff_t pos = 0;
0359 char *buffer = kunit_kzalloc(test, max_len, GFP_USER);
0360 char __user *user_buffer = (char __user *)buffer;
0361 unsigned long greater_than_max = (unsigned long)INT_MAX + 1;
0362
0363 KUNIT_ASSERT_GT(test, greater_than_max, (unsigned long)INT_MAX);
0364 KUNIT_ASSERT_LT(test, (size_t)snprintf(buffer, max_len, "%lu",
0365 greater_than_max),
0366 max_len);
0367 KUNIT_EXPECT_EQ(test, -EINVAL, proc_dointvec(&table, KUNIT_PROC_WRITE,
0368 user_buffer, &len, &pos));
0369 KUNIT_ASSERT_EQ(test, max_len, len);
0370 KUNIT_EXPECT_EQ(test, 0, *((int *)table.data));
0371 }
0372
0373 static struct kunit_case sysctl_test_cases[] = {
0374 KUNIT_CASE(sysctl_test_api_dointvec_null_tbl_data),
0375 KUNIT_CASE(sysctl_test_api_dointvec_table_maxlen_unset),
0376 KUNIT_CASE(sysctl_test_api_dointvec_table_len_is_zero),
0377 KUNIT_CASE(sysctl_test_api_dointvec_table_read_but_position_set),
0378 KUNIT_CASE(sysctl_test_dointvec_read_happy_single_positive),
0379 KUNIT_CASE(sysctl_test_dointvec_read_happy_single_negative),
0380 KUNIT_CASE(sysctl_test_dointvec_write_happy_single_positive),
0381 KUNIT_CASE(sysctl_test_dointvec_write_happy_single_negative),
0382 KUNIT_CASE(sysctl_test_api_dointvec_write_single_less_int_min),
0383 KUNIT_CASE(sysctl_test_api_dointvec_write_single_greater_int_max),
0384 {}
0385 };
0386
0387 static struct kunit_suite sysctl_test_suite = {
0388 .name = "sysctl_test",
0389 .test_cases = sysctl_test_cases,
0390 };
0391
0392 kunit_test_suites(&sysctl_test_suite);
0393
0394 MODULE_LICENSE("GPL v2");