The solution for enabling of ptrace and PTRACE_ATTACH in Docker Containers

logo

For the last two years we have been using Docker containerization solutions for the needs of development, CI and production environments. All current products for the customers are being developed to be run in Docker.

We have a very positive experience about that solution. However, Docker changes a lot, from version to version it introduces new amazing stuff like Compose, Swarm, additional security features, which, sometimes, lead to errors in containers that was considered as stable.

Thus, with great amazement we have discovered that a container which was developed and tested 3 months ago is no longer functional in a new Docker version. The container is not a typical thing because it uses strace to analyze a process behaviour to diagnose deviant behaviour of it.

Today our developers started an integration process of that container in an application and found that it doesn’t work anymore and the reason is connected to ptrace which is reported by strace like:

strace: attach: ptrace(PTRACE_ATTACH, ...): Operation not permitted Could not attach to process.  If your uid matches the uid of the target 
process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try again as the root user.  For more details, see /etc/sysctl.d/10-ptrace.conf

You probably wonder, the case is quite rare — strace in Docker… Er, but there are some similar questions in the internet which are more or less address the same problem. So, what’s the reason and how to tackle with it? There are several things.

Seccomp Mechanism

In distros with new Linux operating system kernel there is modern kernel mechanism — seccomp, which enables Docker blocking of system calls inside a container. The Docker documentation about this feature is located at official Docker documentation page. As one can discover there, ptrace is blocked. Thin seccomp configuration can be implemented by overriding the default configuration file by using docker run command line argument –security-opt seccomp=/path/to/file.json. Our container is launched in a protected environment, so we disabled it completely by setting --security-opt seccomp=unconfined.

Yama Mechanism

Strace shown us an clue about other possible ptrace limitation — procfs pseudofile /proc/sys/kernel/yama/ptrace_scope, which introduces additional ptrace limitation capabilities. Let’s take a look at the kernel docs and discover that the file content is presented by digits 0-3 which in case define ptrace capabilities:

The sysctl settings (writable only with CAP_SYS_PTRACE) are:

0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other
    process running under the same uid, as long as it is dumpable (i.e.
    did not transition uids, start privileged, or have called
    prctl(PR_SET_DUMPABLE...) already). Similarly, PTRACE_TRACEME is
    unchanged.

1 - restricted ptrace: a process must have a predefined relationship
    with the inferior it wants to call PTRACE_ATTACH on. By default,
    this relationship is that of only its descendants when the above
    classic criteria is also met. To change the relationship, an
    inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare
    an allowed debugger PID to call PTRACE_ATTACH on the inferior.
    Using PTRACE_TRACEME is unchanged.

2 - admin-only attach: only processes with CAP_SYS_PTRACE may use ptrace
    with PTRACE_ATTACH, or through children calling PTRACE_TRACEME.

3 - no attach: no processes may use ptrace with PTRACE_ATTACH nor via
    PTRACE_TRACEME. Once set, this sysctl value cannot be changed.

By executing following command:

docker exec -it <container> cat /proc/sys/kernel/yama/ptrace_scope

We found that in our case file has value of “1” set, and since our processes were executed with the same UID but not in the parent-child hierarchy, Yama blocked PTRACE_ATTACH.

We tried to put “0” value into /proc/sys/kernel/yama/ptrace_scope but failed because we got “/proc is read only” message.

Privileged Execution Mode

We overcame that “read-only procfs” limitation by running our container in “privileged” execution mode setting “–privileged” docker run flag. We also put “0” to /proc/sys/kernel/yama/ptrace_scope by modification of application bootstrap code.

echo 0 > /proc/sys/kernel/yama/ptrace_scope

All above means allowed us to solve the problem. The example solution can be found in our web ssh proxy container.