Reading process memory from another process (procfs, libprocstat, kvm)

Hello,

I've been successfully reading some process memory from another process using procfs
and /proc/{pid}/mem file with standard fopen, fseek and fread functions. It works just fine.

When reading procfs(5), it's telling:
Code:
DESCRIPTION
     This functionality is deprecated.  Users are advised to use
     libprocstat(3) and kvm(3) instead.
Although I've tried a few time, I could not find how to read the process memory with kvm and kvm_read.
I've also searched inside the kernel code for kvm examples, but with no real success.

I know ptrace can be used, but I specificaly do not need the process to be stopped. The process has to continue running normaly without any pause.

Any pointers please?
I'd really like to use libprocstat and kvm as advised in the manual. I also understand that the reading has to be made from a process with root permissions.
 
look at procstat source code
procstat vm
I think I've already tried looking that code, but either I stopped too early the code reading, or I just found out it could only return the process memory map, which of course is useful, but I couldn't read the process memory itself and to cast a buffer of that read memory into an existing C structure.
Is there something I'm missing?
 
a sample function I'm using for this:

C:
void *get_vm_data(pid_t pid, uintptr_t addr, size_t structsz, char quiet) {
  char mfpath[MAXPATHLEN + 1];
  char *buf;
  FILE *mf;
  size_t sz;

  if (addr == 0) {
    return NULL;
  }

  buf = malloc(structsz);
  if (buf == NULL) {
    if (!quiet) {
      printf("could not allocate buf\n");
    }
    return NULL;
  }

  snprintf(mfpath, MAXPATHLEN, "/proc/%d/mem", pid);
  mf = fopen(mfpath, "r");
  if (mf == NULL) {
    if (!quiet) {
      printf("could not open mem: %s\n", mfpath);
    }
    return NULL;
  }

  fseeko(mf, addr, SEEK_SET);
  sz = fread(buf, 1, structsz, mf);
  if (sz == 0 || sz != structsz) {
    if (!quiet) {
      printf("get_vm_data: could not read vm data, addr=%#010x, sz=%u\n", addr,
             sz);
    }
    free(buf);
    return NULL;
  }

  fclose(mf);
  return buf;
}

On MacOS, a similar function would be mach_vm_read.
 
yes, it looks like you can't read the memory via libprocstat. you can get the vmmap, env, etc and its done via sysctl (inside libprocstat (kern.proc.*)
 
Does anyone have some pointers on how to use kvm(3)()?

I've tried already a few things with kvm_open(3)() and kvm_read(3)(), but it seems that it's clearly not the process memory I'm targeting. Tried to dump the memory from the process memory map with kvm_read, but the dump didn't show anything from the real memory of the process dumped from procfs.

How to target another process memory with kvm(3)?()
Why would FreeBSD deprecate procfs and point to libprocstat(3) and kvm(3) in the manual, but not to be able to read another process memory with the new way?
Something is not really clear and I can't find anything to help me do this on FreeBSD.
 
I've probably badly explained what I'm trying to achieve, in order to make things clearer:
  • I've got an executable/service that's running on my FreeBSD system
  • I do not have the code for that executable/service, just some headers definitions (C structures) it's using while it runs.
  • I cannot stop the executable/service for any reason, since it may simply kill itself, breaking the "no stop" rule.
  • I'm not using or producing cores (with gcore) since it stops the executable/service, for sure.
  • it is actually possible to read some of the memory of this process from another one with the procfs and /proc/{pid}/mem, and to cast these buffers to C structures, enabling me to create some live stats that actually do not exists as any sort of output from this executable/service.
  • procfs manual tells it's deprecated, and I should use libprocstat and kvm to do that
  • I've read procfs, procstat, libprocstat, proc sources inside the FreeBSD sources, and I could see that to produce the output for /proc/{pid}/mem, some vm_* functions are used, but they can only be used when the KERNEL compilation flags are on.
  • I thought I could use kvm(3) to read (-only) the system memory and that I would be able to find the executable/service memory I'm looking to access to in order to stop using deprecated procfs, but that does not seem to be an easy migration task.
  • It seems procfs has been marked as deprecated for a while now, and it's still in FreeBSD. Would procfs become obsolete sooner or later? Would there still be a way to read process memory without stopping the process when procfs becomes obsolete?
I'm sorry if it does not look "secured" to read process memory, I'm not modifying the memory, the goal is only to produce stats without having the executable/service to stop (it can be restarted, ofc, but it's breaking the live stats feature I'd like to be able to produce).
 
If you can read from core file, you should be able to read from a live process too.
A slightly modified sample program:
Code:
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <fcntl.h>
#include <kvm.h>
#include <libprocstat.h>
#include <limits.h>
#include <paths.h>
#include <unistd.h>

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main(int argc, char *argv[])
{
    kvm_t *kd;
    struct kinfo_proc *kp;
    struct kinfo_vmentry *vms, *vm;
    struct procstat *ps;
    const char *nlistf, *memf;
    int pid = atoi(argv[1]);
    unsigned int n_proc = 0;
    unsigned int n_vm = 0;
    int i, j;
    char errbuf[_POSIX2_LINE_MAX];
    char buf[0x1000 + 1];

    nlistf = NULL;
    memf = _PATH_DEVNULL;
    buf[0x1000] = '\0';

    kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
    // ps = procstat_open_kvm(nlistf, memf);
    ps = procstat_open_sysctl();
    kp = procstat_getprocs(ps, KERN_PROC_PID, pid, &n_proc);
    vms = procstat_getvmmap(ps, kp, &n_vm);
    for (i = 0; i < n_vm; ++i) {
        vm = &vms[i];

        printf("kve_start: %#lx\n", vm->kve_start);
        printf("kve_end:   %#lx\n", vm->kve_end);
        printf("kve_path:  %s\n", vm->kve_path);

        kvm_read(kd, vm->kve_start, buf, 0x1000U);
    }

    procstat_freevmmap(ps, vms);
    procstat_close(ps);
}

I am not sure about kvm_read(). Something can be read, but I do not know if it is the right data.
 
If you can read from core file, you should be able to read from a live process too.
A slightly modified sample program:
Code:
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <fcntl.h>
#include <kvm.h>
#include <libprocstat.h>
#include <limits.h>
#include <paths.h>
#include <unistd.h>

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main(int argc, char *argv[])
{
    kvm_t *kd;
    struct kinfo_proc *kp;
    struct kinfo_vmentry *vms, *vm;
    struct procstat *ps;
    const char *nlistf, *memf;
    int pid = atoi(argv[1]);
    unsigned int n_proc = 0;
    unsigned int n_vm = 0;
    int i, j;
    char errbuf[_POSIX2_LINE_MAX];
    char buf[0x1000 + 1];

    nlistf = NULL;
    memf = _PATH_DEVNULL;
    buf[0x1000] = '\0';

    kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
    // ps = procstat_open_kvm(nlistf, memf);
    ps = procstat_open_sysctl();
    kp = procstat_getprocs(ps, KERN_PROC_PID, pid, &n_proc);
    vms = procstat_getvmmap(ps, kp, &n_vm);
    for (i = 0; i < n_vm; ++i) {
        vm = &vms[i];

        printf("kve_start: %#lx\n", vm->kve_start);
        printf("kve_end:   %#lx\n", vm->kve_end);
        printf("kve_path:  %s\n", vm->kve_path);

        kvm_read(kd, vm->kve_start, buf, 0x1000U);
    }

    procstat_freevmmap(ps, vms);
    procstat_close(ps);
}

I am not sure about kvm_read(). Something can be read, but I do not know if it is the right data.
Thank you for the code sample.
I've also tried that code many time before coming to the forum with different parameter on the kvm_open* functions, getting the memory map is not really the problem here, it's easy ofc.
Here, the kvm_read function does not read the targeted pid process memory, sadly.
 
Sorry to point out the obvious, but kvm stands for kernel virtual memory.
The manual page for kvm functions tells the same.
So, it looks like it's a wrong tool for what you want.

Look at what debuggers use to do their job on live processes.
I suspect it's built around ptrace(2).
DTrace could potentially be of some help too.
 
Sorry to point out the obvious, but kvm stands for kernel virtual memory.
The manual page for kvm functions tells the same.
So, it looks like it's a wrong tool for what you want.

Look at what debuggers use to do their job on live processes.
I suspect it's built around ptrace(2).
DTrace could potentially be of some help too.
Yes ofc, it reads about kernel virtual memory.
But I'm not making it up when procfs has the /proc/{pid}/mem, and its man tells deprecated, to use libprocstat and kvm.
So to my understanding, that would mean it should still be ok to read processes memory.
But now, the only thing but procfs that can help me to read process memory is to use ptrace, which stops the process and I can't use that. It's clearly not a 1:1 feature replacement solution.

I did not look into dtrace, or if it's usable in userland development in C, or if it can read process memory. So I'll take a look at.
 
But I'm not making it up when procfs has the /proc/{pid}/mem, and its man tells deprecated, to use libprocstat and kvm.
I have no reason to doubt.
procfs exposes many things.
Whoever wrote that advice probably did not have 'mem' specifically in mind.

Also, deprecated does not necessarily mean going away soon.
Many things have been deprecated for years and are still here.
 
Back
Top