diff --git a/changelog/21640.txt b/changelog/21640.txt new file mode 100644 index 000000000000..458561ae1aae --- /dev/null +++ b/changelog/21640.txt @@ -0,0 +1,3 @@ +```release-note:bug +core: fix race when updating a mount's route entry tainted status and incoming requests +``` diff --git a/vault/router.go b/vault/router.go index 3497e8244a60..818b304cfa8d 100644 --- a/vault/router.go +++ b/vault/router.go @@ -58,7 +58,7 @@ func NewRouter() *Router { // routeEntry is used to represent a mount point in the router type routeEntry struct { - tainted bool + tainted atomic.Bool backend logical.Backend mountEntry *MountEntry storageView logical.Storage @@ -125,7 +125,7 @@ func (entry *routeEntry) Deserialize() map[string]interface{} { entry.l.RLock() defer entry.l.RUnlock() ret := map[string]interface{}{ - "tainted": entry.tainted, + "tainted": entry.tainted.Load(), "storage_prefix": entry.storagePrefix, } for k, v := range entry.mountEntry.Deserialize() { @@ -189,12 +189,12 @@ func (r *Router) Mount(backend logical.Backend, prefix string, mountEntry *Mount // Create a mount entry re := &routeEntry{ - tainted: mountEntry.Tainted, backend: backend, mountEntry: mountEntry, storagePrefix: storageView.Prefix(), storageView: storageView, } + re.tainted.Store(mountEntry.Tainted) re.rootPaths.Store(pathsToRadix(paths.Root)) loginPathsEntry, err := parseUnauthenticatedPaths(paths.Unauthenticated) if err != nil { @@ -290,7 +290,7 @@ func (r *Router) Taint(ctx context.Context, path string) error { defer r.l.Unlock() _, raw, ok := r.root.LongestPrefix(path) if ok { - raw.(*routeEntry).tainted = true + raw.(*routeEntry).tainted.Store(true) } return nil } @@ -307,7 +307,7 @@ func (r *Router) Untaint(ctx context.Context, path string) error { defer r.l.Unlock() _, raw, ok := r.root.LongestPrefix(path) if ok { - raw.(*routeEntry).tainted = false + raw.(*routeEntry).tainted.Store(false) } return nil } @@ -605,7 +605,7 @@ func (r *Router) routeCommon(ctx context.Context, req *logical.Request, existenc // If the path is tainted, we reject any operation except for // Rollback and Revoke - if re.tainted { + if re.tainted.Load() { switch req.Operation { case logical.RevokeOperation, logical.RollbackOperation: default: