Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions agent/reseed_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const (
urandomPath = "/dev/urandom"
systemdRandomSeed = "/var/lib/systemd/random-seed"
machineIDPath = "/etc/machine-id"
dbusMachineIDPath = "/var/lib/dbus/machine-id"
)

// runReseed injects host-fed entropy and forces a CRNG reseed so clones don't
Expand Down Expand Up @@ -117,6 +118,9 @@ func regenMachineID(ctx context.Context) error {
if err := os.Truncate(machineIDPath, 0); err != nil {
return fmt.Errorf("truncate %s: %w", machineIDPath, err)
}
if err := dropStaleDBusMachineID(dbusMachineIDPath); err != nil {
return err
}
if path, err := exec.LookPath("systemd-machine-id-setup"); err == nil {
if err := exec.CommandContext(ctx, path).Run(); err == nil { //nolint:gosec // path resolved by LookPath for a fixed binary name, not user input
return nil
Expand All @@ -126,6 +130,26 @@ func regenMachineID(ctx context.Context) error {
return writeRandomMachineID()
}

// dropStaleDBusMachineID removes a baked regular-file D-Bus copy that
// systemd-machine-id-setup would re-adopt; a symlink or missing file is left
// alone, and any other lstat error is surfaced so regen fails loudly.
func dropStaleDBusMachineID(path string) error {
fi, err := os.Lstat(path)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return nil
}
return fmt.Errorf("lstat %s: %w", path, err)
}
if !fi.Mode().IsRegular() {
return nil
}
if err := os.Remove(path); err != nil {
return fmt.Errorf("remove %s: %w", path, err)
}
return nil
}

// writeRandomMachineID is the fallback when systemd-machine-id-setup is
// unavailable: a fresh random id, matching /etc/machine-id's own format.
func writeRandomMachineID() error {
Expand Down
51 changes: 51 additions & 0 deletions agent/reseed_linux_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//go:build linux

package agent

import (
"errors"
"io/fs"
"os"
"path/filepath"
"testing"
)

func TestDropStaleDBusMachineID(t *testing.T) {
t.Run("regular file is removed", func(t *testing.T) {
path := filepath.Join(t.TempDir(), "machine-id")
if err := os.WriteFile(path, []byte("oldid\n"), 0o444); err != nil {
t.Fatalf("seed: %v", err)
}
if err := dropStaleDBusMachineID(path); err != nil {
t.Fatalf("dropStaleDBusMachineID: %v", err)
}
if _, err := os.Lstat(path); !errors.Is(err, fs.ErrNotExist) {
t.Errorf("regular file still present (err=%v), want removed", err)
}
})

t.Run("symlink is preserved", func(t *testing.T) {
dir := t.TempDir()
target := filepath.Join(dir, "etc-machine-id")
if err := os.WriteFile(target, []byte("id\n"), 0o444); err != nil {
t.Fatalf("seed target: %v", err)
}
link := filepath.Join(dir, "machine-id")
if err := os.Symlink(target, link); err != nil {
t.Fatalf("symlink: %v", err)
}
if err := dropStaleDBusMachineID(link); err != nil {
t.Fatalf("dropStaleDBusMachineID: %v", err)
}
if fi, err := os.Lstat(link); err != nil || fi.Mode()&os.ModeSymlink == 0 {
t.Errorf("symlink not preserved (fi=%v err=%v)", fi, err)
}
})

t.Run("missing file is a no-op", func(t *testing.T) {
path := filepath.Join(t.TempDir(), "does-not-exist")
if err := dropStaleDBusMachineID(path); err != nil {
t.Errorf("dropStaleDBusMachineID on missing file: %v, want nil", err)
}
})
}