fix: harden target recovery metadata safety

This commit is contained in:
proxyctl coordinator
2026-07-17 10:59:14 +08:00
parent a5360028ca
commit 613fe56540
7 changed files with 436 additions and 10 deletions
+54 -2
View File
@@ -20,7 +20,10 @@ import (
"proxyctl/internal/target"
)
const service = "docker.service"
const (
service = "docker.service"
recoveryVersion = 1
)
type Configuration struct {
DaemonConfigPath string
@@ -188,9 +191,10 @@ func parseProperties(output string) map[string]string {
}
type recovery struct {
Version int `json:"version"`
Original []byte `json:"original,omitempty"`
OriginalExists bool `json:"originalExists"`
OriginalMode uint32 `json:"originalMode,omitempty"`
OriginalMode uint32 `json:"originalMode"`
ConfigFingerprint string `json:"configFingerprint"`
RestartedFingerprint string `json:"restartedFingerprint,omitempty"`
}
@@ -277,6 +281,7 @@ func (a *Adapter) enable(ctx context.Context, p profile.Profile) error {
return fmt.Errorf("read Docker daemon configuration: %w", readErr)
}
if !managed {
metadata.Version = recoveryVersion
metadata.OriginalExists = readErr == nil
if metadata.OriginalExists {
metadata.Original = append([]byte(nil), current...)
@@ -372,12 +377,59 @@ func (a *Adapter) readRecovery() (recovery, bool, error) {
if err != nil {
return recovery{}, false, err
}
var fields map[string]json.RawMessage
if err := json.Unmarshal(data, &fields); err != nil {
return recovery{}, true, err
}
if fields == nil {
return recovery{}, true, errors.New("Docker daemon recovery metadata must be a JSON object")
}
var value recovery
if err := json.Unmarshal(data, &value); err != nil {
return recovery{}, true, err
}
if err := validateRecovery(value, fields); err != nil {
return recovery{}, true, err
}
return value, true, nil
}
func validateRecovery(value recovery, fields map[string]json.RawMessage) error {
for _, name := range []string{"version", "originalExists", "originalMode", "configFingerprint"} {
if _, present := fields[name]; !present {
return fmt.Errorf("Docker daemon recovery metadata is missing required field %q", name)
}
}
if value.Version != recoveryVersion {
return fmt.Errorf("unsupported Docker daemon recovery metadata version %d", value.Version)
}
if !validFingerprint(value.ConfigFingerprint) {
return errors.New("Docker daemon recovery metadata has an invalid configuration fingerprint")
}
if value.RestartedFingerprint != "" && (value.RestartedFingerprint != value.ConfigFingerprint || !validFingerprint(value.RestartedFingerprint)) {
return errors.New("Docker daemon recovery metadata has an inconsistent restarted fingerprint")
}
_, hasOriginal := fields["original"]
if value.OriginalExists {
if !hasOriginal {
return errors.New("Docker daemon recovery metadata is missing the recorded original configuration or mode")
}
if value.OriginalMode > 0o777 {
return errors.New("Docker daemon recovery metadata has an invalid original file mode")
}
if err := validateConfigSchema(value.Original); err != nil {
return fmt.Errorf("Docker daemon recovery metadata has an invalid original configuration: %w", err)
}
} else if hasOriginal || len(value.Original) != 0 || value.OriginalMode != 0 {
return errors.New("Docker daemon recovery metadata records original data although the original did not exist")
}
return nil
}
func validFingerprint(value string) bool {
decoded, err := hex.DecodeString(value)
return err == nil && len(decoded) == sha256.Size
}
func (a *Adapter) writeRecovery(value recovery) error {
data, err := json.MarshalIndent(value, "", " ")
if err != nil {