1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <string>
18 #include <unordered_map>
19
20 extern "C" {
21
22 #include "libufdt.h"
23 #include "ufdt_node_pool.h"
24 #include "ufdt_overlay.h"
25 #include "ufdt_overlay_internal.h"
26
27 }
28
29 #include "ufdt_test_overlay.h"
30
31 static bool ufdt_node_compare(struct ufdt_node *node_a, struct ufdt_node *node_b,
32 struct ufdt* tree_a, struct ufdt* tree_b);
33
34 /*
35 * Helper method to check if the tree rooted at node_b is a subset of the tree rooted
36 * at node_a.
37 */
compare_child_nodes(struct ufdt_node * node_a,struct ufdt_node * node_b,struct ufdt * tree_a,struct ufdt * tree_b)38 static bool compare_child_nodes(struct ufdt_node *node_a, struct ufdt_node *node_b,
39 struct ufdt * tree_a, struct ufdt * tree_b) {
40 bool result = true;
41 struct ufdt_node *it;
42
43 for (it = ((struct ufdt_node_fdt_node *)node_b)->child; it; it = it->sibling) {
44 struct ufdt_node *cur_node = it;
45 struct ufdt_node *target_node = NULL;
46
47 if (ufdt_node_tag(cur_node) == FDT_BEGIN_NODE) {
48 target_node =
49 ufdt_node_get_subnode_by_name(node_a, ufdt_node_name(cur_node));
50 } else {
51 target_node =
52 ufdt_node_get_property_by_name(node_a, ufdt_node_name(cur_node));
53 }
54
55 if (target_node == NULL) {
56 result = false;
57 } else {
58 result = ufdt_node_compare(target_node, cur_node, tree_a, tree_b);
59 }
60
61 if (!result) {
62 break;
63 }
64 }
65
66 return result;
67 }
68
69 /*
70 * Method to compare two nodes with tag FDT_PROP. Also accounts for the cases where
71 * the property type is phandle.
72 */
ufdt_compare_property(struct ufdt_node * node_final,struct ufdt_node * node_overlay,struct ufdt * tree_final,struct ufdt * tree_overlay)73 static bool ufdt_compare_property(struct ufdt_node* node_final, struct ufdt_node* node_overlay,
74 struct ufdt* tree_final, struct ufdt* tree_overlay) {
75 if (ufdt_node_tag(node_final) == FDT_PROP) {
76 /* Return -1 if property names are differemt */
77 if (strcmp(ufdt_node_name(node_final), ufdt_node_name(node_overlay)) != 0)
78 return false;
79
80 int length_data_final = 0, length_data_overlay = 0;
81 char *prop_data_final = ufdt_node_get_fdt_prop_data(node_final, &length_data_final);
82 char *prop_data_overlay = ufdt_node_get_fdt_prop_data(node_overlay,
83 &length_data_overlay);
84
85 /* Confirm length for the property values are the same */
86 if (length_data_final != length_data_overlay) {
87 return false;
88 }
89
90 if (((length_data_final == 0) && (length_data_overlay ==0)) ||
91 (memcmp(prop_data_final, prop_data_overlay, length_data_final) == 0)) {
92 // Return if the properties have same value.
93 return true;
94 } else {
95 /* check for the presence of phandles */
96 for (int i = 0; i < length_data_final; i += sizeof(fdt32_t)) {
97 int offset_data_a = fdt32_to_cpu(
98 *reinterpret_cast<fdt32_t *>(prop_data_final + i));
99 int offset_data_b = fdt32_to_cpu(
100 *reinterpret_cast<fdt32_t *>(prop_data_overlay + i));
101 if (offset_data_a == offset_data_b) continue;
102 /* If the offsets have phandles, they would have valid target nodes */
103 struct ufdt_node * target_node_a = ufdt_get_node_by_phandle(tree_final,
104 offset_data_a);
105 struct ufdt_node * target_node_b = ufdt_get_node_by_phandle(tree_overlay,
106 offset_data_b);
107
108 /*
109 * verify that the target nodes are valid and point to the same node.
110 */
111 if ((target_node_a == NULL) || (target_node_b == NULL) ||
112 strcmp(ufdt_node_name(target_node_a),
113 ufdt_node_name(target_node_b)) != 0) {
114 return false;
115 }
116 }
117 }
118 }
119
120 return true;
121 }
122
123 /*
124 * Checks if the ufdt tree rooted at node_b is a subtree of the tree rooted at
125 * node_a.
126 */
ufdt_node_compare(struct ufdt_node * node_final,struct ufdt_node * node_overlay,struct ufdt * tree_final,struct ufdt * tree_overlay)127 static bool ufdt_node_compare(struct ufdt_node *node_final, struct ufdt_node *node_overlay,
128 struct ufdt * tree_final, struct ufdt * tree_overlay) {
129 if (ufdt_node_tag(node_final) == FDT_PROP) {
130 return ufdt_compare_property(node_final, node_overlay, tree_final, tree_overlay);
131 }
132
133 return compare_child_nodes(node_final, node_overlay, tree_final, tree_overlay);
134 }
135
136
137 /*
138 * Multiple fragments may fixup to the same node on the base device tree.
139 * Combine these fragments for easier verification.
140 */
ufdt_combine_fixup(struct ufdt * tree,const char * fixup,struct ufdt_node ** prev_node,struct ufdt_node_pool * node_pool)141 void ufdt_combine_fixup(struct ufdt *tree, const char *fixup,
142 struct ufdt_node **prev_node, struct ufdt_node_pool *node_pool) {
143 char *path, *prop_ptr, *offset_ptr;
144 char path_buf[1024];
145 char *path_mem = NULL;
146 int result = 0;
147
148 size_t fixup_len = strlen(fixup) + 1;
149 if (fixup_len > sizeof(path_buf)) {
150 path_mem = static_cast<char *>(dto_malloc(fixup_len));
151 path = path_mem;
152 } else {
153 path = path_buf;
154 }
155 dto_memcpy(path, fixup, fixup_len);
156
157 prop_ptr = dto_strchr(path, ':');
158 if (prop_ptr == NULL) {
159 dto_error("Missing property part in '%s'\n", path);
160 goto fail;
161 }
162
163 *prop_ptr = '\0';
164 prop_ptr++;
165
166 offset_ptr = dto_strchr(prop_ptr, ':');
167 if (offset_ptr == NULL) {
168 dto_error("Missing offset part in '%s'\n", path);
169 goto fail;
170 }
171
172 *offset_ptr = '\0';
173 offset_ptr++;
174
175 result = dto_strcmp(prop_ptr, "target");
176 /* If the property being fixed up is not target, ignore and return */
177 if (result == 0) {
178 struct ufdt_node *target_node;
179 target_node = ufdt_get_node_by_path(tree, path);
180 if (target_node == NULL) {
181 dto_error("Path '%s' not found\n", path);
182 } else {
183 /* The goal is to combine fragments that have a common target */
184 if (*prev_node != NULL) {
185 ufdt_node_merge_into(*prev_node, target_node, node_pool);
186 } else {
187 *prev_node = target_node;
188 }
189 }
190 }
191
192 fail:
193 if (path_mem) {
194 dto_free(path_mem);
195 }
196
197 return;
198 }
199
200 /*
201 * Creates a table of node paths to their corresponding phandles by walking
202 * through the 'symbols' node of the main device tree. The table would be
203 * used in combining overlay nodes that map to the same nodes in the
204 * main device tree.
205 */
create_path_phandle_map(std::unordered_map<uint32_t,std::string> * phandle_path_map,struct ufdt * main_tree)206 void create_path_phandle_map(std::unordered_map<uint32_t, std::string>* phandle_path_map,
207 struct ufdt* main_tree) {
208 int len = 0;
209 struct ufdt_node *main_symbols_node =
210 ufdt_get_node_by_path(main_tree, "/__symbols__");
211 if (!main_symbols_node) {
212 dto_error("No node __symbols__ in main dtb.\n");
213 return;
214 }
215
216 struct ufdt_node **it = nullptr;
217 for_each_prop(it, main_symbols_node) {
218 const char* symbol_path = ufdt_node_get_fdt_prop_data(*it, &len);
219 struct ufdt_node* symbol_node = ufdt_get_node_by_path(main_tree, symbol_path);
220 uint32_t phandle = ufdt_node_get_phandle(symbol_node);
221 (*phandle_path_map)[phandle] = std::string(symbol_path);
222 }
223 }
224
225 /*
226 * Recursively checks whether a node from another overlay fragment had overlaid the
227 * target node and if so merges the node into the previous node.
228 */
combine_overlay_node(std::unordered_map<std::string,struct ufdt_node * > * path_node_map,std::string path,struct ufdt_node * node,struct ufdt_node_pool * pool)229 static void combine_overlay_node(std::unordered_map<std::string,
230 struct ufdt_node*>* path_node_map,
231 std::string path,
232 struct ufdt_node* node,
233 struct ufdt_node_pool* pool) {
234 struct ufdt_node **it = nullptr;
235 for_each_node(it, node) {
236 //skips properties
237 if (ufdt_node_tag(*it) == FDT_BEGIN_NODE) {
238 combine_overlay_node(path_node_map, path + "/" + ufdt_node_name(*it), *it, pool);
239 }
240 }
241
242 if (path_node_map->find(path) != path_node_map->end()) {
243 ufdt_node_merge_into((*path_node_map)[path], node, pool);
244 } else {
245 //This is the first node overlaying the target node, add the same to the
246 //table.
247 (*path_node_map)[path] = node;
248 }
249 }
250
251 /* END of doing fixup in the overlay ufdt. */
252
ufdt_verify_overlay_node(struct ufdt_node * target_node,struct ufdt_node * overlay_node,struct ufdt * target_tree,struct ufdt * overlay_tree)253 static bool ufdt_verify_overlay_node(struct ufdt_node *target_node,
254 struct ufdt_node *overlay_node,
255 struct ufdt * target_tree,
256 struct ufdt * overlay_tree) {
257 return ufdt_node_compare(target_node, overlay_node, target_tree, overlay_tree);
258 }
259
260 /*
261 * verify one overlay fragment (subtree).
262 */
ufdt_verify_fragment(struct ufdt * tree,struct ufdt * overlay_tree,struct ufdt_node * frag_node)263 static int ufdt_verify_fragment(struct ufdt *tree,
264 struct ufdt *overlay_tree,
265 struct ufdt_node *frag_node) {
266 struct ufdt_node *target_node = NULL;
267 struct ufdt_node *overlay_node = NULL;
268 enum overlay_result target_search_result = ufdt_overlay_get_target(tree, frag_node,
269 &target_node);
270 if (target_node == NULL) {
271 return target_search_result;
272 }
273
274 overlay_node = ufdt_node_get_node_by_path(frag_node, "__overlay__");
275 if (overlay_node == NULL) {
276 dto_error("missing __overlay__ sub-node\n");
277 return OVERLAY_RESULT_MISSING_OVERLAY;
278 }
279
280 bool result = ufdt_verify_overlay_node(target_node, overlay_node, tree, overlay_tree);
281
282 if (!result) {
283 dto_error("failed to verify overlay node %s to target %s\n",
284 ufdt_node_name(overlay_node), ufdt_node_name(target_node));
285 return OVERLAY_RESULT_VERIFY_FAIL;
286 }
287
288 return OVERLAY_RESULT_OK;
289 }
290
291 /*
292 * verify each fragment in overlay.
293 */
ufdt_overlay_verify_fragments(struct ufdt * final_tree,struct ufdt * overlay_tree)294 static int ufdt_overlay_verify_fragments(struct ufdt *final_tree,
295 struct ufdt *overlay_tree) {
296 enum overlay_result err;
297 struct ufdt_node **it;
298 for_each_node(it, overlay_tree->root) {
299 err = static_cast<enum overlay_result>(ufdt_verify_fragment(final_tree, overlay_tree,
300 *it));
301 if (err == OVERLAY_RESULT_VERIFY_FAIL) {
302 return -1;
303 }
304 }
305 return 0;
306 }
307
308 /*
309 * Examine target nodes for fragments in all overlays and combine ones with the
310 * same target.
311 */
ufdt_overlay_combine_common_nodes(struct ufdt ** overlay_trees,size_t overlay_count,struct ufdt * final_tree,struct ufdt_node_pool * pool)312 static void ufdt_overlay_combine_common_nodes(struct ufdt** overlay_trees,
313 size_t overlay_count,
314 struct ufdt* final_tree,
315 struct ufdt_node_pool* pool
316 ) {
317 std::unordered_map<std::string, struct ufdt_node*> path_node_map;
318 std::unordered_map<uint32_t, std::string> phandle_path_map;
319
320 create_path_phandle_map(&phandle_path_map, final_tree);
321
322 struct ufdt_node **it = nullptr;
323 for (size_t i = 0; i < overlay_count; i++) {
324 for_each_node(it, overlay_trees[i]->root) {
325 uint32_t target = 0;
326 const void* val = ufdt_node_get_fdt_prop_data_by_name(*it, "target", NULL);
327 if (val) {
328 dto_memcpy(&target, val, sizeof(target));
329 target = fdt32_to_cpu(target);
330 std::string path = phandle_path_map[target];
331 struct ufdt_node* overlay_node = ufdt_node_get_node_by_path(*it, "__overlay__");
332 if (overlay_node != nullptr) {
333 combine_overlay_node(&path_node_map, path, overlay_node, pool);
334 }
335 }
336 }
337 }
338 }
339
340 /*
341 * Makes sure that all phandles in the overlays are unique since they will be
342 * combined before verification.
343 */
ufdt_resolve_duplicate_phandles(ufdt ** overlay_tree,size_t overlay_count)344 int ufdt_resolve_duplicate_phandles(ufdt** overlay_tree, size_t overlay_count) {
345 size_t phandle_offset = 0;
346 for (size_t i = 0; i < overlay_count; i++) {
347 ufdt_try_increase_phandle(overlay_tree[i], phandle_offset);
348 if (ufdt_overlay_do_local_fixups(overlay_tree[i], phandle_offset) < 0) {
349 return -1;
350 }
351 phandle_offset = ufdt_get_max_phandle(overlay_tree[i]);
352 }
353
354 return 0;
355 }
356
357 /*
358 * Combines all overlays into a single tree at overlay_trees[0]
359 */
ufdt_combine_all_overlays(struct ufdt ** overlay_trees,size_t overlay_count,struct ufdt * final_tree,struct ufdt_node_pool * pool)360 int ufdt_combine_all_overlays(struct ufdt** overlay_trees, size_t overlay_count,
361 struct ufdt* final_tree, struct ufdt_node_pool* pool) {
362 struct ufdt* combined_overlay_tree = nullptr;
363
364 if (!overlay_trees || !overlay_count || !final_tree || !pool) {
365 return -1;
366 }
367
368 /*
369 * If there are duplicate phandles amongst the overlays, replace them with
370 * unique ones.
371 */
372 if (ufdt_resolve_duplicate_phandles(overlay_trees, overlay_count) < 0) {
373 return -1;
374 }
375
376 /*
377 * For each overlay, perform fixup for each fragment.
378 */
379 for (size_t i = 0; i < overlay_count; i++) {
380 if (ufdt_overlay_do_fixups(final_tree, overlay_trees[i]) < 0) {
381 dto_error("failed to perform fixups in overlay\n");
382 return -1;
383 }
384 }
385
386 /*
387 * Iterate through each overlay and combine all nodes with the same target
388 * node.
389 */
390 ufdt_overlay_combine_common_nodes(overlay_trees, overlay_count, final_tree, pool);
391
392 /*
393 * Combine all overlays into the tree at overlay_trees[0] for easy
394 * verification.
395 */
396 combined_overlay_tree = overlay_trees[0];
397 struct ufdt_node* combined_root_node = combined_overlay_tree->root;
398
399 for (size_t i = 1; i < overlay_count; i++) {
400 struct ufdt_node** it = nullptr;
401 struct ufdt_node* root_node = overlay_trees[i]->root;
402 for_each_node(it, root_node) {
403 ufdt_node_add_child(combined_root_node, *it);
404 }
405 ((struct ufdt_node_fdt_node *)root_node)->child = nullptr;
406 }
407
408 /*
409 * Rebuild the phandle_table for the combined tree.
410 */
411 combined_overlay_tree->phandle_table = build_phandle_table(combined_overlay_tree);
412
413 return 0;
414 }
415
ufdt_verify_dtbo(struct fdt_header * final_fdt_header,size_t final_fdt_size,void ** overlay_arr,size_t overlay_count)416 int ufdt_verify_dtbo(struct fdt_header* final_fdt_header,
417 size_t final_fdt_size, void** overlay_arr,
418 size_t overlay_count) {
419 const size_t min_fdt_size = 8;
420 struct ufdt_node_pool pool;
421 struct ufdt* final_tree = nullptr;
422 struct ufdt** overlay_trees = nullptr;
423 int result = 1;
424
425 if (final_fdt_header == NULL) {
426 goto fail;
427 }
428
429 if (final_fdt_size < min_fdt_size || final_fdt_size != fdt_totalsize(final_fdt_header)) {
430 dto_error("Bad fdt size!\n");
431 goto fail;
432 }
433
434 for (size_t i = 0; i < overlay_count; i++) {
435 if ((fdt_magic(overlay_arr[i]) != FDT_MAGIC) || !fdt_totalsize(overlay_arr[i])) {
436 dto_error("Corrupted or empty overlay\n");
437 goto fail;
438 }
439 }
440 ufdt_node_pool_construct(&pool);
441 final_tree = ufdt_from_fdt(final_fdt_header, final_fdt_size, &pool);
442
443 overlay_trees = new ufdt*[overlay_count];
444 for (size_t i = 0; i < overlay_count; i++) {
445 size_t fdt_size = fdt_totalsize(overlay_arr[i]);
446 overlay_trees[i] = ufdt_from_fdt(overlay_arr[i], fdt_size, &pool);
447 }
448
449 if (ufdt_combine_all_overlays(overlay_trees, overlay_count, final_tree, &pool) < 0) {
450 dto_error("Unable to combine overlays\n");
451 goto fail;
452 }
453 if (ufdt_overlay_verify_fragments(final_tree, overlay_trees[0]) < 0) {
454 dto_error("Failed to verify overlay application\n");
455 goto fail;
456 } else {
457 result = 0;
458 }
459
460 fail:
461 if (overlay_trees) {
462 for (size_t i = 0; i < overlay_count; i++) {
463 ufdt_destruct(overlay_trees[i], &pool);
464 }
465 delete[] overlay_trees;
466 }
467
468 ufdt_destruct(final_tree, &pool);
469 ufdt_node_pool_destruct(&pool);
470 return result;
471 }
472