1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | // |
5 | // File: DataBuffer.inl |
6 | // |
7 | |
8 | // |
9 | // Class code:DataBuffer provides secure access to a block of memory. |
10 | // |
11 | // ====================================================================================== |
12 | |
13 | #pragma once |
14 | |
15 | #include "databuffer.h" |
16 | |
17 | // -------------------------------------------------------------------------------------- |
18 | // |
19 | // Creates empty memory block. |
20 | // |
21 | inline |
22 | DataBuffer::DataBuffer() |
23 | { |
24 | Clear(); |
25 | } // DataBuffer::DataBuffer |
26 | |
27 | // -------------------------------------------------------------------------------------- |
28 | // |
29 | // Creates memory block (pbData, of size cbSize). |
30 | // |
31 | inline |
32 | DataBuffer::DataBuffer( |
33 | __in_bcount(cbSize) BYTE *pbData, |
34 | UINT32 cbSize) |
35 | { |
36 | m_pbData = pbData; |
37 | m_cbSize = cbSize; |
38 | } // DataBuffer::DataBuffer |
39 | |
40 | // -------------------------------------------------------------------------------------- |
41 | // |
42 | // Creates memory block copy. |
43 | // |
44 | inline |
45 | DataBuffer::DataBuffer( |
46 | const DataBuffer &source) |
47 | { |
48 | m_pbData = source.m_pbData; |
49 | m_cbSize = source.m_cbSize; |
50 | } // DataBuffer::DataBuffer |
51 | |
52 | #ifdef _WIN64 |
53 | #define const_pbBadFood (((BYTE *)NULL) + 0xbaadf00dbaadf00d) |
54 | #else //!_WIN64 |
55 | #define const_pbBadFood (((BYTE *)NULL) + 0xbaadf00d) |
56 | #endif //!_WIN64 |
57 | |
58 | // -------------------------------------------------------------------------------------- |
59 | // |
60 | // Initializes memory block to empty data. The object could be already initialzied. |
61 | // |
62 | inline |
63 | void |
64 | DataBuffer::Clear() |
65 | { |
66 | m_cbSize = 0; |
67 | // For debugging purposes let's put invalid non-NULL pointer here |
68 | INDEBUG_MD(m_pbData = const_pbBadFood); |
69 | } // DataBuffer::Clear |
70 | |
71 | #undef const_pbBadFood |
72 | |
73 | // -------------------------------------------------------------------------------------- |
74 | // |
75 | // Initializes memory block to data (pbData, of size cbSize). The object should be empty before. |
76 | // |
77 | inline |
78 | void |
79 | DataBuffer::Init( |
80 | __in_bcount(cbSize) BYTE *pbData, |
81 | UINT32 cbSize) |
82 | { |
83 | _ASSERTE(IsEmpty()); |
84 | |
85 | m_pbData = pbData; |
86 | m_cbSize = cbSize; |
87 | } // DataBuffer::Init |
88 | |
89 | // -------------------------------------------------------------------------------------- |
90 | // |
91 | // Reads data of type T without skipping the read data (returns pointer to the type in *ppTypeData). |
92 | // Returns FALSE if there's not enough data (of size T) in the blob, doesn't initialize the pointer |
93 | // *ppTypeData then. |
94 | // Returns TRUE otherwise, fills *ppTypeData with the "read" type start, but doesn't move the memory |
95 | // block (doesn't skip the "read" data). |
96 | // |
97 | template<class T> |
98 | __checkReturn |
99 | inline |
100 | BOOL |
101 | DataBuffer::PeekData( |
102 | __deref_out T **ppTypeData) |
103 | { |
104 | if (m_cbSize < sizeof(T)) |
105 | { // There's not enough data in the memory block |
106 | return FALSE; |
107 | } |
108 | // Fill the start of the "read" type |
109 | *ppTypeData = reinterpret_cast<T *>(m_pbData); |
110 | return TRUE; |
111 | } // DataBuffer::PeekData |
112 | |
113 | // -------------------------------------------------------------------------------------- |
114 | // |
115 | // Reads data of type T at offset nOffset without skipping the read data (returns pointer to the type in |
116 | // *ppTypeData). |
117 | // Returns FALSE if there's not enough data (of size T) at offset nOffset in the buffer, doesn't |
118 | // initialize the pointer *ppTypeData then. |
119 | // Returns TRUE otherwise, fills *ppTypeData with the type start, but doesn't move the memory block |
120 | // (doesn't skip any "read" data). |
121 | template<class T> |
122 | __checkReturn |
123 | inline |
124 | BOOL |
125 | DataBuffer::PeekDataAt( |
126 | UINT32 nOffset, |
127 | __deref_out T **ppTypeData) |
128 | { |
129 | if (m_cbSize < nOffset) |
130 | { // The offset is not in the memory block |
131 | return FALSE; |
132 | } |
133 | if ((m_cbSize - nOffset) < sizeof(T)) |
134 | { // The type is not fully in the memory block |
135 | return FALSE; |
136 | } |
137 | // Fill the start of the "read" type |
138 | *ppTypeData = reinterpret_cast<T *>(m_pbData + nOffset); |
139 | return TRUE; |
140 | } // DataBuffer::PeekDataAt |
141 | |
142 | // -------------------------------------------------------------------------------------- |
143 | // |
144 | // Reads data of type T and skips the data (instead of reading the bytes, returns pointer to the type in |
145 | // *ppTypeData). |
146 | // Returns FALSE if there's not enough data (of size T) in the blob, doesn't initialize the pointer |
147 | // *ppTypeData then. |
148 | // Returns TRUE otherwise, fills *ppTypeData with the "read" type start and moves the memory block |
149 | // behind the "read" type. |
150 | // |
151 | template<class T> |
152 | __checkReturn |
153 | inline |
154 | BOOL |
155 | DataBuffer::GetData( |
156 | __deref_out T **ppTypeData) |
157 | { |
158 | if (m_cbSize < sizeof(T)) |
159 | { // There's not enough data in the memory block |
160 | return FALSE; |
161 | } |
162 | // Fill the start of the "read" type |
163 | *ppTypeData = reinterpret_cast<T *>(m_pbData); |
164 | SkipBytes_InternalInsecure(sizeof(T)); |
165 | return TRUE; |
166 | } // DataBuffer::GetData |
167 | |
168 | // -------------------------------------------------------------------------------------- |
169 | // |
170 | // Reads data of size cbDataSize and skips the data (instead of reading the bytes, returns pointer to |
171 | // the bytes in *ppbDataPointer). |
172 | // Returns FALSE if there's not enough data in the blob, doesn't initialize the pointer *ppbDataPointer |
173 | // then. |
174 | // Returns TRUE otherwise, fills *ppbDataPointer with the "read" data start and moves the memory block |
175 | // behind the "read" data. |
176 | // |
177 | __checkReturn |
178 | inline |
179 | BOOL |
180 | DataBuffer::GetDataOfSize( |
181 | UINT32 cbDataSize, |
182 | __out_bcount(cbDataSize) BYTE **ppbDataPointer) |
183 | { |
184 | if (m_cbSize < cbDataSize) |
185 | { // There's not enough data in the memory block |
186 | return FALSE; |
187 | } |
188 | // Fill the start of the "read" data |
189 | *ppbDataPointer = m_pbData; |
190 | SkipBytes_InternalInsecure(cbDataSize); |
191 | return TRUE; |
192 | } // DataBuffer::GetDataOfSize |
193 | |
194 | // -------------------------------------------------------------------------------------- |
195 | // |
196 | // Truncates the buffer to exact size (cbSize). |
197 | // Returns FALSE if there's less than cbSize data represented. |
198 | // Returns TRUE otherwise and truncates the represented data size to cbSize. |
199 | // |
200 | __checkReturn |
201 | inline |
202 | BOOL |
203 | DataBuffer::TruncateToExactSize(UINT32 cbSize) |
204 | { |
205 | // Check if there's at least cbSize data present |
206 | if (m_cbSize < cbSize) |
207 | { // There's less than cbSize data present |
208 | // Fail the operation |
209 | return FALSE; |
210 | } |
211 | // Truncate represented data to size cbSize |
212 | m_cbSize = cbSize; |
213 | return TRUE; |
214 | } // DataBuffer::TruncateToExactSize |
215 | |
216 | // -------------------------------------------------------------------------------------- |
217 | // |
218 | // Truncates the buffer by size (cbSize). |
219 | // Returns FALSE if there's less than cbSize data represented. |
220 | // Returns TRUE otherwise and truncates the represented data size by cbSize. |
221 | // |
222 | __checkReturn |
223 | inline |
224 | BOOL |
225 | DataBuffer::TruncateBySize(UINT32 cbSize) |
226 | { |
227 | // Check if there's at least cbSize data present |
228 | if (m_cbSize < cbSize) |
229 | { // There's less than cbSize data present |
230 | // Fail the operation |
231 | return FALSE; |
232 | } |
233 | // Truncate represented data by size cbSize |
234 | m_cbSize -= cbSize; |
235 | return TRUE; |
236 | } // DataBuffer::TruncateBySize |
237 | |
238 | // -------------------------------------------------------------------------------------- |
239 | // |
240 | // Skips the buffer to size (cbSize). |
241 | // Returns FALSE if there's less than cbSize data represented. |
242 | // Returns TRUE otherwise and skips data at the beggining, so that the result has size cbSize. |
243 | // |
244 | __checkReturn |
245 | inline |
246 | BOOL |
247 | DataBuffer::SkipToExactSize(UINT32 cbSize) |
248 | { |
249 | // Check if there's at least cbSize data present |
250 | if (m_cbSize < cbSize) |
251 | { // There's less than cbSize data present |
252 | // Fail the operation |
253 | return FALSE; |
254 | } |
255 | SkipBytes_InternalInsecure(m_cbSize - cbSize); |
256 | return TRUE; |
257 | } // DataBuffer::SkipToExactSize |
258 | |
259 | // -------------------------------------------------------------------------------------- |
260 | // |
261 | // Skips 'cbSize' bytes in the represented memory block. The caller is responsible for making sure that the |
262 | // represented memory block contains at least 'cbSize' bytes, otherwise there will be a security issue. |
263 | // Should be used only internally, never call it from outside of this class. |
264 | // |
265 | inline |
266 | void |
267 | DataBuffer::SkipBytes_InternalInsecure(UINT32 cbSize) |
268 | { |
269 | // The caller is responsible for this check, just double check here |
270 | _ASSERTE(m_cbSize >= cbSize); |
271 | // Move the memory block by 'cbSize' bytes |
272 | m_pbData += cbSize; |
273 | m_cbSize -= cbSize; |
274 | } // DataBuffer::SkipBytes_InternalInsecure |
275 | |