[llvm] 61069bd - [Support] Add SipHash-based 16-bit ptrauth ABI-stable hash. (#93902)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 14 17:57:16 PDT 2024
Author: Ahmed Bougacha
Date: 2024-06-14T17:57:12-07:00
New Revision: 61069bd5a3954076018ed30c77094d6259bcbc90
URL: https://github.com/llvm/llvm-project/commit/61069bd5a3954076018ed30c77094d6259bcbc90
DIFF: https://github.com/llvm/llvm-project/commit/61069bd5a3954076018ed30c77094d6259bcbc90.diff
LOG: [Support] Add SipHash-based 16-bit ptrauth ABI-stable hash. (#93902)
This finally wraps the now-lightly-modified SipHash C reference
implementation, for the main interface we need (16-bit ptrauth
discriminators).
The exact algorithm is the little-endian interpretation of the
non-doubled (i.e. 64-bit) result of applying a SipHash-2-4 using the
constant seed `b5d4c9eb79104a796fec8b1b428781d4` (big-endian), with the
result reduced by modulo to the range of non-zero discriminators (i.e.
`(rawHash % 65535) + 1`).
By "stable" we mean that the result of this hash algorithm will the same
across different compiler versions and target platforms.
The 16-bit hashes are used extensively for the AArch64 ptrauth ABI,
because AArch64 can efficiently load a 16-bit immediate into the high
bits of a register without disturbing the remainder of the value, which
serves as a nice blend operation.
16 bits is also sufficiently compact to not inflate a loader relocation.
We disallow zero to guarantee a different discriminator from the places
in the ABI that use a constant zero.
Co-authored-by: John McCall <rjmccall at apple.com>
Added:
Modified:
llvm/include/llvm/Support/SipHash.h
llvm/lib/Support/SipHash.cpp
llvm/unittests/Support/SipHashTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Support/SipHash.h b/llvm/include/llvm/Support/SipHash.h
index 56dea80ef2e6b..ab05ff38769eb 100644
--- a/llvm/include/llvm/Support/SipHash.h
+++ b/llvm/include/llvm/Support/SipHash.h
@@ -9,6 +9,9 @@
// An implementation of SipHash, a hash function optimized for speed on
// short inputs. Based on the SipHash reference implementation.
//
+// Also provides one specific wrapper on top of SipHash-2-4-64 to compute
+// compute ABI-stable ptrauth discriminators.
+//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_SIPHASH_H
@@ -19,6 +22,7 @@
namespace llvm {
template <typename T> class ArrayRef;
+class StringRef;
/// Computes a SipHash-2-4 64-bit result.
void getSipHash_2_4_64(ArrayRef<uint8_t> In, const uint8_t (&K)[16],
@@ -28,6 +32,21 @@ void getSipHash_2_4_64(ArrayRef<uint8_t> In, const uint8_t (&K)[16],
void getSipHash_2_4_128(ArrayRef<uint8_t> In, const uint8_t (&K)[16],
uint8_t (&Out)[16]);
+/// Compute a stable non-zero 16-bit hash of the given string.
+///
+/// The exact algorithm is the little-endian interpretation of the
+/// non-doubled (i.e. 64-bit) result of applying a SipHash-2-4 using
+/// a specific seed value which can be found in the source.
+/// This 64-bit result is truncated to a non-zero 16-bit value.
+///
+/// We use a 16-bit discriminator because ARM64 can efficiently load
+/// a 16-bit immediate into the high bits of a register without disturbing
+/// the remainder of the value, which serves as a nice blend operation.
+/// 16 bits is also sufficiently compact to not inflate a loader relocation.
+/// We disallow zero to guarantee a
diff erent discriminator from the places
+/// in the ABI that use a constant zero.
+uint16_t getPointerAuthStableSipHash(StringRef S);
+
} // end namespace llvm
#endif
diff --git a/llvm/lib/Support/SipHash.cpp b/llvm/lib/Support/SipHash.cpp
index ed1a305f0443f..68545913a4f59 100644
--- a/llvm/lib/Support/SipHash.cpp
+++ b/llvm/lib/Support/SipHash.cpp
@@ -5,16 +5,26 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+//
+// This file implements an ABI-stable string hash based on SipHash, used to
+// compute ptrauth discriminators.
+//
+//===----------------------------------------------------------------------===//
#include "llvm/Support/SipHash.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
#include "llvm/Support/Endian.h"
#include <cstdint>
using namespace llvm;
using namespace support;
+#define DEBUG_TYPE "llvm-siphash"
+
// Lightly adapted from the SipHash reference C implementation:
// https://github.com/veorq/SipHash
// by Jean-Philippe Aumasson and Daniel J. Bernstein
@@ -153,3 +163,23 @@ void llvm::getSipHash_2_4_128(ArrayRef<uint8_t> In, const uint8_t (&K)[16],
uint8_t (&Out)[16]) {
siphash<2, 4>(In.data(), In.size(), K, Out);
}
+
+/// Compute an ABI-stable 16-bit hash of the given string.
+uint16_t llvm::getPointerAuthStableSipHash(StringRef Str) {
+ static const uint8_t K[16] = {0xb5, 0xd4, 0xc9, 0xeb, 0x79, 0x10, 0x4a, 0x79,
+ 0x6f, 0xec, 0x8b, 0x1b, 0x42, 0x87, 0x81, 0xd4};
+
+ uint8_t RawHashBytes[8];
+ getSipHash_2_4_64(arrayRefFromStringRef(Str), K, RawHashBytes);
+ uint64_t RawHash = endian::read64le(RawHashBytes);
+
+ // Produce a non-zero 16-bit discriminator.
+ uint16_t Discriminator = (RawHash % 0xFFFF) + 1;
+ LLVM_DEBUG(
+ dbgs() << "ptrauth stable hash discriminator: " << utostr(Discriminator)
+ << " (0x"
+ << utohexstr(Discriminator, /*Lowercase=*/false, /*Width=*/4)
+ << ")"
+ << " of: " << Str << "\n");
+ return Discriminator;
+}
diff --git a/llvm/unittests/Support/SipHashTest.cpp b/llvm/unittests/Support/SipHashTest.cpp
index bd05c278fc7a2..7c557eb488acc 100644
--- a/llvm/unittests/Support/SipHashTest.cpp
+++ b/llvm/unittests/Support/SipHashTest.cpp
@@ -50,7 +50,25 @@ TEST(SipHashTest, SipHash_2_4_128) {
}
}
-// Below are the unmodified expected outputs from vectors.h
+// Tests for the ptrauth-specific SipHash wrapper.
+TEST(SipHashTest, PointerAuthSipHash) {
+ // Test some basic cases.
+ EXPECT_EQ(0xE793, getPointerAuthStableSipHash(""));
+ EXPECT_EQ(0xF468, getPointerAuthStableSipHash("strlen"));
+ EXPECT_EQ(0x2D15, getPointerAuthStableSipHash("_ZN1 ind; f"));
+
+ // Test some known strings that are already enshrined in the ABI.
+ EXPECT_EQ(0x6AE1, getPointerAuthStableSipHash("isa"));
+ EXPECT_EQ(0xB5AB, getPointerAuthStableSipHash("objc_class:superclass"));
+ EXPECT_EQ(0xC0BB, getPointerAuthStableSipHash("block_descriptor"));
+ EXPECT_EQ(0xC310, getPointerAuthStableSipHash("method_list_t"));
+
+ // Test limit cases where we
diff er from naive truncations from 64-bit hashes.
+ EXPECT_EQ(1, getPointerAuthStableSipHash("_Zptrkvttf"));
+ EXPECT_EQ(0xFFFF, getPointerAuthStableSipHash("_Zaflhllod"));
+}
+
+// Below are the unmodified expected outputs from the reference vectors.h.
const uint8_t ExpectedSipHash64[64][8] = {
{
More information about the llvm-commits
mailing list