Re: git: 3ce04aca49e9 - main - proc: Add a sysctl to fetch virtual address space layout info
Date: Wed, 19 Jan 2022 21:18:46 UTC
On Mon, Jan 17, 2022 at 09:13:10PM +0000, Mark Johnston wrote: > The branch main has been updated by markj: > > URL: https://cgit.FreeBSD.org/src/commit/?id=3ce04aca49e9228c3c6ab24ffbee709f5b464765 > > commit 3ce04aca49e9228c3c6ab24ffbee709f5b464765 > Author: Mark Johnston <markj@FreeBSD.org> > AuthorDate: 2022-01-17 16:43:03 +0000 > Commit: Mark Johnston <markj@FreeBSD.org> > CommitDate: 2022-01-17 21:12:43 +0000 > > proc: Add a sysctl to fetch virtual address space layout info > > This provides information about fixed regions of the target process' > user memory map. > > Reviewed by: kib > MFC after: 1 month > Sponsored by: The FreeBSD Foundation > Differential Revision: https://reviews.freebsd.org/D33708 > --- > sys/compat/freebsd32/freebsd32.h | 13 +++++++ > sys/kern/kern_proc.c | 78 ++++++++++++++++++++++++++++++++++++++++ > sys/sys/sysctl.h | 1 + > sys/sys/user.h | 19 ++++++++++ > 4 files changed, 111 insertions(+) > > diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h > index 1f6270d684ee..96bf79d28c02 100644 > --- a/sys/compat/freebsd32/freebsd32.h > +++ b/sys/compat/freebsd32/freebsd32.h > @@ -432,6 +432,19 @@ struct kinfo_sigtramp32 { > uint32_t ksigtramp_spare[4]; > }; > > +struct kinfo_vm_layout32 { > + uint32_t kvm_min_user_addr; > + uint32_t kvm_max_user_addr; > + uint32_t kvm_text_addr; > + uint32_t kvm_text_size; > + uint32_t kvm_data_addr; > + uint32_t kvm_data_size; > + uint32_t kvm_stack_addr; > + uint32_t kvm_stack_size; > + int kvm_map_flags; > + uint32_t kvm_spare[14]; > +}; > + > struct kld_file_stat_1_32 { > int version; /* set to sizeof(struct kld_file_stat_1) */ > char name[MAXPATHLEN]; > diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c > index 1ef8d86295b3..b5896cedf3b9 100644 > --- a/sys/kern/kern_proc.c > +++ b/sys/kern/kern_proc.c > @@ -3200,6 +3200,80 @@ errlocked: > return (error); > } > > +static int > +sysctl_kern_proc_vm_layout(SYSCTL_HANDLER_ARGS) > +{ > + struct kinfo_vm_layout kvm; > + struct proc *p; > + struct vmspace *vmspace; > + int error, *name; > + > + name = (int *)arg1; > + if ((u_int)arg2 != 1) > + return (EINVAL); > + > + error = pget((pid_t)name[0], PGET_CANDEBUG, &p); > + if (error != 0) > + return (error); > +#ifdef COMPAT_FREEBSD32 > + if (SV_CURPROC_FLAG(SV_ILP32)) { > + if (!SV_PROC_FLAG(p, SV_ILP32)) { > + PROC_UNLOCK(p); > + return (EINVAL); > + } > + } > +#endif > + vmspace = vmspace_acquire_ref(p); > + PROC_UNLOCK(p); > + > + memset(&kvm, 0, sizeof(kvm)); > + kvm.kvm_min_user_addr = vm_map_min(&vmspace->vm_map); > + kvm.kvm_max_user_addr = vm_map_max(&vmspace->vm_map); > + kvm.kvm_text_addr = (uintptr_t)vmspace->vm_taddr; > + kvm.kvm_text_size = vmspace->vm_tsize; > + kvm.kvm_data_addr = (uintptr_t)vmspace->vm_daddr; > + kvm.kvm_data_size = vmspace->vm_dsize; > + kvm.kvm_stack_addr = (uintptr_t)vmspace->vm_maxsaddr; > + kvm.kvm_stack_size = vmspace->vm_ssize; > + if ((vmspace->vm_map.flags & MAP_WIREFUTURE) != 0) > + kvm.kvm_map_flags |= KMAP_FLAG_WIREFUTURE; > + if ((vmspace->vm_map.flags & MAP_ASLR) != 0) > + kvm.kvm_map_flags |= KMAP_FLAG_ASLR; > + if ((vmspace->vm_map.flags & MAP_ASLR_IGNSTART) != 0) > + kvm.kvm_map_flags |= KMAP_FLAG_ASLR_IGNSTART; > + if ((vmspace->vm_map.flags & MAP_WXORX) != 0) > + kvm.kvm_map_flags |= KMAP_FLAG_WXORX; > + if ((vmspace->vm_map.flags & MAP_ASLR_STACK) != 0) > + kvm.kvm_map_flags |= KMAP_FLAG_ASLR_STACK; > + > +#ifdef COMPAT_FREEBSD32 > + if (SV_CURPROC_FLAG(SV_ILP32)) { > + struct kinfo_vm_layout32 kvm32; > + > + memset(&kvm32, 0, sizeof(kvm32)); > + kvm32.kvm_min_user_addr = (uint32_t)kvm.kvm_min_user_addr; If this is kept (see below), could the CP macros be used from sys/abi_compat.h be used? > + kvm32.kvm_max_user_addr = (uint32_t)kvm.kvm_max_user_addr; > + kvm32.kvm_text_addr = (uint32_t)kvm.kvm_text_addr; > + kvm32.kvm_text_size = (uint32_t)kvm.kvm_text_size; > + kvm32.kvm_data_addr = (uint32_t)kvm.kvm_data_addr; > + kvm32.kvm_data_size = (uint32_t)kvm.kvm_data_size; > + kvm32.kvm_stack_addr = (uint32_t)kvm.kvm_stack_addr; > + kvm32.kvm_stack_size = (uint32_t)kvm.kvm_stack_size; > + kvm32.kvm_map_flags = kvm.kvm_map_flags; > + vmspace_free(vmspace); > + error = SYSCTL_OUT(req, &kvm32, sizeof(kvm32)); > + goto out; > + } > +#endif > + > + error = SYSCTL_OUT(req, &kvm, sizeof(kvm)); > +#ifdef COMPAT_FREEBSD32 > +out: > +#endif > + vmspace_free(vmspace); > + return (error); > +} > + > SYSCTL_NODE(_kern, KERN_PROC, proc, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, > "Process table"); > > @@ -3318,6 +3392,10 @@ static SYSCTL_NODE(_kern_proc, KERN_PROC_SIGFASTBLK, sigfastblk, CTLFLAG_RD | > CTLFLAG_ANYBODY | CTLFLAG_MPSAFE, sysctl_kern_proc_sigfastblk, > "Thread sigfastblock address"); > > +static SYSCTL_NODE(_kern_proc, KERN_PROC_VM_LAYOUT, vm_layout, CTLFLAG_RD | > + CTLFLAG_ANYBODY | CTLFLAG_MPSAFE, sysctl_kern_proc_vm_layout, > + "Process virtual address space layout info"); > + > int allproc_gen; > > /* > diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h > index 71a34652ff44..f25152db8215 100644 > --- a/sys/sys/sysctl.h > +++ b/sys/sys/sysctl.h > @@ -1013,6 +1013,7 @@ TAILQ_HEAD(sysctl_ctx_list, sysctl_ctx_entry); > #define KERN_PROC_CWD 42 /* process current working directory */ > #define KERN_PROC_NFDS 43 /* number of open file descriptors */ > #define KERN_PROC_SIGFASTBLK 44 /* address of fastsigblk magic word */ > +#define KERN_PROC_VM_LAYOUT 45 /* virtual address space layout info */ > > /* > * KERN_IPC identifiers > diff --git a/sys/sys/user.h b/sys/sys/user.h > index e8bfba981e83..f57a69aed13e 100644 > --- a/sys/sys/user.h > +++ b/sys/sys/user.h > @@ -598,6 +598,25 @@ struct kinfo_sigtramp { > void *ksigtramp_spare[4]; > }; > > +#define KMAP_FLAG_WIREFUTURE 0x01 /* all future mappings wil be wired */ > +#define KMAP_FLAG_ASLR 0x02 /* ASLR is applied to mappings */ > +#define KMAP_FLAG_ASLR_IGNSTART 0x04 /* ASLR may map into sbrk grow region */ > +#define KMAP_FLAG_WXORX 0x08 /* W^X mapping policy is enforced */ > +#define KMAP_FLAG_ASLR_STACK 0x10 /* the stack location is randomized */ > + > +struct kinfo_vm_layout { > + uintptr_t kvm_min_user_addr; > + uintptr_t kvm_max_user_addr; > + uintptr_t kvm_text_addr; > + size_t kvm_text_size; > + uintptr_t kvm_data_addr; > + size_t kvm_data_size; > + uintptr_t kvm_stack_addr; > + size_t kvm_stack_size; > + int kvm_map_flags; Should there be an explicit pad here? > + uintptr_t kvm_spare[14]; > +}; I'd prefer these were kvaddr_t's (uint64_t) as that would eliminate the need for a 32-bit translation (and avoid future complications on for CheriABI). All the _addrs really are addresses rather than pointers. > + > #ifdef _KERNEL > /* Flags for kern_proc_out function. */ > #define KERN_PROC_NOTHREADS 0x1 > -- Brooks