Search code examples
dockeripcshared-memory

"Permission denied" when trying to access a shared memory from a docker container even though --ipc is set to "host"


I'm trying to set up a shared memory in my host computer and access it in a centos:7 docker container with the shmat function. I've created a shared memory using ipcmk -M 1024 and wrote a C program with the ID hardcoded (for debugging purposes):

// shmtest.c
const char* shm_id = "98321";

shared_memory = shmat(atoi(shm_id), NULL, 0);

if (shared_memory == (void*)-1) {
    perror("No shared memory area");
    abort();
}

fprintf(stdout, "Shared memory found!\n");

My Dockerfile is very simple, all I do is copy the compiled program and keep the container alive so that I can inspect it with an interactive shell:

# Dockerfile
FROM centos:7
COPY ./shmtest /root/
CMD tail -f /dev/null

I build and start the container using

docker build -t shm-docker .
docker run --ipc="host" shm-docker

Inside the docker container, I run my shmtest program, but can't access the shared memory:

./shmtest 
No shared memory area: Permission denied
Aborted

However, ipcs shows the shared memory:

ipcs -m | grep 98321
0x8a39b8b3 98321      1000       644        65536      0

I've tried:

  • Starting the docker container with -v /dev/:/dev/ and -v /dev/shm/:/dev/shm/, without any luck
  • Giving my program the CAP_IPC_OWNER and CAP_IPC_LOCK capability with setcap; then I couldn't run it (./shmtest: Operation not permitted)
  • Switching out centos:7 in my Dockerfile with ubuntu:18.04, still didn't work, which means that this problem is not specific to centos

Unfortunately, I don't know a lot about permissions, but I've noticed that my shared memory shows the number 644 when running ipcs and various other ones show 600. I've also tried accessing those and I still get the same error.

What am I missing here? Is my idea even valid or is it not possible to access the shared memory this way?


Solution

  • The permissions 644 of the shared memory allow its owner to read and write (first 6) but only gives read access to everyone else (last 4).

    The root user in the docker container isn't the owner of the shared memory, so he doesn't have permission to write to the shared memory.

    If you have access to the tool which creates the shared memory, you could change the permissions to something like 606, which means read and write access to the owner and everyone else, too. For example, the ipcmk command has a -p option, so you would run ipcmk -M 1024 -p 0606.

    If you can't change how the shared memory is created, this can be solved by either adding the --privileged flag or, more precisely, the --cap-add=IPC_OWNER flag to the docker run command. From the docker run reference:

    When the operator executes docker run --privileged, Docker will enable access to all devices on the host as well as set some configuration in AppArmor or SELinux to allow the container nearly all the same access to the host as processes running outside containers on the host.

    In addition to --privileged, the operator can have fine grain control over the capabilities using --cap-add and --cap-drop.

    And regarding the IPC_OWNER capability:

    IPC_OWNER - Bypass permission checks for operations on System V IPC objects.

    The full command is now either

    docker run --ipc="host" --privileged shm-docker
    

    or

    docker run --ipc="host" --cap-add=IPC_OWNER shm-docker
    

    A good tool to understand permissions is the Chmod Calculator, which is an interactive tool to see how permissions are encoded in octal digits and characters, too.