mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-15 12:54:27 +00:00
pmc: Rework PROCEXEC event to support PIEs
Currently the PROCEXEC event only reports a single address, entryaddr, which is the entry point of the interpreter in the typical dynamic case, and used solely to calculate the base address of the interpreter. For PDEs this is fine, since the base address is known from the program headers, but for PIEs the base address varies at run time based on where the kernel chooses to load it, and so pmcstat has no way of knowing the real address ranges for the executable. This was less of an issue in the past since PIEs were rare, but now they're on by default on 64-bit architectures it's more of a problem. To solve this, pass through what was picked for et_dyn_addr by the kernel, and use that as the offset for the executable's start address just as is done for everything in the kernel. Since we're changing this interface, sanitise the way we determine the interpreter's base address by passing it through directly rather than indirectly via the entry point and having to subtract off whatever the ELF header's e_entry is (and anything that wants the entry point in future can still add that back on as needed; this merely changes the interface to directly provide the underlying variables involved). This will be followed up by a bump to the pmc major version. Reviewed by: jhb Differential Revision: https://reviews.freebsd.org/D39595
This commit is contained in:
parent
659a0041dd
commit
94426d21bf
|
@ -163,9 +163,12 @@ procexec_to_json(struct pmclog_ev *ev)
|
|||
startent = startentry(ev);
|
||||
snprintf(eventbuf, sizeof(eventbuf),
|
||||
"%s, \"pmcid\": \"0x%08x\", \"pid\": \"%d\", "
|
||||
"\"start\": \"0x%016jx\", \"pathname\": \"%s\"}\n",
|
||||
"\"base\": \"0x%016jx\", \"dyn\": \"0x%016jx\", "
|
||||
"\"pathname\": \"%s\"}\n",
|
||||
startent.c_str(), ev->pl_u.pl_x.pl_pmcid, ev->pl_u.pl_x.pl_pid,
|
||||
(uintmax_t)ev->pl_u.pl_x.pl_entryaddr, ev->pl_u.pl_x.pl_pathname);
|
||||
(uintmax_t)ev->pl_u.pl_x.pl_baseaddr,
|
||||
(uintmax_t)ev->pl_u.pl_x.pl_dynaddr,
|
||||
ev->pl_u.pl_x.pl_pathname);
|
||||
return string(eventbuf);
|
||||
}
|
||||
|
||||
|
|
|
@ -393,7 +393,8 @@ pmclog_get_event(void *cookie, char **data, ssize_t *len,
|
|||
PMCLOG_GET_PATHLEN(pathlen,evlen,pmclog_procexec);
|
||||
PMCLOG_READ32(le,ev->pl_u.pl_x.pl_pid);
|
||||
PMCLOG_READ32(le,ev->pl_u.pl_x.pl_pmcid);
|
||||
PMCLOG_READADDR(le,ev->pl_u.pl_x.pl_entryaddr);
|
||||
PMCLOG_READADDR(le,ev->pl_u.pl_x.pl_baseaddr);
|
||||
PMCLOG_READADDR(le,ev->pl_u.pl_x.pl_dynaddr);
|
||||
PMCLOG_READSTRING(le,ev->pl_u.pl_x.pl_pathname,pathlen);
|
||||
break;
|
||||
case PMCLOG_TYPE_PROCEXIT:
|
||||
|
|
|
@ -132,7 +132,8 @@ struct pmclog_ev_proccreate {
|
|||
struct pmclog_ev_procexec {
|
||||
pid_t pl_pid;
|
||||
pmc_id_t pl_pmcid;
|
||||
uintfptr_t pl_entryaddr;
|
||||
uintptr_t pl_baseaddr;
|
||||
uintptr_t pl_dynaddr;
|
||||
char pl_pathname[PATH_MAX];
|
||||
};
|
||||
|
||||
|
|
|
@ -336,7 +336,7 @@ struct pmcstat_image *
|
|||
int pmcstat_string_lookup_hash(pmcstat_interned_string _is);
|
||||
|
||||
void pmcstat_process_elf_exec(struct pmcstat_process *_pp,
|
||||
struct pmcstat_image *_image, uintfptr_t _entryaddr,
|
||||
struct pmcstat_image *_image, uintptr_t _baseaddr, uintptr_t _dynaddr,
|
||||
struct pmcstat_args *args, struct pmc_plugins *plugins,
|
||||
struct pmcstat_stats *pmcstat_stats);
|
||||
|
||||
|
@ -344,9 +344,9 @@ void pmcstat_image_link(struct pmcstat_process *_pp,
|
|||
struct pmcstat_image *_i, uintfptr_t _lpc);
|
||||
|
||||
void pmcstat_process_aout_exec(struct pmcstat_process *_pp,
|
||||
struct pmcstat_image *_image, uintfptr_t _entryaddr);
|
||||
struct pmcstat_image *_image, uintptr_t _baseaddr);
|
||||
void pmcstat_process_exec(struct pmcstat_process *_pp,
|
||||
pmcstat_interned_string _path, uintfptr_t _entryaddr,
|
||||
pmcstat_interned_string _path, uintptr_t _baseaddr, uintptr_t _dynaddr,
|
||||
struct pmcstat_args *args, struct pmc_plugins *plugins,
|
||||
struct pmcstat_stats *pmcstat_stats);
|
||||
void pmcstat_image_determine_type(struct pmcstat_image *_image, struct pmcstat_args *args);
|
||||
|
|
|
@ -353,8 +353,8 @@ pmcstat_analyze_log(struct pmcstat_args *args,
|
|||
ev.pl_u.pl_x.pl_pathname);
|
||||
assert(image_path != NULL);
|
||||
pmcstat_process_exec(pp, image_path,
|
||||
ev.pl_u.pl_x.pl_entryaddr, args,
|
||||
plugins, pmcstat_stats);
|
||||
ev.pl_u.pl_x.pl_baseaddr, ev.pl_u.pl_x.pl_dynaddr,
|
||||
args, plugins, pmcstat_stats);
|
||||
break;
|
||||
|
||||
case PMCLOG_TYPE_PROCEXIT:
|
||||
|
|
|
@ -61,11 +61,11 @@ __FBSDID("$FreeBSD$");
|
|||
|
||||
void
|
||||
pmcstat_process_aout_exec(struct pmcstat_process *pp,
|
||||
struct pmcstat_image *image, uintfptr_t entryaddr)
|
||||
struct pmcstat_image *image, uintptr_t baseaddr)
|
||||
{
|
||||
(void) pp;
|
||||
(void) image;
|
||||
(void) entryaddr;
|
||||
(void) baseaddr;
|
||||
/* TODO Implement a.out handling */
|
||||
}
|
||||
|
||||
|
@ -75,18 +75,21 @@ pmcstat_process_aout_exec(struct pmcstat_process *pp,
|
|||
|
||||
void
|
||||
pmcstat_process_elf_exec(struct pmcstat_process *pp,
|
||||
struct pmcstat_image *image, uintfptr_t entryaddr,
|
||||
struct pmcstat_image *image, uintptr_t baseaddr, uintptr_t dynaddr,
|
||||
struct pmcstat_args *args, struct pmc_plugins *plugins,
|
||||
struct pmcstat_stats *pmcstat_stats)
|
||||
{
|
||||
uintmax_t libstart;
|
||||
struct pmcstat_image *rtldimage;
|
||||
|
||||
assert(image->pi_type == PMCSTAT_IMAGE_ELF32 ||
|
||||
image->pi_type == PMCSTAT_IMAGE_ELF64);
|
||||
|
||||
/* Create a map entry for the base executable. */
|
||||
pmcstat_image_link(pp, image, image->pi_vaddr);
|
||||
/*
|
||||
* The exact address where the executable gets mapped in will vary for
|
||||
* PIEs. The dynamic address recorded at process exec time corresponds
|
||||
* to the address where the executable's file object had been mapped to.
|
||||
*/
|
||||
pmcstat_image_link(pp, image, image->pi_vaddr + dynaddr);
|
||||
|
||||
/*
|
||||
* For dynamically linked executables we need to determine
|
||||
|
@ -105,16 +108,14 @@ pmcstat_process_elf_exec(struct pmcstat_process *pp,
|
|||
* [ TEXT DATA BSS HEAP -->*RTLD SHLIBS <--STACK]
|
||||
* ^ ^
|
||||
* 0 VM_MAXUSER_ADDRESS
|
||||
|
||||
*
|
||||
* The exact address where the loader gets mapped in
|
||||
* will vary according to the size of the executable
|
||||
* and the limits on the size of the process'es data
|
||||
* segment at the time of exec(). The entry address
|
||||
* segment at the time of exec(). The base address
|
||||
* recorded at process exec time corresponds to the
|
||||
* 'start' address inside the dynamic linker. From
|
||||
* this we can figure out the address where the
|
||||
* runtime loader's file object had been mapped to.
|
||||
* address where the runtime loader's file object had
|
||||
* been mapped to.
|
||||
*/
|
||||
rtldimage = pmcstat_image_from_path(image->pi_dynlinkerpath,
|
||||
0, args, plugins);
|
||||
|
@ -135,8 +136,7 @@ pmcstat_process_elf_exec(struct pmcstat_process *pp,
|
|||
return;
|
||||
}
|
||||
|
||||
libstart = entryaddr - rtldimage->pi_entry;
|
||||
pmcstat_image_link(pp, rtldimage, libstart);
|
||||
pmcstat_image_link(pp, rtldimage, baseaddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ pmcstat_process_elf_exec(struct pmcstat_process *pp,
|
|||
|
||||
void
|
||||
pmcstat_process_exec(struct pmcstat_process *pp,
|
||||
pmcstat_interned_string path, uintfptr_t entryaddr,
|
||||
pmcstat_interned_string path, uintptr_t baseaddr, uintptr_t dynaddr,
|
||||
struct pmcstat_args *args, struct pmc_plugins *plugins,
|
||||
struct pmcstat_stats *pmcstat_stats)
|
||||
{
|
||||
|
@ -167,13 +167,13 @@ pmcstat_process_exec(struct pmcstat_process *pp,
|
|||
case PMCSTAT_IMAGE_ELF32:
|
||||
case PMCSTAT_IMAGE_ELF64:
|
||||
pmcstat_stats->ps_exec_elf++;
|
||||
pmcstat_process_elf_exec(pp, image, entryaddr,
|
||||
pmcstat_process_elf_exec(pp, image, baseaddr, dynaddr,
|
||||
args, plugins, pmcstat_stats);
|
||||
break;
|
||||
|
||||
case PMCSTAT_IMAGE_AOUT:
|
||||
pmcstat_stats->ps_exec_aout++;
|
||||
pmcstat_process_aout_exec(pp, image, entryaddr);
|
||||
pmcstat_process_aout_exec(pp, image, baseaddr);
|
||||
break;
|
||||
|
||||
case PMCSTAT_IMAGE_INDETERMINABLE:
|
||||
|
|
|
@ -198,9 +198,9 @@ CTASSERT(offsetof(struct pmclog_pmcattach,pl_pathname) == 5*4 + TSDELTA);
|
|||
CTASSERT(sizeof(struct pmclog_pmcdetach) == 5*4 + TSDELTA);
|
||||
CTASSERT(sizeof(struct pmclog_proccsw) == 7*4 + 8 + TSDELTA);
|
||||
CTASSERT(sizeof(struct pmclog_procexec) == 5*4 + PATH_MAX +
|
||||
sizeof(uintfptr_t) + TSDELTA);
|
||||
2*sizeof(uintptr_t) + TSDELTA);
|
||||
CTASSERT(offsetof(struct pmclog_procexec,pl_pathname) == 5*4 + TSDELTA +
|
||||
sizeof(uintfptr_t));
|
||||
2*sizeof(uintptr_t));
|
||||
CTASSERT(sizeof(struct pmclog_procexit) == 5*4 + 8 + TSDELTA);
|
||||
CTASSERT(sizeof(struct pmclog_procfork) == 5*4 + TSDELTA);
|
||||
CTASSERT(sizeof(struct pmclog_sysexit) == 6*4);
|
||||
|
@ -1096,7 +1096,7 @@ pmclog_process_proccsw(struct pmc *pm, struct pmc_process *pp, pmc_value_t v, st
|
|||
|
||||
void
|
||||
pmclog_process_procexec(struct pmc_owner *po, pmc_id_t pmid, pid_t pid,
|
||||
uintfptr_t startaddr, char *path)
|
||||
uintptr_t baseaddr, uintptr_t dynaddr, char *path)
|
||||
{
|
||||
int pathlen, recordlen;
|
||||
|
||||
|
@ -1107,7 +1107,8 @@ pmclog_process_procexec(struct pmc_owner *po, pmc_id_t pmid, pid_t pid,
|
|||
PMCLOG_RESERVE(po, PMCLOG_TYPE_PROCEXEC, recordlen);
|
||||
PMCLOG_EMIT32(pid);
|
||||
PMCLOG_EMIT32(pmid);
|
||||
PMCLOG_EMITADDR(startaddr);
|
||||
PMCLOG_EMITADDR(baseaddr);
|
||||
PMCLOG_EMITADDR(dynaddr);
|
||||
PMCLOG_EMITSTRING(path,pathlen);
|
||||
PMCLOG_DESPATCH_SYNC(po);
|
||||
}
|
||||
|
|
|
@ -2126,7 +2126,8 @@ pmc_hook_handler(struct thread *td, int function, void *arg)
|
|||
CK_LIST_FOREACH(po, &pmc_ss_owners, po_ssnext)
|
||||
if (po->po_flags & PMC_PO_OWNS_LOGFILE)
|
||||
pmclog_process_procexec(po, PMC_ID_INVALID,
|
||||
p->p_pid, pk->pm_entryaddr, fullpath);
|
||||
p->p_pid, pk->pm_baseaddr, pk->pm_dynaddr,
|
||||
fullpath);
|
||||
PMC_EPOCH_EXIT();
|
||||
|
||||
PROC_LOCK(p);
|
||||
|
@ -2170,8 +2171,8 @@ pmc_hook_handler(struct thread *td, int function, void *arg)
|
|||
if (po->po_sscount == 0 &&
|
||||
po->po_flags & PMC_PO_OWNS_LOGFILE)
|
||||
pmclog_process_procexec(po, pm->pm_id,
|
||||
p->p_pid, pk->pm_entryaddr,
|
||||
fullpath);
|
||||
p->p_pid, pk->pm_baseaddr,
|
||||
pk->pm_dynaddr, fullpath);
|
||||
}
|
||||
|
||||
if (freepath)
|
||||
|
|
|
@ -919,7 +919,8 @@ do_execve(struct thread *td, struct image_args *args, struct mac *mac_p,
|
|||
if (PMC_SYSTEM_SAMPLING_ACTIVE() || PMC_PROC_IS_USING_PMCS(p)) {
|
||||
VOP_UNLOCK(imgp->vp);
|
||||
pe.pm_credentialschanged = credential_changing;
|
||||
pe.pm_entryaddr = imgp->entry_addr;
|
||||
pe.pm_baseaddr = imgp->reloc_base;
|
||||
pe.pm_dynaddr = imgp->et_dyn_addr;
|
||||
|
||||
PMC_CALL_HOOK_X(td, PMC_FN_PROCESS_EXEC, (void *) &pe);
|
||||
vn_lock(imgp->vp, LK_SHARED | LK_RETRY);
|
||||
|
|
|
@ -76,7 +76,8 @@ typedef enum ring_type {
|
|||
|
||||
struct pmckern_procexec {
|
||||
int pm_credentialschanged;
|
||||
uintfptr_t pm_entryaddr;
|
||||
uintptr_t pm_baseaddr;
|
||||
uintptr_t pm_dynaddr;
|
||||
};
|
||||
|
||||
struct pmckern_map_in {
|
||||
|
|
|
@ -202,7 +202,10 @@ struct pmclog_procexec {
|
|||
PMCLOG_ENTRY_HEADER
|
||||
uint32_t pl_pid;
|
||||
uint32_t pl_pmcid;
|
||||
uintfptr_t pl_start; /* keep 8 byte aligned */
|
||||
/* keep 8 byte aligned */
|
||||
uintptr_t pl_base; /* AT_BASE */
|
||||
/* keep 8 byte aligned */
|
||||
uintptr_t pl_dyn; /* PIE load base */
|
||||
char pl_pathname[PATH_MAX];
|
||||
} __packed;
|
||||
|
||||
|
@ -314,7 +317,7 @@ void pmclog_process_pmcdetach(struct pmc *_pm, pid_t _pid);
|
|||
void pmclog_process_proccsw(struct pmc *_pm, struct pmc_process *_pp,
|
||||
pmc_value_t _v, struct thread *);
|
||||
void pmclog_process_procexec(struct pmc_owner *_po, pmc_id_t _pmid, pid_t _pid,
|
||||
uintfptr_t _startaddr, char *_path);
|
||||
uintfptr_t _baseaddr, uintptr_t _dynaddr, char *_path);
|
||||
void pmclog_process_procexit(struct pmc *_pm, struct pmc_process *_pp);
|
||||
void pmclog_process_procfork(struct pmc_owner *_po, pid_t _oldpid, pid_t _newpid);
|
||||
void pmclog_process_sysexit(struct pmc_owner *_po, pid_t _pid);
|
||||
|
|
|
@ -459,10 +459,11 @@ pmcstat_print_log(void)
|
|||
ev.pl_u.pl_pc.pl_pcomm);
|
||||
break;
|
||||
case PMCLOG_TYPE_PROCEXEC:
|
||||
PMCSTAT_PRINT_ENTRY("exec","0x%x %d %p \"%s\"",
|
||||
PMCSTAT_PRINT_ENTRY("exec","0x%x %d %p %p \"%s\"",
|
||||
ev.pl_u.pl_x.pl_pmcid,
|
||||
ev.pl_u.pl_x.pl_pid,
|
||||
(void *) ev.pl_u.pl_x.pl_entryaddr,
|
||||
(void *)ev.pl_u.pl_x.pl_baseaddr,
|
||||
(void *)ev.pl_u.pl_x.pl_dynaddr,
|
||||
ev.pl_u.pl_x.pl_pathname);
|
||||
break;
|
||||
case PMCLOG_TYPE_PROCEXIT:
|
||||
|
|
Loading…
Reference in a new issue