fix(auth): close diagnostic filesystem races
This commit is contained in:
@@ -60,6 +60,7 @@ type response struct {
|
||||
Entries *[]safeio.PrivateDirectoryEntry `json:"entries,omitempty"`
|
||||
More *bool `json:"more,omitempty"`
|
||||
Validated bool `json:"validated,omitempty"`
|
||||
Prepared bool `json:"prepared,omitempty"`
|
||||
}
|
||||
|
||||
// Run accepts exactly one strict JSON request on stdin and emits exactly one JSON response on
|
||||
@@ -110,11 +111,17 @@ func execute(input request) (response, error) {
|
||||
return response{}, errInvalid
|
||||
}
|
||||
if input.Operation == "validate-root" {
|
||||
if _, err := preflightRoot(input.Root); err != nil {
|
||||
if err := validateStorageLayout(input.Root); err != nil {
|
||||
return response{}, errInvalid
|
||||
}
|
||||
return response{Version: protocolVersion, OK: true, Validated: true}, nil
|
||||
}
|
||||
if input.Operation == "ensure-layout" {
|
||||
if err := ensureStorageLayout(input.Root); err != nil {
|
||||
return response{}, errInvalid
|
||||
}
|
||||
return response{Version: protocolVersion, OK: true, Prepared: true}, nil
|
||||
}
|
||||
if input.Operation == "read-auth-config" {
|
||||
root, err := existingPrivateRoot(input.Root)
|
||||
if err != nil {
|
||||
@@ -225,7 +232,7 @@ func validOperationShape(input request) bool {
|
||||
noAfterName := input.AfterName == ""
|
||||
noContinuation := !input.Continuation
|
||||
switch input.Operation {
|
||||
case "validate-root":
|
||||
case "validate-root", "ensure-layout":
|
||||
return input.Directory == "" && input.Filename == "" && noContents && noMaximumEntries && noAfterName && noContinuation
|
||||
case "read-auth-config":
|
||||
return input.Directory == "" && authConfigFilename.MatchString(input.Filename) && noContents && noMaximumEntries && noAfterName && noContinuation
|
||||
@@ -260,6 +267,63 @@ func existingPrivateRoot(root string) (string, error) {
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func validateStorageLayout(root string) error {
|
||||
exists, err := preflightRoot(root)
|
||||
if err != nil {
|
||||
return errInvalid
|
||||
}
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
existingChildren := make([]string, 0, 2)
|
||||
for _, directory := range []string{"sessions", "oidc"} {
|
||||
path := filepath.Join(root, directory)
|
||||
if filepath.Dir(path) != root {
|
||||
return errInvalid
|
||||
}
|
||||
childExists, err := safeio.PreflightPrivateDirectory(path)
|
||||
if err != nil {
|
||||
return errInvalid
|
||||
}
|
||||
if childExists {
|
||||
existingChildren = append(existingChildren, path)
|
||||
}
|
||||
}
|
||||
// Close permission/identity races between the individual side-effect-free preflights.
|
||||
if safeio.ValidatePrivateDirectory(root) != nil {
|
||||
return errInvalid
|
||||
}
|
||||
for _, directory := range []string{"sessions", "oidc"} {
|
||||
if _, err := safeio.PreflightPrivateDirectory(filepath.Join(root, directory)); err != nil {
|
||||
return errInvalid
|
||||
}
|
||||
}
|
||||
for _, path := range existingChildren {
|
||||
if safeio.ValidatePrivateDirectory(path) != nil {
|
||||
return errInvalid
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureStorageLayout(root string) error {
|
||||
if _, err := preflightRoot(root); err != nil || safeio.EnsurePrivateDirectory(root) != nil {
|
||||
return errInvalid
|
||||
}
|
||||
for _, directory := range []string{"sessions", "oidc"} {
|
||||
path := filepath.Join(root, directory)
|
||||
if filepath.Dir(path) != root || safeio.EnsurePrivateDirectory(path) != nil {
|
||||
return errInvalid
|
||||
}
|
||||
}
|
||||
if safeio.ValidatePrivateDirectory(root) != nil ||
|
||||
safeio.ValidatePrivateDirectory(filepath.Join(root, "sessions")) != nil ||
|
||||
safeio.ValidatePrivateDirectory(filepath.Join(root, "oidc")) != nil {
|
||||
return errInvalid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func contentResponse(found bool, contents []byte) response {
|
||||
if !found {
|
||||
return response{Version: protocolVersion, OK: true}
|
||||
|
||||
Reference in New Issue
Block a user