1 // SPDX-License-Identifier: (GPL-2.0-or-later << 2 /* 1 /* 3 * libfdt - Flat Device Tree manipulation 2 * libfdt - Flat Device Tree manipulation 4 * Copyright (C) 2006 David Gibson, IBM Corpor 3 * Copyright (C) 2006 David Gibson, IBM Corporation. >> 4 * >> 5 * libfdt is dual licensed: you can use it either under the terms of >> 6 * the GPL, or the BSD license, at your option. >> 7 * >> 8 * a) This library is free software; you can redistribute it and/or >> 9 * modify it under the terms of the GNU General Public License as >> 10 * published by the Free Software Foundation; either version 2 of the >> 11 * License, or (at your option) any later version. >> 12 * >> 13 * This library is distributed in the hope that it will be useful, >> 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of >> 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> 16 * GNU General Public License for more details. >> 17 * >> 18 * You should have received a copy of the GNU General Public >> 19 * License along with this library; if not, write to the Free >> 20 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, >> 21 * MA 02110-1301 USA >> 22 * >> 23 * Alternatively, >> 24 * >> 25 * b) Redistribution and use in source and binary forms, with or >> 26 * without modification, are permitted provided that the following >> 27 * conditions are met: >> 28 * >> 29 * 1. Redistributions of source code must retain the above >> 30 * copyright notice, this list of conditions and the following >> 31 * disclaimer. >> 32 * 2. Redistributions in binary form must reproduce the above >> 33 * copyright notice, this list of conditions and the following >> 34 * disclaimer in the documentation and/or other materials >> 35 * provided with the distribution. >> 36 * >> 37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND >> 38 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, >> 39 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF >> 40 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE >> 41 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR >> 42 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, >> 43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT >> 44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; >> 45 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) >> 46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >> 47 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR >> 48 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, >> 49 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 5 */ 50 */ 6 #include "libfdt_env.h" 51 #include "libfdt_env.h" 7 52 8 #include <fdt.h> 53 #include <fdt.h> 9 #include <libfdt.h> 54 #include <libfdt.h> 10 55 11 #include "libfdt_internal.h" 56 #include "libfdt_internal.h" 12 57 13 /* 58 /* 14 * Minimal sanity check for a read-only tree. 59 * Minimal sanity check for a read-only tree. fdt_ro_probe_() checks 15 * that the given buffer contains what appears 60 * that the given buffer contains what appears to be a flattened 16 * device tree with sane information in its he 61 * device tree with sane information in its header. 17 */ 62 */ 18 int32_t fdt_ro_probe_(const void *fdt) !! 63 int fdt_ro_probe_(const void *fdt) 19 { 64 { 20 uint32_t totalsize = fdt_totalsize(fdt << 21 << 22 if (can_assume(VALID_DTB)) << 23 return totalsize; << 24 << 25 /* The device tree must be at an 8-byt << 26 if ((uintptr_t)fdt & 7) << 27 return -FDT_ERR_ALIGNMENT; << 28 << 29 if (fdt_magic(fdt) == FDT_MAGIC) { 65 if (fdt_magic(fdt) == FDT_MAGIC) { 30 /* Complete tree */ 66 /* Complete tree */ 31 if (!can_assume(LATEST)) { !! 67 if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) 32 if (fdt_version(fdt) < !! 68 return -FDT_ERR_BADVERSION; 33 return -FDT_ER !! 69 if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) 34 if (fdt_last_comp_vers !! 70 return -FDT_ERR_BADVERSION; 35 FDT_LA << 36 return -FDT_ER << 37 } << 38 } else if (fdt_magic(fdt) == FDT_SW_MA 71 } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { 39 /* Unfinished sequential-write 72 /* Unfinished sequential-write blob */ 40 if (!can_assume(VALID_INPUT) & !! 73 if (fdt_size_dt_struct(fdt) == 0) 41 return -FDT_ERR_BADSTA 74 return -FDT_ERR_BADSTATE; 42 } else { 75 } else { 43 return -FDT_ERR_BADMAGIC; 76 return -FDT_ERR_BADMAGIC; 44 } 77 } 45 78 46 if (totalsize < INT32_MAX) !! 79 return 0; 47 return totalsize; << 48 else << 49 return -FDT_ERR_TRUNCATED; << 50 } 80 } 51 81 52 static int check_off_(uint32_t hdrsize, uint32 82 static int check_off_(uint32_t hdrsize, uint32_t totalsize, uint32_t off) 53 { 83 { 54 return (off >= hdrsize) && (off <= tot 84 return (off >= hdrsize) && (off <= totalsize); 55 } 85 } 56 86 57 static int check_block_(uint32_t hdrsize, uint 87 static int check_block_(uint32_t hdrsize, uint32_t totalsize, 58 uint32_t base, uint32_ 88 uint32_t base, uint32_t size) 59 { 89 { 60 if (!check_off_(hdrsize, totalsize, ba 90 if (!check_off_(hdrsize, totalsize, base)) 61 return 0; /* block start out o 91 return 0; /* block start out of bounds */ 62 if ((base + size) < base) 92 if ((base + size) < base) 63 return 0; /* overflow */ 93 return 0; /* overflow */ 64 if (!check_off_(hdrsize, totalsize, ba 94 if (!check_off_(hdrsize, totalsize, base + size)) 65 return 0; /* block end out of 95 return 0; /* block end out of bounds */ 66 return 1; 96 return 1; 67 } 97 } 68 98 69 size_t fdt_header_size_(uint32_t version) 99 size_t fdt_header_size_(uint32_t version) 70 { 100 { 71 if (version <= 1) 101 if (version <= 1) 72 return FDT_V1_SIZE; 102 return FDT_V1_SIZE; 73 else if (version <= 2) 103 else if (version <= 2) 74 return FDT_V2_SIZE; 104 return FDT_V2_SIZE; 75 else if (version <= 3) 105 else if (version <= 3) 76 return FDT_V3_SIZE; 106 return FDT_V3_SIZE; 77 else if (version <= 16) 107 else if (version <= 16) 78 return FDT_V16_SIZE; 108 return FDT_V16_SIZE; 79 else 109 else 80 return FDT_V17_SIZE; 110 return FDT_V17_SIZE; 81 } 111 } 82 112 83 size_t fdt_header_size(const void *fdt) << 84 { << 85 return can_assume(LATEST) ? FDT_V17_SI << 86 fdt_header_size_(fdt_version(f << 87 } << 88 << 89 int fdt_check_header(const void *fdt) 113 int fdt_check_header(const void *fdt) 90 { 114 { 91 size_t hdrsize; 115 size_t hdrsize; 92 116 93 /* The device tree must be at an 8-byt << 94 if ((uintptr_t)fdt & 7) << 95 return -FDT_ERR_ALIGNMENT; << 96 << 97 if (fdt_magic(fdt) != FDT_MAGIC) 117 if (fdt_magic(fdt) != FDT_MAGIC) 98 return -FDT_ERR_BADMAGIC; 118 return -FDT_ERR_BADMAGIC; 99 if (!can_assume(LATEST)) { << 100 if ((fdt_version(fdt) < FDT_FI << 101 || (fdt_last_comp_version( << 102 FDT_LAST_SUPPORTED_VER << 103 return -FDT_ERR_BADVER << 104 if (fdt_version(fdt) < fdt_las << 105 return -FDT_ERR_BADVER << 106 } << 107 hdrsize = fdt_header_size(fdt); 119 hdrsize = fdt_header_size(fdt); 108 if (!can_assume(VALID_DTB)) { !! 120 if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) 109 if ((fdt_totalsize(fdt) < hdrs !! 121 || (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)) 110 || (fdt_totalsize(fdt) > I !! 122 return -FDT_ERR_BADVERSION; 111 return -FDT_ERR_TRUNCA !! 123 if (fdt_version(fdt) < fdt_last_comp_version(fdt)) >> 124 return -FDT_ERR_BADVERSION; 112 125 113 /* Bounds check memrsv block * !! 126 if ((fdt_totalsize(fdt) < hdrsize) 114 if (!check_off_(hdrsize, fdt_t !! 127 || (fdt_totalsize(fdt) > INT_MAX)) 115 fdt_off_mem_rs !! 128 return -FDT_ERR_TRUNCATED; 116 return -FDT_ERR_TRUNCA << 117 129 118 /* Bounds check structure bloc !! 130 /* Bounds check memrsv block */ 119 if (!can_assume(LATEST) && fdt !! 131 if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt))) 120 if (!check_off_(hdrsiz !! 132 return -FDT_ERR_TRUNCATED; 121 fdt_of << 122 return -FDT_ER << 123 } else { << 124 if (!check_block_(hdrs << 125 fdt_ << 126 fdt_ << 127 return -FDT_ER << 128 } << 129 133 130 /* Bounds check strings block !! 134 /* Bounds check structure block */ >> 135 if (fdt_version(fdt) < 17) { >> 136 if (!check_off_(hdrsize, fdt_totalsize(fdt), >> 137 fdt_off_dt_struct(fdt))) >> 138 return -FDT_ERR_TRUNCATED; >> 139 } else { 131 if (!check_block_(hdrsize, fdt 140 if (!check_block_(hdrsize, fdt_totalsize(fdt), 132 fdt_off_dt_s !! 141 fdt_off_dt_struct(fdt), 133 fdt_size_dt_ !! 142 fdt_size_dt_struct(fdt))) 134 return -FDT_ERR_TRUNCA 143 return -FDT_ERR_TRUNCATED; 135 } 144 } 136 145 >> 146 /* Bounds check strings block */ >> 147 if (!check_block_(hdrsize, fdt_totalsize(fdt), >> 148 fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt))) >> 149 return -FDT_ERR_TRUNCATED; >> 150 137 return 0; 151 return 0; 138 } 152 } 139 153 140 const void *fdt_offset_ptr(const void *fdt, in 154 const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) 141 { 155 { 142 unsigned int uoffset = offset; !! 156 unsigned absoffset = offset + fdt_off_dt_struct(fdt); 143 unsigned int absoffset = offset + fdt_ << 144 157 145 if (offset < 0) !! 158 if ((absoffset < offset) >> 159 || ((absoffset + len) < absoffset) >> 160 || (absoffset + len) > fdt_totalsize(fdt)) 146 return NULL; 161 return NULL; 147 162 148 if (!can_assume(VALID_INPUT)) !! 163 if (fdt_version(fdt) >= 0x11) 149 if ((absoffset < uoffset) !! 164 if (((offset + len) < offset) 150 || ((absoffset + len) < ab << 151 || (absoffset + len) > fdt << 152 return NULL; << 153 << 154 if (can_assume(LATEST) || fdt_version( << 155 if (((uoffset + len) < uoffset << 156 || ((offset + len) > fdt_s 165 || ((offset + len) > fdt_size_dt_struct(fdt))) 157 return NULL; 166 return NULL; 158 167 159 return fdt_offset_ptr_(fdt, offset); 168 return fdt_offset_ptr_(fdt, offset); 160 } 169 } 161 170 162 uint32_t fdt_next_tag(const void *fdt, int sta 171 uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) 163 { 172 { 164 const fdt32_t *tagp, *lenp; 173 const fdt32_t *tagp, *lenp; 165 uint32_t tag, len, sum; !! 174 uint32_t tag; 166 int offset = startoffset; 175 int offset = startoffset; 167 const char *p; 176 const char *p; 168 177 169 *nextoffset = -FDT_ERR_TRUNCATED; 178 *nextoffset = -FDT_ERR_TRUNCATED; 170 tagp = fdt_offset_ptr(fdt, offset, FDT 179 tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); 171 if (!can_assume(VALID_DTB) && !tagp) !! 180 if (!tagp) 172 return FDT_END; /* premature e 181 return FDT_END; /* premature end */ 173 tag = fdt32_to_cpu(*tagp); 182 tag = fdt32_to_cpu(*tagp); 174 offset += FDT_TAGSIZE; 183 offset += FDT_TAGSIZE; 175 184 176 *nextoffset = -FDT_ERR_BADSTRUCTURE; 185 *nextoffset = -FDT_ERR_BADSTRUCTURE; 177 switch (tag) { 186 switch (tag) { 178 case FDT_BEGIN_NODE: 187 case FDT_BEGIN_NODE: 179 /* skip name */ 188 /* skip name */ 180 do { 189 do { 181 p = fdt_offset_ptr(fdt 190 p = fdt_offset_ptr(fdt, offset++, 1); 182 } while (p && (*p != '\0')); 191 } while (p && (*p != '\0')); 183 if (!can_assume(VALID_DTB) && !! 192 if (!p) 184 return FDT_END; /* pre 193 return FDT_END; /* premature end */ 185 break; 194 break; 186 195 187 case FDT_PROP: 196 case FDT_PROP: 188 lenp = fdt_offset_ptr(fdt, off 197 lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); 189 if (!can_assume(VALID_DTB) && !! 198 if (!lenp) 190 return FDT_END; /* pre 199 return FDT_END; /* premature end */ 191 << 192 len = fdt32_to_cpu(*lenp); << 193 sum = len + offset; << 194 if (!can_assume(VALID_DTB) && << 195 (INT_MAX <= sum || sum < ( << 196 return FDT_END; /* pre << 197 << 198 /* skip-name offset, length an 200 /* skip-name offset, length and value */ 199 offset += sizeof(struct fdt_pr !! 201 offset += sizeof(struct fdt_property) - FDT_TAGSIZE 200 !! 202 + fdt32_to_cpu(*lenp); 201 if (!can_assume(LATEST) && !! 203 if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 && 202 fdt_version(fdt) < 0x10 && !! 204 ((offset - fdt32_to_cpu(*lenp)) % 8) != 0) 203 ((offset - len) % 8) != 0) << 204 offset += 4; 205 offset += 4; 205 break; 206 break; 206 207 207 case FDT_END: 208 case FDT_END: 208 case FDT_END_NODE: 209 case FDT_END_NODE: 209 case FDT_NOP: 210 case FDT_NOP: 210 break; 211 break; 211 212 212 default: 213 default: 213 return FDT_END; 214 return FDT_END; 214 } 215 } 215 216 216 if (!fdt_offset_ptr(fdt, startoffset, 217 if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) 217 return FDT_END; /* premature e 218 return FDT_END; /* premature end */ 218 219 219 *nextoffset = FDT_TAGALIGN(offset); 220 *nextoffset = FDT_TAGALIGN(offset); 220 return tag; 221 return tag; 221 } 222 } 222 223 223 int fdt_check_node_offset_(const void *fdt, in 224 int fdt_check_node_offset_(const void *fdt, int offset) 224 { 225 { 225 if (!can_assume(VALID_INPUT) !! 226 if ((offset < 0) || (offset % FDT_TAGSIZE) 226 && ((offset < 0) || (offset % FDT_ !! 227 || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) 227 return -FDT_ERR_BADOFFSET; << 228 << 229 if (fdt_next_tag(fdt, offset, &offset) << 230 return -FDT_ERR_BADOFFSET; 228 return -FDT_ERR_BADOFFSET; 231 229 232 return offset; 230 return offset; 233 } 231 } 234 232 235 int fdt_check_prop_offset_(const void *fdt, in 233 int fdt_check_prop_offset_(const void *fdt, int offset) 236 { 234 { 237 if (!can_assume(VALID_INPUT) !! 235 if ((offset < 0) || (offset % FDT_TAGSIZE) 238 && ((offset < 0) || (offset % FDT_ !! 236 || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) 239 return -FDT_ERR_BADOFFSET; << 240 << 241 if (fdt_next_tag(fdt, offset, &offset) << 242 return -FDT_ERR_BADOFFSET; 237 return -FDT_ERR_BADOFFSET; 243 238 244 return offset; 239 return offset; 245 } 240 } 246 241 247 int fdt_next_node(const void *fdt, int offset, 242 int fdt_next_node(const void *fdt, int offset, int *depth) 248 { 243 { 249 int nextoffset = 0; 244 int nextoffset = 0; 250 uint32_t tag; 245 uint32_t tag; 251 246 252 if (offset >= 0) 247 if (offset >= 0) 253 if ((nextoffset = fdt_check_no 248 if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0) 254 return nextoffset; 249 return nextoffset; 255 250 256 do { 251 do { 257 offset = nextoffset; 252 offset = nextoffset; 258 tag = fdt_next_tag(fdt, offset 253 tag = fdt_next_tag(fdt, offset, &nextoffset); 259 254 260 switch (tag) { 255 switch (tag) { 261 case FDT_PROP: 256 case FDT_PROP: 262 case FDT_NOP: 257 case FDT_NOP: 263 break; 258 break; 264 259 265 case FDT_BEGIN_NODE: 260 case FDT_BEGIN_NODE: 266 if (depth) 261 if (depth) 267 (*depth)++; 262 (*depth)++; 268 break; 263 break; 269 264 270 case FDT_END_NODE: 265 case FDT_END_NODE: 271 if (depth && ((--(*dep 266 if (depth && ((--(*depth)) < 0)) 272 return nextoff 267 return nextoffset; 273 break; 268 break; 274 269 275 case FDT_END: 270 case FDT_END: 276 if ((nextoffset >= 0) 271 if ((nextoffset >= 0) 277 || ((nextoffset == 272 || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) 278 return -FDT_ER 273 return -FDT_ERR_NOTFOUND; 279 else 274 else 280 return nextoff 275 return nextoffset; 281 } 276 } 282 } while (tag != FDT_BEGIN_NODE); 277 } while (tag != FDT_BEGIN_NODE); 283 278 284 return offset; 279 return offset; 285 } 280 } 286 281 287 int fdt_first_subnode(const void *fdt, int off 282 int fdt_first_subnode(const void *fdt, int offset) 288 { 283 { 289 int depth = 0; 284 int depth = 0; 290 285 291 offset = fdt_next_node(fdt, offset, &d 286 offset = fdt_next_node(fdt, offset, &depth); 292 if (offset < 0 || depth != 1) 287 if (offset < 0 || depth != 1) 293 return -FDT_ERR_NOTFOUND; 288 return -FDT_ERR_NOTFOUND; 294 289 295 return offset; 290 return offset; 296 } 291 } 297 292 298 int fdt_next_subnode(const void *fdt, int offs 293 int fdt_next_subnode(const void *fdt, int offset) 299 { 294 { 300 int depth = 1; 295 int depth = 1; 301 296 302 /* 297 /* 303 * With respect to the parent, the dep 298 * With respect to the parent, the depth of the next subnode will be 304 * the same as the last. 299 * the same as the last. 305 */ 300 */ 306 do { 301 do { 307 offset = fdt_next_node(fdt, of 302 offset = fdt_next_node(fdt, offset, &depth); 308 if (offset < 0 || depth < 1) 303 if (offset < 0 || depth < 1) 309 return -FDT_ERR_NOTFOU 304 return -FDT_ERR_NOTFOUND; 310 } while (depth > 1); 305 } while (depth > 1); 311 306 312 return offset; 307 return offset; 313 } 308 } 314 309 315 const char *fdt_find_string_(const char *strta 310 const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) 316 { 311 { 317 int len = strlen(s) + 1; 312 int len = strlen(s) + 1; 318 const char *last = strtab + tabsize - 313 const char *last = strtab + tabsize - len; 319 const char *p; 314 const char *p; 320 315 321 for (p = strtab; p <= last; p++) 316 for (p = strtab; p <= last; p++) 322 if (memcmp(p, s, len) == 0) 317 if (memcmp(p, s, len) == 0) 323 return p; 318 return p; 324 return NULL; 319 return NULL; 325 } 320 } 326 321 327 int fdt_move(const void *fdt, void *buf, int b 322 int fdt_move(const void *fdt, void *buf, int bufsize) 328 { 323 { 329 if (!can_assume(VALID_INPUT) && bufsiz << 330 return -FDT_ERR_NOSPACE; << 331 << 332 FDT_RO_PROBE(fdt); 324 FDT_RO_PROBE(fdt); 333 325 334 if (fdt_totalsize(fdt) > (unsigned int !! 326 if (fdt_totalsize(fdt) > bufsize) 335 return -FDT_ERR_NOSPACE; 327 return -FDT_ERR_NOSPACE; 336 328 337 memmove(buf, fdt, fdt_totalsize(fdt)); 329 memmove(buf, fdt, fdt_totalsize(fdt)); 338 return 0; 330 return 0; 339 } 331 } 340 332
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.