/* * Copyright (c) 2022 Google Inc. All rights reserved * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, * including without limitation the rights to use, copy, modify, merge, * publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include #define LOCAL_TRACE (0) extern char __trusty_dtb_start; extern char __trusty_dtb_end; struct dtb_embedded_iterator { uintptr_t offset; }; void dtb_embedded_iterator_reset(struct dtb_embedded_iterator* iter) { if (iter) { iter->offset = 0; } } int dtb_embedded_iterator_new(struct dtb_embedded_iterator** piter) { ASSERT(piter); struct dtb_embedded_iterator* iter = (struct dtb_embedded_iterator*)calloc( 1, sizeof(struct dtb_embedded_iterator)); if (!iter) { TRACEF("failed to allocate iterator\n"); return ERR_NO_MEMORY; } dtb_embedded_iterator_reset(iter); *piter = iter; return NO_ERROR; } void dtb_embedded_iterator_free(struct dtb_embedded_iterator** piter) { ASSERT(piter); if (*piter) { free(*piter); *piter = NULL; } } int dtb_embedded_iterator_next(struct dtb_embedded_iterator* iter, const void** dtb, size_t* dtb_size) { if (!iter) { TRACEF("Invalid iterator\n"); return ERR_INVALID_ARGS; } if (!dtb) { TRACEF("Invalid dtb pointer\n"); return ERR_INVALID_ARGS; } if (!dtb_size) { TRACEF("Invalid dtb size pointer\n"); return ERR_INVALID_ARGS; } /* Check that the iterator is within the embedded dtb range */ uintptr_t end = (uintptr_t)&__trusty_dtb_end; uintptr_t start = (uintptr_t)&__trusty_dtb_start; uintptr_t total_size = end - start; if (iter->offset >= total_size) { TRACEF("Embedded dtb iterator at offset %" PRIuPTR "out of range\n", iter->offset); return ERR_OUT_OF_RANGE; } /* Validate the header of the next dtb */ const void* dtb_start = (const void*)(start + iter->offset); int rc = fdt_check_header(dtb_start); if (rc < 0) { TRACEF("Embedded dtb at offset %" PRIuPTR " has an invalid header (%d)\n", iter->offset, rc); return ERR_BAD_STATE; } /* * Check that the dtb size is in the expected range. Each dtb's size is read * from its header plus 4 bytes from the symbol size inserted by * INCBIN_ALIGNED. Then we round up to 8 bytes since each individual dtb is * 8-byte aligned. */ const size_t dtb_alignment = 8; const size_t sym_size = 4; size_t next_dtb_size = round_up(fdt_totalsize(dtb_start) + sym_size, dtb_alignment); if (next_dtb_size + iter->offset > total_size) { TRACEF("Embedded dtb at offset %" PRIuPTR " has invalid size %zu\n", iter->offset, next_dtb_size); return ERR_BAD_LEN; } iter->offset += next_dtb_size; *dtb = dtb_start; *dtb_size = next_dtb_size; LTRACEF("Found embedded dtb at offset %" PRIuPTR "\n", iter->offset); return NO_ERROR; }