Move a running process into a tmux session
It’s rare, but sometimes it still happens that I forget to open a tmux or screen session when working with something that is supposed to be quickly done. However, it also happens that “quickly done” turns into “tedious and ugly” and now the process lives longer than it was supposed to and I become afraid of ssh disconnects or something.
So an obvious solution is killing the process and running it in a newly
created tmux session — but what if the process ran for a while and I don’t want
to kill it because I either lose progress or end up in a mess?
Instead of killing and re-running a process, it would be much smoother to just
move it into a tmux session. This involves changing the parent of a process,
which is not exactly trivial, but thankfully @nelhage made a tool for that: reptyr.
If you’re interested in how reptyr
actually achieves its goal, check out his blog posts[^1]1!
As for usage, it is very easy:
- Suspend the respective process with
Ctrl-Z
- Send the job to background using
bg
- Take away the ownership from the shell using
disown
- Start or enter your tmux/screen session
- Run
reptyr PID
to attach the process to the current shell
It also has some additional useful features, such as TTY-stealing, which is documented in the man page.
Before compiling reptyr
, make sure to check whether it is in your distributions repository. At the time of writing, this was at least the case for Gentoo, Fedora, and Debian.
Update (2023-01-05): ptrace scoping
A fellow Gentoo enthusiast noticed that on recent systems, the following error occurs when invoking reptyr
as regular user:
Unable to attach to pid 1348999: Operation not permitted
The kernel denied permission while attaching. If your uid matches
the target's, check the value of /proc/sys/kernel/yama/ptrace_scope.
For more information, see /etc/sysctl.d/10-ptrace.conf
And this is how I learned about ptrace scoping, a feature that was added to the Linux kernel in version 3.4.
The problem:
In order to attach to a process, reptyr
uses the ptrace
system call, which
is used to debug processes. In order to prevent unprivileged users from
attaching to processes, the kernel has a feature called “ptrace scoping” which
allows you to restrict which users and processes can attach to which processes.
The value of /proc/sys/kernel/yama/ptrace_scope
determines the scope of
ptrace
:
0
: No restrictions, anything can be attached as long as the uids match.1
: Only the process owner and root can attach to a process. Also, some kind of relationship is required between the processes.2
: Only root can attach to a process.3
: No one can attach to a process.
On my Gentoo, it was set to 1
by default, which seems reasonable.
As there is no relationship between the process I want to move and the reptyr
process, reptyr
is denied the permission to attach via ptrace
.
So what can we do about this?
I assumed that I could use the prctl
system call to set PR_SET_PTRACER
to PR_SET_PTRACER_ANY
for the process I want to move.
However, it seems that I can only set a tracer for the calling process, not for an arbitrary one, which I find rather annoying.
If somebody finds out how to do this, I would be glad to include it here instead of the following “dirty” workaround.
The workaround:
The only remaining option I found so far is temporarily setting ptrace_scope
to 0
before invoking reptyr
,
which can be done by running sysctl -w kernel.yama.ptrace_scope=0
.
Note that this creates a security problem, as now all processes can be attached.
For security reasons, I prefer to reset it to 1
right after the process has been re-attached.