diff options
| -rw-r--r-- | fs/proc/array.c | 4 | ||||
| -rw-r--r-- | include/linux/string_helpers.h | 8 | ||||
| -rw-r--r-- | lib/string_helpers.c | 49 | ||||
| -rw-r--r-- | lib/test-string_helpers.c | 40 | ||||
| -rw-r--r-- | lib/vsprintf.c | 8 | ||||
| -rw-r--r-- | net/sunrpc/cache.c | 8 |
6 files changed, 44 insertions, 73 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index a4490c0a4644..13f047ad08e4 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
| @@ -99,8 +99,8 @@ static inline void task_name(struct seq_file *m, struct task_struct *p) | |||
| 99 | buf = m->buf + m->count; | 99 | buf = m->buf + m->count; |
| 100 | 100 | ||
| 101 | /* Ignore error for now */ | 101 | /* Ignore error for now */ |
| 102 | string_escape_str(tcomm, &buf, m->size - m->count, | 102 | buf += string_escape_str(tcomm, buf, m->size - m->count, |
| 103 | ESCAPE_SPACE | ESCAPE_SPECIAL, "\n\\"); | 103 | ESCAPE_SPACE | ESCAPE_SPECIAL, "\n\\"); |
| 104 | 104 | ||
| 105 | m->count = buf - m->buf; | 105 | m->count = buf - m->buf; |
| 106 | seq_putc(m, '\n'); | 106 | seq_putc(m, '\n'); |
diff --git a/include/linux/string_helpers.h b/include/linux/string_helpers.h index 657571817260..0991913f4953 100644 --- a/include/linux/string_helpers.h +++ b/include/linux/string_helpers.h | |||
| @@ -47,22 +47,22 @@ static inline int string_unescape_any_inplace(char *buf) | |||
| 47 | #define ESCAPE_ANY_NP (ESCAPE_ANY | ESCAPE_NP) | 47 | #define ESCAPE_ANY_NP (ESCAPE_ANY | ESCAPE_NP) |
| 48 | #define ESCAPE_HEX 0x20 | 48 | #define ESCAPE_HEX 0x20 |
| 49 | 49 | ||
| 50 | int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz, | 50 | int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, |
| 51 | unsigned int flags, const char *esc); | 51 | unsigned int flags, const char *esc); |
| 52 | 52 | ||
| 53 | static inline int string_escape_mem_any_np(const char *src, size_t isz, | 53 | static inline int string_escape_mem_any_np(const char *src, size_t isz, |
| 54 | char **dst, size_t osz, const char *esc) | 54 | char *dst, size_t osz, const char *esc) |
| 55 | { | 55 | { |
| 56 | return string_escape_mem(src, isz, dst, osz, ESCAPE_ANY_NP, esc); | 56 | return string_escape_mem(src, isz, dst, osz, ESCAPE_ANY_NP, esc); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | static inline int string_escape_str(const char *src, char **dst, size_t sz, | 59 | static inline int string_escape_str(const char *src, char *dst, size_t sz, |
| 60 | unsigned int flags, const char *esc) | 60 | unsigned int flags, const char *esc) |
| 61 | { | 61 | { |
| 62 | return string_escape_mem(src, strlen(src), dst, sz, flags, esc); | 62 | return string_escape_mem(src, strlen(src), dst, sz, flags, esc); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | static inline int string_escape_str_any_np(const char *src, char **dst, | 65 | static inline int string_escape_str_any_np(const char *src, char *dst, |
| 66 | size_t sz, const char *esc) | 66 | size_t sz, const char *esc) |
| 67 | { | 67 | { |
| 68 | return string_escape_str(src, dst, sz, ESCAPE_ANY_NP, esc); | 68 | return string_escape_str(src, dst, sz, ESCAPE_ANY_NP, esc); |
diff --git a/lib/string_helpers.c b/lib/string_helpers.c index 9c48ddad0f0d..1826c7407258 100644 --- a/lib/string_helpers.c +++ b/lib/string_helpers.c | |||
| @@ -274,11 +274,6 @@ static bool escape_space(unsigned char c, char **dst, char *end) | |||
| 274 | return false; | 274 | return false; |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | if (out + 2 > end) { | ||
| 278 | *dst = out + 2; | ||
| 279 | return true; | ||
| 280 | } | ||
| 281 | |||
| 282 | if (out < end) | 277 | if (out < end) |
| 283 | *out = '\\'; | 278 | *out = '\\'; |
| 284 | ++out; | 279 | ++out; |
| @@ -309,11 +304,6 @@ static bool escape_special(unsigned char c, char **dst, char *end) | |||
| 309 | return false; | 304 | return false; |
| 310 | } | 305 | } |
| 311 | 306 | ||
| 312 | if (out + 2 > end) { | ||
| 313 | *dst = out + 2; | ||
| 314 | return true; | ||
| 315 | } | ||
| 316 | |||
| 317 | if (out < end) | 307 | if (out < end) |
| 318 | *out = '\\'; | 308 | *out = '\\'; |
| 319 | ++out; | 309 | ++out; |
| @@ -332,11 +322,6 @@ static bool escape_null(unsigned char c, char **dst, char *end) | |||
| 332 | if (c) | 322 | if (c) |
| 333 | return false; | 323 | return false; |
| 334 | 324 | ||
| 335 | if (out + 2 > end) { | ||
| 336 | *dst = out + 2; | ||
| 337 | return true; | ||
| 338 | } | ||
| 339 | |||
| 340 | if (out < end) | 325 | if (out < end) |
| 341 | *out = '\\'; | 326 | *out = '\\'; |
| 342 | ++out; | 327 | ++out; |
| @@ -352,11 +337,6 @@ static bool escape_octal(unsigned char c, char **dst, char *end) | |||
| 352 | { | 337 | { |
| 353 | char *out = *dst; | 338 | char *out = *dst; |
| 354 | 339 | ||
| 355 | if (out + 4 > end) { | ||
| 356 | *dst = out + 4; | ||
| 357 | return true; | ||
| 358 | } | ||
| 359 | |||
| 360 | if (out < end) | 340 | if (out < end) |
| 361 | *out = '\\'; | 341 | *out = '\\'; |
| 362 | ++out; | 342 | ++out; |
| @@ -378,11 +358,6 @@ static bool escape_hex(unsigned char c, char **dst, char *end) | |||
| 378 | { | 358 | { |
| 379 | char *out = *dst; | 359 | char *out = *dst; |
| 380 | 360 | ||
| 381 | if (out + 4 > end) { | ||
| 382 | *dst = out + 4; | ||
| 383 | return true; | ||
| 384 | } | ||
| 385 | |||
| 386 | if (out < end) | 361 | if (out < end) |
| 387 | *out = '\\'; | 362 | *out = '\\'; |
| 388 | ++out; | 363 | ++out; |
| @@ -449,20 +424,17 @@ static bool escape_hex(unsigned char c, char **dst, char *end) | |||
| 449 | * it if needs. | 424 | * it if needs. |
| 450 | * | 425 | * |
| 451 | * Return: | 426 | * Return: |
| 452 | * The amount of the characters processed to the destination buffer, or | 427 | * The total size of the escaped output that would be generated for |
| 453 | * %-ENOMEM if the size of buffer is not enough to put an escaped character is | 428 | * the given input and flags. To check whether the output was |
| 454 | * returned. | 429 | * truncated, compare the return value to osz. There is room left in |
| 455 | * | 430 | * dst for a '\0' terminator if and only if ret < osz. |
| 456 | * Even in the case of error @dst pointer will be updated to point to the byte | ||
| 457 | * after the last processed character. | ||
| 458 | */ | 431 | */ |
| 459 | int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz, | 432 | int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, |
| 460 | unsigned int flags, const char *esc) | 433 | unsigned int flags, const char *esc) |
| 461 | { | 434 | { |
| 462 | char *p = *dst; | 435 | char *p = dst; |
| 463 | char *end = p + osz; | 436 | char *end = p + osz; |
| 464 | bool is_dict = esc && *esc; | 437 | bool is_dict = esc && *esc; |
| 465 | int ret; | ||
| 466 | 438 | ||
| 467 | while (isz--) { | 439 | while (isz--) { |
| 468 | unsigned char c = *src++; | 440 | unsigned char c = *src++; |
| @@ -502,13 +474,6 @@ int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz, | |||
| 502 | escape_passthrough(c, &p, end); | 474 | escape_passthrough(c, &p, end); |
| 503 | } | 475 | } |
| 504 | 476 | ||
| 505 | if (p > end) { | 477 | return p - dst; |
| 506 | *dst = end; | ||
| 507 | return -ENOMEM; | ||
| 508 | } | ||
| 509 | |||
| 510 | ret = p - *dst; | ||
| 511 | *dst = p; | ||
| 512 | return ret; | ||
| 513 | } | 478 | } |
| 514 | EXPORT_SYMBOL(string_escape_mem); | 479 | EXPORT_SYMBOL(string_escape_mem); |
diff --git a/lib/test-string_helpers.c b/lib/test-string_helpers.c index ab0d30e1e18f..8e376efd88a4 100644 --- a/lib/test-string_helpers.c +++ b/lib/test-string_helpers.c | |||
| @@ -260,16 +260,28 @@ static __init const char *test_string_find_match(const struct test_string_2 *s2, | |||
| 260 | return NULL; | 260 | return NULL; |
| 261 | } | 261 | } |
| 262 | 262 | ||
| 263 | static __init void | ||
| 264 | test_string_escape_overflow(const char *in, int p, unsigned int flags, const char *esc, | ||
| 265 | int q_test, const char *name) | ||
| 266 | { | ||
| 267 | int q_real; | ||
| 268 | |||
| 269 | q_real = string_escape_mem(in, p, NULL, 0, flags, esc); | ||
| 270 | if (q_real != q_test) | ||
| 271 | pr_warn("Test '%s' failed: flags = %u, osz = 0, expected %d, got %d\n", | ||
| 272 | name, flags, q_test, q_real); | ||
| 273 | } | ||
| 274 | |||
| 263 | static __init void test_string_escape(const char *name, | 275 | static __init void test_string_escape(const char *name, |
| 264 | const struct test_string_2 *s2, | 276 | const struct test_string_2 *s2, |
| 265 | unsigned int flags, const char *esc) | 277 | unsigned int flags, const char *esc) |
| 266 | { | 278 | { |
| 267 | int q_real = 512; | 279 | size_t out_size = 512; |
| 268 | char *out_test = kmalloc(q_real, GFP_KERNEL); | 280 | char *out_test = kmalloc(out_size, GFP_KERNEL); |
| 269 | char *out_real = kmalloc(q_real, GFP_KERNEL); | 281 | char *out_real = kmalloc(out_size, GFP_KERNEL); |
| 270 | char *in = kmalloc(256, GFP_KERNEL); | 282 | char *in = kmalloc(256, GFP_KERNEL); |
| 271 | char *buf = out_real; | ||
| 272 | int p = 0, q_test = 0; | 283 | int p = 0, q_test = 0; |
| 284 | int q_real; | ||
| 273 | 285 | ||
| 274 | if (!out_test || !out_real || !in) | 286 | if (!out_test || !out_real || !in) |
| 275 | goto out; | 287 | goto out; |
| @@ -301,29 +313,19 @@ static __init void test_string_escape(const char *name, | |||
| 301 | q_test += len; | 313 | q_test += len; |
| 302 | } | 314 | } |
| 303 | 315 | ||
| 304 | q_real = string_escape_mem(in, p, &buf, q_real, flags, esc); | 316 | q_real = string_escape_mem(in, p, out_real, out_size, flags, esc); |
| 305 | 317 | ||
| 306 | test_string_check_buf(name, flags, in, p, out_real, q_real, out_test, | 318 | test_string_check_buf(name, flags, in, p, out_real, q_real, out_test, |
| 307 | q_test); | 319 | q_test); |
| 320 | |||
| 321 | test_string_escape_overflow(in, p, flags, esc, q_test, name); | ||
| 322 | |||
| 308 | out: | 323 | out: |
| 309 | kfree(in); | 324 | kfree(in); |
| 310 | kfree(out_real); | 325 | kfree(out_real); |
| 311 | kfree(out_test); | 326 | kfree(out_test); |
| 312 | } | 327 | } |
| 313 | 328 | ||
| 314 | static __init void test_string_escape_nomem(void) | ||
| 315 | { | ||
| 316 | char *in = "\eb \\C\007\"\x90\r]"; | ||
| 317 | char out[64], *buf = out; | ||
| 318 | int rc = -ENOMEM, ret; | ||
| 319 | |||
| 320 | ret = string_escape_str_any_np(in, &buf, strlen(in), NULL); | ||
| 321 | if (ret == rc) | ||
| 322 | return; | ||
| 323 | |||
| 324 | pr_err("Test 'escape nomem' failed: got %d instead of %d\n", ret, rc); | ||
| 325 | } | ||
| 326 | |||
| 327 | static int __init test_string_helpers_init(void) | 329 | static int __init test_string_helpers_init(void) |
| 328 | { | 330 | { |
| 329 | unsigned int i; | 331 | unsigned int i; |
| @@ -342,8 +344,6 @@ static int __init test_string_helpers_init(void) | |||
| 342 | for (i = 0; i < (ESCAPE_ANY_NP | ESCAPE_HEX) + 1; i++) | 344 | for (i = 0; i < (ESCAPE_ANY_NP | ESCAPE_HEX) + 1; i++) |
| 343 | test_string_escape("escape 1", escape1, i, TEST_STRING_2_DICT_1); | 345 | test_string_escape("escape 1", escape1, i, TEST_STRING_2_DICT_1); |
| 344 | 346 | ||
| 345 | test_string_escape_nomem(); | ||
| 346 | |||
| 347 | return -EINVAL; | 347 | return -EINVAL; |
| 348 | } | 348 | } |
| 349 | module_init(test_string_helpers_init); | 349 | module_init(test_string_helpers_init); |
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 4da1e7aaf9d5..3a1e0843f9a2 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
| @@ -1235,8 +1235,12 @@ char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec, | |||
| 1235 | 1235 | ||
| 1236 | len = spec.field_width < 0 ? 1 : spec.field_width; | 1236 | len = spec.field_width < 0 ? 1 : spec.field_width; |
| 1237 | 1237 | ||
| 1238 | /* Ignore the error. We print as many characters as we can */ | 1238 | /* |
| 1239 | string_escape_mem(addr, len, &buf, end - buf, flags, NULL); | 1239 | * string_escape_mem() writes as many characters as it can to |
| 1240 | * the given buffer, and returns the total size of the output | ||
| 1241 | * had the buffer been big enough. | ||
| 1242 | */ | ||
| 1243 | buf += string_escape_mem(addr, len, buf, buf < end ? end - buf : 0, flags, NULL); | ||
| 1240 | 1244 | ||
| 1241 | return buf; | 1245 | return buf; |
| 1242 | } | 1246 | } |
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 5199bb1a017e..2928afffbb81 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
| @@ -1072,10 +1072,12 @@ void qword_add(char **bpp, int *lp, char *str) | |||
| 1072 | 1072 | ||
| 1073 | if (len < 0) return; | 1073 | if (len < 0) return; |
| 1074 | 1074 | ||
| 1075 | ret = string_escape_str(str, &bp, len, ESCAPE_OCTAL, "\\ \n\t"); | 1075 | ret = string_escape_str(str, bp, len, ESCAPE_OCTAL, "\\ \n\t"); |
| 1076 | if (ret < 0 || ret == len) | 1076 | if (ret >= len) { |
| 1077 | bp += len; | ||
| 1077 | len = -1; | 1078 | len = -1; |
| 1078 | else { | 1079 | } else { |
| 1080 | bp += ret; | ||
| 1079 | len -= ret; | 1081 | len -= ret; |
| 1080 | *bp++ = ' '; | 1082 | *bp++ = ' '; |
| 1081 | len--; | 1083 | len--; |
