Skip to content

[Bug] Mutex leak in remove_from_front() when exception thrown under CONSISTENCY_CHECKING #54

@hanqing2025

Description

@hanqing2025

Describe the Bug

A mutex leak in remove_from_front() causes permanent deadlock when an exception is thrown while holding the lock. When compiled with CONSISTENCY_CHECKING defined, the function acquires a mutex but throws std::runtime_error without releasing it, as C++ exception unwinding bypasses the pthread_mutex_unlock() call.

Location: src/prioque.cpp (lines 222-247)

void remove_from_front(Queue * q, void *element)
{
    Queue_element temp;

    // lock entire queue
    pthread_mutex_lock(&(q->lock));  // Line 222: Lock acquired

#if defined(CONSISTENCY_CHECKING)
    if(q->queue == 0) {
        std::string msg("Malloc failed in function remove_from_front()\n");
        fprintf(stderr, "%s", msg.c_str());
        throw std::runtime_error(msg);  // Line 228: BUG - exception with lock held!
    }
    else
#endif
    {
        memcpy(element, q->queue->info, q->elementsize);
        free(q->queue->info);
        q->queue->info = NULL;
        temp = q->queue;
        q->queue = q->queue->next;
        free(temp);
        (q->queuelength)--;
    }

    nolock_rewind_queue(q);

    // release lock on queue
    pthread_mutex_unlock(&(q->lock));  // Line 247: Never reached on exception
}

Impact:

  • Queue mutex q->lock remains permanently locked when exception is thrown
  • All subsequent queue operations block permanently on pthread_mutex_lock()
  • File carving operations completely stall → Denial of Service
  • Forensic analysis process becomes unresponsive

Execution Flow:

Thread 1:
  → pthread_mutex_lock(&(q->lock))       // Lock acquired
  → Check: q->queue == 0                 // Condition TRUE (NULL queue)
  → throw std::runtime_error(msg)        // Exception thrown
  → C++ stack unwinding begins
  → pthread_mutex_unlock() SKIPPED       // BUG: lock never released
  → q->lock remains locked forever

Thread 2, 3, ...N:
  → Attempt any queue operation
  → pthread_mutex_lock(&(q->lock))       // BLOCKS permanently
  → All carving threads frozen
  → Scalpel becomes unresponsive

This occurs when Scalpel is compiled with CONSISTENCY_CHECKING defined and q->queue is NULL. The C++ exception mechanism unwinds the stack but does not call pthread_mutex_unlock(), leaving the mutex permanently locked.


I would appreciate it if you could review and confirm this potential issue. Thank you for your time and for maintaining this project!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions