002-file-Check-buffer-size-after-strtok.patch 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. From eae126f66663e5c73e5d290b8e3134449489340f Mon Sep 17 00:00:00 2001
  2. From: Hauke Mehrtens <[email protected]>
  3. Date: Sun, 4 Oct 2020 17:14:49 +0200
  4. Subject: [PATCH] file: Check buffer size after strtok()
  5. MIME-Version: 1.0
  6. Content-Type: text/plain; charset=UTF-8
  7. Content-Transfer-Encoding: 8bit
  8. This fixes a heap overflow in the parsing of the uci line.
  9. The line which is parsed and put into pctx->buf is null terminated and
  10. stored on the heap. In the uci_parse_line() function we use strtok() to
  11. split this string in multiple parts after divided by a space or tab.
  12. strtok() replaces these characters with a NULL byte. If the next byte is
  13. NULL we assume that this NULL byte was added by strtok() and try to
  14. parse the string after this NULL byte. If this NULL byte was not added
  15. by strtok(), but by fgets() to mark the end of the string we would read
  16. over this end of the string in uninitialized memory and later over the
  17. allocated buffer.
  18. Fix this problem by storing how long the line we read was and check if
  19. we would read over the end of the string here.
  20. This also adds the input which detected this crash to the corpus of the
  21. fuzzer.
  22. Signed-off-by: Hauke Mehrtens <[email protected]>
  23. [fixed merge conflict in tests]
  24. Signed-off-by: Petr Štetiar <[email protected]>
  25. ---
  26. file.c | 19 ++++++++++++++++---
  27. tests/cram/test-san_uci_import.t | 1 +
  28. tests/cram/test_uci_import.t | 1 +
  29. .../2e18ecc3a759dedc9357b1298e9269eccc5c5a6b | 1 +
  30. uci_internal.h | 1 +
  31. 5 files changed, 20 insertions(+), 3 deletions(-)
  32. create mode 100644 tests/fuzz/corpus/2e18ecc3a759dedc9357b1298e9269eccc5c5a6b
  33. --- a/file.c
  34. +++ b/file.c
  35. @@ -64,6 +64,7 @@ __private void uci_getln(struct uci_cont
  36. return;
  37. ofs += strlen(p);
  38. + pctx->buf_filled = ofs;
  39. if (pctx->buf[ofs - 1] == '\n') {
  40. pctx->line++;
  41. return;
  42. @@ -121,6 +122,15 @@ static inline void addc(struct uci_conte
  43. *pos_src += 1;
  44. }
  45. +static int uci_increase_pos(struct uci_parse_context *pctx, size_t add)
  46. +{
  47. + if (pctx->pos + add > pctx->buf_filled)
  48. + return -EINVAL;
  49. +
  50. + pctx->pos += add;
  51. + return 0;
  52. +}
  53. +
  54. /*
  55. * parse a double quoted string argument from the command line
  56. */
  57. @@ -385,7 +395,8 @@ static void uci_parse_package(struct uci
  58. char *name;
  59. /* command string null-terminated by strtok */
  60. - pctx->pos += strlen(pctx_cur_str(pctx)) + 1;
  61. + if (uci_increase_pos(pctx, strlen(pctx_cur_str(pctx)) + 1))
  62. + uci_parse_error(ctx, "package without name");
  63. ofs_name = next_arg(ctx, true, true, true);
  64. assert_eol(ctx);
  65. @@ -417,7 +428,8 @@ static void uci_parse_config(struct uci_
  66. }
  67. /* command string null-terminated by strtok */
  68. - pctx->pos += strlen(pctx_cur_str(pctx)) + 1;
  69. + if (uci_increase_pos(pctx, strlen(pctx_cur_str(pctx)) + 1))
  70. + uci_parse_error(ctx, "config without name");
  71. ofs_type = next_arg(ctx, true, false, false);
  72. type = pctx_str(pctx, ofs_type);
  73. @@ -467,7 +479,8 @@ static void uci_parse_option(struct uci_
  74. uci_parse_error(ctx, "option/list command found before the first section");
  75. /* command string null-terminated by strtok */
  76. - pctx->pos += strlen(pctx_cur_str(pctx)) + 1;
  77. + if (uci_increase_pos(pctx, strlen(pctx_cur_str(pctx)) + 1))
  78. + uci_parse_error(ctx, "option without name");
  79. ofs_name = next_arg(ctx, true, true, false);
  80. ofs_value = next_arg(ctx, false, false, false);
  81. --- a/uci_internal.h
  82. +++ b/uci_internal.h
  83. @@ -33,6 +33,7 @@ struct uci_parse_context
  84. const char *name;
  85. char *buf;
  86. int bufsz;
  87. + size_t buf_filled;
  88. int pos;
  89. };
  90. #define pctx_pos(pctx) ((pctx)->pos)