Fix `error mounting "/etc/hosts" to rootfs at "/etc/hosts": mount
/etc/hosts:/etc/hosts (via /proc/self/fd/6), flags: 0x5021: operation
not permitted`.
This error was introduced in 7d08d84b039d2f4661a2242e765a141e65943920
(`dockerd-rootless.sh: set rootlesskit --state-dir=DIR`) that changed
the filesystem of the state dir from /tmp to /run (in a typical setup).
Fix issue 47248
Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
| ... | ... |
@@ -1,3 +1,6 @@ |
| 1 |
+// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16: |
|
| 2 |
+//go:build go1.19 |
|
| 3 |
+ |
|
| 1 | 4 |
package v2 // import "github.com/docker/docker/plugin/v2" |
| 2 | 5 |
|
| 3 | 6 |
import ( |
| ... | ... |
@@ -6,7 +9,10 @@ import ( |
| 6 | 6 |
"runtime" |
| 7 | 7 |
"strings" |
| 8 | 8 |
|
| 9 |
+ "github.com/containerd/containerd/pkg/userns" |
|
| 9 | 10 |
"github.com/docker/docker/api/types" |
| 11 |
+ "github.com/docker/docker/internal/rootless/mountopts" |
|
| 12 |
+ "github.com/docker/docker/internal/sliceutil" |
|
| 10 | 13 |
"github.com/docker/docker/oci" |
| 11 | 14 |
specs "github.com/opencontainers/runtime-spec/specs-go" |
| 12 | 15 |
"github.com/pkg/errors" |
| ... | ... |
@@ -136,5 +142,35 @@ func (p *Plugin) InitSpec(execRoot string) (*specs.Spec, error) {
|
| 136 | 136 |
p.modifyRuntimeSpec(&s) |
| 137 | 137 |
} |
| 138 | 138 |
|
| 139 |
+ // Rootless mode requires modifying the mount flags |
|
| 140 |
+ // https://github.com/moby/moby/issues/47248#issuecomment-1927776700 |
|
| 141 |
+ // https://github.com/moby/moby/pull/47558 |
|
| 142 |
+ if userns.RunningInUserNS() {
|
|
| 143 |
+ for i := range s.Mounts {
|
|
| 144 |
+ m := &s.Mounts[i] |
|
| 145 |
+ for _, o := range m.Options {
|
|
| 146 |
+ switch o {
|
|
| 147 |
+ case "bind", "rbind": |
|
| 148 |
+ if _, err := os.Lstat(m.Source); err != nil {
|
|
| 149 |
+ if errors.Is(err, os.ErrNotExist) {
|
|
| 150 |
+ continue |
|
| 151 |
+ } |
|
| 152 |
+ return nil, err |
|
| 153 |
+ } |
|
| 154 |
+ // UnprivilegedMountFlags gets the set of mount flags that are set on the mount that contains the given |
|
| 155 |
+ // path and are locked by CL_UNPRIVILEGED. This is necessary to ensure that |
|
| 156 |
+ // bind-mounting "with options" will not fail with user namespaces, due to |
|
| 157 |
+ // kernel restrictions that require user namespace mounts to preserve |
|
| 158 |
+ // CL_UNPRIVILEGED locked flags. |
|
| 159 |
+ unpriv, err := mountopts.UnprivilegedMountFlags(m.Source) |
|
| 160 |
+ if err != nil {
|
|
| 161 |
+ return nil, errors.Wrapf(err, "failed to get unprivileged mount flags for %+v", m) |
|
| 162 |
+ } |
|
| 163 |
+ m.Options = sliceutil.Dedup(append(m.Options, unpriv...)) |
|
| 164 |
+ } |
|
| 165 |
+ } |
|
| 166 |
+ } |
|
| 167 |
+ } |
|
| 168 |
+ |
|
| 139 | 169 |
return &s, nil |
| 140 | 170 |
} |