blob: a0cc9b69120369bd157c53972a12b5b6f33c4ead [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
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070053#include "UsefulBuf.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070054
55#define USEFUL_OUT_BUF_MAGIC (0x0B0F) // used to catch use of uninitialized or corrupted UOBs
56
57/*
58 Public function -- see UsefulBuf.h
59 */
60int UsefulBuf_Copy(UsefulBuf *pDest, const UsefulBufC Src)
61{
62 if(Src.len > pDest->len)
63 return 1;
64
Laurence Lundblade74f68412018-09-13 12:18:49 -070065 memcpy(pDest->ptr, Src.ptr, Src.len);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070066
67 pDest->len = Src.len;
68
69 return 0;
70}
71
72/*
73 Public function -- see UsefulBuf.h
74 */
75int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2)
76{
77 // use the comparisons rather than subtracting lengths to
78 // return an int instead of a size_t
79 if(UB1.len < UB2.len) {
80 return -1;
81 } else if (UB1.len > UB2.len) {
82 return 1;
83 } // else UB1.len == UB2.len
84
85 return memcmp(UB1.ptr, UB2.ptr, UB1.len);
86}
87
88
89/*
90 Public function -- see UsefulBuf.h
91 */
92void UsefulBuf_Set(UsefulBuf *pDest, uint8_t value)
93{
94 memset(pDest->ptr, value, pDest->len);
95}
96
97
98/*
99 returns SIZE_MAX when there is no match
100 */
101size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind)
102{
103 if(BytesToSearch.len < BytesToFind.len) {
104 return SIZE_MAX;
105 }
106
107 for(size_t uPos = 0; uPos <= BytesToSearch.len - BytesToFind.len; uPos++) {
108 if(!UsefulBuf_Compare((UsefulBufC){((uint8_t *)BytesToSearch.ptr) + uPos, BytesToFind.len}, BytesToFind)) {
109 return uPos;
110 }
111 }
112
113 return SIZE_MAX;
114}
115
116
117/*
118 Public function -- see UsefulBuf.h
119
120 The core of UsefulOutBuf -- put some bytes in the buffer without writing off the end of it.
121
122 THIS FUNCTION DOES POINTER MATH
123 */
124void UsefulOutBuf_Init(UsefulOutBuf *me, void *pStorage, size_t uStorageSize)
125{
126 me->magic = USEFUL_OUT_BUF_MAGIC;
127 UsefulOutBuf_Reset(me);
128
129 me->UB.ptr = pStorage;
130 me->size = uStorageSize;
131
132 // The following check fails on ThreadX
133#if 0
134 // Sanity check on the pointer and size to be sure we are not
135 // passed a buffer that goes off the end of the address space.
136 // Given this test, we know that all unsigned lengths less than
137 // me->size are valid and won't wrap in any pointer additions
138 // based off of pStorage in the rest of this code.
139 const uintptr_t ptrM = UINTPTR_MAX - uStorageSize;
140 if(pStorage && (uintptr_t)pStorage > ptrM) // Check #0
141 me->err = 1;
142#endif
143}
144
145
146/*
147 Public function -- see UsefulBuf.h
148
149 The core of UsefulOutBuf -- put some bytes in the buffer without writing off the end of it.
150
151 Code Reviewers: THIS FUNCTION DOES POINTER MATH
152
153 This function inserts the source buffer, NewData, into the destination buffer, me->UB.ptr.
154
155 Destination is represented as:
156 me->UB.ptr -- start of the buffer
157 me->UB.len -- length of valid data in the buffer
158 me->size -- size of the buffer UB.ptr
159
160 Source is data:
161 NewData.ptr -- start of source buffer
162 NewData.len -- length of source buffer
163
164 Insertion point:
165 uInsertionPos.
166
167 Steps:
168
169 0. Corruption checks on UsefulOutBuf
170
171 1. Figure out if the new data will fit or not
172
173 2. Is insertion position in the range of valid data?
174
175 3. If insertion point is not at the end, slide data to the right of the insertion point to the right
176
177 4. Put the new data in at the insertion position.
178
179 */
180void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData, size_t uInsertionPos)
181{
182 if(me->err) {
183 // Already in error state.
184 return;
185 }
186
187 /* 0. Sanity check the UsefulOutBuf structure */
188 // A "counter measure". If magic number is not the right number it
189 // probably means me was not initialized or it was corrupted. Attackers
190 // can defeat this, but it is a hurdle and does good with very
191 // little code.
192 if(me->magic != USEFUL_OUT_BUF_MAGIC) {
193 me->err = 1;
194 return; // Magic number is wrong due to uninitalization or corrption
195 }
196
197 // Make sure valid data is less than buffer size. This would only occur
198 // if there was corruption of me, but it is also part of the checks to
199 // be sure there is no pointer arithmatic under/overflow.
200 if(me->UB.len > me->size) { // Check #1
201 me->err = 1;
202 return; // Offset of valid data is off the end of the UsefulOutBuf due to uninitialization or corruption
203 }
204
205 /* 1. Will it fit? */
206 // WillItFit() is the same as: NewData.len <= (me->size - me->UB.len)
207 // Check #1 makes sure subtraction in RoomLeft will not wrap around
208 if(! UsefulOutBuf_WillItFit(me, NewData.len)) { // Check #2
209 // The new data will not fit into the the buffer.
210 me->err = 1;
211 return;
212 }
213
214 /* 2. Check the Insertion Position */
215 // This, with Check #1, also confirms that uInsertionPos <= me->size
216 if(uInsertionPos > me->UB.len) { // Check #3
217 // Off the end of the valid data in the buffer.
218 me->err = 1;
219 return;
220 }
221
222 /* 3. Slide existing data to the right */
223 uint8_t *pSourceOfMove = ((uint8_t *)me->UB.ptr) + uInsertionPos; // PtrMath #1
224 size_t uNumBytesToMove = me->UB.len - uInsertionPos; // PtrMath #2
225 uint8_t *pDestinationOfMove = pSourceOfMove + NewData.len; // PtrMath #3
226 size_t uRoomInDestination = me->size - (uInsertionPos + NewData.len); // PtrMath #4
227
228 if(uNumBytesToMove && me->UB.ptr) {
Laurence Lundblade74f68412018-09-13 12:18:49 -0700229 memmove(pDestinationOfMove, pSourceOfMove, uNumBytesToMove);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700230 }
231
232 /* 4. Put the new data in */
233 uint8_t *pInsertionPoint = ((uint8_t *)me->UB.ptr) + uInsertionPos; // PtrMath #5
234 uRoomInDestination = me->size - uInsertionPos; // PtrMath #6
235 if(me->UB.ptr) {
Laurence Lundblade74f68412018-09-13 12:18:49 -0700236 memmove(pInsertionPoint, NewData.ptr, NewData.len);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700237 }
238 me->UB.len += NewData.len ;
239}
240
241
242/*
243 Rationale that describes why the above pointer math is safe
244
245 PtrMath #1 will never wrap around over because
246 Check #0 in UsefulOutBuf_Init makes sure me-UB.ptr + me->size doesn't wrap
247 Check #1 makes sure me->UB.len is less than me->size
248 Check #3 makes sure uInsertionPos is less than me->UB.len
249
250 PtrMath #2 will never wrap around under because
251 Check #3 makes sure uInsertionPos is less than me->UB.len
252
253 PtrMath #3 will never wrap around over because todo
254 PtrMath #1 is checked resulting in pStartOfDataToMove being between me->UB.ptr and a maximum valid ptr
255
256 PtrMath #4 will never wrap under because
257 Check #3 makes sure uInsertionPos is less than me->UB.len
258 Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos)
259 This algebraically rearranges to me->size > uInsertionPos + NewData.len
260
261 PtrMath #5 is exactly the same as PtrMath #1
262
263 PtrMath #6 will never wrap under because
264 Check #1 makes sure me->UB.len is less than me->size
265 Check #3 makes sure uInsertionPos is less than me->UB.len
266 */
267
268
269/*
270 Public function -- see UsefulBuf.h
271
272 Returns the resulting valid data in a UsefulBuf
273
274 */
275int UsefulOutBuf_OutUBuf(UsefulOutBuf *me, UsefulBuf *O)
276{
277 if(me->err) {
278 return me->err;
279 }
280
281 if(me->magic != USEFUL_OUT_BUF_MAGIC) {
282 me->err = 1;
283 return 1;
284 }
285
286 *O = me->UB;
287 return 0;
288}
289
290
291/*
292 Public function -- see UsefulBuf.h
293
294 Copy out the data accumulated in the output buffer.
295
296 */
297int UsefulOutBuf_CopyOut(UsefulOutBuf *me, void *pBuf, size_t uBufSize, size_t *puCopied)
298{
299 UsefulBuf B;
300 if(UsefulOutBuf_OutUBuf(me, &B)) {
301 return 1; // was in error state or was corrupted
302 }
303
304 if(B.len > uBufSize) {
305 return 1; // buffer was too small
306 }
307
Laurence Lundblade74f68412018-09-13 12:18:49 -0700308 memmove(pBuf, B.ptr, B.len);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700309
310 *puCopied = me->UB.len;
311
312 return 0;
313}
314
315
316
317
318/*
319 Public function -- see UsefulBuf.h
320
321 The core of UsefulInputBuf -- consume some bytes without going off the end of the buffer.
322
323 Code Reviewers: THIS FUNCTION DOES POINTER MATH
324 */
325const void * UsefulInputBuf_GetBytes(UsefulInputBuf *me, size_t uAmount)
326{
327 // Already in error state. Do nothing.
328 if(me->err) {
329 return NULL;
330 }
331
332 if(!UsefulInputBuf_BytesAvailable(me, uAmount)) {
333 // The number of bytes asked for at current position are more than available
334 me->err = 1;
335 return NULL;
336 }
337
338 // This is going to succeed
339 const void * const result = ((uint8_t *)me->UB.ptr) + me->cursor;
340 me->cursor += uAmount; // this will not overflow because of check using UsefulInputBuf_BytesAvailable()
341 return result;
342}
343