fix: deadlock in session rename (lock ordering inversion)

This commit is contained in:
Levi Neely 2026-05-19 15:26:33 +02:00
parent 4cf8a666e3
commit d9622dfc7a
2 changed files with 12 additions and 2 deletions

View File

@ -283,7 +283,10 @@ func New(sink *olog.Sink, opts ...ServerOption) *Server {
s.AddGroup("agent", newID) s.AddGroup("agent", newID)
oldPrefix := "/s/" + oldID oldPrefix := "/s/" + oldID
newPrefix := "/s/" + newID newPrefix := "/s/" + newID
for _, c := range s.conns { s.mu.RLock()
conns := s.conns
s.mu.RUnlock()
for _, c := range conns {
c.mu.Lock() c.mu.Lock()
for _, f := range c.fids { for _, f := range c.fids {
if f.path == oldPrefix || strings.HasPrefix(f.path, oldPrefix+"/") { if f.path == oldPrefix || strings.HasPrefix(f.path, oldPrefix+"/") {

View File

@ -465,27 +465,34 @@ func (s *SessionStore) createSession(args []string) error {
func (s *SessionStore) renameSession(oldID, newID string) error { func (s *SessionStore) renameSession(oldID, newID string) error {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock()
sess, ok := s.sessions[oldID] sess, ok := s.sessions[oldID]
if !ok { if !ok {
s.mu.Unlock()
return fmt.Errorf("session not found: %s", oldID) return fmt.Errorf("session not found: %s", oldID)
} }
if _, exists := s.sessions[newID]; exists { if _, exists := s.sessions[newID]; exists {
s.mu.Unlock()
return fmt.Errorf("session already exists: %s", newID) return fmt.Errorf("session already exists: %s", newID)
} }
if sess.Core.IsRunning() { if sess.Core.IsRunning() {
s.mu.Unlock()
return fmt.Errorf("cannot rename while agent is running") return fmt.Errorf("cannot rename while agent is running")
} }
if err := sess.Core.SetSessionID(newID); err != nil { if err := sess.Core.SetSessionID(newID); err != nil {
s.mu.Unlock()
return err return err
} }
sess.id = newID sess.id = newID
s.sessions[newID] = sess s.sessions[newID] = sess
delete(s.sessions, oldID) delete(s.sessions, oldID)
s.mu.Unlock()
// OnRename must be called without holding s.mu to avoid deadlock
// with connection handlers that hold connState.mu and call into
// SessionStore (e.g. SessionByUname during Tattach).
if s.cfg.OnRename != nil { if s.cfg.OnRename != nil {
s.cfg.OnRename(oldID, newID) s.cfg.OnRename(oldID, newID)
} }