From 25a00ab9758e784dd78d6a2e8a5ee6978fc0ae1e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Vivek=20Das=C2=A0Mohapatra?= <vivek@collabora.co.uk>
Date: Wed, 24 May 2017 20:32:28 +0100
Subject: [PATCH] capsule-dlmopen.c: don't fake dynamic section size from
 wrap()

When munging the ELF data structures from the capsule-export code path
via dl_iterate_phdr, we get the dynamic section size as a callback arg
so we can double-check we haven't ended up outside the memory region
we expect to be working on.

Unfortunately when using link_map traversal to do the same sort of thing
to install wrapper functions inside the capsule we don't have this
information. We were using SIZE_MAX on ELFCLASS64 to pass a "big enough"
size parameter but this calculation does not work on ELFCLASS32.

Rather than go out of our way to produce a bogus-but-big-enough value
we now pass 0 for the size and have the called functions know that they
can't do the double-check if passed a size of 0.

The last entry in the dyn section should have a D_TAG of DT_NULL
anyway so we'll only crash off the end of the dynamic section if
the linker is broken or malicious (which is probably not worth
defending against, all things considered).
---
 capsule/capsule-dlmopen.c  | 3 +--
 utils/process-pt-dynamic.c | 6 ++++--
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/capsule/capsule-dlmopen.c b/capsule/capsule-dlmopen.c
index e800ae13a..97c77973b 100644
--- a/capsule/capsule-dlmopen.c
+++ b/capsule/capsule-dlmopen.c
@@ -1326,7 +1326,6 @@ wrap (const char *name,
     //
     // the utility functions expect an upper bound though so set that to
     // something suitably large:
-    size_t size = SIZE_MAX - base - (ElfW(Addr)) dyn;
     relocation_data_t rdata = { 0 };
 
     rdata.target    = name;
@@ -1361,7 +1360,7 @@ wrap (const char *name,
 
     // install any required wrappers inside the capsule:
     process_pt_dynamic( (void *)start, // offset from phdr to dyn section
-                        size,   //  fake size value (max possible value)
+                        0,      //  fake size value
                         base,   //  address of phdr in memory
                         process_dt_rela,
                         process_dt_rel,
diff --git a/utils/process-pt-dynamic.c b/utils/process-pt-dynamic.c
index 0e0d31334..c84280848 100644
--- a/utils/process-pt-dynamic.c
+++ b/utils/process-pt-dynamic.c
@@ -84,7 +84,8 @@ find_strtab (ElfW(Addr) base, void *start, size_t size, int *siz)
     const char *tab = NULL;
 
     for( entry = start + base;
-         (entry->d_tag != DT_NULL) && ((void *)entry < (start + base + size));
+         (entry->d_tag != DT_NULL) &&
+           ((size == 0) || ((void *)entry < (start + base + size)));
          entry++ )
     {
         if( entry->d_tag == DT_STRTAB )
@@ -474,7 +475,8 @@ process_pt_dynamic (void *start,
            "strtab is at %p: %s%s", strtab, strtab, strtab ? "…" : "");
 
     for( entry = start + base;
-         (entry->d_tag != DT_NULL) && ((void *)entry < (start + base + size));
+         (entry->d_tag != DT_NULL) &&
+           ((size == 0) || ((void *)entry < (start + base + size)));
          entry++ )
         switch( entry->d_tag )
         {
-- 
GitLab