Source code of Windows XP (NT5)
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.

100 lines
2.7 KiB

  1. // Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved.
  2. #ifndef _CHECKBMI_H_
  3. #define _CHECKBMI_H_
  4. #ifdef __cplusplus
  5. extern "C" {
  6. #endif
  7. // Helper
  8. inline BOOL MultiplyCheckOverflow(DWORD a, DWORD b, DWORD *pab) {
  9. *pab = a * b;
  10. if ((a == 0) || (((*pab) / a) == b)) {
  11. return TRUE;
  12. }
  13. return FALSE;
  14. }
  15. // Checks if the fields in a BITMAPINFOHEADER won't generate
  16. // overlows and buffer overruns
  17. // This is not a complete check and does not guarantee code using this structure will be secure
  18. // from attack
  19. // Bugs this is guarding against:
  20. // 1. Total structure size calculation overflowing
  21. // 2. biClrUsed > 256 for 8-bit palettized content
  22. // 3. Total bitmap size in bytes overflowing
  23. // 4. biSize < size of the base structure leading to accessessing random memory
  24. // 5. Total structure size exceeding know size of data
  25. //
  26. inline BOOL ValidateBitmapInfoHeader(
  27. const BITMAPINFOHEADER *pbmi, // pointer to structure to check
  28. DWORD cbSize // size of memory block containing structure
  29. )
  30. {
  31. DWORD dwWidthInBytes;
  32. DWORD dwBpp;
  33. DWORD dwWidthInBits;
  34. DWORD dwHeight;
  35. DWORD dwSizeImage;
  36. DWORD dwClrUsed;
  37. // Reject bad parameters - do the size check first to avoid reading bad memory
  38. if (cbSize < sizeof(BITMAPINFOHEADER) ||
  39. pbmi->biSize < sizeof(BITMAPINFOHEADER) ||
  40. pbmi->biSize > 4096) {
  41. return FALSE;
  42. }
  43. // Use bpp of 32 for validating against further overflows if not set for compressed format
  44. dwBpp = 32;
  45. // Strictly speaking abs can overflow so cast explicitly to DWORD
  46. dwHeight = (DWORD)abs(pbmi->biHeight);
  47. if (!MultiplyCheckOverflow(dwBpp, (DWORD)pbmi->biWidth, &dwWidthInBits)) {
  48. return FALSE;
  49. }
  50. // Compute correct width in bytes - rounding up to 4 bytes
  51. dwWidthInBytes = (dwWidthInBits / 8 + 3) & ~3;
  52. if (!MultiplyCheckOverflow(dwWidthInBytes, dwHeight, &dwSizeImage)) {
  53. return FALSE;
  54. }
  55. // Fail if total size is 0 - this catches indivual quantities being 0
  56. // Also don't allow huge values > 1GB which might cause arithmetic
  57. // errors for users
  58. if (dwSizeImage > 0x40000000 ||
  59. pbmi->biSizeImage > 0x40000000) {
  60. return FALSE;
  61. }
  62. // Fail if biClrUsed looks bad
  63. if (pbmi->biClrUsed > 256) {
  64. return FALSE;
  65. }
  66. if (pbmi->biClrUsed == 0 && dwBpp <= 8) {
  67. dwClrUsed = (1 << dwBpp);
  68. } else {
  69. dwClrUsed = pbmi->biClrUsed;
  70. }
  71. // Check total size
  72. if (cbSize < pbmi->biSize + dwClrUsed * sizeof(RGBQUAD) +
  73. (pbmi->biCompression == BI_BITFIELDS ? 3 * sizeof(DWORD) : 0)) {
  74. return FALSE;
  75. }
  76. return TRUE;
  77. }
  78. #ifdef __cplusplus
  79. }
  80. #endif
  81. #endif // _CHECKBMI_H_