Fix timing leakage in cache hit/miss for non-error conditions

Bug #1359862 reported by Jason Gerard DeRose
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Dbase32
Fix Released
Critical
Jason Gerard DeRose

Bug Description

Another timing attack issue, furthering the work started in lp:1359828
https://bugs.launchpad.net/dbase32/+bug/1359828

The DB32_REVERSE lookup table means the Dbase32 C implementation is subject to cache timing attacks when the ID to be decoded or validated contains invalid characters. This can't be fully fixed as long as we're using such a lookup table.

However, the current implementation can also potentially leak information through cache hits and misses when decoding or validating a *valid* Dbase32 ID. And this *is* something we can fix.

The problem is that the entries for valid characters in the DB32_REVERSE table span two (64 byte) cache lines, and they aren't distributed uniformly. One cache line will contain 7 valid entries, and the other will contain the remaining 25 valid entries. Even without working out a proof of concept attack against this, the non uniform distribution between two cache lines doesn't pass the security smell test.

I believe the correct solution is probably to rotate the DB32_REVERSE table to the left by 51 bytes so that all valid entries fit in a single cache line. Although it will still be possible to get distinguishing information through cache hits and misses when the ID contains invalid characters, it wont be possible to gain any insight into what characters a valid ID contains.

For reference, here's the reverse table used in Dbase32 1.1 and earlier:

static const uint8_t DB32_REVERSE[256] = {
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,
      0, // '3' [51]
      1, // '4' [52]
      2, // '5' [53]
      3, // '6' [54]
      4, // '7' [55]
      5, // '8' [56]
      6, // '9' [57]
    255, // ':' [58]
    255, // ';' [59]
    255, // '<' [60]
    255, // '=' [61]
    255, // '>' [62]
    255, // '?' [63]
    255, // '@' [64]
      7, // 'A' [65]
      8, // 'B' [66]
      9, // 'C' [67]
     10, // 'D' [68]
     11, // 'E' [69]
     12, // 'F' [70]
     13, // 'G' [71]
     14, // 'H' [72]
     15, // 'I' [73]
     16, // 'J' [74]
     17, // 'K' [75]
     18, // 'L' [76]
     19, // 'M' [77]
     20, // 'N' [78]
     21, // 'O' [79]
     22, // 'P' [80]
     23, // 'Q' [81]
     24, // 'R' [82]
     25, // 'S' [83]
     26, // 'T' [84]
     27, // 'U' [85]
     28, // 'V' [86]
     29, // 'W' [87]
     30, // 'X' [88]
     31, // 'Y' [89]
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
    255,255,255,255,255,255,255,255,255,255,255,255,255,255,
};

Tags: security

Related branches

summary: - Mitagate timing leakage in cache misses for non-error conditions
+ Fix timing leakage in cache misses for non-error conditions
summary: - Fix timing leakage in cache misses for non-error conditions
+ Fix timing leakage in cache hit/miss for non-error conditions
description: updated
tags: added: security
Revision history for this message
Jason Gerard DeRose (jderose) wrote :

Note that the proposed fix doesn't fix the problem for CPU with a 32 byte (or smaller) L1 cache line size, like ARM Cortex-A9:
http://www.7-cpu.com/cpu/Cortex-A9.html

However, Cortex-A15 (and newer), plus all modern Intel CPU, use a 64 byte L1 cache line size.

Changed in dbase32:
milestone: 1.2 → 1.3
Changed in dbase32:
status: Triaged → In Progress
Revision history for this message
Jason Gerard DeRose (jderose) wrote :

One more point: on systems with a 32-byte cache line size, if we rotate the table to the left by 42 bytes (rather than 51 bytes), each 32-byte cache line will have an equal number of valid entries (16 entries each), which at least makes the table balanced between the two cache lines.

This only makes certain specific scenarios a bit more difficult to attack, but I still feel this is a worthwhile detail. If anyone has evidence to the contrary (evidence that an *imbalanced* distribution between two 32-byte cache lines is somehow safer), please let me know!

Changed in dbase32:
status: In Progress → Fix Committed
Changed in dbase32:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.