fix: harden target recovery metadata safety
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user