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:
parent
35bb6ca08e
commit
8823aaaff9
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user