Index: sys/compat/freebsd32/freebsd32.h =================================================================== --- sys/compat/freebsd32/freebsd32.h +++ sys/compat/freebsd32/freebsd32.h @@ -432,6 +432,19 @@ 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]; Index: sys/kern/kern_proc.c =================================================================== --- sys/kern/kern_proc.c +++ sys/kern/kern_proc.c @@ -3200,6 +3200,78 @@ 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; + u_int namelen; + + name = (int *)arg1; + namelen = arg2; + if (namelen != 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; + +#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)); +out: + vmspace_free(vmspace); + return (error); +} + SYSCTL_NODE(_kern, KERN_PROC, proc, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Process table"); @@ -3318,6 +3390,10 @@ 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; /* Index: sys/sys/sysctl.h =================================================================== --- sys/sys/sysctl.h +++ sys/sys/sysctl.h @@ -1013,6 +1013,7 @@ #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 Index: sys/sys/user.h =================================================================== --- sys/sys/user.h +++ sys/sys/user.h @@ -598,6 +598,24 @@ 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 */ + +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 Index: tests/sys/kern/kern_copyin.c =================================================================== --- tests/sys/kern/kern_copyin.c +++ tests/sys/kern/kern_copyin.c @@ -33,6 +33,8 @@ #include #include #include +#include + #include #include #include @@ -74,27 +76,20 @@ static uintptr_t get_maxuser_address(void) { + struct kinfo_vm_layout kvm; size_t len; - uintptr_t psstrings; int error, mib[4]; mib[0] = CTL_KERN; mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PS_STRINGS; + mib[2] = KERN_PROC_VM_LAYOUT; mib[3] = getpid(); - len = sizeof(psstrings); - error = sysctl(mib, nitems(mib), &psstrings, &len, NULL, 0); + len = sizeof(kvm); + error = sysctl(mib, nitems(mib), &kvm, &len, NULL, 0); if (error != 0) return (0); - if (psstrings == PS_STRINGS_LA57) - return (VM_MAXUSER_ADDRESS_LA57); - if (psstrings == PS_STRINGS_LA48) - return (VM_MAXUSER_ADDRESS_LA48); - /* AMD LA48 with clipped UVA */ - if (psstrings == PS_STRINGS_LA48 - PAGE_SIZE) - return (VM_MAXUSER_ADDRESS_LA48 - PAGE_SIZE); - return (0); + return (kvm.kvm_max_user_addr); } #endif