kldxref: handle modules with md_cval at the end of allocated sections

Attempting to retrieve an md_cval string from a kernel module with
kldxref would throw a offset error for modules created using lld, since
this value would be placed at the end of all allocated sections.

Add an ef_read_seg_string method to the ef interface, to allow reading
strings of varying size without attempting to read beyond the segment's
bounds.

PR:		224875
Submitted by:	Mitchell Horne <mhorne063@gmail.com>
Reviewed by:	cem, kib
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D13923
This commit is contained in:
emaste 2018-01-16 18:20:12 +00:00
parent 35bb6ca08e
commit 8823aaaff9
4 changed files with 54 additions and 2 deletions

View File

@ -90,6 +90,8 @@ static int ef_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr);
static int ef_seg_read(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
static int ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len,
void *dest);
static int ef_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len,
char *dest);
static int ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
void **ptr);
static int ef_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len,
@ -106,6 +108,7 @@ static struct elf_file_ops ef_file_ops = {
ef_read_entry,
ef_seg_read,
ef_seg_read_rel,
ef_seg_read_string,
ef_seg_read_entry,
ef_seg_read_entry_rel,
ef_symaddr,
@ -497,6 +500,28 @@ ef_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void*dest)
return (0);
}
static int
ef_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len, char *dest)
{
u_long ofs = ef_get_offset(ef, offset);
ssize_t r;
if (ofs == 0 || ofs == (Elf_Off)-1) {
if (ef->ef_verbose)
warnx("ef_seg_read_string(%s): bad offset (%lx:%ld)",
ef->ef_name, (long)offset, ofs);
return (EFAULT);
}
r = pread(ef->ef_fd, dest, len, ofs);
if (r < 0)
return (errno);
if (strnlen(dest, len) == len)
return (EFAULT);
return (0);
}
static int
ef_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void**ptr)
{

View File

@ -21,6 +21,8 @@
(ef)->ef_ops->seg_read((ef)->ef_ef, offset, len, dest)
#define EF_SEG_READ_REL(ef, offset, len, dest) \
(ef)->ef_ops->seg_read_rel((ef)->ef_ef, offset, len, dest)
#define EF_SEG_READ_STRING(ef, offset, len, dest) \
(ef)->ef_ops->seg_read_string((ef)->ef_ef, offset, len, dest)
#define EF_SEG_READ_ENTRY(ef, offset, len, ptr) \
(ef)->ef_ops->seg_read_entry((ef)->kf_ef, offset, len, ptr)
#define EF_SEG_READ_ENTRY_REL(ef, offset, len, ptr) \
@ -44,6 +46,8 @@ struct elf_file_ops {
int (*seg_read)(elf_file_t ef, Elf_Off offset, size_t len, void *dest);
int (*seg_read_rel)(elf_file_t ef, Elf_Off offset, size_t len,
void *dest);
int (*seg_read_string)(elf_file_t, Elf_Off offset, size_t len,
char *dest);
int (*seg_read_entry)(elf_file_t ef, Elf_Off offset, size_t len,
void**ptr);
int (*seg_read_entry_rel)(elf_file_t ef, Elf_Off offset, size_t len,

View File

@ -110,6 +110,8 @@ static int ef_obj_seg_read(elf_file_t ef, Elf_Off offset, size_t len,
void *dest);
static int ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len,
void *dest);
static int ef_obj_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len,
char *dest);
static int ef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len,
void **ptr);
static int ef_obj_seg_read_entry_rel(elf_file_t ef, Elf_Off offset, size_t len,
@ -126,6 +128,7 @@ static struct elf_file_ops ef_obj_file_ops = {
ef_obj_read_entry,
ef_obj_seg_read,
ef_obj_seg_read_rel,
ef_obj_seg_read_string,
ef_obj_seg_read_entry,
ef_obj_seg_read_entry_rel,
ef_obj_symaddr,
@ -298,6 +301,27 @@ ef_obj_seg_read_rel(elf_file_t ef, Elf_Off offset, size_t len, void *dest)
return (0);
}
static int
ef_obj_seg_read_string(elf_file_t ef, Elf_Off offset, size_t len, char *dest)
{
if (offset >= ef->size) {
if (ef->ef_verbose)
warnx("ef_obj_seg_read_string(%s): bad offset (%lx)",
ef->ef_name, (long)offset);
return (EFAULT);
}
if (ef->size - offset < len)
len = ef->size - offset;
if (strnlen(ef->address + offset, len) == len)
return (EFAULT);
memcpy(dest, ef->address + offset, len);
return (0);
}
static int
ef_obj_seg_read_entry(elf_file_t ef, Elf_Off offset, size_t len, void **ptr)
{

View File

@ -571,9 +571,8 @@ read_kld(char *filename, char *kldname)
check(EF_SEG_READ_REL(&ef, (Elf_Off)*p, sizeof(md),
&md));
p++;
check(EF_SEG_READ(&ef, (Elf_Off)md.md_cval,
check(EF_SEG_READ_STRING(&ef, (Elf_Off)md.md_cval,
sizeof(cval), cval));
cval[MAXMODNAME] = '\0';
parse_entry(&md, cval, &ef, kldname);
}
if (error)