Fix submounts of /dev being read-only with Docker 25+ (#4997)

As described in #4996, Docker 25+ changes made sub-mounts of the /dev
filesystem to be mounted read-only. Revert to the previous behavior by
adjusting the ReadOnlyNonRecursive option. Cleaner way would be to
upstream support for setting this option via Mount class arguments, so
this change is meant to be rather a hotfix for the issue. Even better
approach would be mounting /dev non-recursively, and taking care of
creating all necessary filesystems when creating containers in
Supervisor.
This commit is contained in:
Jan Čermák 2024-04-02 21:07:53 +02:00 committed by GitHub
parent a9265afd4c
commit 906e400ab7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 17 additions and 8 deletions

View File

@ -74,6 +74,7 @@ MOUNT_DBUS = Mount(
type=MountType.BIND, source="/run/dbus", target="/run/dbus", read_only=True
)
MOUNT_DEV = Mount(type=MountType.BIND, source="/dev", target="/dev", read_only=True)
MOUNT_DEV.setdefault("BindOptions", {})["ReadOnlyNonRecursive"] = True
MOUNT_DOCKER = Mount(
type=MountType.BIND,
source="/run/docker.sock",

View File

@ -1 +1,6 @@
"""Docker tests."""
from docker.types import Mount
# dev mount with equivalent of bind-recursive=writable specified via dict value
DEV_MOUNT = Mount(type="bind", source="/dev", target="/dev", read_only=True)
DEV_MOUNT["BindOptions"] = {"ReadOnlyNonRecursive": True}

View File

@ -19,6 +19,7 @@ from supervisor.resolution.const import ContextType, IssueType
from supervisor.resolution.data import Issue
from ..common import load_json_fixture
from . import DEV_MOUNT
@pytest.fixture(name="addonsdata_system")
@ -66,11 +67,8 @@ def test_base_volumes_included(
coresys, addonsdata_system, "basic-addon-config.json"
)
# Dev added as ro
assert (
Mount(type="bind", source="/dev", target="/dev", read_only=True)
in docker_addon.mounts
)
# Dev added as ro with bind-recursive=writable option
assert DEV_MOUNT in docker_addon.mounts
# Data added as rw
assert (

View File

@ -9,6 +9,8 @@ from docker.types import Mount
from supervisor.coresys import CoreSys
from supervisor.docker.manager import DockerAPI
from . import DEV_MOUNT
async def test_start(coresys: CoreSys, tmp_supervisor_data: Path, path_extern):
"""Test starting audio plugin."""
@ -26,8 +28,9 @@ async def test_start(coresys: CoreSys, tmp_supervisor_data: Path, path_extern):
assert run.call_args.kwargs["ulimits"] == [
{"Name": "rtprio", "Soft": 10, "Hard": 10}
]
assert run.call_args.kwargs["mounts"] == [
Mount(type="bind", source="/dev", target="/dev", read_only=True),
DEV_MOUNT,
Mount(
type="bind",
source=coresys.config.path_extern_audio.as_posix(),

View File

@ -12,6 +12,8 @@ from supervisor.docker.homeassistant import DockerHomeAssistant
from supervisor.docker.manager import DockerAPI
from supervisor.homeassistant.const import LANDINGPAGE
from . import DEV_MOUNT
async def test_homeassistant_start(
coresys: CoreSys, tmp_supervisor_data: Path, path_extern
@ -42,7 +44,7 @@ async def test_homeassistant_start(
"HASSIO_TOKEN": ANY,
}
assert run.call_args.kwargs["mounts"] == [
Mount(type="bind", source="/dev", target="/dev", read_only=True),
DEV_MOUNT,
Mount(type="bind", source="/run/dbus", target="/run/dbus", read_only=True),
Mount(type="bind", source="/run/udev", target="/run/udev", read_only=True),
Mount(
@ -128,7 +130,7 @@ async def test_landingpage_start(
"HASSIO_TOKEN": ANY,
}
assert run.call_args.kwargs["mounts"] == [
Mount(type="bind", source="/dev", target="/dev", read_only=True),
DEV_MOUNT,
Mount(type="bind", source="/run/dbus", target="/run/dbus", read_only=True),
Mount(type="bind", source="/run/udev", target="/run/udev", read_only=True),
Mount(