Search code examples
macoskernel-extensionxnu

Retrieve path of process from OSX 10.10/10.11 kernel


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?


Solution

  • 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.