1 |
commit: e11815bb7f0656f39e122073e0e3284ec7f5d021 |
2 |
Author: Mike Frysinger <vapier <AT> gentoo <DOT> org> |
3 |
AuthorDate: Wed Mar 30 03:35:44 2016 +0000 |
4 |
Commit: Mike Frysinger <vapier <AT> gentoo <DOT> org> |
5 |
CommitDate: Wed Mar 30 03:35:44 2016 +0000 |
6 |
URL: https://gitweb.gentoo.org/proj/sandbox.git/commit/?id=e11815bb |
7 |
|
8 |
libsandbox: fix symtab walking with some ELFs |
9 |
|
10 |
The strtab assumption works if there is no SysV hash table. |
11 |
Add logic to handle that scenario. |
12 |
|
13 |
URL: https://bugs.gentoo.org/578524 |
14 |
Reported-by: Toralf Förster <toralf.foerster <AT> gmx.de> |
15 |
Signed-off-by: Mike Frysinger <vapier <AT> gentoo.org> |
16 |
|
17 |
libsandbox/wrapper-funcs/__wrapper_exec.c | 30 +++++++++++++++++------------- |
18 |
1 file changed, 17 insertions(+), 13 deletions(-) |
19 |
|
20 |
diff --git a/libsandbox/wrapper-funcs/__wrapper_exec.c b/libsandbox/wrapper-funcs/__wrapper_exec.c |
21 |
index f7f51ab..d372366 100644 |
22 |
--- a/libsandbox/wrapper-funcs/__wrapper_exec.c |
23 |
+++ b/libsandbox/wrapper-funcs/__wrapper_exec.c |
24 |
@@ -83,10 +83,10 @@ static bool sb_check_exec(const char *filename, char *const argv[]) |
25 |
({ \ |
26 |
Elf##n##_Ehdr *ehdr = (void *)elf; \ |
27 |
Elf##n##_Phdr *phdr = (void *)(elf + ehdr->e_phoff); \ |
28 |
- Elf##n##_Addr vaddr, filesz, vsym = 0, vstr = 0; \ |
29 |
- Elf##n##_Off offset, symoff = 0, stroff = 0; \ |
30 |
+ Elf##n##_Addr vaddr, filesz, vsym = 0, vstr = 0, vhash = 0; \ |
31 |
+ Elf##n##_Off offset, symoff = 0, stroff = 0, hashoff = 0; \ |
32 |
Elf##n##_Dyn *dyn; \ |
33 |
- Elf##n##_Sym *sym; \ |
34 |
+ Elf##n##_Sym *sym, *symend; \ |
35 |
uint##n##_t ent_size = 0, str_size = 0; \ |
36 |
bool dynamic = false; \ |
37 |
size_t i; \ |
38 |
@@ -106,6 +106,7 @@ static bool sb_check_exec(const char *filename, char *const argv[]) |
39 |
case DT_SYMENT: ent_size = dyn->d_un.d_val; break; \ |
40 |
case DT_STRTAB: vstr = dyn->d_un.d_val; break; \ |
41 |
case DT_STRSZ: str_size = dyn->d_un.d_val; break; \ |
42 |
+ case DT_HASH: vhash = dyn->d_un.d_val; break; \ |
43 |
} \ |
44 |
++dyn; \ |
45 |
} \ |
46 |
@@ -123,6 +124,8 @@ static bool sb_check_exec(const char *filename, char *const argv[]) |
47 |
symoff = offset + (vsym - vaddr); \ |
48 |
if (vstr >= vaddr && vstr < vaddr + filesz) \ |
49 |
stroff = offset + (vstr - vaddr); \ |
50 |
+ if (vhash >= vaddr && vhash < vaddr + filesz) \ |
51 |
+ hashoff = offset + (vhash - vaddr); \ |
52 |
} \ |
53 |
\ |
54 |
/* Finally walk the symbol table. This should generally be fast as \ |
55 |
@@ -130,18 +133,20 @@ static bool sb_check_exec(const char *filename, char *const argv[]) |
56 |
* out there do not export any symbols at all. \ |
57 |
*/ \ |
58 |
if (symoff && stroff) { \ |
59 |
- sym = (void *)(elf + symoff); \ |
60 |
+ /* Hash entries are always 32-bits. */ \ |
61 |
+ uint32_t *hashes = (void *)(elf + hashoff); \ |
62 |
/* Nowhere is the # of symbols recorded, or the size of the symbol \ |
63 |
- * table. Instead, we do what glibc does: assume that the string \ |
64 |
- * table always follows the symbol table. This seems like a poor \ |
65 |
- * assumption to make, but glibc has gotten by this long. We could \ |
66 |
- * rely on DT_HASH and walking all the buckets to find the largest \ |
67 |
- * symbol index, but that's also a bit hacky. \ |
68 |
+ * table. Instead, we do what glibc does: use the sysv hash table \ |
69 |
+ * if it exists, else assume that the string table always directly \ |
70 |
+ * follows the symbol table. This seems like a poor assumption to \ |
71 |
+ * make, but glibc has gotten by this long. \ |
72 |
* \ |
73 |
* We don't sanity check the ranges here as you aren't executing \ |
74 |
* corrupt programs in the sandbox. \ |
75 |
*/ \ |
76 |
- for (i = 0; i < (vstr - vsym) / ent_size; ++i) { \ |
77 |
+ sym = (void *)(elf + symoff); \ |
78 |
+ symend = vhash ? (sym + hashes[1]) : (void *)(elf + stroff); \ |
79 |
+ while (sym < symend) { \ |
80 |
char *symname = (void *)(elf + stroff + sym->st_name); \ |
81 |
if (ELF##n##_ST_VISIBILITY(sym->st_other) == STV_DEFAULT && \ |
82 |
sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE && \ |
83 |
@@ -149,9 +154,8 @@ static bool sb_check_exec(const char *filename, char *const argv[]) |
84 |
/* Minor optimization to avoid strcmp. */ \ |
85 |
symname[0] == '_' && symname[1] == '_') { \ |
86 |
/* Blacklist internal C library symbols. */ \ |
87 |
- size_t j; \ |
88 |
- for (j = 0; j < ARRAY_SIZE(libc_alloc_syms); ++j) \ |
89 |
- if (!strcmp(symname, libc_alloc_syms[j])) { \ |
90 |
+ for (i = 0; i < ARRAY_SIZE(libc_alloc_syms); ++i) \ |
91 |
+ if (!strcmp(symname, libc_alloc_syms[i])) { \ |
92 |
run_in_process = false; \ |
93 |
goto use_trace; \ |
94 |
} \ |