From 95095f8406ce1bfc938237babf13a7ac36f73c6c Mon Sep 17 00:00:00 2001 From: Maxim Vladimirskiy Date: Fri, 26 Oct 2018 15:06:15 +0300 Subject: [PATCH] etcdserver: Remove infinite loop in doSerialize Once chk(ai) fails with auth.ErrAuthOldRevision it will always do, regardless how many times you retry. So the error is better be returned to fail the pending request and make the client re-authenticate. --- etcdserver/v3_server.go | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/etcdserver/v3_server.go b/etcdserver/v3_server.go index 9d429e329..bf4adf188 100644 --- a/etcdserver/v3_server.go +++ b/etcdserver/v3_server.go @@ -523,29 +523,25 @@ func (s *EtcdServer) raftRequest(ctx context.Context, r pb.InternalRaftRequest) // doSerialize handles the auth logic, with permissions checked by "chk", for a serialized request "get". Returns a non-nil error on authentication failure. func (s *EtcdServer) doSerialize(ctx context.Context, chk func(*auth.AuthInfo) error, get func()) error { - for { - ai, err := s.AuthInfoFromCtx(ctx) - if err != nil { - return err - } - if ai == nil { - // chk expects non-nil AuthInfo; use empty credentials - ai = &auth.AuthInfo{} - } - if err = chk(ai); err != nil { - if err == auth.ErrAuthOldRevision { - continue - } - return err - } - // fetch response for serialized request - get() - // empty credentials or current auth info means no need to retry - if ai.Revision == 0 || ai.Revision == s.authStore.Revision() { - return nil - } - // avoid TOCTOU error, retry of the request is required. + ai, err := s.AuthInfoFromCtx(ctx) + if err != nil { + return err } + if ai == nil { + // chk expects non-nil AuthInfo; use empty credentials + ai = &auth.AuthInfo{} + } + if err = chk(ai); err != nil { + return err + } + // fetch response for serialized request + get() + // check for stale token revision in case the auth store was updated while + // the request has been handled. + if ai.Revision != 0 && ai.Revision != s.authStore.Revision() { + return auth.ErrAuthOldRevision + } + return nil } func (s *EtcdServer) processInternalRaftRequestOnce(ctx context.Context, r pb.InternalRaftRequest) (*applyResult, error) {