Skip to content

Commit 885cb4c

Browse files
frezbosmira
authored andcommitted
fix: make etc binds read-only
Fix the `/etc` bind mounts read-only by calling a remount as `ro`. The proper fix is to use new `fsopen` and `fsmount` API's. Signed-off-by: Noel Georgi <git@frezbo.dev> (cherry picked from commit 8dea57a)
1 parent 508cc7b commit 885cb4c

File tree

2 files changed

+38
-15
lines changed

2 files changed

+38
-15
lines changed

internal/app/machined/pkg/controllers/files/cri_registry_config.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"github.com/siderolabs/gen/optional"
1919
"github.com/siderolabs/gen/xslices"
2020
"go.uber.org/zap"
21-
"golang.org/x/sys/unix"
2221

2322
"github.com/siderolabs/talos/internal/pkg/containers/cri/containerd"
2423
"github.com/siderolabs/talos/pkg/machinery/constants"
@@ -69,15 +68,10 @@ func (ctrl *CRIRegistryConfigController) Run(ctx context.Context, r controller.R
6968
// shadow path is writeable, controller is going to update it
7069
// base path is read-only, containerd will read from it
7170
if !ctrl.bindMountCreated {
72-
// create shadow path
73-
if err := os.MkdirAll(shadowPath, 0o700); err != nil {
71+
if err := createBindMountDir(shadowPath, basePath); err != nil {
7472
return err
7573
}
7674

77-
if err := unix.Mount(shadowPath, basePath, "", unix.MS_BIND|unix.MS_RDONLY, ""); err != nil {
78-
return fmt.Errorf("failed to create bind mount for %s -> %s: %w", shadowPath, basePath, err)
79-
}
80-
8175
ctrl.bindMountCreated = true
8276
}
8377

internal/app/machined/pkg/controllers/files/etcfile.go

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,17 +125,17 @@ func (ctrl *EtcFileController) Run(ctx context.Context, r controller.Runtime, lo
125125
if !mountExists {
126126
logger.Debug("creating bind mount", zap.String("src", src), zap.String("dst", dst))
127127

128-
if err = createBindMount(src, dst, spec.TypedSpec().Mode); err != nil {
128+
if err = createBindMountFile(src, dst, spec.TypedSpec().Mode); err != nil {
129129
return fmt.Errorf("failed to create shadow bind mount %q -> %q: %w", src, dst, err)
130130
}
131131

132132
ctrl.bindMounts[filename] = struct{}{}
133133
}
134134

135-
logger.Debug("writing file contents", zap.String("dst", dst), zap.Stringer("version", spec.Metadata().Version()))
135+
logger.Debug("writing file contents", zap.String("src", src), zap.Stringer("version", spec.Metadata().Version()))
136136

137-
if err = UpdateFile(dst, spec.TypedSpec().Contents, spec.TypedSpec().Mode, spec.TypedSpec().SelinuxLabel); err != nil {
138-
return fmt.Errorf("error updating %q: %w", dst, err)
137+
if err = UpdateFile(src, spec.TypedSpec().Contents, spec.TypedSpec().Mode, spec.TypedSpec().SelinuxLabel); err != nil {
138+
return fmt.Errorf("error updating %q: %w", src, err)
139139
}
140140

141141
if err = safe.WriterModify(ctx, r, files.NewEtcFileStatus(files.NamespaceName, filename), func(r *files.EtcFileStatus) error {
@@ -168,10 +168,10 @@ func (ctrl *EtcFileController) Run(ctx context.Context, r controller.Runtime, lo
168168
}
169169
}
170170

171-
// createBindMount creates a common way to create a writable source file with a
171+
// createBindMountFile creates a common way to create a writable source file with a
172172
// bind mounted destination. This is most commonly used for well known files
173173
// under /etc that need to be adjusted during startup.
174-
func createBindMount(src, dst string, mode os.FileMode) (err error) {
174+
func createBindMountFile(src, dst string, mode os.FileMode) (err error) {
175175
if err = os.MkdirAll(filepath.Dir(src), 0o755); err != nil {
176176
return err
177177
}
@@ -186,8 +186,37 @@ func createBindMount(src, dst string, mode os.FileMode) (err error) {
186186
return err
187187
}
188188

189-
if err = unix.Mount(src, dst, "", unix.MS_BIND|unix.MS_RDONLY, ""); err != nil {
190-
return fmt.Errorf("failed to create bind mount for %s: %w", dst, err)
189+
return bindMount(src, dst)
190+
}
191+
192+
// createBindMountDir creates a common way to create a writable source dir with a
193+
// bind mounted destination. This is most commonly used for well known directories
194+
// under /etc that need to be adjusted during startup.
195+
func createBindMountDir(src, dst string) (err error) {
196+
if err = os.MkdirAll(src, 0o755); err != nil {
197+
return err
198+
}
199+
200+
return bindMount(src, dst)
201+
}
202+
203+
// bindMount creates a common way to create a readonly bind mounted destination.
204+
func bindMount(src, dst string) (err error) {
205+
sourceFD, err := unix.OpenTree(unix.AT_FDCWD, src, unix.OPEN_TREE_CLONE|unix.OPEN_TREE_CLOEXEC)
206+
if err != nil {
207+
return fmt.Errorf("failed to opentree source %s: %w", src, err)
208+
}
209+
210+
defer unix.Close(sourceFD) //nolint:errcheck
211+
212+
if err := unix.MountSetattr(sourceFD, "", unix.AT_EMPTY_PATH, &unix.MountAttr{
213+
Attr_set: unix.MOUNT_ATTR_RDONLY,
214+
}); err != nil {
215+
return fmt.Errorf("failed to set mount attribute: %w", err)
216+
}
217+
218+
if err := unix.MoveMount(sourceFD, "", unix.AT_FDCWD, dst, unix.MOVE_MOUNT_F_EMPTY_PATH); err != nil {
219+
return fmt.Errorf("failed to move mount from %s to %s: %w", src, dst, err)
191220
}
192221

193222
return nil

0 commit comments

Comments
 (0)