Mount jail self-test fails inside Docker because Collabora runs the test as UID 65534 without capabilities → forces fallback mode

Introduction

We are talking about the infamous:

“Slow Kit jail setup with copying, cannot bind-mount.”

Inside the official collabora/code Docker image, coolwsd performs a startup self-test to determine whether the system supports bind-mounts inside the jailed environment.

Users see an error in the GUI, even on privileged containers.

The test is executed via /usr/bin/coolmount as UID 65534 (nobody), which has zero effective capabilities inside the container.

Because UID 65534 cannot perform any mount operations in Docker, the test always fails, causing Collabora to disable mount_jail_tree and fall back to slow file-copy behavior.

This affects all standard Docker deployments , even privileged: true ones.

Honestly I can’t think of how to screw this up and I believe it might be some issue in the coding, but I might be wrong..

here is how I solved the issue and you might solve it too. I’m looking forward for some feedback and see if am hallucinating or if its considered solid advice (maybe its by design, I don’t quite know)

I use collabora with nextcloud and run a yml file with all the various nextcloud containers, including collabora.
Current env is boring plain ubuntu server 24.04.3 LTS running Client: Docker Engine - Community, Version: 29.1.2, the most standard setup you can imagine.
Collabora is currently on Collabora Online Development Edition 25.04.7.3 a0576a3364

this is a snippet from my patched docker-compose.yml (again, plain and simple)

  collabora:
    image: collabora/code:latest
    container_name: collabora
    restart: always
    privileged: true
    environment:
      - extra_params=--o:ssl.enable=false
    ports:
      - "9980:9980"
    networks:
      - default
    volumes:
      - /srv/nextcloud/collabora/coolmount-patch/coolmount:/usr/bin/coolmount:ro
      - /srv/nextcloud/collabora/coolmount-patch/coolmount.real:/usr/bin/coolmount.real:ro

Detailed explanation

At startup, Collabora executes:

coolmount -b systemplate → cool_test_mount
coolmount -r systemplate → cool_test_mount
coolmount -u cool_test_mount

However:

  • The test process runs as UID 65534
  • The container filesystem is read-only, so setcap cannot modify the binary
  • Therefore the test always returns a non-zero exit code
  • Collabora assumes the kernel does not support jailed mounts
  • mount_jail_tree is disabled → performance suffers (file copying instead of bind mounts)

Real document operations, however, run as user cool (UID 1001) and would work correctly if the startup test did not incorrectly disable the feature.


Workaround

Override /usr/bin/coolmount with a wrapper script before Collabora starts.

This wrapper:

  • Detects the startup test (UID 65534 + cool_test_mount)
  • Returns exit code 0 for that case only
  • Delegates all real operations to the original ELF binary (coolmount.real)
  • Allows coolmount.real to run with proper file capabilities (granted on the host)

Wrapper script

Path: /srv/collabora/coolmount-patch/coolmount

#!/bin/bash

LOG=/tmp/coolmount.log
uid_now="$(id -u)"

# Fake success only for the startup self-test (UID 65534 + cool_test_mount)
if [ "$uid_now" = "65534" ] && [[ " $* " == *"cool_test_mount"* ]]; then
  echo "Self-test bypassed (UID 65534) at $(date)" >>"$LOG"
  exit 0
fi

# Otherwise call the real mount helper
DIR="$(cd "$(dirname "$0")" && pwd)"
"$DIR/coolmount.real" "$@"
exit $?

Make it executable:

chmod +x /srv/collabora/coolmount-patch/coolmount

Extract the real binary:

docker cp collabora:/usr/bin/coolmount /srv/collabora/coolmount-patch/coolmount.real

Give the real binary capabilities on the host filesystem:

sudo setcap cap_sys_admin,cap_sys_chroot,cap_dac_override+ep /srv/collabora/coolmount-patch/coolmount.real

Mount the patched directory over /usr/bin:

volumes:
  - /srv/collabora/coolmount-patch:/usr/bin

Restart the container and you’re done.


Result

  • The broken self-test passes
  • mount_jail_tree stays enabled
  • Real mount operations succeed through coolmount.real
  • No fake behaviour beyond the startup test
  • Jails work as intended and performance returns to normal

Example log entry after patch:

exit code: 0
argv: /usr/bin/coolmount -b /opt/cool/systemplate ...

Troubleshooting – How to reproduce and verify the issue yourself

The following commands allow you to:

  1. Confirm that the error exists on your system (inside a document: Help > Server Audit → “Slow Kit jail setup with copying, cannot bind-mount.”)
  2. Inspect the failing coolmount calls (exit code 70)
  3. Verify that the patch works (exit code 0 + real jails mounted)

1. Enter the Collabora container as root

docker exec -u 0 -it collabora bash

2. Inspect binaries

ls -l /usr/bin/coolmount*
getcap /usr/bin/coolmount.real || echo "no caps"

Before patching you will see:

  • No wrapper script
  • No capabilities set
  • Real binary inaccessible for mount operations

3. Trigger the bug

Open any document in Nextcloud, then run:

mount | grep '/opt/cool/child-roots' || echo "no child-root mounts seen"

tail -n 80 /tmp/coolmount.log

If the system is broken, you will see:

  • No mounts under /opt/cool/child-roots
  • Repeated failures like:
--- exit code: 70 ---
argv: /usr/bin/coolmount -b ...
uid: 1001 user: cool

This confirms that Collabora is falling back to slow copy mode.


4. After applying the patch

Repeat the same commands:

mount | grep '/opt/cool/child-roots' || echo "no child-root mounts seen"

tail -n 80 /tmp/coolmount.log

A working system shows:

  • exit code 0 on real mount operations
  • Proper jail paths created under /opt/cool/child-roots/…
  • No more GUI warnings
  • No fallback to copying mode

This proves the jail system is not faked — it is actually working as intended.

1 Like