[libc-commits] [libc] [libc] add option for hardened freelist (PR #205382)
Daniel Thornburgh via libc-commits
libc-commits at lists.llvm.org
Tue Jul 14 16:47:59 PDT 2026
================
@@ -15,9 +15,110 @@
#define LLVM_LIBC_SRC___SUPPORT_FREELIST_H
#include "block.h"
+#include "hdr/stdint_proxy.h"
+#include "src/__support/CPP/bit.h"
+#include "src/__support/libc_assert.h"
+#include "src/__support/macros/config.h"
+
+#ifndef LIBC_COPT_HARDEN_FREELIST
+#define LIBC_COPT_HARDEN_FREELIST false
+#endif
+
+#if LIBC_COPT_HARDEN_FREELIST
+#define LIBC_HARDENING_ASSERT(cond) \
+ do { \
+ if (LIBC_UNLIKELY(!(cond))) { \
+ __builtin_trap(); \
+ } \
+ } while (0)
+#else
+#define LIBC_HARDENING_ASSERT(cond) LIBC_ASSERT(cond)
+#endif
namespace LIBC_NAMESPACE_DECL {
+/// Secrets used to encrypt and verify forward and backward pointers in free
+/// lists when hardening is enabled.
+///
+/// When hardening is enabled (LIBC_COPT_HARDEN_FREELIST), we use XOR and
+/// bit-rotation encoding to protect the forward (`next`) and backward (`prev`)
+/// pointers in free list nodes. This encoding mechanism protects heap integrity
+/// against memory corruption and software bugs.
+///
+/// Threat Model and Security Guarantees:
+/// To effectively protect against intentional attackers who might attempt to
+/// infer the secret keys from memory, this hardening mechanism relies on the
+/// following assumptions:
+///
+/// - Header Separation: We assume that the allocator metadata (the heap header
+/// and secret keys) is isolated from dynamic data memory. This ensures that a
+/// linear buffer overflow read cannot easily dump the secret keys from
+/// adjacent memory.
+///
+/// - Allocation Randomness: We assume that allocation and deallocation patterns
+/// have sufficient randomness or diversity such that an attacker cannot
+/// reliably predict the exact memory layout of free list nodes. If an
+/// attacker could reliably guess node addresses and read forward/backward
+/// pointers via local overflow reads, they could XOR known addresses against
+/// encoded pointers to derive the secret keys.
+struct FreeListSecrets {
+ static constexpr int NODE_PTR_ROTATE_DISTANCE = 17;
+
+#if LIBC_COPT_HARDEN_FREELIST
+ uintptr_t k0;
+ uintptr_t k1;
+ uintptr_t k2;
+
+ LIBC_INLINE constexpr FreeListSecrets(uintptr_t k0, uintptr_t k1,
+ uintptr_t k2)
+ : k0(k0), k1(k1), k2(k2) {}
+ LIBC_INLINE constexpr FreeListSecrets() : k0(0), k1(0), k2(0) {}
----------------
mysterymath wrote:
It seems fraught with peril to have a "secrets" constructor that puts in zeros. Def think this shouldn't exist; if you want all zeros, you should have to say that.
https://github.com/llvm/llvm-project/pull/205382
More information about the libc-commits
mailing list