pages tagged ptraceyakkinghttp://yakking.branchable.com/tags/ptrace/yakkingikiwiki2017-05-10T12:00:12ZIs your process running 4 - Linux-specific approacheshttp://yakking.branchable.com/posts/procrun-4-linux/Richard Maw2017-05-10T12:00:12Z2017-05-10T12:00:06Z
<p>We previously discussed the traditional UNIX mechanisms for service management,
and how they assumed benign and well written software.</p>
<p>Fortunately Linux provides more than just traditional UNIX system calls,
so offers some features that can be used to track processes more completely.</p>
<h1>Intercepting processes with <a href="http://man7.org/linux/man-pages/man2/ptrace.2.html">ptrace(2)</a></h1>
<p>If you could run some code when a process creates a subprocess or exits
then you could use this to track which processes are active
and where they came from.</p>
<p>Debuggers like <a href="http://man7.org/linux/man-pages/man1/gdb.1.html">gdb(1)</a> also need to know this information
since you might want to set a breakpoint for subprocesses too.</p>
<p>So it would be possible to do this using the same mechanism as debuggers.</p>
<p>This is what <a href="http://upstart.ubuntu.com/">Upstart</a> does to work out which process to track
for double-forking daemons.</p>
<p>Unfortunately a process cannot be traced by multiple processes,
so if <a href="http://upstart.ubuntu.com/">Upstart</a> is tracing a process to track its subprocesses
then a debugger cannot be attached to the process.</p>
<p>For <a href="http://upstart.ubuntu.com/">Upstart</a> it detaches the debugger after it has worked out the main PID,
so it's a small window where it is undebuggable,
so it's only a problem for debugging faults during startup,
but detaching after the double-fork means
it can't trace any further subprocesses.</p>
<p>Continuing to trace subprocesses adds a noticeable performance impact though,
so it's for the best that it stops tracing after the double-fork.</p>
<h1>Store process in a <a href="http://man7.org/linux/man-pages/man7/cgroups.7.html">cgroup</a></h1>
<p><a href="http://man7.org/linux/man-pages/man7/cgroups.7.html">cgroups</a> are a Linux <a href="https://en.wikipedia.org/wiki/Virtual_file_system">virtual filesystem</a>
that lets you create hierarchies to organise processes,
and apply resource controls at each level.</p>
<p><a href="http://man7.org/linux/man-pages/man7/cgroups.7.html">cgroups</a> were created to handle the deficiency
of traditional UNIX resource control system calls
such as <a href="http://man7.org/linux/man-pages/man2/setrlimit.2.html">setrlimit(2)</a>,
which only apply to a single process
and can be thwarted by creating subprocesses,
since while a process inherits limits of its parent process
it does not share them with it.</p>
<p>Subprocesses of a process in a <a href="http://man7.org/linux/man-pages/man7/cgroups.7.html">cgroup</a> on the other hand
are part of the same <a href="http://man7.org/linux/man-pages/man7/cgroups.7.html">cgroup</a> and share the same resource limits.</p>
<p>In each <a href="http://man7.org/linux/man-pages/man7/cgroups.7.html">cgroup</a> directory there is a <code>cgroup.procs</code> virtual file,
which lists the process IDs of every process in the <a href="http://man7.org/linux/man-pages/man7/cgroups.7.html">cgroup</a>,
making it effectively a kernel-maintained PIDfile.</p>
<p>This is what <a href="https://www.freedesktop.org/wiki/Software/systemd/">systemd</a> uses for its services,
and you can request a <a href="http://man7.org/linux/man-pages/man7/cgroups.7.html">cgroup</a> for your own processes
by asking <a href="https://www.freedesktop.org/wiki/Software/systemd/">systemd</a> (via <a href="http://man7.org/linux/man-pages/man1/systemd-run.1.html">systemd-run(1)</a> or the DBus interface)
or <a href="https://linuxcontainers.org/cgmanager/introduction/">cgmanager</a> (via <a href="http://manpages.ubuntu.com/manpages/yakkety/man1/cgm.1.html">cgm(1)</a> or the DBus interface)
to do so on your behalf.</p>
<h2>Why can't I mount my own cgroupfs?</h2>
<p>Unfortunately you can only safely have 1 process using a cgroup tree at a time,
and you can only have one cgroupfs mounted at a time,
so you always need to ask some daemon to manage cgroups on your behalf.</p>
<p>See <a href="https://lwn.net/Articles/555920">Changes coming for systemd and control groups</a>
for why a single writer and a single hierarchy are required.</p>
<h1>Conclusion</h1>
<p>It is necessary to track all the subprocesses of a service somehow,
using <a href="http://man7.org/linux/man-pages/man2/ptrace.2.html">ptrace(2)</a> prevents it being used for debugging,
<a href="http://man7.org/linux/man-pages/man7/cgroups.7.html">cgroups</a> are an interface designed for this purpose
but technical limitations mean you need to ask another service to do it.</p>
<p>So I would recommend writing a <a href="https://www.freedesktop.org/software/systemd/man/systemd.service.html">systemd service</a>
if your processes are a per-system or per-user service,
or to use the <a href="https://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/#theapis">DBus API</a> to create <a href="http://man7.org/linux/man-pages/man7/cgroups.7.html">cgroups</a> if not.</p>
<p>Thus <a href="http://man7.org/linux/man-pages/man7/cgroups.7.html">cgroups</a> allow us to know our processes are running,
and currently the best way to use cgroups is via <a href="https://www.freedesktop.org/wiki/Software/systemd/">systemd</a>.
The implications of relying on <a href="https://www.freedesktop.org/wiki/Software/systemd/">systemd</a> to do this
are best served as a subject of another article.</p>
<p>If you are interested in learning more about <a href="http://man7.org/linux/man-pages/man7/cgroups.7.html">cgroups</a>,
I recommend reading <a href="https://lwn.net/Articles/604609/">Neil Brown's excellent series on LWN
</a>.</p>