Allow safe custom restore targets
This commit is contained in:
@@ -16,11 +16,7 @@ func ValidateRestoreTarget(target, restoreRoot string, inPlace, confirmed bool)
|
||||
return "", errors.New("validation: protected system restore target")
|
||||
}
|
||||
if !inPlace {
|
||||
root := filepath.Clean(restoreRoot)
|
||||
if clean != root && !strings.HasPrefix(clean, root+string(os.PathSeparator)) {
|
||||
return "", errors.New("validation: staging restore must remain below restoreRoot")
|
||||
}
|
||||
if err := rejectSymlinks(root, clean); err != nil {
|
||||
if err := validateStagingRestoreTarget(clean, restoreRoot); err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else if !confirmed {
|
||||
@@ -35,6 +31,19 @@ func ValidateRestoreTarget(target, restoreRoot string, inPlace, confirmed bool)
|
||||
return clean, nil
|
||||
}
|
||||
|
||||
func validateStagingRestoreTarget(target, restoreRoot string) error {
|
||||
allowedRoots := []string{filepath.Clean(restoreRoot), "/mnt/user", "/mnt/disks", "/mnt/remotes"}
|
||||
for _, root := range allowedRoots {
|
||||
if root == "." || root == "" {
|
||||
continue
|
||||
}
|
||||
if target == root || strings.HasPrefix(target, root+string(os.PathSeparator)) {
|
||||
return rejectSymlinks(root, target)
|
||||
}
|
||||
}
|
||||
return errors.New("validation: staging restore target must be below restoreRoot, /mnt/user, /mnt/disks, or /mnt/remotes")
|
||||
}
|
||||
|
||||
func rejectSymlinks(root, target string) error {
|
||||
relative, err := filepath.Rel(root, target)
|
||||
if err != nil {
|
||||
|
||||
@@ -12,6 +12,12 @@ func TestValidateRestoreTarget(t *testing.T) {
|
||||
if got, err := ValidateRestoreTarget(target, root, false, false); err != nil || got != target {
|
||||
t.Fatalf("staging target rejected: %q %v", got, err)
|
||||
}
|
||||
if got, err := ValidateRestoreTarget("/mnt/user/Transfer", root, false, false); err != nil || got != "/mnt/user/Transfer" {
|
||||
t.Fatalf("user share restore target rejected: %q %v", got, err)
|
||||
}
|
||||
if _, err := ValidateRestoreTarget("/home/root/restore", root, false, false); err == nil {
|
||||
t.Fatal("staging target outside allowed restore roots accepted")
|
||||
}
|
||||
if _, err := ValidateRestoreTarget("/etc", root, true, true); err == nil {
|
||||
t.Fatal("protected target accepted")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user