CWE-362 – Race Condition

A race condition occurs within concurrent environments and is effectively a property of a code sequence.

  • Depending on the context, a code sequence may be in the form of a function call, a small number of instructions, a series of program invocations, etc.

A race condition violates basic properties:

  • Exclusivity - the code sequence is given exclusive access to the shared resource.

    • no other code sequence can modify the properties of the shared resource before the original sequence has completed execution.

  • Atomicity - the code sequence is behaviorally atomic.

    • no other thread or process can concurrently execute the same sequence of instructions (or a subset) against the same resource.

Race condition exists when an "interfering code sequence" can still access the shared resource, violating exclusivity.

Programmers may assume that certain code sequences execute too quickly to be affected by an interfering code sequence; when they are not, this violates atomicity.

  • “too quickly” may degrade with time to slower execution as functionality is added.

  • “too quickly” is system dependent.

E-commerce application that supports transfers between accounts.

  • It takes the total amount of the transfer, sends it to the new account, and deducts the amount from the original account.

Race condition between.

  • GetBalanceFromDatabase()

  • SendNewBalanceToDatabase()

$transfer_amount = GetTransferAmount();
$balance = GetBalanceFromDatabase();

if ($transfer_amount < 0) {
    FatalError("Bad Transfer Amount");
}

$newbalance = $balance - $transfer_amount;

if (($balance - $transfer_amount) < 0) {
    FatalError("Insufficient Funds");
}
    
SendNewBalanceToDatabase($newbalance);
NotifyUser("Transfer of $transfer_amount succeeded.");
NotifyUser("New balance: $newbalance");

Example - Banking

$transfer_amount = GetTransferAmount();
$balance = GetBalance();

if ($transfer_amount < 0) {
    FatalError("Bad Transfer Amount");
}

$nb = $balance - $transfer_amount;

if (($balance - $transfer_amount) < 0) {
    FatalError("Insufficient Funds");
}

SetNewBalanceToDB($nb);
NotifyUser("Transfer of $transfer_amount succeeded.");
NotifyUser("New balance: $newbalance");

The balance could have changed between the instructions:

  • $balance = GetBalance();
  • if (($balance - $transfer_amount) < 0) ...

Other operations could have happened between these lines. $newbalance is set to a static value.

  • Initial balance: 1000€

  • Total transferred out: 1100€

  • Final balance: 800€

  • Result: Bank lost 700€

Last updated