blob: 7fc5e12cd74b0db003b4f0f08092b16241e3d423 [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
2Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are
6met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above
10 copyright notice, this list of conditions and the following
11 disclaimer in the documentation and/or other materials provided
12 with the distribution.
13 * Neither the name of The Linux Foundation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16
17THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28==============================================================================*/
29
30/*===================================================================================
31 FILE: UsefulBuf.c
32
33 DESCRIPTION: General purpose input and output buffers
34
35 EDIT HISTORY FOR FILE:
36
37 This section contains comments describing changes made to the module.
38 Notice that changes are listed in reverse chronological order.
39
40 when who what, where, why
41 -------- ---- ---------------------------------------------------
42 09/07/17 llundbla Fix critical bug in UsefulBuf_Find() -- a read off
43 the end of memory when the bytes to find is longer
44 than the bytes to search.
45 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected comparison
46 for < or > for unequal length buffers. Added
47 UsefulBuf_Set() function.
48 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst
49 11/13/16 llundbla Initial Version.
50
51 =====================================================================================*/
52
53#include <string.h>
54#include "UsefulBuf.h"
55#include <stringl.h>
56
57#define USEFUL_OUT_BUF_MAGIC (0x0B0F) // used to catch use of uninitialized or corrupted UOBs
58
59/*
60 Public function -- see UsefulBuf.h
61 */
62int UsefulBuf_Copy(UsefulBuf *pDest, const UsefulBufC Src)
63{
64 if(Src.len > pDest->len)
65 return 1;
66
67 memscpy(pDest->ptr, pDest->len, Src.ptr, Src.len);
68
69 pDest->len = Src.len;
70
71 return 0;
72}
73
74/*
75 Public function -- see UsefulBuf.h
76 */
77int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2)
78{
79 // use the comparisons rather than subtracting lengths to
80 // return an int instead of a size_t
81 if(UB1.len < UB2.len) {
82 return -1;
83 } else if (UB1.len > UB2.len) {
84 return 1;
85 } // else UB1.len == UB2.len
86
87 return memcmp(UB1.ptr, UB2.ptr, UB1.len);
88}
89
90
91/*
92 Public function -- see UsefulBuf.h
93 */
94void UsefulBuf_Set(UsefulBuf *pDest, uint8_t value)
95{
96 memset(pDest->ptr, value, pDest->len);
97}
98
99
100/*
101 returns SIZE_MAX when there is no match
102 */
103size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind)
104{
105 if(BytesToSearch.len < BytesToFind.len) {
106 return SIZE_MAX;
107 }
108
109 for(size_t uPos = 0; uPos <= BytesToSearch.len - BytesToFind.len; uPos++) {
110 if(!UsefulBuf_Compare((UsefulBufC){((uint8_t *)BytesToSearch.ptr) + uPos, BytesToFind.len}, BytesToFind)) {
111 return uPos;
112 }
113 }
114
115 return SIZE_MAX;
116}
117
118
119/*
120 Public function -- see UsefulBuf.h
121
122 The core of UsefulOutBuf -- put some bytes in the buffer without writing off the end of it.
123
124 THIS FUNCTION DOES POINTER MATH
125 */
126void UsefulOutBuf_Init(UsefulOutBuf *me, void *pStorage, size_t uStorageSize)
127{
128 me->magic = USEFUL_OUT_BUF_MAGIC;
129 UsefulOutBuf_Reset(me);
130
131 me->UB.ptr = pStorage;
132 me->size = uStorageSize;
133
134 // The following check fails on ThreadX
135#if 0
136 // Sanity check on the pointer and size to be sure we are not
137 // passed a buffer that goes off the end of the address space.
138 // Given this test, we know that all unsigned lengths less than
139 // me->size are valid and won't wrap in any pointer additions
140 // based off of pStorage in the rest of this code.
141 const uintptr_t ptrM = UINTPTR_MAX - uStorageSize;
142 if(pStorage && (uintptr_t)pStorage > ptrM) // Check #0
143 me->err = 1;
144#endif
145}
146
147
148/*
149 Public function -- see UsefulBuf.h
150
151 The core of UsefulOutBuf -- put some bytes in the buffer without writing off the end of it.
152
153 Code Reviewers: THIS FUNCTION DOES POINTER MATH
154
155 This function inserts the source buffer, NewData, into the destination buffer, me->UB.ptr.
156
157 Destination is represented as:
158 me->UB.ptr -- start of the buffer
159 me->UB.len -- length of valid data in the buffer
160 me->size -- size of the buffer UB.ptr
161
162 Source is data:
163 NewData.ptr -- start of source buffer
164 NewData.len -- length of source buffer
165
166 Insertion point:
167 uInsertionPos.
168
169 Steps:
170
171 0. Corruption checks on UsefulOutBuf
172
173 1. Figure out if the new data will fit or not
174
175 2. Is insertion position in the range of valid data?
176
177 3. If insertion point is not at the end, slide data to the right of the insertion point to the right
178
179 4. Put the new data in at the insertion position.
180
181 */
182void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData, size_t uInsertionPos)
183{
184 if(me->err) {
185 // Already in error state.
186 return;
187 }
188
189 /* 0. Sanity check the UsefulOutBuf structure */
190 // A "counter measure". If magic number is not the right number it
191 // probably means me was not initialized or it was corrupted. Attackers
192 // can defeat this, but it is a hurdle and does good with very
193 // little code.
194 if(me->magic != USEFUL_OUT_BUF_MAGIC) {
195 me->err = 1;
196 return; // Magic number is wrong due to uninitalization or corrption
197 }
198
199 // Make sure valid data is less than buffer size. This would only occur
200 // if there was corruption of me, but it is also part of the checks to
201 // be sure there is no pointer arithmatic under/overflow.
202 if(me->UB.len > me->size) { // Check #1
203 me->err = 1;
204 return; // Offset of valid data is off the end of the UsefulOutBuf due to uninitialization or corruption
205 }
206
207 /* 1. Will it fit? */
208 // WillItFit() is the same as: NewData.len <= (me->size - me->UB.len)
209 // Check #1 makes sure subtraction in RoomLeft will not wrap around
210 if(! UsefulOutBuf_WillItFit(me, NewData.len)) { // Check #2
211 // The new data will not fit into the the buffer.
212 me->err = 1;
213 return;
214 }
215
216 /* 2. Check the Insertion Position */
217 // This, with Check #1, also confirms that uInsertionPos <= me->size
218 if(uInsertionPos > me->UB.len) { // Check #3
219 // Off the end of the valid data in the buffer.
220 me->err = 1;
221 return;
222 }
223
224 /* 3. Slide existing data to the right */
225 uint8_t *pSourceOfMove = ((uint8_t *)me->UB.ptr) + uInsertionPos; // PtrMath #1
226 size_t uNumBytesToMove = me->UB.len - uInsertionPos; // PtrMath #2
227 uint8_t *pDestinationOfMove = pSourceOfMove + NewData.len; // PtrMath #3
228 size_t uRoomInDestination = me->size - (uInsertionPos + NewData.len); // PtrMath #4
229
230 if(uNumBytesToMove && me->UB.ptr) {
231 memsmove(pDestinationOfMove, uRoomInDestination, pSourceOfMove, uNumBytesToMove);
232 }
233
234 /* 4. Put the new data in */
235 uint8_t *pInsertionPoint = ((uint8_t *)me->UB.ptr) + uInsertionPos; // PtrMath #5
236 uRoomInDestination = me->size - uInsertionPos; // PtrMath #6
237 if(me->UB.ptr) {
238 memsmove(pInsertionPoint, uRoomInDestination, NewData.ptr, NewData.len);
239 }
240 me->UB.len += NewData.len ;
241}
242
243
244/*
245 Rationale that describes why the above pointer math is safe
246
247 PtrMath #1 will never wrap around over because
248 Check #0 in UsefulOutBuf_Init makes sure me-UB.ptr + me->size doesn't wrap
249 Check #1 makes sure me->UB.len is less than me->size
250 Check #3 makes sure uInsertionPos is less than me->UB.len
251
252 PtrMath #2 will never wrap around under because
253 Check #3 makes sure uInsertionPos is less than me->UB.len
254
255 PtrMath #3 will never wrap around over because todo
256 PtrMath #1 is checked resulting in pStartOfDataToMove being between me->UB.ptr and a maximum valid ptr
257
258 PtrMath #4 will never wrap under because
259 Check #3 makes sure uInsertionPos is less than me->UB.len
260 Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos)
261 This algebraically rearranges to me->size > uInsertionPos + NewData.len
262
263 PtrMath #5 is exactly the same as PtrMath #1
264
265 PtrMath #6 will never wrap under because
266 Check #1 makes sure me->UB.len is less than me->size
267 Check #3 makes sure uInsertionPos is less than me->UB.len
268 */
269
270
271/*
272 Public function -- see UsefulBuf.h
273
274 Returns the resulting valid data in a UsefulBuf
275
276 */
277int UsefulOutBuf_OutUBuf(UsefulOutBuf *me, UsefulBuf *O)
278{
279 if(me->err) {
280 return me->err;
281 }
282
283 if(me->magic != USEFUL_OUT_BUF_MAGIC) {
284 me->err = 1;
285 return 1;
286 }
287
288 *O = me->UB;
289 return 0;
290}
291
292
293/*
294 Public function -- see UsefulBuf.h
295
296 Copy out the data accumulated in the output buffer.
297
298 */
299int UsefulOutBuf_CopyOut(UsefulOutBuf *me, void *pBuf, size_t uBufSize, size_t *puCopied)
300{
301 UsefulBuf B;
302 if(UsefulOutBuf_OutUBuf(me, &B)) {
303 return 1; // was in error state or was corrupted
304 }
305
306 if(B.len > uBufSize) {
307 return 1; // buffer was too small
308 }
309
310 memsmove(pBuf, uBufSize, B.ptr, B.len);
311
312 *puCopied = me->UB.len;
313
314 return 0;
315}
316
317
318
319
320/*
321 Public function -- see UsefulBuf.h
322
323 The core of UsefulInputBuf -- consume some bytes without going off the end of the buffer.
324
325 Code Reviewers: THIS FUNCTION DOES POINTER MATH
326 */
327const void * UsefulInputBuf_GetBytes(UsefulInputBuf *me, size_t uAmount)
328{
329 // Already in error state. Do nothing.
330 if(me->err) {
331 return NULL;
332 }
333
334 if(!UsefulInputBuf_BytesAvailable(me, uAmount)) {
335 // The number of bytes asked for at current position are more than available
336 me->err = 1;
337 return NULL;
338 }
339
340 // This is going to succeed
341 const void * const result = ((uint8_t *)me->UB.ptr) + me->cursor;
342 me->cursor += uAmount; // this will not overflow because of check using UsefulInputBuf_BytesAvailable()
343 return result;
344}
345