aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/proc/array.c4
-rw-r--r--include/linux/string_helpers.h8
-rw-r--r--lib/string_helpers.c49
-rw-r--r--lib/test-string_helpers.c40
-rw-r--r--lib/vsprintf.c8
-rw-r--r--net/sunrpc/cache.c8
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
50int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz, 50int 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
53static inline int string_escape_mem_any_np(const char *src, size_t isz, 53static 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
59static inline int string_escape_str(const char *src, char **dst, size_t sz, 59static 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
65static inline int string_escape_str_any_np(const char *src, char **dst, 65static 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 */
459int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz, 432int 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}
514EXPORT_SYMBOL(string_escape_mem); 479EXPORT_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
263static __init void
264test_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
263static __init void test_string_escape(const char *name, 275static __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
308out: 323out:
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
314static __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
327static int __init test_string_helpers_init(void) 329static 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}
349module_init(test_string_helpers_init); 349module_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--;