CWE-412 is a product that checks for a lock correctly, but the lock can be controlled by someone outside the intended sphere of control. The code is fine. The lock is in the wrong place.
How it happens
Locks can be a mutex, an exclusive file lock, or a shared resource treated as a lock, such as a file whose existence means busy. If an untrusted user can create or hold that object, they decide when your program may proceed.
MITRE's examples include a program that could not run because an attacker obtained a mutex (CVE-2001-0682), and programs blocked when an attacker locked a critical output file (CVE-2002-1914).
What an attacker gains
Availability. The program may wait indefinitely until the attacker lets go, especially when there is a blocking operation on the lock. If the lock can be held for an indefinite period, the denial of service can be permanent.
How to find it
MITRE notes that automated code analysis might not reliably detect this, since the application's security model decides which locks are critical. So review by hand:
- List every lock, lock file and named mutex.
- For each, ask who can create or hold it. World writable directories and global names are red flags.
How to fix it
- Put lock files in directories only the service account can write.
- Use unnamed or private locks where possible, instead of globally named ones.
- Use lock timeouts so a blocked call gives up.
- Set restrictive permissions on shared objects used as locks.
Design choices that help
The safest lock is one the attacker cannot name. A private in memory mutex inside your process cannot be taken from outside. A lock file in a directory owned by the service account cannot be created by other users. When you must share a lock across processes, give it a restrictive access control list and a timeout, and decide ahead of time what the program does when it cannot get the lock: retry, skip or fail cleanly.
Quick check
Why can scanners miss this?
Whether a lock is critical depends on your design, which a scanner cannot know.