[CRIU] [PATCH 5/9] pie/util-vdso: check elf structure end oob

Dmitry Safonov dsafonov at virtuozzo.com
Wed Mar 30 08:12:26 PDT 2016


Add checks that structure end is inside memory area [mem, mem + size]
before dereferencing structures.
Otherwise, for example, vdso_fill_symtable will try to dereference
ehdr members even with vma size 0.

Signed-off-by: Dmitry Safonov <dsafonov at virtuozzo.com>
---
 criu/pie/util-vdso.c | 42 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 36 insertions(+), 6 deletions(-)

diff --git a/criu/pie/util-vdso.c b/criu/pie/util-vdso.c
index 1c3f7ec38f3a..5d1605380135 100644
--- a/criu/pie/util-vdso.c
+++ b/criu/pie/util-vdso.c
@@ -29,7 +29,22 @@ static bool __ptr_oob(uintptr_t ptr, uintptr_t start, size_t size)
 {
 	uintptr_t end = start + size;
 
-	return ptr > end || ptr < start;
+	return ptr >= end || ptr < start;
+}
+
+/* Check if pointed structure's end is out-of-bound */
+static bool __ptr_struct_end_oob(uintptr_t ptr, size_t struct_size,
+				uintptr_t start, size_t size)
+{
+	return __ptr_oob(ptr + struct_size - 1, start, size);
+}
+
+/* Check if pointed structure is out-of-bound */
+static bool __ptr_struct_oob(uintptr_t ptr, size_t struct_size,
+				uintptr_t start, size_t size)
+{
+	return __ptr_oob(ptr, start, size) ||
+		__ptr_struct_end_oob(ptr, struct_size, start, size);
 }
 
 /*
@@ -103,6 +118,8 @@ int vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t)
 
 	pr_debug("Parsing at %lx %lx\n", (long)mem, (long)mem + (long)size);
 
+	if (__ptr_struct_end_oob(mem, sizeof(Ehdr_t), mem, size))
+		goto err_oob;
 	/*
 	 * Make sure it's a file we support.
 	 */
@@ -113,9 +130,13 @@ int vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t)
 	 * We need PT_LOAD and PT_DYNAMIC here. Each once.
 	 */
 	addr = mem + ehdr->e_phoff;
+	if (__ptr_oob(addr, mem, size))
+		goto err_oob;
+
 	for (i = 0; i < ehdr->e_phnum; i++, addr += sizeof(Phdr_t)) {
-		if (__ptr_oob(addr, mem, size))
+		if (__ptr_struct_end_oob(addr, sizeof(Phdr_t), mem, size))
 			goto err_oob;
+
 		phdr = (void *)addr;
 		switch (phdr->p_type) {
 		case PT_DYNAMIC:
@@ -147,9 +168,12 @@ int vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t)
 	 * needed. Note that we're interested in a small set of tags.
 	 */
 	addr = mem + dynamic->p_offset;
+	if (__ptr_oob(addr, mem, size))
+		goto err_oob;
+
 	for (i = 0; i < dynamic->p_filesz / sizeof(*d);
 			i++, addr += sizeof(Dyn_t)) {
-		if (__ptr_oob(addr, mem, size))
+		if (__ptr_struct_end_oob(addr, sizeof(Dyn_t), mem, size))
 			goto err_oob;
 		d = (void *)addr;
 
@@ -184,7 +208,7 @@ int vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t)
 	dynsymbol_names = (void *)addr;
 
 	addr = mem + dyn_hash->d_un.d_ptr - load->p_vaddr;
-	if (__ptr_oob(addr, mem, size))
+	if (__ptr_struct_oob(addr, sizeof(Word_t), mem, size))
 		goto err_oob;
 	hash = (void *)addr;
 
@@ -206,7 +230,7 @@ int vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t)
 			char *name;
 
 			addr += sizeof(Sym_t)*j;
-			if (__ptr_oob(addr, mem, size))
+			if (__ptr_struct_oob(addr, sizeof(Sym_t), mem, size))
 				continue;
 			sym = (void *)addr;
 
@@ -215,10 +239,16 @@ int vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t)
 				continue;
 
 			addr = (uintptr_t)dynsymbol_names + sym->st_name;
-			if (__ptr_oob(addr, mem, size))
+			if (__ptr_struct_oob(addr, sizeof(t->symbols[i].name),
+						mem, size))
 				continue;
 			name = (void *)addr;
 
+			/*
+			 * XXX: Hope will not go out of mem+size.
+			 * (i.e. with broken elf or malicious pointer in header)
+			 * Otherwise, we need builtin_strncmp.
+			 */
 			if (builtin_strcmp(name, symbol))
 				continue;
 
-- 
2.7.4



More information about the CRIU mailing list