From: David Gibson <da...@gibson.dropbear.id.au>

When creating a tree with the sequential write functions, certain things
have to be done in a certain order.  You must create the memory reserve map
and only then can you create the actual tree structure.

The -FDT_ERR_BADSTATE return code is for if you try to do things out of
order.  However, we weren't checking that very thoroughly, so it was
possible to generate a corrupted blob if, for example, you started calling
fdt_begin_node() etc. before calling fdt_finish_reservemap().

This makes the state checking more thorough disallow that.

Signed-off-by: David Gibson <da...@gibson.dropbear.id.au>
Tested-by: Alexey Kardashevskiy <a...@ozlabs.ru>
Reviewed-by: Alexey Kardashevskiy <a...@ozlabs.ru>
Reviewed-by: Simon Glass <s...@chromium.org>
---
 cpukit/dtc/libfdt/fdt_sw.c | 89 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 75 insertions(+), 14 deletions(-)

diff --git a/cpukit/dtc/libfdt/fdt_sw.c b/cpukit/dtc/libfdt/fdt_sw.c
index 9f6fe2085d..178b3657b0 100644
--- a/cpukit/dtc/libfdt/fdt_sw.c
+++ b/cpukit/dtc/libfdt/fdt_sw.c
@@ -57,9 +57,10 @@
 
 static int fdt_sw_probe_(void *fdt)
 {
-       if (fdt_magic(fdt) != FDT_SW_MAGIC)
+       if (fdt_magic(fdt) == FDT_MAGIC)
+               return -FDT_ERR_BADSTATE;
+       else if (fdt_magic(fdt) != FDT_SW_MAGIC)
                return -FDT_ERR_BADMAGIC;
-       /* FIXME: should check more details about the header state */
        return 0;
 }
 
@@ -70,6 +71,61 @@ static int fdt_sw_probe_(void *fdt)
                        return err; \
        }
 
+/* 'memrsv' state:     Initial state after fdt_create()
+ *
+ * Allowed functions:
+ *     fdt_add_reservmap_entry()
+ *     fdt_finish_reservemap()         [moves to 'struct' state]
+ */
+static int fdt_sw_probe_memrsv_(void *fdt)
+{
+       int err = fdt_sw_probe_(fdt);
+       if (err)
+               return err;
+
+       if (fdt_off_dt_strings(fdt) != 0)
+               return -FDT_ERR_BADSTATE;
+       return 0;
+}
+
+#define FDT_SW_PROBE_MEMRSV(fdt) \
+       { \
+               int err; \
+               if ((err = fdt_sw_probe_memrsv_(fdt)) != 0) \
+                       return err; \
+       }
+
+/* 'struct' state:     Enter this state after fdt_finish_reservemap()
+ *
+ * Allowed functions:
+ *     fdt_begin_node()
+ *     fdt_end_node()
+ *     fdt_property*()
+ *     fdt_finish()                    [moves to 'complete' state]
+ */
+static int fdt_sw_probe_struct_(void *fdt)
+{
+       int err = fdt_sw_probe_(fdt);
+       if (err)
+               return err;
+
+       if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt))
+               return -FDT_ERR_BADSTATE;
+       return 0;
+}
+
+#define FDT_SW_PROBE_STRUCT(fdt) \
+       { \
+               int err; \
+               if ((err = fdt_sw_probe_struct_(fdt)) != 0) \
+                       return err; \
+       }
+
+/* 'complete' state:   Enter this state after fdt_finish()
+ *
+ * Allowed functions: none
+ */
+
 static void *fdt_grab_space_(void *fdt, size_t len)
 {
        int offset = fdt_size_dt_struct(fdt);
@@ -102,7 +158,7 @@ int fdt_create(void *buf, int bufsize)
        fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
                                              sizeof(struct 
fdt_reserve_entry)));
        fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
-       fdt_set_off_dt_strings(fdt, bufsize);
+       fdt_set_off_dt_strings(fdt, 0);
 
        return 0;
 }
@@ -133,8 +189,9 @@ int fdt_resize(void *fdt, void *buf, int bufsize)
                memmove(buf, fdt, headsize);
        }
 
-       fdt_set_off_dt_strings(buf, bufsize);
        fdt_set_totalsize(buf, bufsize);
+       if (fdt_off_dt_strings(buf))
+               fdt_set_off_dt_strings(buf, bufsize);
 
        return 0;
 }
@@ -144,10 +201,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, 
uint64_t size)
        struct fdt_reserve_entry *re;
        int offset;
 
-       FDT_SW_PROBE(fdt);
-
-       if (fdt_size_dt_struct(fdt))
-               return -FDT_ERR_BADSTATE;
+       FDT_SW_PROBE_MEMRSV(fdt);
 
        offset = fdt_off_dt_struct(fdt);
        if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
@@ -164,16 +218,23 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, 
uint64_t size)
 
 int fdt_finish_reservemap(void *fdt)
 {
-       return fdt_add_reservemap_entry(fdt, 0, 0);
+       int err = fdt_add_reservemap_entry(fdt, 0, 0);
+
+       if (err)
+               return err;
+
+       fdt_set_off_dt_strings(fdt, fdt_totalsize(fdt));
+       return 0;
 }
 
 int fdt_begin_node(void *fdt, const char *name)
 {
        struct fdt_node_header *nh;
-       int namelen = strlen(name) + 1;
+       int namelen;
 
-       FDT_SW_PROBE(fdt);
+       FDT_SW_PROBE_STRUCT(fdt);
 
+       namelen = strlen(name) + 1;
        nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
        if (! nh)
                return -FDT_ERR_NOSPACE;
@@ -187,7 +248,7 @@ int fdt_end_node(void *fdt)
 {
        fdt32_t *en;
 
-       FDT_SW_PROBE(fdt);
+       FDT_SW_PROBE_STRUCT(fdt);
 
        en = fdt_grab_space_(fdt, FDT_TAGSIZE);
        if (! en)
@@ -225,7 +286,7 @@ int fdt_property_placeholder(void *fdt, const char *name, 
int len, void **valp)
        struct fdt_property *prop;
        int nameoff;
 
-       FDT_SW_PROBE(fdt);
+       FDT_SW_PROBE_STRUCT(fdt);
 
        nameoff = fdt_find_add_string_(fdt, name);
        if (nameoff == 0)
@@ -262,7 +323,7 @@ int fdt_finish(void *fdt)
        uint32_t tag;
        int offset, nextoffset;
 
-       FDT_SW_PROBE(fdt);
+       FDT_SW_PROBE_STRUCT(fdt);
 
        /* Add terminator */
        end = fdt_grab_space_(fdt, sizeof(*end));
-- 
2.13.7

_______________________________________________
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel

Reply via email to