AJA NTV2 SDK  18.0.0.2717
NTV2 SDK 18.0.0.2717
checkbmi.h
Go to the documentation of this file.
1 // Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved.
2 
3 #ifndef _CHECKBMI_H_
4 #define _CHECKBMI_H_
5 
6 #ifdef __cplusplus
7 extern "C" {
8 #endif
9 
10 // Helper
11 __inline BOOL MultiplyCheckOverflow(DWORD a, DWORD b, __deref_out_range(==, a * b) DWORD *pab) {
12  *pab = a * b;
13  if ((a == 0) || (((*pab) / a) == b)) {
14  return TRUE;
15  }
16  return FALSE;
17 }
18 
19 
20 // Checks if the fields in a BITMAPINFOHEADER won't generate
21 // overlows and buffer overruns
22 // This is not a complete check and does not guarantee code using this structure will be secure
23 // from attack
24 // Bugs this is guarding against:
25 // 1. Total structure size calculation overflowing
26 // 2. biClrUsed > 256 for 8-bit palettized content
27 // 3. Total bitmap size in bytes overflowing
28 // 4. biSize < size of the base structure leading to accessessing random memory
29 // 5. Total structure size exceeding know size of data
30 //
31 
32 __success(return != 0) __inline BOOL ValidateBitmapInfoHeader(
33  const BITMAPINFOHEADER *pbmi, // pointer to structure to check
34  __out_range(>=, sizeof(BITMAPINFOHEADER)) DWORD cbSize // size of memory block containing structure
35 )
36 {
37  DWORD dwWidthInBytes;
38  DWORD dwBpp;
39  DWORD dwWidthInBits;
40  DWORD dwHeight;
41  DWORD dwSizeImage;
42  DWORD dwClrUsed;
43 
44  // Reject bad parameters - do the size check first to avoid reading bad memory
45  if (cbSize < sizeof(BITMAPINFOHEADER) ||
46  pbmi->biSize < sizeof(BITMAPINFOHEADER) ||
47  pbmi->biSize > 4096) {
48  return FALSE;
49  }
50 
51  // Reject 0 size
52  if (pbmi->biWidth == 0 || pbmi->biHeight == 0) {
53  return FALSE;
54  }
55 
56  // Use bpp of 200 for validating against further overflows if not set for compressed format
57  dwBpp = 200;
58 
59  if (pbmi->biBitCount > dwBpp) {
60  return FALSE;
61  }
62 
63  // Strictly speaking abs can overflow so cast explicitly to DWORD
64  dwHeight = (DWORD)abs(pbmi->biHeight);
65 
66  if (!MultiplyCheckOverflow(dwBpp, (DWORD)pbmi->biWidth, &dwWidthInBits)) {
67  return FALSE;
68  }
69 
70  // Compute correct width in bytes - rounding up to 4 bytes
71  dwWidthInBytes = (dwWidthInBits / 8 + 3) & ~3;
72 
73  if (!MultiplyCheckOverflow(dwWidthInBytes, dwHeight, &dwSizeImage)) {
74  return FALSE;
75  }
76 
77  // Fail if total size is 0 - this catches indivual quantities being 0
78  // Also don't allow huge values > 1GB which might cause arithmetic
79  // errors for users
80  if (dwSizeImage > 0x40000000 ||
81  pbmi->biSizeImage > 0x40000000) {
82  return FALSE;
83  }
84 
85  // Fail if biClrUsed looks bad
86  if (pbmi->biClrUsed > 256) {
87  return FALSE;
88  }
89 
90  if (pbmi->biClrUsed == 0 && pbmi->biBitCount <= 8 && pbmi->biBitCount > 0) {
91  dwClrUsed = (1 << pbmi->biBitCount);
92  } else {
93  dwClrUsed = pbmi->biClrUsed;
94  }
95 
96  // Check total size
97  if (cbSize < pbmi->biSize + dwClrUsed * sizeof(RGBQUAD) +
98  (pbmi->biCompression == BI_BITFIELDS ? 3 * sizeof(DWORD) : 0)) {
99  return FALSE;
100  }
101 
102  // If it is RGB validate biSizeImage - lots of code assumes the size is correct
103  if (pbmi->biCompression == BI_RGB || pbmi->biCompression == BI_BITFIELDS) {
104  if (pbmi->biSizeImage != 0) {
105  DWORD dwBits = (DWORD)pbmi->biWidth * (DWORD)pbmi->biBitCount;
106  DWORD dwWidthInBytes = ((DWORD)((dwBits+31) & (~31)) / 8);
107  DWORD dwTotalSize = (DWORD)abs(pbmi->biHeight) * dwWidthInBytes;
108  if (dwTotalSize > pbmi->biSizeImage) {
109  return FALSE;
110  }
111  }
112  }
113  return TRUE;
114 }
115 
116 #ifdef __cplusplus
117 }
118 #endif
119 
120 #endif // _CHECKBMI_H_
__out_range
__out_range(>=, sizeof(BITMAPINFOHEADER)) DWORD cbSize)
Definition: checkbmi.h:34
__success
__success(return !=0) __inline BOOL ValidateBitmapInfoHeader(const BITMAPINFOHEADER *pbmi
MultiplyCheckOverflow
__inline BOOL MultiplyCheckOverflow(DWORD a, DWORD b, __deref_out_range(==, a *b) DWORD *pab)
Definition: checkbmi.h:11