CWE-832 is an attempt to unlock a resource that is not locked. MITRE marks it as not language specific. It matters most in systems code with explicit locks: kernels, drivers and multithreaded services.
How it happens
The unlock call sits on a path where the lock was never taken, often an error branch. Depending on the lock implementation, the unlock may corrupt memory or the lock's own tracking data.
// Vulnerable: error path unlocks without having locked
int op(struct obj *o) {
if (!o->ready) goto out; // lock not taken yet
pthread_mutex_lock(&o->m);
work(o);
out:
pthread_mutex_unlock(&o->m);
return 0;
}
MITRE lists these examples: CVE-2010-4210, where an OS kernel function unlocked a mutex that was not locked, causing a panic or overwrite of arbitrary memory; CVE-2008-4302, a chain where unhandled failure of a function call led to the unlock and a crash; and CVE-2009-1243, where a kernel unlocked in incorrect circumstances, leading to a panic.
What an attacker gains
Sometimes nothing, depending on the lock. When effects exist, MITRE says the most common one is corrupted state, which can mean a crash, memory modification, and potentially code execution.
How to find it
MITRE lists automated static analysis, which can model paths in source or compiled code and spot unlock calls that are not preceded by a lock on every path. Code review of error handling and cleanup labels is productive too.
How to fix it
The record lists no formal mitigations. Useful habits:
- Lock and unlock in the same function with matching structure.
- Check return values from calls that can fail before relying on state.
- Use scoped lock guards, such as
std::lock_guardin C++, so release is automatic and only after acquisition. - Keep one exit path and make it track whether the lock is held.
Quick check
Why do error paths cause this?
Cleanup code is often shared. A jump to it before the lock is taken runs the unlock anyway.