Browse Source

Merge pull request #5739 from heyitsanthony/serialize-txn

etcdserver: make serialized txns auth-aware
Anthony Romano 9 years ago
parent
commit
84c416491e
2 changed files with 26 additions and 9 deletions
  1. 13 6
      etcdserver/apply_auth.go
  2. 13 3
      etcdserver/v3_server.go

+ 13 - 6
etcdserver/apply_auth.go

@@ -15,31 +15,38 @@
 package etcdserver
 
 import (
+	"sync"
+
 	"github.com/coreos/etcd/auth"
 	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
 )
 
 type authApplierV3 struct {
 	applierV3
-	as   auth.AuthStore
+	as auth.AuthStore
+
+	// mu serializes Apply so that user isn't corrupted and so that
+	// serialized requests don't leak data from TOCTOU errors
+	mu   sync.Mutex
 	user string
 }
 
 func newAuthApplierV3(as auth.AuthStore, base applierV3) *authApplierV3 {
-	return &authApplierV3{base, as, ""}
+	return &authApplierV3{applierV3: base, as: as}
 }
 
 func (aa *authApplierV3) Apply(r *pb.InternalRaftRequest) *applyResult {
-	var user string
+	aa.mu.Lock()
+	defer aa.mu.Unlock()
 	if r.Header != nil {
 		// backward-compatible with pre-3.0 releases when internalRaftRequest
 		// does not have header field
-		user = r.Header.Username
+		aa.user = r.Header.Username
 	}
-	if needAdminPermission(r) && !aa.as.IsAdminPermitted(user) {
+	if needAdminPermission(r) && !aa.as.IsAdminPermitted(aa.user) {
+		aa.user = ""
 		return &applyResult{err: auth.ErrPermissionDenied}
 	}
-	aa.user = user
 	ret := aa.applierV3.Apply(r)
 	aa.user = ""
 	return ret

+ 13 - 3
etcdserver/v3_server.go

@@ -124,11 +124,21 @@ func (s *EtcdServer) DeleteRange(ctx context.Context, r *pb.DeleteRangeRequest)
 }
 
 func (s *EtcdServer) Txn(ctx context.Context, r *pb.TxnRequest) (*pb.TxnResponse, error) {
+	var result *applyResult
+	var err error
+
 	if isTxnSerializable(r) {
-		return s.applyV3.Txn(r)
+		user, err := s.usernameFromCtx(ctx)
+		if err != nil {
+			return nil, err
+		}
+		result = s.applyV3.Apply(
+			&pb.InternalRaftRequest{
+				Header: &pb.RequestHeader{Username: user},
+				Txn:    r})
+	} else {
+		result, err = s.processInternalRaftRequest(ctx, pb.InternalRaftRequest{Txn: r})
 	}
-
-	result, err := s.processInternalRaftRequest(ctx, pb.InternalRaftRequest{Txn: r})
 	if err != nil {
 		return nil, err
 	}