xref: /optee_os/core/lib/qcbor/src/UsefulBuf.c (revision 2e6f5bf11f69414c8c2cedf3c2bd7eab8aa5beb3)
1 /* ==========================================================================
2  * Copyright (c) 2016-2018, The Linux Foundation.
3  * Copyright (c) 2018-2024, Laurence Lundblade.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
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  *
20  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
21  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  * ========================================================================= */
32 
33 
34 
35 /*=============================================================================
36  FILE:  UsefulBuf.c
37 
38  DESCRIPTION:  General purpose input and output buffers
39 
40  EDIT HISTORY FOR FILE:
41 
42  This section contains comments describing changes made to the module.
43  Notice that changes are listed in reverse chronological order.
44 
45  when        who          what, where, why
46  --------    ----         ---------------------------------------------------
47  21/05/2024  llundblade   Comment formatting and some code tidiness.
48  19/12/2022  llundblade   Don't pass NULL to memmove when adding empty data.
49  4/11/2022   llundblade   Add GetOutPlace and Advance to UsefulOutBuf
50  3/6/2021    mcr/llundblade  Fix warnings related to --Wcast-qual
51  01/28/2020  llundblade   Refine integer signedness to quiet static analysis.
52  01/08/2020  llundblade   Documentation corrections & improved code formatting.
53  11/08/2019  llundblade   Re check pointer math and update comments
54  3/6/2019    llundblade   Add UsefulBuf_IsValue()
55  09/07/17    llundbla     Fix critical bug in UsefulBuf_Find() -- a read off
56                           the end of memory when the bytes to find is longer
57                           than the bytes to search.
58  06/27/17    llundbla     Fix UsefulBuf_Compare() bug. Only affected comparison
59                           for < or > for unequal length buffers.  Added
60                           UsefulBuf_Set() function.
61  05/30/17    llundbla     Functions for NULL UsefulBufs and const / unconst
62  11/13/16    llundbla     Initial Version.
63 
64  ============================================================================*/
65 
66 #include "UsefulBuf.h"
67 
68 /* used to catch use of uninitialized or corrupted UsefulOutBuf */
69 #define USEFUL_OUT_BUF_MAGIC  (0x0B0F)
70 
71 
72 /*
73  * Public function -- see UsefulBuf.h
74  */
75 UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src)
76 {
77    /* Do this with subtraction so it doesn't give an erroneous
78     * result if uOffset + Src.len overflows. Right side is equivalent to
79     * uOffset + Src.len > Dest.len
80     */
81    if(uOffset > Dest.len || Src.len > Dest.len - uOffset) {
82       return NULLUsefulBufC;
83    }
84 
85    memcpy((uint8_t *)Dest.ptr + uOffset, Src.ptr, Src.len);
86 
87    return (UsefulBufC){Dest.ptr, Src.len + uOffset};
88 }
89 
90 
91 /*
92  * Public function -- see UsefulBuf.h
93  */
94 int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2)
95 {
96    /* Use comparisons rather than subtracting lengths to
97     * return an int instead of a size_t
98     */
99    if(UB1.len < UB2.len) {
100       return -1;
101    } else if (UB1.len > UB2.len) {
102       return 1;
103    } /* else UB1.len == UB2.len */
104 
105    return memcmp(UB1.ptr, UB2.ptr, UB1.len);
106 }
107 
108 
109 /*
110  * Public function -- see UsefulBuf.h
111  */
112 size_t UsefulBuf_IsValue(const UsefulBufC UB, uint8_t uValue)
113 {
114    if(UsefulBuf_IsNULLOrEmptyC(UB)) {
115       /* Not a match */
116       return 0;
117    }
118 
119    const uint8_t * const pEnd = (const uint8_t *)UB.ptr + UB.len;
120    for(const uint8_t *p = UB.ptr; p < pEnd; p++) {
121       if(*p != uValue) {
122          /* Byte didn't match */
123          /* Cast from signed to unsigned. Safe because the loop increments.*/
124          return (size_t)(p - (const uint8_t *)UB.ptr);
125       }
126    }
127 
128    /* Success. All bytes matched */
129    return SIZE_MAX;
130 }
131 
132 
133 /*
134  * Public function -- see UsefulBuf.h
135  */
136 size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind)
137 {
138    if(BytesToSearch.len < BytesToFind.len) {
139       return SIZE_MAX;
140    }
141 
142    for(size_t uPos = 0; uPos <= BytesToSearch.len - BytesToFind.len; uPos++) {
143       UsefulBufC SearchNext;
144 
145       SearchNext.ptr = ((const uint8_t *)BytesToSearch.ptr) + uPos;
146       SearchNext.len = BytesToFind.len;
147       if(!UsefulBuf_Compare(SearchNext, BytesToFind)) {
148          return uPos;
149       }
150    }
151 
152    return SIZE_MAX;
153 }
154 
155 
156 /*
157  * Public function -- see UsefulBuf.h
158  *
159  * Code Reviewers: THIS FUNCTION DOES POINTER MATH
160  */
161 void UsefulOutBuf_Init(UsefulOutBuf *pMe, UsefulBuf Storage)
162 {
163     pMe->magic  = USEFUL_OUT_BUF_MAGIC;
164     UsefulOutBuf_Reset(pMe);
165     pMe->UB     = Storage;
166 
167 #if 0
168    /* This check is off by default.
169     *
170     * The following check fails on ThreadX
171     *
172     * Sanity check on the pointer and size to be sure we are not
173     * passed a buffer that goes off the end of the address space.
174     * Given this test, we know that all unsigned lengths less than
175     * me->size are valid and won't wrap in any pointer additions
176     * based off of pStorage in the rest of this code.
177     */
178     const uintptr_t ptrM = UINTPTR_MAX - Storage.len;
179     if(Storage.ptr && (uintptr_t)Storage.ptr > ptrM) /* Check #0 */
180         me->err = 1;
181 #endif
182 }
183 
184 
185 
186 /*
187  * Public function -- see UsefulBuf.h
188  *
189  * The core of UsefulOutBuf -- put some bytes in the buffer without writing off
190  *                             the end of it.
191  *
192  * Code Reviewers: THIS FUNCTION DOES POINTER MATH
193  *
194  * This function inserts the source buffer, NewData, into the destination
195  * buffer, me->UB.ptr.
196  *
197  * Destination is represented as:
198  *   me->UB.ptr -- start of the buffer
199  *   me->UB.len -- size of the buffer UB.ptr
200  *   me->data_len -- length of value data in UB
201  *
202  * Source is data:
203  *   NewData.ptr -- start of source buffer
204  *   NewData.len -- length of source buffer
205  *
206  * Insertion point:
207  *   uInsertionPos.
208  *
209  * Steps:
210  *
211  * 0. Corruption checks on UsefulOutBuf
212  *
213  * 1. Figure out if the new data will fit or not
214  *
215  * 2. Is insertion position in the range of valid data?
216  *
217  * 3. If insertion point is not at the end, slide data to the right of the
218  *    insertion point to the right
219  *
220  * 4. Put the new data in at the insertion position.
221  *
222  */
223 void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *pMe, UsefulBufC NewData, size_t uInsertionPos)
224 {
225    if(pMe->err) {
226       /* Already in error state. */
227       return;
228    }
229 
230    /* 0. Sanity check the UsefulOutBuf structure
231     * A "counter measure". If magic number is not the right number it
232     * probably means pMe was not initialized or it was corrupted. Attackers
233     * can defeat this, but it is a hurdle and does good with very
234     * little code.
235     */
236    if(pMe->magic != USEFUL_OUT_BUF_MAGIC) {
237       pMe->err = 1;
238       return;  /* Magic number is wrong due to uninitalization or corrption */
239    }
240 
241    /* Make sure valid data is less than buffer size. This would only occur
242     * if there was corruption of me, but it is also part of the checks to
243     * be sure there is no pointer arithmatic under/overflow.
244     */
245    if(pMe->data_len > pMe->UB.len) {  /* Check #1 */
246       pMe->err = 1;
247       /* Offset of valid data is off the end of the UsefulOutBuf due to
248        * uninitialization or corruption
249        */
250       return;
251    }
252 
253    /* 1. Will it fit?
254     * WillItFit() is the same as: NewData.len <= (me->UB.len - me->data_len)
255     * Check #1 makes sure subtraction in RoomLeft will not wrap around
256     */
257    if(! UsefulOutBuf_WillItFit(pMe, NewData.len)) { /* Check #2 */
258       /* The new data will not fit into the the buffer. */
259       pMe->err = 1;
260       return;
261    }
262 
263    /* 2. Check the Insertion Position
264     * This, with Check #1, also confirms that uInsertionPos <= me->data_len and
265     * that uInsertionPos + pMe->UB.ptr will not wrap around the end of the
266     * address space.
267     */
268    if(uInsertionPos > pMe->data_len) { /* Check #3 */
269       /* Off the end of the valid data in the buffer. */
270       pMe->err = 1;
271       return;
272    }
273 
274    /* 3. Slide existing data to the right */
275    if (!UsefulOutBuf_IsBufferNULL(pMe)) {
276       uint8_t *pSourceOfMove      = ((uint8_t *)pMe->UB.ptr) + uInsertionPos; /* PtrMath #1 */
277       size_t   uNumBytesToMove    = pMe->data_len - uInsertionPos; /* PtrMath #2 */
278       uint8_t *pDestinationOfMove = pSourceOfMove + NewData.len; /* PtrMath #3*/
279 
280       /* To know memmove won't go off end of destination, see PtrMath #4.
281        * Use memove because it handles overlapping buffers
282        */
283       memmove(pDestinationOfMove, pSourceOfMove, uNumBytesToMove);
284 
285       /* 4. Put the new data in */
286       uint8_t *pInsertionPoint = pSourceOfMove;
287       /* To know memmove won't go off end of destination, see PtrMath #5 */
288       if(NewData.ptr != NULL) {
289          memmove(pInsertionPoint, NewData.ptr, NewData.len);
290       }
291    }
292 
293    pMe->data_len += NewData.len;
294 }
295 
296 
297 /*
298  * Rationale that describes why the above pointer math is safe
299  *
300  * PtrMath #1 will never wrap around over because
301  *   Check #0 in UsefulOutBuf_Init that me->UB.ptr + me->UB.len doesn't wrap
302  *   Check #1 makes sure me->data_len is less than me->UB.len
303  *   Check #3 makes sure uInsertionPos is less than me->data_len
304  *
305  * PtrMath #2 will never wrap around under because
306  *   Check #3 makes sure uInsertionPos is less than me->data_len
307  *
308  * PtrMath #3 will never wrap around over because
309  *   PtrMath #1 is checked resulting in pSourceOfMove being between me->UB.ptr and me->UB.ptr + me->data_len
310  *   Check #2 that NewData.len will fit in the unused space left in me->UB
311  *
312  * PtrMath #4 will never wrap under because
313  *   Calculation for extent or memmove is uRoomInDestination  = me->UB.len - (uInsertionPos + NewData.len)
314  *   Check #3 makes sure uInsertionPos is less than me->data_len
315  *   Check #3 allows Check #2 to be refactored as NewData.Len > (me->size - uInsertionPos)
316  *   This algebraically rearranges to me->size > uInsertionPos + NewData.len
317  *
318  * PtrMath #5 will never wrap under because
319  *   Calculation for extent of memove is uRoomInDestination = me->UB.len - uInsertionPos;
320  *   Check #1 makes sure me->data_len is less than me->size
321  *   Check #3 makes sure uInsertionPos is less than me->data_len
322  */
323 
324 
325 /*
326  * Public function for advancing data length. See qcbor/UsefulBuf.h
327  */
328 void UsefulOutBuf_Advance(UsefulOutBuf *pMe, size_t uAmount)
329 {
330    /* This function is a trimmed down version of
331     * UsefulOutBuf_InsertUsefulBuf(). This could be combined with the
332     * code in UsefulOutBuf_InsertUsefulBuf(), but that would make
333     * UsefulOutBuf_InsertUsefulBuf() bigger and this will be very
334     * rarely used.
335     */
336 
337    if(pMe->err) {
338       /* Already in error state. */
339       return;
340    }
341 
342    /* 0. Sanity check the UsefulOutBuf structure
343     *
344     * A "counter measure". If magic number is not the right number it
345     * probably means me was not initialized or it was
346     * corrupted. Attackers can defeat this, but it is a hurdle and
347     * does good with very little code.
348     */
349    if(pMe->magic != USEFUL_OUT_BUF_MAGIC) {
350       pMe->err = 1;
351       return;  /* Magic number is wrong due to uninitalization or corrption */
352    }
353 
354    /* Make sure valid data is less than buffer size. This would only
355     * occur if there was corruption of me, but it is also part of the
356     * checks to be sure there is no pointer arithmatic
357     * under/overflow.
358     */
359    if(pMe->data_len > pMe->UB.len) {  /* Check #1 */
360       pMe->err = 1;
361       /* Offset of valid data is off the end of the UsefulOutBuf due
362        * to uninitialization or corruption.
363        */
364       return;
365    }
366 
367    /* 1. Will it fit?
368     *
369     * WillItFit() is the same as: NewData.len <= (me->UB.len -
370     * me->data_len) Check #1 makes sure subtraction in RoomLeft will
371     * not wrap around
372     */
373    if(! UsefulOutBuf_WillItFit(pMe, uAmount)) { /* Check #2 */
374       /* The new data will not fit into the the buffer. */
375       pMe->err = 1;
376       return;
377    }
378 
379    pMe->data_len += uAmount;
380 }
381 
382 
383 /*
384  * Public function -- see UsefulBuf.h
385  */
386 UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pMe)
387 {
388    if(pMe->err) {
389       return NULLUsefulBufC;
390    }
391 
392    if(pMe->magic != USEFUL_OUT_BUF_MAGIC) {
393       pMe->err = 1;
394       return NULLUsefulBufC;
395    }
396 
397    return (UsefulBufC){pMe->UB.ptr, pMe->data_len};
398 }
399 
400 
401 /*
402  * Public function -- see UsefulBuf.h
403  *
404  * Copy out the data accumulated in to the output buffer.
405  */
406 UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pMe, UsefulBuf pDest)
407 {
408    const UsefulBufC Tmp = UsefulOutBuf_OutUBuf(pMe);
409    if(UsefulBuf_IsNULLC(Tmp)) {
410       return NULLUsefulBufC;
411    }
412    return UsefulBuf_Copy(pDest, Tmp);
413 }
414 
415 
416 
417 
418 /*
419  * Public function -- see UsefulBuf.h
420  *
421  * The core of UsefulInputBuf -- consume bytes without going off end of buffer.
422  *
423  * Code Reviewers: THIS FUNCTION DOES POINTER MATH
424  */
425 const void * UsefulInputBuf_GetBytes(UsefulInputBuf *pMe, size_t uAmount)
426 {
427    /* Already in error state. Do nothing. */
428    if(pMe->err) {
429       return NULL;
430    }
431 
432    if(!UsefulInputBuf_BytesAvailable(pMe, uAmount)) {
433       /* Number of bytes asked for is more than available */
434       pMe->err = 1;
435       return NULL;
436    }
437 
438    /* This is going to succeed */
439    const void * const result = ((const uint8_t *)pMe->UB.ptr) + pMe->cursor;
440    /* Won't overflow because of check using UsefulInputBuf_BytesAvailable() */
441    pMe->cursor += uAmount;
442    return result;
443 }
444