_kvm_uread maps a userspace page to a slot in the amap, but only checks whether the slot is indeed within the amap. It must also use the slot to extract the correct vm_anon in order to find the physical address to read from.
The attached program shows that kvm_uread otherwise attempts reads from an incorrect userspace address. ok? Index: lib/libkvm/kvm_proc.c =================================================================== RCS file: /cvs/src/lib/libkvm/kvm_proc.c,v retrieving revision 1.52 diff -u -p -r1.52 kvm_proc.c --- lib/libkvm/kvm_proc.c 22 Oct 2014 04:13:35 -0000 1.52 +++ lib/libkvm/kvm_proc.c 16 Apr 2016 18:23:32 -0000 @@ -163,7 +163,7 @@ _kvm_ureadm(kvm_t *kd, const struct kinf if (slot > amap.am_nslot) return (NULL); - addr = (u_long)amap.am_anon + (offset / kd->nbpg) * sizeof(anonp); + addr = (u_long)(amap.am_anon + slot); if (KREAD(kd, addr, &anonp)) return (NULL);
/* * Compile with: gcc -O2 libkvmtest.c -o libkvmtest -lkvm * Run as root. */ #include <sys/param.h> #include <sys/sysctl.h> #include <sys/mman.h> #include <err.h> #include <fcntl.h> #include <kvm.h> #include <stdio.h> #include <string.h> #include <unistd.h> #define ARGSIZE (2 * 4096) #define DO_MUNMAP 1 int main(int argc, char **argv) { int cnt, i; char *p, **pargv; kvm_t *kd; struct kinfo_proc *kp; p = mmap(NULL, ARGSIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (p == MAP_FAILED) err(1, "mmap"); /* * Make sure that the kernel creates an amap the mapped range * by populating it with pages. */ memset(p, 0, ARGSIZE); /* * Now unmap the first page. This causes the mapped * range to be split into two vm_map_entries. The * first entry is freed. The second vm_amp_entry represents * the second page in the range. The second map entry points * to the previously created amap. Since the amap still * contains two slots to represent the original range, * the second vm_map_entry must point into the amap with * an offset of 1 to refer to the slot representing the second * page. */ #if DO_MUNMAP if (munmap(p, 4096) == -1) err(1, "munmap"); #endif p[4096] = 'A'; argv[0] = &p[4096]; kd = kvm_openfiles("./libkvmtest", "/dev/mem", NULL, O_RDONLY, NULL); if (kd == NULL) errx(1, "kvm_open"); kp = kvm_getprocs(kd, KERN_PROC_PID, getpid(), sizeof *kp, &cnt); if (kp == NULL || cnt != 1) errx(1, "kvm_getprocs"); pargv = kvm_getargv(kd, kp, 8192); if (pargv == NULL) errx(1, "pargv"); for (i = 0; pargv[i] != NULL; i++) printf("pargv[%d]: %s\n", i, pargv[i]); return 0; }