Runc: The example `runc spec` file does not work with ubuntu `apt update`

Created on 7 Aug 2018  路  14Comments  路  Source: opencontainers/runc

Hello! I'm having some trouble getting the default OCI runtime file to perform some ordinary root-ish actions. Reading through the documentation, I'm not quite sure what to change.

I've identified a quick, basic example:

./runc-1.0.0-rc5 spec
mkdir rootfs
docker export $(docker create ubuntu) | tar -C rootfs -xf -

# Allow writes
sed -i 's/"readonly": true/"readonly": false/' config.json

# Change command to `apt update`
sed -i 's/"sh"/"apt", "update"/' config.json

./runc-1.0.0-rc5 run dummyId

I would expect this to have a relatively benign network error, since I have not removed the network namespace. Instead, I get a bunch of permission errors:

E: setgroups 65534 failed - setgroups (1: Operation not permitted)
E: setegid 65534 failed - setegid (1: Operation not permitted)
E: seteuid 100 failed - seteuid (1: Operation not permitted)
E: setgroups 0 failed - setgroups (1: Operation not permitted)
rm: cannot remove '/var/cache/apt/archives/partial/*.deb': Permission denied
Reading package lists... Done
W: chown to _apt:root of directory /var/lib/apt/lists/partial failed - SetupAPTPartialDirectory (1: Operation not permitted)
W: chown to _apt:root of directory /var/lib/apt/lists/auxfiles failed - SetupAPTPartialDirectory (1: Operation not permitted)
E: setgroups 65534 failed - setgroups (1: Operation not permitted)
E: setegid 65534 failed - setegid (1: Operation not permitted)
E: seteuid 100 failed - seteuid (1: Operation not permitted)
E: setgroups 0 failed - setgroups (1: Operation not permitted)
E: Method gave invalid 400 URI Failure message: Failed to setgroups - setgroups (1: Operation not permitted)
E: Method gave invalid 400 URI Failure message: Failed to setgroups - setgroups (1: Operation not permitted)
E: Method http has died unexpectedly!
E: Sub-process http returned an error code (112)

What do I need to change to allow setegid / etc to succeed?
Should that maybe be a flag on runc spec?
Any help would be appreciated :)

_(Obviously, I only used sed to make it trivial for someone else to try. I wouldn't use that normally.)_

Most helpful comment

Regardless, I think the runc spec command is just an example and in no way provides a secure or recommendation on that values go in your spec.

All 14 comments

It looks like you're trying to run in rootless mode -- in other words you are trying to run runc as an unprivileged user. Either use sudo runc run ... or take a look at https://rootlesscontaine.rs/ to learn more about how to use rootless containers.

I am using a root shell by way of sudo bash, sorry that it wasn't clear:

$ whoami
root

Perhaps there is something wrong with my environment? I've been able to reproduce the instructions above with two different machines now, both of which are patched & up-to-date. This is using the rc5 release amd64 binary.

Can anyone lend a hand? I've now been able to reproduce the steps above in a fresh vagrant:

image

This was using the ubuntu/artful64 vagrant box, inside a tempdir to avoid any filesystem mounting issues. Not sure what else I can try :/

Can you attach a copy of your config.json?

Sure can:
https://gist.github.com/dramaticostrich/6c412423a6c912228aaaea5ddabe1205

Should be the same as anyone who runs runc spec with rc5 and adds the above sed commands.

Were you able to resolve this?
I am facing multiple issues including this one when creating a runc container with the latest docker mariadb image. Unable to start the mariadb service either. Thought I'd create a debian9 slim container and directly install mariadb in it as a work around but again stuck with error you get above for apt.

image

I am running as root and have set read-only to false in config.json.

Were you able to resolve this?
I am facing multiple issues including this one when creating a runc container with the latest docker mariadb image. Unable to start the mariadb service either. Thought I'd create a debian9 slim container and directly install mariadb in it as a work around but again stuck with error you get above for apt.

image

I am running as root and have set read-only to false in config.json.

Resolved using the config below.

{
    "ociVersion": "1.0.0",
    "process": {
        "terminal": true,
        "user": {},
        "args": [
            "bash"
        ],
        "env": [
            "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
            "TERM=xterm"
        ],
        "cwd": "/",
        "capabilities": {
            "bounding": [
                "CAP_AUDIT_WRITE",
                "CAP_KILL",
                "CAP_NET_BIND_SERVICE",
                                "CAP_CHOWN",
                                "CAP_DAC_OVERRIDE",
                                "CAP_FSETID",
                                "CAP_FOWNER",
                                "CAP_MKNOD",
                                "CAP_NET_RAW",
                                "CAP_SETGID",
                                "CAP_SETUID",
                                "CAP_SETFCAP",
                                "CAP_SETPCAP",
                                "CAP_NET_BIND_SERVICE",
                                "CAP_SYS_CHROOT",
                                "CAP_KILL",
                                "CAP_AUDIT_WRITE"
            ],
            "effective": [
                "CAP_AUDIT_WRITE",
                "CAP_KILL",
                "CAP_NET_BIND_SERVICE",
                                "CAP_CHOWN",
                                "CAP_DAC_OVERRIDE",
                                "CAP_FSETID",
                                "CAP_FOWNER",
                                "CAP_MKNOD",
                                "CAP_NET_RAW",
                                "CAP_SETGID",
                                "CAP_SETUID",
                                "CAP_SETFCAP",
                                "CAP_SETPCAP",
                                "CAP_NET_BIND_SERVICE",
                                "CAP_SYS_CHROOT",
                                "CAP_KILL",
                                "CAP_AUDIT_WRITE"
            ],
            "inheritable": [
                "CAP_AUDIT_WRITE",
                "CAP_KILL",
                "CAP_NET_BIND_SERVICE",
                                "CAP_CHOWN",
                                "CAP_DAC_OVERRIDE",
                                "CAP_FSETID",
                                "CAP_FOWNER",
                                "CAP_MKNOD",
                                "CAP_NET_RAW",
                                "CAP_SETGID",
                                "CAP_SETUID",
                                "CAP_SETFCAP",
                                "CAP_SETPCAP",
                                "CAP_NET_BIND_SERVICE",
                                "CAP_SYS_CHROOT",
                                "CAP_KILL",
                                "CAP_AUDIT_WRITE"
            ],
            "permitted": [
                "CAP_AUDIT_WRITE",
                "CAP_KILL",
                "CAP_NET_BIND_SERVICE",
                                "CAP_CHOWN",
                                "CAP_DAC_OVERRIDE",
                                "CAP_FSETID",
                                "CAP_FOWNER",
                                "CAP_MKNOD",
                                "CAP_NET_RAW",
                                "CAP_SETGID",
                                "CAP_SETUID",
                                "CAP_SETFCAP",
                                "CAP_SETPCAP",
                                "CAP_NET_BIND_SERVICE",
                                "CAP_SYS_CHROOT",
                                "CAP_KILL",
                                "CAP_AUDIT_WRITE"
            ],
            "ambient": [
                "CAP_AUDIT_WRITE",
                "CAP_KILL",
                "CAP_NET_BIND_SERVICE",
                                "CAP_CHOWN",
                                "CAP_DAC_OVERRIDE",
                                "CAP_FSETID",
                                "CAP_FOWNER",
                                "CAP_MKNOD",
                                "CAP_NET_RAW",
                                "CAP_SETGID",
                                "CAP_SETUID",
                                "CAP_SETFCAP",
                                "CAP_SETPCAP",
                                "CAP_NET_BIND_SERVICE",
                                "CAP_SYS_CHROOT",
                                "CAP_KILL",
                                "CAP_AUDIT_WRITE"
            ]
        },
        "rlimits": [
            {
                "type": "RLIMIT_NOFILE",
                "hard": 1024,
                "soft": 1024
            }
        ],
        "noNewPrivileges": true
    },
    "root": {
        "path": "rootfs",
        "readonly": false
    },
    "hostname": "runc",
    "mounts": [
        {
            "destination": "/proc",
            "type": "proc",
            "source": "proc"
        },
                {
            "type": "bind",
            "source": "/etc/resolv.conf",
            "destination": "/etc/resolv.conf",
            "options": [
                                "rbind",
                                "ro"
                        ]
        },
        {
            "destination": "/dev",
            "type": "tmpfs",
            "source": "tmpfs",
            "options": [
                "nosuid",
                "strictatime",
                "mode=755",
                "size=65536k"
            ]
        },
        {
            "destination": "/dev/pts",
            "type": "devpts",
            "source": "devpts",
            "options": [
                "nosuid",
                "noexec",
                "newinstance",
                "ptmxmode=0666",
                "mode=0620"
            ]
        },
        {
            "destination": "/dev/shm",
            "type": "tmpfs",
            "source": "shm",
            "options": [
                "nosuid",
                "noexec",
                "nodev",
                "mode=1777",
                "size=65536k"
            ]
        },
        {
            "destination": "/dev/mqueue",
            "type": "mqueue",
            "source": "mqueue",
            "options": [
                "nosuid",
                "noexec",
                "nodev"
            ]
        },
        {
            "destination": "/sys",
            "type": "sysfs",
            "source": "sysfs",
            "options": [
                "nosuid",
                "noexec",
                "nodev"
            ]
        },
        {
            "destination": "/sys/fs/cgroup",
            "type": "cgroup",
            "source": "cgroup",
            "options": [
                "nosuid",
                "noexec",
                "nodev",
                "relatime"
            ]
        }
    ],
    "linux": {
        "resources": {
            "devices": [
                {
                    "allow": false,
                    "access": "rwm"
                }
            ]
        },
        "namespaces": [
            {
                "type": "pid"
            },
            {
                "type": "ipc"
            },
            {
                "type": "uts"
            },
            {
                "type": "mount"
            }
        ],
        "maskedPaths": [
            "/proc/kcore",
            "/proc/latency_stats",
            "/proc/timer_list",
            "/proc/timer_stats",
            "/proc/sched_debug",
            "/sys/firmware",
            "/proc/scsi"
        ],
        "readonlyPaths": [
            "/proc/asound",
            "/proc/bus",
            "/proc/fs",
            "/proc/irq",
            "/proc/sys",
            "/proc/sysrq-trigger"
        ]
    }
}

Not sure if this is the best way of doing it.

"CAP_CHOWN",
"CAP_DAC_OVERRIDE",
"CAP_FSETID",
"CAP_FOWNER",
"CAP_SETGID",
"CAP_SETUID",
"CAP_SETFCAP",

These are the capabilities you were likely missing. I'm not sure when we changed the defaults, but we really need to add more capabilities to the default configuration. This is the default that umoci generates.

"bounding": [
                "CAP_CHOWN",
                "CAP_DAC_OVERRIDE",
                "CAP_FSETID",
                "CAP_FOWNER",
                "CAP_MKNOD",
                "CAP_NET_RAW",
                "CAP_SETGID",
                "CAP_SETUID",
                "CAP_SETFCAP",
                "CAP_SETPCAP",
                "CAP_NET_BIND_SERVICE",
                "CAP_SYS_CHROOT",
                "CAP_KILL",
                "CAP_AUDIT_WRITE"
],

Why do we default to CAP_AUDIT_WRITE? Do we really want containers writing audit messages?

I just looked back into the git history and this has been the default for more than 2 years... This is really odd -- I've never noticed that runc spec was _that_ broken with regards to capabilities.

@rhatdan Yeah, CAP_AUDIT_WRITE doesn't make much sense to me (though the audit folks do have some odd things tied to CAP_AUDIT_WRITE). However it should be noted that Docker (and thus cri-o too probably) also set CAP_AUDIT_WRITE. umoci does it because that's the default that runtime-spec used, but I think we should probably change it.

I'm going to submit a patch to fix up these defaults.

We drop a lot of additional CAPS in CRI-O then Docker uses, since we don't default to doing builds.
CAP_AUDIT_WRITE, I believe was added way back so people could run tools like sshd inside of a container. Perhaps sshd did not handle the lack of this CAP well. But since this is not a common practice, I don't think is should be the default.

Regardless, I think the runc spec command is just an example and in no way provides a secure or recommendation on that values go in your spec.

I just wanted to point out that the solution to this issue is not to drop rootless runc, like the config.json posted above, but rather to create _two_ uid and gid mappings. See #2517 for an example.

It is entirely possible to make seteuid and setegid etc work inside a rootless container.

I've added these capabilities but still getting the same error.

"CAP_CHOWN",
"CAP_DAC_OVERRIDE",
"CAP_FSETID",
"CAP_FOWNER",
"CAP_SETGID",
"CAP_SETUID",
"CAP_SETFCAP",

These are the capabilities you were likely missing. I'm not sure when we changed the defaults, but we really need to add more capabilities to the default configuration. This is the default that umoci generates.

"bounding": [
                "CAP_CHOWN",
                "CAP_DAC_OVERRIDE",
                "CAP_FSETID",
                "CAP_FOWNER",
                "CAP_MKNOD",
                "CAP_NET_RAW",
                "CAP_SETGID",
                "CAP_SETUID",
                "CAP_SETFCAP",
                "CAP_SETPCAP",
                "CAP_NET_BIND_SERVICE",
                "CAP_SYS_CHROOT",
                "CAP_KILL",
                "CAP_AUDIT_WRITE"
],
Was this page helpful?
0 / 5 - 0 ratings