From d17e85d1cef57492197464ce9f0babe2b30f124a Mon Sep 17 00:00:00 2001 From: Alexandre Rodrigues Date: Sun, 20 Sep 2026 18:45:29 -0300 Subject: [PATCH] opts: reject bind-recursive=enabled on non-bind mounts Signed-off-by: Alexandre Rodrigues --- opts/mount.go | 2 +- opts/mount_test.go | 27 ++++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/opts/mount.go b/opts/mount.go index 60ca36665d27..8087aab1fe46 100644 --- a/opts/mount.go +++ b/opts/mount.go @@ -90,7 +90,7 @@ func (m *MountOpt) Set(value string) error { case "bind-recursive": switch val { case "enabled": // read-only mounts are recursively read-only if Engine >= v25 && kernel >= v5.12, otherwise writable - // NOP + ensureBindOptions(&mount) case "disabled": // previously "bind-nonrecursive=true" ensureBindOptions(&mount).NonRecursive = true case "writable": // conforms to the default read-only bind-mount of Docker v24; read-only mounts are recursively mounted but not recursively read-only diff --git a/opts/mount_test.go b/opts/mount_test.go index 2014c98d55c4..2295d57cb462 100644 --- a/opts/mount_test.go +++ b/opts/mount_test.go @@ -168,6 +168,26 @@ func TestMountOptErrors(t *testing.T) { value: "type=bind,target=/foo,source=/foo,volume-nocopy=true", expErr: "cannot mix 'volume-*' options with mount type 'bind'", }, + { + doc: "bind-recursive enabled with volume", + value: "type=volume,target=/foo,bind-recursive=enabled", + expErr: "cannot mix 'bind-*' options with mount type 'volume'", + }, + { + doc: "bind-recursive enabled with default mount type", + value: "target=/foo,bind-recursive=enabled", + expErr: "cannot mix 'bind-*' options with mount type 'volume'", + }, + { + doc: "bind-recursive enabled with tmpfs", + value: "type=tmpfs,target=/foo,bind-recursive=enabled", + expErr: "cannot mix 'bind-*' options with mount type 'tmpfs'", + }, + { + doc: "bind-recursive enabled before image type", + value: "bind-recursive=enabled,type=image,source=alpine,target=/foo", + expErr: "cannot mix 'bind-*' options with mount type 'image'", + }, } for _, tc := range tests { @@ -525,9 +545,10 @@ func TestMountOptSetBindRecursive(t *testing.T) { assert.NilError(t, m.Set("type=bind,source=/foo,target=/bar,bind-recursive=enabled")) assert.Check(t, is.DeepEqual([]mount.Mount{ { - Type: mount.TypeBind, - Source: "/foo", - Target: "/bar", + Type: mount.TypeBind, + Source: "/foo", + Target: "/bar", + BindOptions: &mount.BindOptions{}, }, }, m.Value())) })