https://github.com/ahmedbougacha updated https://github.com/llvm/llvm-project/pull/93902
>From bf413d68cff5ad963c43bb584590908bf03bc3ce Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha <ah...@bougacha.org> Date: Tue, 4 Jun 2024 12:36:33 -0700 Subject: [PATCH] [Support] Add SipHash-based 16-bit ptrauth stable hash. This finally wraps the now-lightly-modified SipHash C reference implementation, for the main interface we need (16-bit ptrauth discriminators). This intentionally doesn't expose a raw interface beyond that to encourage others to carefully consider their use. 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 <rjmcc...@apple.com> --- llvm/include/llvm/Support/SipHash.h | 39 ++++++++++++++++++++++++++ llvm/lib/Support/SipHash.cpp | 35 +++++++++++++++++++++++ llvm/unittests/Support/CMakeLists.txt | 1 + llvm/unittests/Support/SipHashTest.cpp | 33 ++++++++++++++++++++++ 4 files changed, 108 insertions(+) create mode 100644 llvm/include/llvm/Support/SipHash.h create mode 100644 llvm/unittests/Support/SipHashTest.cpp diff --git a/llvm/include/llvm/Support/SipHash.h b/llvm/include/llvm/Support/SipHash.h new file mode 100644 index 0000000000000..91447b2344eeb --- /dev/null +++ b/llvm/include/llvm/Support/SipHash.h @@ -0,0 +1,39 @@ +//===--- SipHash.h - An ABI-stable string SipHash ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// A family of ABI-stable string hash algorithms based on SipHash, currently +// used to compute ptrauth discriminators. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_SIPHASH_H +#define LLVM_SUPPORT_SIPHASH_H + +#include <cstdint> + +namespace llvm { +class StringRef; + +/// 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 different 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 ef882ae4d8745..b1b4bede7637d 100644 --- a/llvm/lib/Support/SipHash.cpp +++ b/llvm/lib/Support/SipHash.cpp @@ -5,10 +5,23 @@ // 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/StringExtras.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Debug.h" #include <cstdint> +using namespace llvm; + +#define DEBUG_TYPE "llvm-siphash" + // Lightly adapted from the SipHash reference C implementation by // Jean-Philippe Aumasson and Daniel J. Bernstein. @@ -133,3 +146,25 @@ static inline ResultTy siphash(const unsigned char *in, uint64_t inlen, return firstHalf | (ResultTy(secondHalf) << (sizeof(ResultTy) == 8 ? 0 : 64)); } + +//===--- LLVM-specific wrapper around siphash. + +/// 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}; + + // The aliasing is fine here because of omnipotent char. + const auto *Data = reinterpret_cast<const uint8_t *>(Str.data()); + uint64_t RawHash = siphash<2, 4, uint64_t>(Data, Str.size(), K); + + // 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/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt index 2718be8450f80..631f2e6bf00df 100644 --- a/llvm/unittests/Support/CMakeLists.txt +++ b/llvm/unittests/Support/CMakeLists.txt @@ -75,6 +75,7 @@ add_llvm_unittest(SupportTests ScopedPrinterTest.cpp SHA256.cpp SignalsTest.cpp + SipHashTest.cpp SourceMgrTest.cpp SpecialCaseListTest.cpp SuffixTreeTest.cpp diff --git a/llvm/unittests/Support/SipHashTest.cpp b/llvm/unittests/Support/SipHashTest.cpp new file mode 100644 index 0000000000000..49e4e003f637e --- /dev/null +++ b/llvm/unittests/Support/SipHashTest.cpp @@ -0,0 +1,33 @@ +//===- llvm/unittest/Support/SipHashTest.cpp ------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/SipHash.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +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 differ from naive truncations from 64-bit hashes. + EXPECT_EQ(1, getPointerAuthStableSipHash("_Zptrkvttf")); + EXPECT_EQ(0xFFFF, getPointerAuthStableSipHash("_Zaflhllod")); +} + +} // end anonymous namespace _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits