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