3

I would like to retrieve the path of a process from a PID in a kext, like so: Get name from PID? However, sys/proc_info.h and libproc.h are not available anymore (afaik).

Is there any other way to retrieve proc_info for a process struct proc *p from a kext?

pmdj
  • 22,018
  • 3
  • 52
  • 103
Vis
  • 301
  • 1
  • 10

1 Answers1

3

The function that is supposed to return a process's main executable's vnode, proc_getexecutablevnode() is in the private KPI, which is only available to kexts published by Apple.

The information it relies on is supposedly stored in the p_textvp field of struct proc, which once again is not part of the public ABI - Apple can choose to change its layout, so even if you do import its definition into your code, your code might be incorrect in future or older versions of OS X. However, it turns out this field is NULL anyway.

You may be able to get at the information via the sysctl mechanism, but I can't see an obvious way to do it. You should be able to obtain the information in userspace via the proc_info() system call. It's not documented by Apple, but you can read the source. This is backed by information stored in the process's address space, and as such, the process can actually fake it.

Finally, if your kext is loaded at boot time, you can keep track of the process's executable file yourself by registering a KAUTH listener in the KAUTH_SCOPE_FILEOP. The event KAUTH_FILEOP_EXEC will tell you whenever a process (successfully) calls one of the exec() functions, including the vnode in question. On OS X/macOS, posix_spawn() is much more common, as fork/exec are explicitly disallowed for multithreaded processes, and most processes on macOS have more than one thread. This is relevant here because the KAUTH_FILEOP_EXEC event handler as triggered by posix_spawn() actually runs in the parent process's context. So you need to do some additional wrangling to correlate the executable vnode information with the child process PID.

One more note: be aware that the path to the executable file isn't necessarily well-defined. Unlike on Windows, files being executed can be moved or deleted, so the path can change, or go away entirely. Moreover, files can be hardlinked, in which case they have multiple paths. The vnode_t is the kernel type that identifies a file, regardless of its name/path/etc. - a regular user process will always have an executable vnode, but that vnode might not have a valid path. Make sure your code doesn't expect it to.

pmdj
  • 22,018
  • 3
  • 52
  • 103
  • Thanks a lot @pmdj. I will try the `p_textvp` approach. Let you know it it works out! – Vis Nov 17 '15 at 07:30
  • _"p_textvp is not used. In Darwin, the proc is not the root of the address space; the task is. There is no concept of "the vnode" for a task's address space, as it is not necessarily initially populated by mapping one. [...]"_ [cont](https://lists.apple.com/archives/Darwin-drivers/2005/Dec/msg00026.html) – Vis Nov 17 '15 at 07:44
  • Do you know how to access `p->p_textvp`? Since I'm getting a `incomplete definition of type 'struct proc` error, like [here](https://stackoverflow.com/questions/17512950/xnu-incudes-in-kext). Adding `proc_internal.h` causes a lot of other errors regarding the definition of `lck_mtx_t` structs not visible. – Vis Nov 17 '15 at 10:03
  • The advice at the mailing list post you linked is sound - you normally don't want to look inside private structs - your kext may cause a kernel panic in versions of OSX other than the headers' version. Also, it sounds like `p_textvp` is NULL anyway (I did not know this) so there's no point anyway. What do you need the executable vnode for, and why does the solution I suggested at the end of my answer not work for you? – pmdj Nov 18 '15 at 18:13
  • OK, thanks, the latter seemed somewhat more effort, but I will try that one. – Vis Nov 20 '15 at 07:43
  • I implemented KAuth, a wonderful explanation is also provided here: https://objective-see.com/blog/blog_0x0A.html Thanks! – Vis Dec 02 '15 at 08:50