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