Use of a custom byte-swap macro without endianness check
The PORTING checkers identify code that might rely on specific implementation details in different compilers. The PORTING.BSWAP.MACRO checker detects situations in which a custom byte-swap macro is used without checking endianness. To cause the PORTING.BSWAP.MACRO checker to flag the code as a byte-swap macro, the macro definition must include a shift operator and the bits to shift, which can be:
- left-shift (<<) or right-shift (>>) operators
- bitwise and (&) or bitwise or (|) operators
- integer literals that are multiples of 8
- byte masks, such as 0xFF or 0xFF00
If the byte-swap macro isn't protected by an endian-guarding macro, Klocwork reports the issue.
Vulnerability and risk
Typical byte-swap macros assume the layout of the integral type in which they're moving data, for example by swapping the MSB with the LSB. In an environment where the endian nature of the underlying chip is potentially different at different times, such as between builds, such operations can be unsafe, especially if the integral type being transformed is read from persistent storage or another hardware environment.
Mitigation and prevention
As with any endian-vulnerable operation, guard the macro definitions with BIG_ENDIAN or LITTLE_ENDIAN guard macros, so that you can be sure that the transformation being performed is appropriate for the environment used.
Vulnerable code example
// Pretty normal byte swapping macro, changes unsigned integers from one type of endian to another
#define SWAPBYTES(x) ( ((x) & 0xff) << 24 ) | ( (((x) >> 8) & 0xff) << 16 ) | ( (((x) >> 16) & 0xff) << 8 ) | ( (((x) >> 24) & 0xff)
In this example, tthe definition of the macro is specific to a particular endian architecture, but the definition isn't guarded as such, and could be inappropriately compiled into a build intended for the opposite architecture.
Fixed code example
// Now the definition is endian-guarded
#define SWAPBYTES(x) ( ((x) & 0xff) << 24 ) | ( (((x) >> 8) & 0xff) << 16 ) | ( (((x) >> 16) & 0xff) << 8 ) | ( (((x) >> 24) & 0xff) )
#define SWAPBYTES(x) ( x )
In the fixed example, the macro definition is guarded with the appropriate endian guard, and an alternative can be defined for the opposite architecture.