You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

128 lines
4.1 KiB

  1. From 960dbb956d9f9cb05b719087faed53c88dc80956 Mon Sep 17 00:00:00 2001
  2. From: Chrostoper Ertl <chertl@microsoft.com>
  3. Date: Thu, 28 Nov 2019 16:33:59 +0000
  4. Subject: [PATCH 06/11] fru: Fix buffer overflow vulnerabilities
  5. Partial fix for CVE-2020-5208, see
  6. https://github.com/ipmitool/ipmitool/security/advisories/GHSA-g659-9qxw-p7cp
  7. The `read_fru_area_section` function only performs size validation of
  8. requested read size, and falsely assumes that the IPMI message will not
  9. respond with more than the requested amount of data; it uses the
  10. unvalidated response size to copy into `frubuf`. If the response is
  11. larger than the request, this can result in overflowing the buffer.
  12. The same issue affects the `read_fru_area` function.
  13. ---
  14. lib/ipmi_fru.c | 33 +++++++++++++++++++++++++++++++--
  15. 1 file changed, 31 insertions(+), 2 deletions(-)
  16. diff --git a/lib/ipmi_fru.c b/lib/ipmi_fru.c
  17. index cf00effc82a2..af99aa99444c 100644
  18. --- a/lib/ipmi_fru.c
  19. +++ b/lib/ipmi_fru.c
  20. @@ -615,7 +615,10 @@ int
  21. read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
  22. uint32_t offset, uint32_t length, uint8_t *frubuf)
  23. {
  24. - uint32_t off = offset, tmp, finish;
  25. + uint32_t off = offset;
  26. + uint32_t tmp;
  27. + uint32_t finish;
  28. + uint32_t size_left_in_buffer;
  29. struct ipmi_rs * rsp;
  30. struct ipmi_rq req;
  31. uint8_t msg_data[4];
  32. @@ -628,10 +631,12 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
  33. finish = offset + length;
  34. if (finish > fru->size) {
  35. + memset(frubuf + fru->size, 0, length - fru->size);
  36. finish = fru->size;
  37. lprintf(LOG_NOTICE, "Read FRU Area length %d too large, "
  38. "Adjusting to %d",
  39. offset + length, finish - offset);
  40. + length = finish - offset;
  41. }
  42. memset(&req, 0, sizeof(req));
  43. @@ -667,6 +672,7 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
  44. }
  45. }
  46. + size_left_in_buffer = length;
  47. do {
  48. tmp = fru->access ? off >> 1 : off;
  49. msg_data[0] = id;
  50. @@ -707,9 +713,18 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
  51. }
  52. tmp = fru->access ? rsp->data[0] << 1 : rsp->data[0];
  53. + if(rsp->data_len < 1
  54. + || tmp > rsp->data_len - 1
  55. + || tmp > size_left_in_buffer)
  56. + {
  57. + printf(" Not enough buffer size");
  58. + return -1;
  59. + }
  60. +
  61. memcpy(frubuf, rsp->data + 1, tmp);
  62. off += tmp;
  63. frubuf += tmp;
  64. + size_left_in_buffer -= tmp;
  65. /* sometimes the size returned in the Info command
  66. * is too large. return 0 so higher level function
  67. * still attempts to parse what was returned */
  68. @@ -742,7 +757,9 @@ read_fru_area_section(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
  69. uint32_t offset, uint32_t length, uint8_t *frubuf)
  70. {
  71. static uint32_t fru_data_rqst_size = 20;
  72. - uint32_t off = offset, tmp, finish;
  73. + uint32_t off = offset;
  74. + uint32_t tmp, finish;
  75. + uint32_t size_left_in_buffer;
  76. struct ipmi_rs * rsp;
  77. struct ipmi_rq req;
  78. uint8_t msg_data[4];
  79. @@ -755,10 +772,12 @@ read_fru_area_section(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
  80. finish = offset + length;
  81. if (finish > fru->size) {
  82. + memset(frubuf + fru->size, 0, length - fru->size);
  83. finish = fru->size;
  84. lprintf(LOG_NOTICE, "Read FRU Area length %d too large, "
  85. "Adjusting to %d",
  86. offset + length, finish - offset);
  87. + length = finish - offset;
  88. }
  89. memset(&req, 0, sizeof(req));
  90. @@ -773,6 +792,8 @@ read_fru_area_section(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
  91. if (fru->access && fru_data_rqst_size > 16)
  92. #endif
  93. fru_data_rqst_size = 16;
  94. +
  95. + size_left_in_buffer = length;
  96. do {
  97. tmp = fru->access ? off >> 1 : off;
  98. msg_data[0] = id;
  99. @@ -804,8 +825,16 @@ read_fru_area_section(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
  100. }
  101. tmp = fru->access ? rsp->data[0] << 1 : rsp->data[0];
  102. + if(rsp->data_len < 1
  103. + || tmp > rsp->data_len - 1
  104. + || tmp > size_left_in_buffer)
  105. + {
  106. + printf(" Not enough buffer size");
  107. + return -1;
  108. + }
  109. memcpy((frubuf + off)-offset, rsp->data + 1, tmp);
  110. off += tmp;
  111. + size_left_in_buffer -= tmp;
  112. /* sometimes the size returned in the Info command
  113. * is too large. return 0 so higher level function
  114. --
  115. 2.27.0