DragonFlyBSD Kernel Audit
DF-0060 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -240,8 +240,14 @@
 	case DT_HASH:
 	{
 	    /* From src/libexec/rtld-elf/rtld.c */
+	    Elf_Addr hoff = dp->d_un.d_ptr;
+	    if (hoff >= lf->size ||
+		hoff + 2 * sizeof(Elf_Hashelt) > lf->size) {
+		kprintf("link_elf: DT_HASH out of bounds\n");
+		return ENOEXEC;
+	    }
 	    const Elf_Hashelt *hashtab = (const Elf_Hashelt *)
-		(ef->address + dp->d_un.d_ptr);
+		(ef->address + hoff);
 	    ef->nbuckets = hashtab[0];
 	    ef->nchains = hashtab[1];
 	    ef->buckets = hashtab + 2;
@@ -249,23 +255,27 @@
 	    break;
 	}
 	case DT_STRTAB:
-	    ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr);
+	    if (dp->d_un.d_ptr < lf->size)
+		ef->strtab = (caddr_t) (ef->address + dp->d_un.d_ptr);
 	    break;
 	case DT_STRSZ:
 	    ef->strsz = dp->d_un.d_val;
 	    break;
 	case DT_SYMTAB:
-	    ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr);
+	    if (dp->d_un.d_ptr < lf->size)
+		ef->symtab = (Elf_Sym*) (ef->address + dp->d_un.d_ptr);
 	    break;
 	case DT_SYMENT:
 	    if (dp->d_un.d_val != sizeof(Elf_Sym))
 		return ENOEXEC;
 	    break;
 	case DT_PLTGOT:
-	    ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr);
+	    if (dp->d_un.d_ptr < lf->size)
+		ef->got = (Elf_Addr *) (ef->address + dp->d_un.d_ptr);
 	    break;
 	case DT_REL:
-	    ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr);
+	    if (dp->d_un.d_ptr < lf->size)
+		ef->rel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr);
 	    break;
 	case DT_RELSZ:
 	    ef->relsize = dp->d_un.d_val;
@@ -275,13 +285,15 @@
 		return ENOEXEC;
 	    break;
 	case DT_JMPREL:
-	    ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr);
+	    if (dp->d_un.d_ptr < lf->size)
+		ef->pltrel = (const Elf_Rel *) (ef->address + dp->d_un.d_ptr);
 	    break;
 	case DT_PLTRELSZ:
 	    ef->pltrelsize = dp->d_un.d_val;
 	    break;
 	case DT_RELA:
-	    ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr);
+	    if (dp->d_un.d_ptr < lf->size)
+		ef->rela = (const Elf_Rela *) (ef->address + dp->d_un.d_ptr);
 	    break;
 	case DT_RELASZ:
 	    ef->relasize = dp->d_un.d_val;