mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2025-01-01 00:18:15 +01:00
Add PT_VM_TIMESTAMP and PT_VM_ENTRY so that the tracing process can
obtain the memory map of the traced process. PT_VM_TIMESTAMP can be used to check if the memory map changed since the last time to avoid iterating over all the VM entries unnecesarily. MFC after: 1 month
This commit is contained in:
parent
4a97e4f030
commit
90b4621a5f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=203696
@ -2,7 +2,7 @@
|
||||
.\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $
|
||||
.\"
|
||||
.\" This file is in the public domain.
|
||||
.Dd March 27, 2009
|
||||
.Dd February 8, 2010
|
||||
.Dt PTRACE 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -327,6 +327,61 @@ This request will trace the specified process on each system call exit.
|
||||
.It PT_SYSCALL
|
||||
This request will trace the specified process
|
||||
on each system call entry and exit.
|
||||
.It PT_VM_TIMESTAMP
|
||||
This request returns the generation number or timestamp of the memory map of
|
||||
the traced process as the return value from
|
||||
.Fn ptrace .
|
||||
This provides a low-cost way for the tracing process to determine if the
|
||||
VM map changed since the last time this request was made.
|
||||
.It PT_VM_ENTRY
|
||||
This request is used to iterate over the entries of the VM map of the traced
|
||||
process.
|
||||
The
|
||||
.Fa addr
|
||||
argument specifies a pointer to a
|
||||
.Vt "struct ptrace_vm_entry" ,
|
||||
which is defined as follows:
|
||||
.Bd -literal
|
||||
struct ptrace_vm_entry {
|
||||
void *pve_cookie;
|
||||
u_long pve_start;
|
||||
u_long pve_end;
|
||||
u_long pve_offset;
|
||||
u_int pve_prot;
|
||||
u_int pve_pathlen;
|
||||
char *pve_path;
|
||||
};
|
||||
.Ed
|
||||
.Pp
|
||||
The first entry is returned by setting
|
||||
.Va pve_cookie
|
||||
to
|
||||
.Dv NULL .
|
||||
Subsequent entries are returned by leaving
|
||||
.Va pve_cookie
|
||||
unmodified from the value returned by previous requests.
|
||||
By setting
|
||||
.Va pve_pathlen
|
||||
to a non-zero value on entry, the pathname of the backing object is returned
|
||||
in the buffer pointed to by
|
||||
.Va pve_path ,
|
||||
provided the entry is backed by a vnode.
|
||||
The
|
||||
.Va pve_pathlen
|
||||
field is updated with the actual length of the pathname (including the
|
||||
terminating null character).
|
||||
The
|
||||
.Va pve_offset
|
||||
field is the offset within the backing object at which the range starts.
|
||||
The range is located in the VM space at
|
||||
.Va pve_start
|
||||
and extends up to
|
||||
.Va pve_end
|
||||
(inclusive).
|
||||
.Pp
|
||||
The
|
||||
.Fa data
|
||||
argument is ignored.
|
||||
.El
|
||||
.Pp
|
||||
Additionally, machine-specific requests can exist.
|
||||
@ -376,6 +431,10 @@ or
|
||||
.Dv PT_SETDBREGS
|
||||
was attempted on a process with no valid register set.
|
||||
(This is normally true only of system processes.)
|
||||
.It
|
||||
.Dv PT_VM_ENTRY
|
||||
was given an invalid value for
|
||||
.Fa pve_cookie .
|
||||
.El
|
||||
.It Bq Er EBUSY
|
||||
.Bl -bullet -compact
|
||||
@ -405,6 +464,22 @@ on a process in violation of the requirements listed under
|
||||
.Dv PT_ATTACH
|
||||
above.
|
||||
.El
|
||||
.It Bq Er ENOENT
|
||||
.Bl -bullet -compact
|
||||
.It
|
||||
.Dv PT_VM_ENTRY
|
||||
previously returned the last entry of the memory map.
|
||||
No more entries exist.
|
||||
.El
|
||||
.It Bq Er ENAMETOOLONG
|
||||
.Bl -bullet -compact
|
||||
.It
|
||||
.Dv PT_VM_ENTRY
|
||||
cannot return the pathname of the backing object because the buffer is not big
|
||||
enough.
|
||||
.Fa pve_pathlen
|
||||
holds the minimum buffer size required on return.
|
||||
.El
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr execve 2 ,
|
||||
|
@ -346,6 +346,92 @@ proc_rwmem(struct proc *p, struct uio *uio)
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ptrace_vm_entry(struct thread *td, struct proc *p, struct ptrace_vm_entry *pve)
|
||||
{
|
||||
vm_map_t map;
|
||||
vm_map_entry_t entry;
|
||||
vm_object_t obj, tobj, lobj;
|
||||
struct vnode *vp;
|
||||
char *freepath, *fullpath;
|
||||
u_int pathlen;
|
||||
int error, vfslocked;
|
||||
|
||||
map = &p->p_vmspace->vm_map;
|
||||
entry = map->header.next;
|
||||
if (pve->pve_cookie != NULL) {
|
||||
while (entry != &map->header && entry != pve->pve_cookie)
|
||||
entry = entry->next;
|
||||
if (entry != pve->pve_cookie)
|
||||
return (EINVAL);
|
||||
entry = entry->next;
|
||||
}
|
||||
while (entry != &map->header && (entry->eflags & MAP_ENTRY_IS_SUB_MAP))
|
||||
entry = entry->next;
|
||||
if (entry == &map->header)
|
||||
return (ENOENT);
|
||||
|
||||
/* We got an entry. */
|
||||
pve->pve_cookie = entry;
|
||||
pve->pve_start = entry->start;
|
||||
pve->pve_end = entry->end - 1;
|
||||
pve->pve_offset = entry->offset;
|
||||
pve->pve_prot = entry->protection;
|
||||
|
||||
/* Backing object's path needed? */
|
||||
if (pve->pve_pathlen == 0)
|
||||
return (0);
|
||||
|
||||
pathlen = pve->pve_pathlen;
|
||||
pve->pve_pathlen = 0;
|
||||
|
||||
obj = entry->object.vm_object;
|
||||
if (obj == NULL)
|
||||
return (0);
|
||||
|
||||
VM_OBJECT_LOCK(obj);
|
||||
for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) {
|
||||
if (tobj != obj)
|
||||
VM_OBJECT_LOCK(tobj);
|
||||
if (lobj != obj)
|
||||
VM_OBJECT_UNLOCK(lobj);
|
||||
lobj = tobj;
|
||||
pve->pve_offset += tobj->backing_object_offset;
|
||||
}
|
||||
if (lobj != NULL) {
|
||||
vp = (lobj->type == OBJT_VNODE) ? lobj->handle : NULL;
|
||||
if (vp != NULL)
|
||||
vref(vp);
|
||||
if (lobj != obj)
|
||||
VM_OBJECT_UNLOCK(lobj);
|
||||
VM_OBJECT_UNLOCK(obj);
|
||||
} else
|
||||
vp = NULL;
|
||||
|
||||
if (vp == NULL)
|
||||
return (0);
|
||||
|
||||
freepath = NULL;
|
||||
fullpath = NULL;
|
||||
vn_fullpath(td, vp, &fullpath, &freepath);
|
||||
vfslocked = VFS_LOCK_GIANT(vp->v_mount);
|
||||
vrele(vp);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
|
||||
error = 0;
|
||||
if (fullpath != NULL) {
|
||||
pve->pve_pathlen = strlen(fullpath) + 1;
|
||||
if (pve->pve_pathlen <= pathlen) {
|
||||
error = copyout(fullpath, pve->pve_path,
|
||||
pve->pve_pathlen);
|
||||
} else
|
||||
error = ENAMETOOLONG;
|
||||
}
|
||||
if (freepath != NULL)
|
||||
free(freepath, M_TEMP);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process debugging system call.
|
||||
*/
|
||||
@ -389,6 +475,7 @@ ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
union {
|
||||
struct ptrace_io_desc piod;
|
||||
struct ptrace_lwpinfo pl;
|
||||
struct ptrace_vm_entry pve;
|
||||
struct dbreg dbreg;
|
||||
struct fpreg fpreg;
|
||||
struct reg reg;
|
||||
@ -429,6 +516,9 @@ ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
case PT_IO:
|
||||
error = COPYIN(uap->addr, &r.piod, sizeof r.piod);
|
||||
break;
|
||||
case PT_VM_ENTRY:
|
||||
error = COPYIN(uap->addr, &r.pve, sizeof r.pve);
|
||||
break;
|
||||
default:
|
||||
addr = uap->addr;
|
||||
break;
|
||||
@ -441,6 +531,9 @@ ptrace(struct thread *td, struct ptrace_args *uap)
|
||||
return (error);
|
||||
|
||||
switch (uap->req) {
|
||||
case PT_VM_ENTRY:
|
||||
error = COPYOUT(&r.pve, uap->addr, sizeof r.pve);
|
||||
break;
|
||||
case PT_IO:
|
||||
error = COPYOUT(&r.piod, uap->addr, sizeof r.piod);
|
||||
break;
|
||||
@ -977,6 +1070,16 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
|
||||
PROC_LOCK(p);
|
||||
break;
|
||||
|
||||
case PT_VM_TIMESTAMP:
|
||||
td->td_retval[0] = p->p_vmspace->vm_map.timestamp;
|
||||
break;
|
||||
|
||||
case PT_VM_ENTRY:
|
||||
PROC_UNLOCK(p);
|
||||
error = ptrace_vm_entry(td, p, addr);
|
||||
PROC_LOCK(p);
|
||||
break;
|
||||
|
||||
default:
|
||||
#ifdef __HAVE_PTRACE_MACHDEP
|
||||
if (req >= PT_FIRSTMACH) {
|
||||
|
@ -67,6 +67,10 @@
|
||||
#define PT_SETFPREGS 36 /* set floating-point registers */
|
||||
#define PT_GETDBREGS 37 /* get debugging registers */
|
||||
#define PT_SETDBREGS 38 /* set debugging registers */
|
||||
|
||||
#define PT_VM_TIMESTAMP 40 /* Get VM version (timestamp) */
|
||||
#define PT_VM_ENTRY 41 /* Get VM map (entry) */
|
||||
|
||||
#define PT_FIRSTMACH 64 /* for machine-specific requests */
|
||||
#include <machine/ptrace.h> /* machine-specific requests, if any */
|
||||
|
||||
@ -98,6 +102,17 @@ struct ptrace_lwpinfo {
|
||||
sigset_t pl_siglist; /* LWP pending signal */
|
||||
};
|
||||
|
||||
/* Argument structure for PT_VM_ENTRY. */
|
||||
struct ptrace_vm_entry {
|
||||
void *pve_cookie; /* Token used to iterate. */
|
||||
u_long pve_start; /* Start VA of range. */
|
||||
u_long pve_end; /* End VA of range (incl). */
|
||||
u_long pve_offset; /* Offset in backing object. */
|
||||
u_int pve_prot; /* Protection of memory range. */
|
||||
u_int pve_pathlen; /* Size of path. */
|
||||
char *pve_path; /* Path name of object. */
|
||||
};
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#define PTRACESTOP_SC(p, td, flag) \
|
||||
|
Loading…
Reference in New Issue
Block a user