Skip to content

Heap canaries #89104

Open
Open
RFC
@quic-cbusold

Description

@quic-cbusold

Introduction

We would like to add heap canaries as an additional (optional) security feature to the heap implementation provided by Zephyr. This is very similar to the (optional) stack canaries feature that is already supported, but targeting the heap instead of the stack. It should be noted that, also very much like stack canaries, this cannot protect against all forms of heap corruption but is rather a compromise between security and performance.

Problem description

As any code base written in C, Zepyhr and its applications are vulnerable to memory safety issues like the notorious buffer overflows, which are a well known threat to the security of digital products. This includes the heap used by Zephyr kernel and applications. Heap canaries are a form of mitigation that prevents or limits the exploitation of such vulnerabilities with heap buffers and thus allows users to increase the security level of their system for the cost of some overhead in code and heap size as well as heap runtime performance.

This is also interesting in light of the Cyber Resilience Act, which requires digital products to enable "appropriate exploitation mitigation mechanisms and techniques" (see Annex I Part I Paragraph 2 Section k).

Proposed change

Our proposal is to add an optional feature which adds canaries between heap blocks in order to detect and prevent certain forms of heap corruption.

Detailed RFC

New config for this feature, e.g., CONFIG_HEAP_CANARIES.

Proposed change (Detailed)

When enabled, each heap should randomly generate and store a unique 4-byte canary value at initialization. This value is then placed at the beginning of the header of each heap block to protect it against overflows from the previous heap block.

Whenever a heap block is modified, the canary in its header should first be validated. That would be (a) in sys_heap_alloc, when a free block is set to used (and optionally split), and (b) in sys_heap_free, when a used block is set to free (and optionally merged with surrounding free blocks). When merging free blocks, the canaries of all impacted blocks should be checked. If any canary does not have the expected value, then the heap must have been corrupted and execution should be stopped with __ASSERT.

Dependencies

Similar to stack canaries, this feature depends on a secure random entropy source for the canary value to be effective.

Concerns and Unresolved Questions

The heap implementation organizes memory into 8-byte chunks. While we only need 4 bytes for sufficient entropy, there is no space left in the header (at least for used blocks) and thus we need to add an additional chunk to the header, increasing its size from 1 to 2 chunks for small heaps and 2 to 3 for large heaps. We do not see an easy way around this without major changes to the heap implementation. How much this impacts the overall heap size overhead depends on the average allocation size.

Placing the canary at the beginning means the offsets of header fields in chunk_field depend on whether this feature is enabled or not. Since this can be done with a compile-time constant, however, this should have no runtime impact. The canary could be placed at the end of the header instead, but then overflows from the previous block would not be detected unless they cross over the canary. We consider overflows more likely than underflows of the current block and therefore prefer this position. Alternatively, the canary could be placed both at the beginning and the end to detect both, but this would have more overhead, at least in code size and performance; we could use the 8-byte chunk, see above.

Alternatives

The heap implementation currently checks for overflows in sys_heap_free by checking if the previous block points to this one. While this is certainly useful, it helps more against accidental overflows than targeted attacks. We have to expect that attacks can predict the heap layout, place the correct value into that field when overflowing the heap and thus avoid detection. The advantage of canaries is that they are (ideally) not guessable by attackers.

Alternative mitigations provide similar protection, but have considerably more overhead and/or require special hardware support not typically available on Zephyr platforms (e.g., Address Sanitizer, ARM MTE or Intel MPX).

Obviously, memory safe languages can also be considered as alternative in the long term, but it seems unrealistic that Zepyhr will be transitioning away from C anytime soon.

Metadata

Metadata

Labels

RFCRequest For Comments: want input from the communityarea: Base OSBase OS Library (lib/os)

Type

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions