I wanted to get the memory map of a child proc with sysctl but noticed
I could only do this as root. I am allowed to ptrace it though so it
felt a bit unfair..

..so what about doing some of the the same checks as is done upon
PT_ATTACH? (and hijacking the global_ptrace global to mean we can get
the memory map also from not direct descending processes if we want).

Index: sys/kern/kern_sysctl.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_sysctl.c,v
retrieving revision 1.305
diff -u -p -u -r1.305 kern_sysctl.c
--- sys/kern/kern_sysctl.c      27 May 2016 19:45:04 -0000      1.305
+++ sys/kern/kern_sysctl.c      27 Jun 2016 14:39:27 -0000
@@ -117,6 +117,7 @@ extern struct disklist_head disklist;
 extern fixpt_t ccpu;
 extern  long numvnodes;
 extern u_int net_livelocks;
+extern int global_ptrace;
 
 extern void nmbclust_update(void);
 
@@ -1980,16 +1981,21 @@ sysctl_proc_vmmap(int *name, u_int namel
                if (findpr->ps_flags & (PS_SYSTEM | PS_EXITING))
                        return (EINVAL);
 
-#if 1
-               /* XXX Allow only root for now */
-               if ((error = suser(cp, 0)) != 0)
+               /* Only owner (unless the last exec gave it setuid/setgid
+                * privs) or root can get vmmap.
+                */
+               if ((findpr->ps_ucred->cr_uid != cp->p_ucred->cr_uid ||
+                   ISSET(findpr->ps_flags, PS_SUGIDEXEC | PS_SUGID)) &&
+                   (error = suser(cp, 0)) != 0) {
                        return (error);
-#else
-               /* Only owner or root can get vmmap */
-               if (findpr->ps_ucred->cr_uid != cp->p_ucred->cr_uid &&
-                   (error = suser(cp, 0)) != 0)
+               }
+
+               /* Must be a child (unless global_ptrace is set) */
+               if (global_ptrace == 0 && !inferior(findpr, cp->p_p) &&
+                   (error = suser(cp, 0)) != 0) {
                        return (error);
-#endif
+               }
+
        } else {
                /* Only root can get kernel_map */
                if ((error = suser(cp, 0)) != 0)


this makes the following snippet work:

#include <sys/param.h>
#include <sys/sysctl.h>

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <err.h>

int main(int argc, char **argv)
{
  int mib[3];
  size_t len;

  struct kinfo_vmentry entry;
  len = sizeof(entry);

  pid_t pid = fork();

  if (pid == 0) {
    sleep(6000);
    exit(0);
  }   

  mib[0] = CTL_KERN;
  mib[1] = KERN_PROC_VMMAP;
  mib[2] = pid;

  entry.kve_start = 0;
  if (sysctl(mib, 3, &entry, &len, NULL, 0) == -1)
    err(1, "sysctl");
  
  printf("kve_start: 0x%lx, kve_end: 0x%lx\n", entry.kve_start, entry.kve_end);
  entry.kve_start = entry.kve_start + 1;
  u_long old_end = entry.kve_end;

  while (sysctl(mib, 3, &entry, &len, NULL, 0) != -1) {
    if (old_end == entry.kve_end)
      break;
    old_end = entry.kve_end;
    printf("kve_start: 0x%lx, kve_end: 0x%lx\n", entry.kve_start, 
entry.kve_end);
    entry.kve_start = entry.kve_start + 1;
  }

  kill(pid, 9);

  return 0;
}

output:

$ ./p_fork           
kve_start: 0x1000, kve_end: 0x1000
kve_start: 0xf9e06100000, kve_end: 0xf9e06101000
kve_start: 0xf9e06200000, kve_end: 0xf9e06201000
kve_start: 0xf9e06301000, kve_end: 0xf9e06302000
kve_start: 0xf9e06401000, kve_end: 0xf9e06402000
kve_start: 0xf9e06501000, kve_end: 0xf9e06502000
kve_start: 0xfa0125d6000, kve_end: 0xfa0125d7000
kve_start: 0xfa016217000, kve_end: 0xfa016218000
[ .. ]

..and then one can do this in radare2 on OpenBSD:

$ r2 -d /bin/ls 
Process with PID 18988 started...
attach 18988 18988
[0x12bd76c037f0]> dm
sys 0000 0x0000000000001000 - 0x0000000000001000 s ---- ? 
sys 224K 0x000012bd76c00000 * 0x000012bd76c38000 s -r-x ? 
sys 032K 0x000012bd76d38000 - 0x000012bd76d40000 s ---x ? 
sys 0000 0x000012bd76e00000 - 0x000012bd76e00000 s ---- ? 
sys 004K 0x000012bd76e40000 - 0x000012bd76e41000 s --wx ? 
sys 004K 0x000012bd76f40000 - 0x000012bd76f41000 s --wx ? 
sys 008K 0x000012bd77040000 - 0x000012bd77042000 s --wx ? 
sys 004K 0x000012bd77042000 - 0x000012bd77043000 s --wx ? 
sys 040K 0x000012bd77043000 - 0x000012bd7704d000 s --wx ? 
sys 0000 0x000012bf76e00000 - 0x000012bf76e00000 s ---- ? 
sys 004K 0x000012c036656000 - 0x000012c036657000 s -r-x ? 
sys 028M 0x00007f7ffdff7000 - 0x00007f7fffbf7000 s ---- ? 
sys 4.0M 0x00007f7fffbf7000 - 0x00007f7fffff0000 s --wx ? 
sys 028K 0x00007f7fffff0000 - 0x00007f7fffff7000 s --wx ? 

(the protection bits are flipped, ignore...)

Is there a better way?

/gabriel

Reply via email to