git: 3ce04aca49e9 - main - proc: Add a sysctl to fetch virtual address space layout info

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Mon, 17 Jan 2022 21:13:10 UTC
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;
+		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;
+	uintptr_t	kvm_spare[14];
+};
+
 #ifdef _KERNEL
 /* Flags for kern_proc_out function. */
 #define KERN_PROC_NOTHREADS	0x1