0001
0002
0003
0004 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0005
0006 #include <linux/init.h>
0007 #include <linux/kernel.h>
0008 #include <linux/slab.h>
0009 #include <linux/module.h>
0010 #include <linux/random.h>
0011 #include <linux/string.h>
0012 #include <linux/string_helpers.h>
0013
0014 static __init bool test_string_check_buf(const char *name, unsigned int flags,
0015 char *in, size_t p,
0016 char *out_real, size_t q_real,
0017 char *out_test, size_t q_test)
0018 {
0019 if (q_real == q_test && !memcmp(out_test, out_real, q_test))
0020 return true;
0021
0022 pr_warn("Test '%s' failed: flags = %#x\n", name, flags);
0023
0024 print_hex_dump(KERN_WARNING, "Input: ", DUMP_PREFIX_NONE, 16, 1,
0025 in, p, true);
0026 print_hex_dump(KERN_WARNING, "Expected: ", DUMP_PREFIX_NONE, 16, 1,
0027 out_test, q_test, true);
0028 print_hex_dump(KERN_WARNING, "Got: ", DUMP_PREFIX_NONE, 16, 1,
0029 out_real, q_real, true);
0030
0031 return false;
0032 }
0033
0034 struct test_string {
0035 const char *in;
0036 const char *out;
0037 unsigned int flags;
0038 };
0039
0040 static const struct test_string strings[] __initconst = {
0041 {
0042 .in = "\\f\\ \\n\\r\\t\\v",
0043 .out = "\f\\ \n\r\t\v",
0044 .flags = UNESCAPE_SPACE,
0045 },
0046 {
0047 .in = "\\40\\1\\387\\0064\\05\\040\\8a\\110\\777",
0048 .out = " \001\00387\0064\005 \\8aH?7",
0049 .flags = UNESCAPE_OCTAL,
0050 },
0051 {
0052 .in = "\\xv\\xa\\x2c\\xD\\x6f2",
0053 .out = "\\xv\n,\ro2",
0054 .flags = UNESCAPE_HEX,
0055 },
0056 {
0057 .in = "\\h\\\\\\\"\\a\\e\\",
0058 .out = "\\h\\\"\a\e\\",
0059 .flags = UNESCAPE_SPECIAL,
0060 },
0061 };
0062
0063 static void __init test_string_unescape(const char *name, unsigned int flags,
0064 bool inplace)
0065 {
0066 int q_real = 256;
0067 char *in = kmalloc(q_real, GFP_KERNEL);
0068 char *out_test = kmalloc(q_real, GFP_KERNEL);
0069 char *out_real = kmalloc(q_real, GFP_KERNEL);
0070 int i, p = 0, q_test = 0;
0071
0072 if (!in || !out_test || !out_real)
0073 goto out;
0074
0075 for (i = 0; i < ARRAY_SIZE(strings); i++) {
0076 const char *s = strings[i].in;
0077 int len = strlen(strings[i].in);
0078
0079
0080 memcpy(&in[p], s, len);
0081 p += len;
0082
0083
0084 if (flags & strings[i].flags) {
0085 s = strings[i].out;
0086 len = strlen(strings[i].out);
0087 }
0088 memcpy(&out_test[q_test], s, len);
0089 q_test += len;
0090 }
0091 in[p++] = '\0';
0092
0093
0094 if (inplace) {
0095 memcpy(out_real, in, p);
0096 if (flags == UNESCAPE_ANY)
0097 q_real = string_unescape_any_inplace(out_real);
0098 else
0099 q_real = string_unescape_inplace(out_real, flags);
0100 } else if (flags == UNESCAPE_ANY) {
0101 q_real = string_unescape_any(in, out_real, q_real);
0102 } else {
0103 q_real = string_unescape(in, out_real, q_real, flags);
0104 }
0105
0106 test_string_check_buf(name, flags, in, p - 1, out_real, q_real,
0107 out_test, q_test);
0108 out:
0109 kfree(out_real);
0110 kfree(out_test);
0111 kfree(in);
0112 }
0113
0114 struct test_string_1 {
0115 const char *out;
0116 unsigned int flags;
0117 };
0118
0119 #define TEST_STRING_2_MAX_S1 32
0120 struct test_string_2 {
0121 const char *in;
0122 struct test_string_1 s1[TEST_STRING_2_MAX_S1];
0123 };
0124
0125 #define TEST_STRING_2_DICT_0 NULL
0126 static const struct test_string_2 escape0[] __initconst = {{
0127 .in = "\f\\ \n\r\t\v",
0128 .s1 = {{
0129 .out = "\\f\\ \\n\\r\\t\\v",
0130 .flags = ESCAPE_SPACE,
0131 },{
0132 .out = "\\f\\134\\040\\n\\r\\t\\v",
0133 .flags = ESCAPE_SPACE | ESCAPE_OCTAL,
0134 },{
0135 .out = "\\f\\x5c\\x20\\n\\r\\t\\v",
0136 .flags = ESCAPE_SPACE | ESCAPE_HEX,
0137 },{
0138
0139 }}
0140 },{
0141 .in = "\\h\\\"\a\e\\",
0142 .s1 = {{
0143 .out = "\\\\h\\\\\\\"\\a\\e\\\\",
0144 .flags = ESCAPE_SPECIAL,
0145 },{
0146 .out = "\\\\\\150\\\\\\\"\\a\\e\\\\",
0147 .flags = ESCAPE_SPECIAL | ESCAPE_OCTAL,
0148 },{
0149 .out = "\\\\\\x68\\\\\\\"\\a\\e\\\\",
0150 .flags = ESCAPE_SPECIAL | ESCAPE_HEX,
0151 },{
0152
0153 }}
0154 },{
0155 .in = "\eb \\C\007\"\x90\r]",
0156 .s1 = {{
0157 .out = "\eb \\C\007\"\x90\\r]",
0158 .flags = ESCAPE_SPACE,
0159 },{
0160 .out = "\\eb \\\\C\\a\\\"\x90\r]",
0161 .flags = ESCAPE_SPECIAL,
0162 },{
0163 .out = "\\eb \\\\C\\a\\\"\x90\\r]",
0164 .flags = ESCAPE_SPACE | ESCAPE_SPECIAL,
0165 },{
0166 .out = "\\033\\142\\040\\134\\103\\007\\042\\220\\015\\135",
0167 .flags = ESCAPE_OCTAL,
0168 },{
0169 .out = "\\033\\142\\040\\134\\103\\007\\042\\220\\r\\135",
0170 .flags = ESCAPE_SPACE | ESCAPE_OCTAL,
0171 },{
0172 .out = "\\e\\142\\040\\\\\\103\\a\\\"\\220\\015\\135",
0173 .flags = ESCAPE_SPECIAL | ESCAPE_OCTAL,
0174 },{
0175 .out = "\\e\\142\\040\\\\\\103\\a\\\"\\220\\r\\135",
0176 .flags = ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_OCTAL,
0177 },{
0178 .out = "\eb \\C\007\"\x90\r]",
0179 .flags = ESCAPE_NP,
0180 },{
0181 .out = "\eb \\C\007\"\x90\\r]",
0182 .flags = ESCAPE_SPACE | ESCAPE_NP,
0183 },{
0184 .out = "\\eb \\C\\a\"\x90\r]",
0185 .flags = ESCAPE_SPECIAL | ESCAPE_NP,
0186 },{
0187 .out = "\\eb \\C\\a\"\x90\\r]",
0188 .flags = ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_NP,
0189 },{
0190 .out = "\\033b \\C\\007\"\\220\\015]",
0191 .flags = ESCAPE_OCTAL | ESCAPE_NP,
0192 },{
0193 .out = "\\033b \\C\\007\"\\220\\r]",
0194 .flags = ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_NP,
0195 },{
0196 .out = "\\eb \\C\\a\"\\220\\r]",
0197 .flags = ESCAPE_SPECIAL | ESCAPE_SPACE | ESCAPE_OCTAL |
0198 ESCAPE_NP,
0199 },{
0200 .out = "\\x1bb \\C\\x07\"\\x90\\x0d]",
0201 .flags = ESCAPE_NP | ESCAPE_HEX,
0202 },{
0203
0204 }}
0205 },{
0206 .in = "\007 \eb\"\x90\xCF\r",
0207 .s1 = {{
0208 .out = "\007 \eb\"\\220\\317\r",
0209 .flags = ESCAPE_OCTAL | ESCAPE_NA,
0210 },{
0211 .out = "\007 \eb\"\\x90\\xcf\r",
0212 .flags = ESCAPE_HEX | ESCAPE_NA,
0213 },{
0214 .out = "\007 \eb\"\x90\xCF\r",
0215 .flags = ESCAPE_NA,
0216 },{
0217
0218 }}
0219 },{
0220
0221 }};
0222
0223 #define TEST_STRING_2_DICT_1 "b\\ \t\r\xCF"
0224 static const struct test_string_2 escape1[] __initconst = {{
0225 .in = "\f\\ \n\r\t\v",
0226 .s1 = {{
0227 .out = "\f\\134\\040\n\\015\\011\v",
0228 .flags = ESCAPE_OCTAL,
0229 },{
0230 .out = "\f\\x5c\\x20\n\\x0d\\x09\v",
0231 .flags = ESCAPE_HEX,
0232 },{
0233 .out = "\f\\134\\040\n\\015\\011\v",
0234 .flags = ESCAPE_ANY | ESCAPE_APPEND,
0235 },{
0236 .out = "\\014\\134\\040\\012\\015\\011\\013",
0237 .flags = ESCAPE_OCTAL | ESCAPE_APPEND | ESCAPE_NAP,
0238 },{
0239 .out = "\\x0c\\x5c\\x20\\x0a\\x0d\\x09\\x0b",
0240 .flags = ESCAPE_HEX | ESCAPE_APPEND | ESCAPE_NAP,
0241 },{
0242 .out = "\f\\134\\040\n\\015\\011\v",
0243 .flags = ESCAPE_OCTAL | ESCAPE_APPEND | ESCAPE_NA,
0244 },{
0245 .out = "\f\\x5c\\x20\n\\x0d\\x09\v",
0246 .flags = ESCAPE_HEX | ESCAPE_APPEND | ESCAPE_NA,
0247 },{
0248
0249 }}
0250 },{
0251 .in = "\\h\\\"\a\xCF\e\\",
0252 .s1 = {{
0253 .out = "\\134h\\134\"\a\\317\e\\134",
0254 .flags = ESCAPE_OCTAL,
0255 },{
0256 .out = "\\134h\\134\"\a\\317\e\\134",
0257 .flags = ESCAPE_ANY | ESCAPE_APPEND,
0258 },{
0259 .out = "\\134h\\134\"\\007\\317\\033\\134",
0260 .flags = ESCAPE_OCTAL | ESCAPE_APPEND | ESCAPE_NAP,
0261 },{
0262 .out = "\\134h\\134\"\a\\317\e\\134",
0263 .flags = ESCAPE_OCTAL | ESCAPE_APPEND | ESCAPE_NA,
0264 },{
0265
0266 }}
0267 },{
0268 .in = "\eb \\C\007\"\x90\r]",
0269 .s1 = {{
0270 .out = "\e\\142\\040\\134C\007\"\x90\\015]",
0271 .flags = ESCAPE_OCTAL,
0272 },{
0273
0274 }}
0275 },{
0276 .in = "\007 \eb\"\x90\xCF\r",
0277 .s1 = {{
0278 .out = "\007 \eb\"\x90\xCF\r",
0279 .flags = ESCAPE_NA,
0280 },{
0281 .out = "\007 \eb\"\x90\xCF\r",
0282 .flags = ESCAPE_SPACE | ESCAPE_NA,
0283 },{
0284 .out = "\007 \eb\"\x90\xCF\r",
0285 .flags = ESCAPE_SPECIAL | ESCAPE_NA,
0286 },{
0287 .out = "\007 \eb\"\x90\xCF\r",
0288 .flags = ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_NA,
0289 },{
0290 .out = "\007 \eb\"\x90\\317\r",
0291 .flags = ESCAPE_OCTAL | ESCAPE_NA,
0292 },{
0293 .out = "\007 \eb\"\x90\\317\r",
0294 .flags = ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_NA,
0295 },{
0296 .out = "\007 \eb\"\x90\\317\r",
0297 .flags = ESCAPE_SPECIAL | ESCAPE_OCTAL | ESCAPE_NA,
0298 },{
0299 .out = "\007 \eb\"\x90\\317\r",
0300 .flags = ESCAPE_ANY | ESCAPE_NA,
0301 },{
0302 .out = "\007 \eb\"\x90\\xcf\r",
0303 .flags = ESCAPE_HEX | ESCAPE_NA,
0304 },{
0305 .out = "\007 \eb\"\x90\\xcf\r",
0306 .flags = ESCAPE_SPACE | ESCAPE_HEX | ESCAPE_NA,
0307 },{
0308 .out = "\007 \eb\"\x90\\xcf\r",
0309 .flags = ESCAPE_SPECIAL | ESCAPE_HEX | ESCAPE_NA,
0310 },{
0311 .out = "\007 \eb\"\x90\\xcf\r",
0312 .flags = ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_HEX | ESCAPE_NA,
0313 },{
0314
0315 }}
0316 },{
0317 .in = "\007 \eb\"\x90\xCF\r",
0318 .s1 = {{
0319 .out = "\007 \eb\"\x90\xCF\r",
0320 .flags = ESCAPE_NAP,
0321 },{
0322 .out = "\007 \eb\"\x90\xCF\\r",
0323 .flags = ESCAPE_SPACE | ESCAPE_NAP,
0324 },{
0325 .out = "\007 \eb\"\x90\xCF\r",
0326 .flags = ESCAPE_SPECIAL | ESCAPE_NAP,
0327 },{
0328 .out = "\007 \eb\"\x90\xCF\\r",
0329 .flags = ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_NAP,
0330 },{
0331 .out = "\007 \eb\"\x90\\317\\015",
0332 .flags = ESCAPE_OCTAL | ESCAPE_NAP,
0333 },{
0334 .out = "\007 \eb\"\x90\\317\\r",
0335 .flags = ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_NAP,
0336 },{
0337 .out = "\007 \eb\"\x90\\317\\015",
0338 .flags = ESCAPE_SPECIAL | ESCAPE_OCTAL | ESCAPE_NAP,
0339 },{
0340 .out = "\007 \eb\"\x90\\317\r",
0341 .flags = ESCAPE_ANY | ESCAPE_NAP,
0342 },{
0343 .out = "\007 \eb\"\x90\\xcf\\x0d",
0344 .flags = ESCAPE_HEX | ESCAPE_NAP,
0345 },{
0346 .out = "\007 \eb\"\x90\\xcf\\r",
0347 .flags = ESCAPE_SPACE | ESCAPE_HEX | ESCAPE_NAP,
0348 },{
0349 .out = "\007 \eb\"\x90\\xcf\\x0d",
0350 .flags = ESCAPE_SPECIAL | ESCAPE_HEX | ESCAPE_NAP,
0351 },{
0352 .out = "\007 \eb\"\x90\\xcf\\r",
0353 .flags = ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_HEX | ESCAPE_NAP,
0354 },{
0355
0356 }}
0357 },{
0358
0359 }};
0360
0361 static const struct test_string strings_upper[] __initconst = {
0362 {
0363 .in = "abcdefgh1234567890test",
0364 .out = "ABCDEFGH1234567890TEST",
0365 },
0366 {
0367 .in = "abCdeFgH1234567890TesT",
0368 .out = "ABCDEFGH1234567890TEST",
0369 },
0370 };
0371
0372 static const struct test_string strings_lower[] __initconst = {
0373 {
0374 .in = "ABCDEFGH1234567890TEST",
0375 .out = "abcdefgh1234567890test",
0376 },
0377 {
0378 .in = "abCdeFgH1234567890TesT",
0379 .out = "abcdefgh1234567890test",
0380 },
0381 };
0382
0383 static __init const char *test_string_find_match(const struct test_string_2 *s2,
0384 unsigned int flags)
0385 {
0386 const struct test_string_1 *s1 = s2->s1;
0387 unsigned int i;
0388
0389 if (!flags)
0390 return s2->in;
0391
0392
0393 flags &= ~ESCAPE_NULL;
0394
0395
0396 if (flags & ESCAPE_OCTAL)
0397 flags &= ~ESCAPE_HEX;
0398
0399 for (i = 0; i < TEST_STRING_2_MAX_S1 && s1->out; i++, s1++)
0400 if (s1->flags == flags)
0401 return s1->out;
0402 return NULL;
0403 }
0404
0405 static __init void
0406 test_string_escape_overflow(const char *in, int p, unsigned int flags, const char *esc,
0407 int q_test, const char *name)
0408 {
0409 int q_real;
0410
0411 q_real = string_escape_mem(in, p, NULL, 0, flags, esc);
0412 if (q_real != q_test)
0413 pr_warn("Test '%s' failed: flags = %#x, osz = 0, expected %d, got %d\n",
0414 name, flags, q_test, q_real);
0415 }
0416
0417 static __init void test_string_escape(const char *name,
0418 const struct test_string_2 *s2,
0419 unsigned int flags, const char *esc)
0420 {
0421 size_t out_size = 512;
0422 char *out_test = kmalloc(out_size, GFP_KERNEL);
0423 char *out_real = kmalloc(out_size, GFP_KERNEL);
0424 char *in = kmalloc(256, GFP_KERNEL);
0425 int p = 0, q_test = 0;
0426 int q_real;
0427
0428 if (!out_test || !out_real || !in)
0429 goto out;
0430
0431 for (; s2->in; s2++) {
0432 const char *out;
0433 int len;
0434
0435
0436 if (flags & ESCAPE_NULL) {
0437 in[p++] = '\0';
0438
0439 if (flags & ESCAPE_NA && !(flags & ESCAPE_APPEND && esc)) {
0440 out_test[q_test++] = '\0';
0441 } else {
0442 out_test[q_test++] = '\\';
0443 out_test[q_test++] = '0';
0444 }
0445 }
0446
0447
0448 out = test_string_find_match(s2, flags);
0449 if (!out)
0450 continue;
0451
0452
0453 len = strlen(s2->in);
0454 memcpy(&in[p], s2->in, len);
0455 p += len;
0456
0457
0458 len = strlen(out);
0459 memcpy(&out_test[q_test], out, len);
0460 q_test += len;
0461 }
0462
0463 q_real = string_escape_mem(in, p, out_real, out_size, flags, esc);
0464
0465 test_string_check_buf(name, flags, in, p, out_real, q_real, out_test,
0466 q_test);
0467
0468 test_string_escape_overflow(in, p, flags, esc, q_test, name);
0469
0470 out:
0471 kfree(in);
0472 kfree(out_real);
0473 kfree(out_test);
0474 }
0475
0476 #define string_get_size_maxbuf 16
0477 #define test_string_get_size_one(size, blk_size, exp_result10, exp_result2) \
0478 do { \
0479 BUILD_BUG_ON(sizeof(exp_result10) >= string_get_size_maxbuf); \
0480 BUILD_BUG_ON(sizeof(exp_result2) >= string_get_size_maxbuf); \
0481 __test_string_get_size((size), (blk_size), (exp_result10), \
0482 (exp_result2)); \
0483 } while (0)
0484
0485
0486 static __init void test_string_get_size_check(const char *units,
0487 const char *exp,
0488 char *res,
0489 const u64 size,
0490 const u64 blk_size)
0491 {
0492 if (!memcmp(res, exp, strlen(exp) + 1))
0493 return;
0494
0495 res[string_get_size_maxbuf - 1] = '\0';
0496
0497 pr_warn("Test 'test_string_get_size' failed!\n");
0498 pr_warn("string_get_size(size = %llu, blk_size = %llu, units = %s)\n",
0499 size, blk_size, units);
0500 pr_warn("expected: '%s', got '%s'\n", exp, res);
0501 }
0502
0503 static __init void __test_string_get_size(const u64 size, const u64 blk_size,
0504 const char *exp_result10,
0505 const char *exp_result2)
0506 {
0507 char buf10[string_get_size_maxbuf];
0508 char buf2[string_get_size_maxbuf];
0509
0510 string_get_size(size, blk_size, STRING_UNITS_10, buf10, sizeof(buf10));
0511 string_get_size(size, blk_size, STRING_UNITS_2, buf2, sizeof(buf2));
0512
0513 test_string_get_size_check("STRING_UNITS_10", exp_result10, buf10,
0514 size, blk_size);
0515
0516 test_string_get_size_check("STRING_UNITS_2", exp_result2, buf2,
0517 size, blk_size);
0518 }
0519
0520 static __init void test_string_get_size(void)
0521 {
0522
0523 test_string_get_size_one(0, 512, "0 B", "0 B");
0524 test_string_get_size_one(1, 512, "512 B", "512 B");
0525 test_string_get_size_one(1100, 1, "1.10 kB", "1.07 KiB");
0526
0527
0528 test_string_get_size_one(16384, 512, "8.39 MB", "8.00 MiB");
0529 test_string_get_size_one(500118192, 512, "256 GB", "238 GiB");
0530 test_string_get_size_one(8192, 4096, "33.6 MB", "32.0 MiB");
0531
0532
0533 test_string_get_size_one(3000, 1900, "5.70 MB", "5.44 MiB");
0534
0535
0536 test_string_get_size_one(U64_MAX, 4096, "75.6 ZB", "64.0 ZiB");
0537 test_string_get_size_one(4096, U64_MAX, "75.6 ZB", "64.0 ZiB");
0538 }
0539
0540 static void __init test_string_upper_lower(void)
0541 {
0542 char *dst;
0543 int i;
0544
0545 for (i = 0; i < ARRAY_SIZE(strings_upper); i++) {
0546 const char *s = strings_upper[i].in;
0547 int len = strlen(strings_upper[i].in) + 1;
0548
0549 dst = kmalloc(len, GFP_KERNEL);
0550 if (!dst)
0551 return;
0552
0553 string_upper(dst, s);
0554 if (memcmp(dst, strings_upper[i].out, len)) {
0555 pr_warn("Test 'string_upper' failed : expected %s, got %s!\n",
0556 strings_upper[i].out, dst);
0557 kfree(dst);
0558 return;
0559 }
0560 kfree(dst);
0561 }
0562
0563 for (i = 0; i < ARRAY_SIZE(strings_lower); i++) {
0564 const char *s = strings_lower[i].in;
0565 int len = strlen(strings_lower[i].in) + 1;
0566
0567 dst = kmalloc(len, GFP_KERNEL);
0568 if (!dst)
0569 return;
0570
0571 string_lower(dst, s);
0572 if (memcmp(dst, strings_lower[i].out, len)) {
0573 pr_warn("Test 'string_lower failed : : expected %s, got %s!\n",
0574 strings_lower[i].out, dst);
0575 kfree(dst);
0576 return;
0577 }
0578 kfree(dst);
0579 }
0580 }
0581
0582 static int __init test_string_helpers_init(void)
0583 {
0584 unsigned int i;
0585
0586 pr_info("Running tests...\n");
0587 for (i = 0; i < UNESCAPE_ALL_MASK + 1; i++)
0588 test_string_unescape("unescape", i, false);
0589 test_string_unescape("unescape inplace",
0590 get_random_int() % (UNESCAPE_ANY + 1), true);
0591
0592
0593 for (i = 0; i < ESCAPE_ALL_MASK + 1; i++)
0594 test_string_escape("escape 0", escape0, i, TEST_STRING_2_DICT_0);
0595
0596
0597 for (i = 0; i < ESCAPE_ALL_MASK + 1; i++)
0598 test_string_escape("escape 1", escape1, i, TEST_STRING_2_DICT_1);
0599
0600
0601 test_string_get_size();
0602
0603
0604 test_string_upper_lower();
0605
0606 return -EINVAL;
0607 }
0608 module_init(test_string_helpers_init);
0609 MODULE_LICENSE("Dual BSD/GPL");