Convert all panics from the link_elf_obj kernel linker for object

files format into printfs and errors to caller.  Some leaks of
resources are there, but the same leaks are present in other error
pathes.  With the change, the kernel at least boots even when module
with unexpected or corrupted ELF structure is preloaded.

Sponsored by:	The FreeBSD Foundation
MFC after:	2 weeks
This commit is contained in:
Konstantin Belousov 2016-03-07 18:44:06 +00:00
parent 5e67bb7b19
commit 3cfce8e4df

View File

@ -140,7 +140,7 @@ static int link_elf_each_function_name(linker_file_t,
static int link_elf_each_function_nameval(linker_file_t,
linker_function_nameval_callback_t,
void *);
static void link_elf_reloc_local(linker_file_t);
static int link_elf_reloc_local(linker_file_t);
static long link_elf_symtab_get(linker_file_t, const Elf_Sym **);
static long link_elf_strtab_get(linker_file_t, caddr_t *);
@ -405,15 +405,26 @@ link_elf_link_preload(linker_class_t cls, const char *filename,
break;
}
}
if (pb != ef->nprogtab)
panic("lost progbits");
if (rl != ef->nreltab)
panic("lost reltab");
if (ra != ef->nrelatab)
panic("lost relatab");
if (pb != ef->nprogtab) {
printf("%s: lost progbits\n", filename);
error = ENOEXEC;
goto out;
}
if (rl != ef->nreltab) {
printf("%s: lost reltab\n", filename);
error = ENOEXEC;
goto out;
}
if (ra != ef->nrelatab) {
printf("%s: lost relatab\n", filename);
error = ENOEXEC;
goto out;
}
/* Local intra-module relocations */
link_elf_reloc_local(lf);
error = link_elf_reloc_local(lf);
if (error != 0)
goto out;
*result = lf;
return (0);
@ -634,8 +645,11 @@ link_elf_load_file(linker_class_t cls, const char *filename,
ef->relatab = malloc(ef->nrelatab * sizeof(*ef->relatab),
M_LINKER, M_WAITOK | M_ZERO);
if (symtabindex == -1)
panic("lost symbol table index");
if (symtabindex == -1) {
link_elf_error(filename, "lost symbol table index");
error = ENOEXEC;
goto out;
}
/* Allocate space for and load the symbol table */
ef->ddbsymcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym);
ef->ddbsymtab = malloc(shdr[symtabindex].sh_size, M_LINKER, M_WAITOK);
@ -650,8 +664,11 @@ link_elf_load_file(linker_class_t cls, const char *filename,
goto out;
}
if (symstrindex == -1)
panic("lost symbol string index");
if (symstrindex == -1) {
link_elf_error(filename, "lost symbol string index");
error = ENOEXEC;
goto out;
}
/* Allocate space for and load the symbol strings */
ef->ddbstrcnt = shdr[symstrindex].sh_size;
ef->ddbstrtab = malloc(shdr[symstrindex].sh_size, M_LINKER, M_WAITOK);
@ -884,19 +901,35 @@ link_elf_load_file(linker_class_t cls, const char *filename,
break;
}
}
if (pb != ef->nprogtab)
panic("lost progbits");
if (rl != ef->nreltab)
panic("lost reltab");
if (ra != ef->nrelatab)
panic("lost relatab");
if (mapbase != (vm_offset_t)ef->address + mapsize)
panic("mapbase 0x%lx != address %p + mapsize 0x%lx (0x%lx)\n",
if (pb != ef->nprogtab) {
link_elf_error(filename, "lost progbits");
error = ENOEXEC;
goto out;
}
if (rl != ef->nreltab) {
link_elf_error(filename, "lost reltab");
error = ENOEXEC;
goto out;
}
if (ra != ef->nrelatab) {
link_elf_error(filename, "lost relatab");
error = ENOEXEC;
goto out;
}
if (mapbase != (vm_offset_t)ef->address + mapsize) {
printf(
"%s: mapbase 0x%lx != address %p + mapsize 0x%lx (0x%lx)\n",
filename != NULL ? filename : "<none>",
(u_long)mapbase, ef->address, (u_long)mapsize,
(u_long)(vm_offset_t)ef->address + mapsize);
error = ENOMEM;
goto out;
}
/* Local intra-module relocations */
link_elf_reloc_local(lf);
error = link_elf_reloc_local(lf);
if (error != 0)
goto out;
/* Pull in dependencies */
VOP_UNLOCK(nd.ni_vp, 0);
@ -1034,12 +1067,16 @@ relocate_file(elf_file_t ef)
/* Perform relocations without addend if there are any: */
for (i = 0; i < ef->nreltab; i++) {
rel = ef->reltab[i].rel;
if (rel == NULL)
panic("lost a reltab!");
if (rel == NULL) {
link_elf_error(ef->lf.filename, "lost a reltab!");
return (ENOEXEC);
}
rellim = rel + ef->reltab[i].nrel;
base = findbase(ef, ef->reltab[i].sec);
if (base == 0)
panic("lost base for reltab");
if (base == 0) {
link_elf_error(ef->lf.filename, "lost base for reltab");
return (ENOEXEC);
}
for ( ; rel < rellim; rel++) {
symidx = ELF_R_SYM(rel->r_info);
if (symidx >= ef->ddbsymcnt)
@ -1053,7 +1090,7 @@ relocate_file(elf_file_t ef)
symname = symbol_name(ef, rel->r_info);
printf("link_elf_obj: symbol %s undefined\n",
symname);
return ENOENT;
return (ENOENT);
}
}
}
@ -1061,12 +1098,17 @@ relocate_file(elf_file_t ef)
/* Perform relocations with addend if there are any: */
for (i = 0; i < ef->nrelatab; i++) {
rela = ef->relatab[i].rela;
if (rela == NULL)
panic("lost a relatab!");
if (rela == NULL) {
link_elf_error(ef->lf.filename, "lost a relatab!");
return (ENOEXEC);
}
relalim = rela + ef->relatab[i].nrela;
base = findbase(ef, ef->relatab[i].sec);
if (base == 0)
panic("lost base for relatab");
if (base == 0) {
link_elf_error(ef->lf.filename,
"lost base for relatab");
return (ENOEXEC);
}
for ( ; rela < relalim; rela++) {
symidx = ELF_R_SYM(rela->r_info);
if (symidx >= ef->ddbsymcnt)
@ -1080,7 +1122,7 @@ relocate_file(elf_file_t ef)
symname = symbol_name(ef, rela->r_info);
printf("link_elf_obj: symbol %s undefined\n",
symname);
return ENOENT;
return (ENOENT);
}
}
}
@ -1092,7 +1134,7 @@ relocate_file(elf_file_t ef)
*/
elf_obj_cleanup_globals_cache(ef);
return 0;
return (0);
}
static int
@ -1375,7 +1417,7 @@ link_elf_fix_link_set(elf_file_t ef)
}
}
static void
static int
link_elf_reloc_local(linker_file_t lf)
{
elf_file_t ef = (elf_file_t)lf;
@ -1393,12 +1435,16 @@ link_elf_reloc_local(linker_file_t lf)
/* Perform relocations without addend if there are any: */
for (i = 0; i < ef->nreltab; i++) {
rel = ef->reltab[i].rel;
if (rel == NULL)
panic("lost a reltab!");
if (rel == NULL) {
link_elf_error(ef->lf.filename, "lost a reltab");
return (ENOEXEC);
}
rellim = rel + ef->reltab[i].nrel;
base = findbase(ef, ef->reltab[i].sec);
if (base == 0)
panic("lost base for reltab");
if (base == 0) {
link_elf_error(ef->lf.filename, "lost base for reltab");
return (ENOEXEC);
}
for ( ; rel < rellim; rel++) {
symidx = ELF_R_SYM(rel->r_info);
if (symidx >= ef->ddbsymcnt)
@ -1415,12 +1461,16 @@ link_elf_reloc_local(linker_file_t lf)
/* Perform relocations with addend if there are any: */
for (i = 0; i < ef->nrelatab; i++) {
rela = ef->relatab[i].rela;
if (rela == NULL)
panic("lost a relatab!");
if (rela == NULL) {
link_elf_error(ef->lf.filename, "lost a relatab!");
return (ENOEXEC);
}
relalim = rela + ef->relatab[i].nrela;
base = findbase(ef, ef->relatab[i].sec);
if (base == 0)
panic("lost base for relatab");
if (base == 0) {
link_elf_error(ef->lf.filename, "lost base for reltab");
return (ENOEXEC);
}
for ( ; rela < relalim; rela++) {
symidx = ELF_R_SYM(rela->r_info);
if (symidx >= ef->ddbsymcnt)
@ -1433,6 +1483,7 @@ link_elf_reloc_local(linker_file_t lf)
elf_obj_lookup);
}
}
return (0);
}
static long