Missing Lock Check
Description
Missing Lock Check is a vulnerability where a product does not check to see if a lock is present before performing sensitive operations on a resource. The weakness occurs when software fails to verify that protective locking mechanisms are in place before accessing or modifying critical resources, creating opportunities for unauthorized access, data corruption, or race conditions. Unlike improper locking where locks are acquired incorrectly, this weakness involves completely failing to verify lock status before proceeding with operations.
Risk
Missing lock checks enable attackers to access or modify resources that should be exclusively controlled. In security-critical operations, bypassing lock verification can lead to privilege escalation or security control circumvention. Concurrent access to unverified resources can corrupt data integrity. In file systems, operations on unlocked files may interfere with other processes. Database operations without lock verification can cause transaction anomalies. The impact ranges from data corruption to complete system compromise depending on the resource's sensitivity.
Solution
Implement a reliable lock mechanism and always verify lock status before performing sensitive operations. Use language-provided locking primitives that combine verification and acquisition atomically. Design APIs that require lock ownership proof before allowing resource access. Implement lock verification at the beginning of every function that accesses protected resources. Use assertions or runtime checks to verify lock invariants during development. Consider using lock-guarded accessor patterns that make unverified access impossible by design.
Common Consequences
| Impact | Details |
|---|---|
| Integrity | Scope: Integrity, Availability Modify Application Data - Attackers may alter application data by accessing resources without proper lock verification. DoS: Instability - System may become unstable due to concurrent uncontrolled access. DoS: Crash, Exit, or Restart - Unexpected state corruption can cause system failures. |
Example Code
Vulnerable Code
// Vulnerable: No lock check before accessing protected resource
#include <pthread.h>
typedef struct {
int data;
pthread_mutex_t lock;
int is_locked;
} ProtectedResource;
// Vulnerable: Doesn't verify lock is held
void vulnerable_modify_data(ProtectedResource *res, int new_value) {
// Vulnerable: No check if lock is actually held
// Assumes caller holds lock, but doesn't verify
res->data = new_value;
}
// Vulnerable: Inconsistent lock checking
void vulnerable_operation(ProtectedResource *res) {
// Sometimes locks, sometimes doesn't
if (some_condition) {
pthread_mutex_lock(&res->lock);
}
// Vulnerable: Proceeds without knowing if locked
res->data++;
if (some_condition) {
pthread_mutex_unlock(&res->lock);
}
}
# Vulnerable: No lock verification before file operations
import fcntl
class VulnerableFileHandler:
def __init__(self, filepath):
self.filepath = filepath
self.file = None
def open_file(self):
self.file = open(self.filepath, 'r+')
# Vulnerable: Doesn't check if file is locked
def write_data(self, data):
# Vulnerable: No verification that we hold the lock
# Another process may have the lock
self.file.write(data)
self.file.flush()
# Vulnerable: Assumes lock without checking
def modify_sensitive_data(self, data):
# Should verify lock is held, but doesn't
self.file.seek(0)
self.file.write(data)
// Vulnerable: No lock verification in protected method
public class VulnerableProtectedResource {
private Object data;
private final Object lock = new Object();
private volatile boolean isLocked = false;
public void acquireLock() {
synchronized(lock) {
isLocked = true;
}
}
public void releaseLock() {
synchronized(lock) {
isLocked = false;
}
}
// Vulnerable: Doesn't verify lock is held
public void modifyData(Object newData) {
// Vulnerable: No check for isLocked
// Caller may have forgotten to acquire lock
this.data = newData;
}
// Vulnerable: Check is not atomic with operation
public void unsafeModify(Object newData) {
if (isLocked) {
// Vulnerable: Lock may be released between check and modify
this.data = newData;
}
}
}
Fixed Code
// Fixed: Always verify lock is held before operations
#include <pthread.h>
#include <assert.h>
typedef struct {
int data;
pthread_mutex_t lock;
pthread_t lock_owner;
int is_locked;
} ProtectedResource;
// Fixed: Verify lock ownership before modification
int secure_modify_data(ProtectedResource *res, int new_value) {
// Fixed: Verify this thread holds the lock
if (!res->is_locked || !pthread_equal(res->lock_owner, pthread_self())) {
return -1; // Error: lock not held by this thread
}
res->data = new_value;
return 0;
}
// Fixed: Proper lock acquisition with ownership tracking
int acquire_lock(ProtectedResource *res) {
int result = pthread_mutex_lock(&res->lock);
if (result == 0) {
res->is_locked = 1;
res->lock_owner = pthread_self();
}
return result;
}
int release_lock(ProtectedResource *res) {
// Fixed: Verify we own the lock before releasing
if (!pthread_equal(res->lock_owner, pthread_self())) {
return -1;
}
res->is_locked = 0;
return pthread_mutex_unlock(&res->lock);
}
// Fixed: Combined lock-check-and-operate pattern
int secure_operation(ProtectedResource *res, int delta) {
if (acquire_lock(res) != 0) {
return -1;
}
// Lock is definitely held here
res->data += delta;
release_lock(res);
return 0;
}
# Fixed: Verify lock before operations
import fcntl
import threading
class SecureFileHandler:
def __init__(self, filepath):
self.filepath = filepath
self.file = None
self.lock_held = False
self._internal_lock = threading.Lock()
def open_file(self):
self.file = open(self.filepath, 'r+')
def acquire_lock(self):
with self._internal_lock:
fcntl.flock(self.file.fileno(), fcntl.LOCK_EX)
self.lock_held = True
def release_lock(self):
with self._internal_lock:
if self.lock_held:
fcntl.flock(self.file.fileno(), fcntl.LOCK_UN)
self.lock_held = False
# Fixed: Verify lock before writing
def write_data(self, data):
with self._internal_lock:
if not self.lock_held:
raise RuntimeError("Lock not held - call acquire_lock() first")
self.file.write(data)
self.file.flush()
# Fixed: Context manager for safe lock-protected operations
def __enter__(self):
self.open_file()
self.acquire_lock()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.release_lock()
if self.file:
self.file.close()
# Usage: Lock verification is automatic
with SecureFileHandler('/path/to/file') as handler:
handler.write_data("safe data") # Lock guaranteed to be held
// Fixed: Lock verification enforced by design
import java.util.concurrent.locks.ReentrantLock;
public class SecureProtectedResource {
private Object data;
private final ReentrantLock lock = new ReentrantLock();
// Fixed: Private method that verifies lock is held
private void verifyLockHeld() {
if (!lock.isHeldByCurrentThread()) {
throw new IllegalStateException("Lock must be held to perform this operation");
}
}
// Fixed: Public method that requires lock verification
public void modifyData(Object newData) {
verifyLockHeld(); // Fixed: Always verify
this.data = newData;
}
public Object getData() {
verifyLockHeld(); // Fixed: Even reads require verification
return this.data;
}
// Fixed: Safe public interface that handles locking
public void safeModify(Object newData) {
lock.lock();
try {
// Lock is definitely held here
this.data = newData;
} finally {
lock.unlock();
}
}
// Fixed: Provide a locked operation callback pattern
public <T> T withLock(java.util.function.Supplier<T> operation) {
lock.lock();
try {
return operation.get();
} finally {
lock.unlock();
}
}
}
// Usage
// resource.withLock(() -> {
// resource.modifyData(newValue); // Lock guaranteed
// return resource.getData();
// });
CVE Examples
- CVE-2004-1056 — Product does not properly check if a lock is present, allowing attackers to access functionality that should be protected.
References
- MITRE Corporation. "CWE-414: Missing Lock Check." https://cwe.mitre.org/data/definitions/414.html
- CERT C Coding Standard. "CON00-C. Avoid race conditions with multiple threads." https://wiki.sei.cmu.edu/confluence/display/c/CON00-C.+Avoid+race+conditions+with+multiple+threads