From 426deb60fd255ee6f96fb20ff0c4996f721da2d8 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Mon, 27 Feb 2023 08:46:02 -0800 Subject: [PATCH] lockdep: fix the TOCTTOU issue The problem is that it checkes circular dependencies and one then adds the target lock to the graph. Reported-by: syzbot+7687e27a2029723c7fb4@syzkaller.appspotmail.com PiperOrigin-RevId: 512637945 --- pkg/sync/locking/lockdep.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/pkg/sync/locking/lockdep.go b/pkg/sync/locking/lockdep.go index 092a5765e..871466c36 100644 --- a/pkg/sync/locking/lockdep.go +++ b/pkg/sync/locking/lockdep.go @@ -72,9 +72,23 @@ type goroutineLocks map[*MutexClass]bool var routineLocks goroutineLocksAtomicPtrMap +// maxChainLen is the maximum length of a lock chain. +const maxChainLen = 32 + // checkLock checks that class isn't in the ancestors of prevClass. func checkLock(class *MutexClass, prevClass *MutexClass, chain []*MutexClass) { chain = append(chain, prevClass) + if len(chain) >= maxChainLen { + // It can be a race condition with another thread that added + // the lock to the graph but don't complete the validation. + var b strings.Builder + fmt.Fprintf(&b, "WARNING: The maximum lock depth has been reached: %s", chain[0]) + for i := 1; i < len(chain); i++ { + fmt.Fprintf(&b, "-> %s", chain[i]) + } + log.Warningf("%s", b.String()) + return + } if c := prevClass.ancestors.Load(class); c != nil { var b strings.Builder fmt.Fprintf(&b, "WARNING: circular locking detected: %s -> %s:\n%s\n", @@ -118,10 +132,14 @@ func AddGLock(class *MutexClass, lockNameIndex int) { return } + if (*currentLocks)[class] { + panic(fmt.Sprintf("nested locking: %s:\n%s", class, log.LocalStack(2))) + } + (*currentLocks)[class] = true // Check dependencies and add locked mutexes to the ancestors list. for prevClass := range *currentLocks { if prevClass == class { - panic(fmt.Sprintf("nested locking: %s:\n%s", class, log.LocalStack(2))) + continue } checkLock(class, prevClass, nil) @@ -130,7 +148,6 @@ func AddGLock(class *MutexClass, lockNameIndex int) { class.ancestors.Store(prevClass, &stacks) } } - (*currentLocks)[class] = true } // DelGLock deletes a lock from the current goroutine.