linux-perf-users.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Namhyung Kim <namhyung@kernel.org>
To: Eric Biggers <ebiggers@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>,
	Ingo Molnar <mingo@redhat.com>,
	Arnaldo Carvalho de Melo <acme@kernel.org>,
	linux-perf-users@vger.kernel.org,
	Mark Rutland <mark.rutland@arm.com>,
	Alexander Shishkin <alexander.shishkin@linux.intel.com>,
	Jiri Olsa <jolsa@kernel.org>, Ian Rogers <irogers@google.com>,
	Adrian Hunter <adrian.hunter@intel.com>,
	James Clark <james.clark@linaro.org>,
	Fangrui Song <maskray@sourceware.org>,
	Pablo Galindo <pablogsal@gmail.com>,
	"Jason A . Donenfeld" <Jason@zx2c4.com>,
	linux-crypto@vger.kernel.org
Subject: Re: [PATCH] perf genelf: Switch from SHA-1 to BLAKE2s for build ID generation
Date: Fri, 5 Dec 2025 13:23:03 -0800	[thread overview]
Message-ID: <aTNNN3SjQO4CsT77@google.com> (raw)
In-Reply-To: <20251205043121.62356-1-ebiggers@kernel.org>

Hello,

On Thu, Dec 04, 2025 at 08:31:21PM -0800, Eric Biggers wrote:
> Recent patches [1] [2] added an implementation of SHA-1 to perf and made
> it be used for build ID generation.
> 
> I had understood the choice of SHA-1, which is a legacy algorithm, to be
> for backwards compatibility.
> 
> It turns out, though, that there's no backwards compatibility
> requirement here other than the size of the build ID field, which is
> fixed at 20 bytes.  Not only did the hash algorithm already change (from
> MD5 to SHA-1), but the inputs to the hash changed too: from
> 'load_addr || code' to just 'code', and now again to
> 'code || symtab || strsym' [3].  Different linkers generate different
> build IDs, with the LLVM linker using BLAKE3 hashes for example [4].
> 
> Therefore, we might as well switch to a more modern algorithm.  Let's go
> with BLAKE2s.  It's faster than SHA-1, isn't cryptographically broken,
> is easier to implement than BLAKE3, and the kernel's implementation in
> lib/crypto/blake2s.c is easily borrowed.  It also natively supports
> variable-length hashes, so it can directly produce the needed 20 bytes.
> 
> Also make the following additional improvements:
> 
> - Provide and use an incremental API, so the three inputs being hashed
>   don't all have to be concatenated into one buffer.
> 
> - Add tag/length prefixes to each of the three inputs, so that different
>   tuples of inputs reliably result in different hashes.

Great!  But I prefer fine-grained patches for the history.  It'd be
awesome if you could split this into 3 pieces - adding BLAKE2s,
converting build-id and remove SHA-1.

Thanks,
Namhyung

> 
> [1] https://lore.kernel.org/linux-perf-users/20250521225307.743726-1-yuzhuo@google.com/
> [2] https://lore.kernel.org/linux-perf-users/20250625202311.23244-1-ebiggers@kernel.org/
> [3] https://lore.kernel.org/linux-perf-users/20251125080748.461014-1-namhyung@kernel.org/
> [4] https://github.com/llvm/llvm-project/commit/d3e5b6f7539b86995aef6e2075c1edb3059385ce
> 
> Signed-off-by: Eric Biggers <ebiggers@kernel.org>
> ---
>  tools/perf/tests/util.c   |  78 ++++++++++++--------
>  tools/perf/util/Build     |   2 +-
>  tools/perf/util/blake2s.c | 151 ++++++++++++++++++++++++++++++++++++++
>  tools/perf/util/blake2s.h |  73 ++++++++++++++++++
>  tools/perf/util/genelf.c  |  58 +++++++--------
>  tools/perf/util/sha1.c    |  97 ------------------------
>  tools/perf/util/sha1.h    |   6 --
>  7 files changed, 302 insertions(+), 163 deletions(-)
>  create mode 100644 tools/perf/util/blake2s.c
>  create mode 100644 tools/perf/util/blake2s.h
>  delete mode 100644 tools/perf/util/sha1.c
>  delete mode 100644 tools/perf/util/sha1.h
> 
> diff --git a/tools/perf/tests/util.c b/tools/perf/tests/util.c
> index b273d287e164..695e061f0fa7 100644
> --- a/tools/perf/tests/util.c
> +++ b/tools/perf/tests/util.c
> @@ -1,9 +1,9 @@
>  // SPDX-License-Identifier: GPL-2.0
>  #include "tests.h"
> +#include "util/blake2s.h"
>  #include "util/debug.h"
> -#include "util/sha1.h"
>  
>  #include <linux/compiler.h>
>  #include <stdlib.h>
>  #include <string2.h>
>  
> @@ -15,49 +15,69 @@ static int test_strreplace(char needle, const char *haystack,
>  
>  	free(new);
>  	return ret == 0;
>  }
>  
> -#define MAX_LEN 512
> +#define MAX_DATA_LEN 512 /* Maximum tested data length */
> +#define HASH_LEN 20 /* Hash length to test */
>  
> -/* Test sha1() for all lengths from 0 to MAX_LEN inclusively. */
> -static int test_sha1(void)
> +/* Test the implementation of the BLAKE2s hash algorithm. */
> +static int test_blake2s(void)
>  {
> -	u8 data[MAX_LEN];
> -	size_t digests_size = (MAX_LEN + 1) * SHA1_DIGEST_SIZE;
> -	u8 *digests;
> -	u8 digest_of_digests[SHA1_DIGEST_SIZE];
> +	u8 data[MAX_DATA_LEN];
> +	u8 hash[HASH_LEN];
> +	u8 hash2[HASH_LEN];
> +	struct blake2s_ctx main_ctx;
>  	/*
> -	 * The correctness of this value was verified by running this test with
> -	 * sha1() replaced by OpenSSL's SHA1().
> +	 * This value was generated by the following Python code:
> +	 *
> +	 * import hashlib
> +	 *
> +	 * data = bytes(i % 256 for i in range(513))
> +	 * h = hashlib.blake2s(digest_size=20)
> +	 * for i in range(513):
> +	 *     h.update(hashlib.blake2s(data=data[:i], digest_size=20).digest())
> +	 * print(h.hexdigest())
>  	 */
> -	static const u8 expected_digest_of_digests[SHA1_DIGEST_SIZE] = {
> -		0x74, 0xcd, 0x4c, 0xb9, 0xd8, 0xa6, 0xd5, 0x95, 0x22, 0x8b,
> -		0x7e, 0xd6, 0x8b, 0x7e, 0x46, 0x95, 0x31, 0x9b, 0xa2, 0x43,
> +	static const u8 expected_hash_of_hashes[20] = {
> +		0xef, 0x9b, 0x13, 0x98, 0x78, 0x8e, 0x74, 0x59, 0x9c, 0xd5,
> +		0x0c, 0xf0, 0x33, 0x97, 0x79, 0x3d, 0x3e, 0xd0, 0x95, 0xa6
>  	};
>  	size_t i;
>  
> -	digests = malloc(digests_size);
> -	TEST_ASSERT_VAL("failed to allocate digests", digests != NULL);
> -
> -	/* Generate MAX_LEN bytes of data. */
> -	for (i = 0; i < MAX_LEN; i++)
> +	/* Generate MAX_DATA_LEN bytes of data. */
> +	for (i = 0; i < MAX_DATA_LEN; i++)
>  		data[i] = i;
>  
> -	/* Calculate a SHA-1 for each length 0 through MAX_LEN inclusively. */
> -	for (i = 0; i <= MAX_LEN; i++)
> -		sha1(data, i, &digests[i * SHA1_DIGEST_SIZE]);
> +	blake2s_init(&main_ctx, sizeof(hash));
> +	for (i = 0; i <= MAX_DATA_LEN; i++) {
> +		struct blake2s_ctx ctx;
> +
> +		/* Compute the BLAKE2s hash of 'i' data bytes. */
> +		blake2s_init(&ctx, HASH_LEN);
> +		blake2s_update(&ctx, data, i);
> +		blake2s_final(&ctx, hash);
>  
> -	/* Calculate digest of all digests calculated above. */
> -	sha1(digests, digests_size, digest_of_digests);
> +		/* Verify that multiple updates produce the same result. */
> +		blake2s_init(&ctx, HASH_LEN);
> +		blake2s_update(&ctx, data, i / 2);
> +		blake2s_update(&ctx, &data[i / 2], i - (i / 2));
> +		blake2s_final(&ctx, hash2);
> +		TEST_ASSERT_VAL("inconsistent BLAKE2s hashes",
> +				memcmp(hash, hash2, HASH_LEN) == 0);
>  
> -	free(digests);
> +		/*
> +		 * Pass the hash to another BLAKE2s context, so that we
> +		 * incrementally compute the hash of all the hashes.
> +		 */
> +		blake2s_update(&main_ctx, hash, HASH_LEN);
> +	}
>  
> -	/* Check for the expected result. */
> -	TEST_ASSERT_VAL("wrong output from sha1()",
> -			memcmp(digest_of_digests, expected_digest_of_digests,
> -			       SHA1_DIGEST_SIZE) == 0);
> +	/* Verify the hash of all the hashes. */
> +	blake2s_final(&main_ctx, hash);
> +	TEST_ASSERT_VAL("wrong BLAKE2s hashes",
> +			memcmp(hash, expected_hash_of_hashes, HASH_LEN) == 0);
>  	return 0;
>  }
>  
>  static int test__util(struct test_suite *t __maybe_unused, int subtest __maybe_unused)
>  {
> @@ -66,9 +86,9 @@ static int test__util(struct test_suite *t __maybe_unused, int subtest __maybe_u
>  	TEST_ASSERT_VAL("replace 1", test_strreplace('3', "123", "4", "124"));
>  	TEST_ASSERT_VAL("replace 2", test_strreplace('a', "abcabc", "ef", "efbcefbc"));
>  	TEST_ASSERT_VAL("replace long", test_strreplace('a', "abcabc", "longlong",
>  							"longlongbclonglongbc"));
>  
> -	return test_sha1();
> +	return test_blake2s();
>  }
>  
>  DEFINE_SUITE("util", util);
> diff --git a/tools/perf/util/Build b/tools/perf/util/Build
> index 1c2a43e1dc68..2a9f3d015c1d 100644
> --- a/tools/perf/util/Build
> +++ b/tools/perf/util/Build
> @@ -3,10 +3,11 @@ include $(srctree)/tools/scripts/utilities.mak
>  
>  perf-util-y += arm64-frame-pointer-unwind-support.o
>  perf-util-y += addr2line.o
>  perf-util-y += addr_location.o
>  perf-util-y += annotate.o
> +perf-util-y += blake2s.o
>  perf-util-y += block-info.o
>  perf-util-y += block-range.o
>  perf-util-y += build-id.o
>  perf-util-y += cacheline.o
>  perf-util-y += capstone.o
> @@ -41,11 +42,10 @@ perf-util-y += rlimit.o
>  perf-util-y += argv_split.o
>  perf-util-y += rbtree.o
>  perf-util-y += libstring.o
>  perf-util-y += bitmap.o
>  perf-util-y += hweight.o
> -perf-util-y += sha1.o
>  perf-util-y += smt.o
>  perf-util-y += strbuf.o
>  perf-util-y += string.o
>  perf-util-y += strlist.o
>  perf-util-y += strfilter.o
> diff --git a/tools/perf/util/blake2s.c b/tools/perf/util/blake2s.c
> new file mode 100644
> index 000000000000..ce5d89a19376
> --- /dev/null
> +++ b/tools/perf/util/blake2s.c
> @@ -0,0 +1,151 @@
> +// SPDX-License-Identifier: GPL-2.0 OR MIT
> +/*
> + * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
> + *
> + * This is an implementation of the BLAKE2s hash and PRF functions.
> + *
> + * Information: https://blake2.net/
> + */
> +
> +#include "blake2s.h"
> +#include <linux/kernel.h>
> +
> +static inline u32 ror32(u32 v, int n)
> +{
> +	return (v >> n) | (v << (32 - n));
> +}
> +
> +static inline void le32_to_cpu_array(u32 a[], size_t n)
> +{
> +	for (size_t i = 0; i < n; i++)
> +		a[i] = le32_to_cpu((__force __le32)a[i]);
> +}
> +
> +static inline void cpu_to_le32_array(u32 a[], size_t n)
> +{
> +	for (size_t i = 0; i < n; i++)
> +		a[i] = (__force u32)cpu_to_le32(a[i]);
> +}
> +
> +static const u8 blake2s_sigma[10][16] = {
> +	{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
> +	{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
> +	{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
> +	{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
> +	{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
> +	{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
> +	{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
> +	{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
> +	{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
> +	{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
> +};
> +
> +static inline void blake2s_increment_counter(struct blake2s_ctx *ctx, u32 inc)
> +{
> +	ctx->t[0] += inc;
> +	ctx->t[1] += (ctx->t[0] < inc);
> +}
> +
> +static void blake2s_compress(struct blake2s_ctx *ctx,
> +			     const u8 *data, size_t nblocks, u32 inc)
> +{
> +	u32 m[16];
> +	u32 v[16];
> +	int i;
> +
> +	while (nblocks > 0) {
> +		blake2s_increment_counter(ctx, inc);
> +		memcpy(m, data, BLAKE2S_BLOCK_SIZE);
> +		le32_to_cpu_array(m, ARRAY_SIZE(m));
> +		memcpy(v, ctx->h, 32);
> +		v[ 8] = BLAKE2S_IV0;
> +		v[ 9] = BLAKE2S_IV1;
> +		v[10] = BLAKE2S_IV2;
> +		v[11] = BLAKE2S_IV3;
> +		v[12] = BLAKE2S_IV4 ^ ctx->t[0];
> +		v[13] = BLAKE2S_IV5 ^ ctx->t[1];
> +		v[14] = BLAKE2S_IV6 ^ ctx->f[0];
> +		v[15] = BLAKE2S_IV7 ^ ctx->f[1];
> +
> +#define G(r, i, a, b, c, d) do { \
> +	a += b + m[blake2s_sigma[r][2 * i + 0]]; \
> +	d = ror32(d ^ a, 16); \
> +	c += d; \
> +	b = ror32(b ^ c, 12); \
> +	a += b + m[blake2s_sigma[r][2 * i + 1]]; \
> +	d = ror32(d ^ a, 8); \
> +	c += d; \
> +	b = ror32(b ^ c, 7); \
> +} while (0)
> +
> +#define ROUND(r) do { \
> +	G(r, 0, v[0], v[ 4], v[ 8], v[12]); \
> +	G(r, 1, v[1], v[ 5], v[ 9], v[13]); \
> +	G(r, 2, v[2], v[ 6], v[10], v[14]); \
> +	G(r, 3, v[3], v[ 7], v[11], v[15]); \
> +	G(r, 4, v[0], v[ 5], v[10], v[15]); \
> +	G(r, 5, v[1], v[ 6], v[11], v[12]); \
> +	G(r, 6, v[2], v[ 7], v[ 8], v[13]); \
> +	G(r, 7, v[3], v[ 4], v[ 9], v[14]); \
> +} while (0)
> +		ROUND(0);
> +		ROUND(1);
> +		ROUND(2);
> +		ROUND(3);
> +		ROUND(4);
> +		ROUND(5);
> +		ROUND(6);
> +		ROUND(7);
> +		ROUND(8);
> +		ROUND(9);
> +
> +#undef G
> +#undef ROUND
> +
> +		for (i = 0; i < 8; ++i)
> +			ctx->h[i] ^= v[i] ^ v[i + 8];
> +
> +		data += BLAKE2S_BLOCK_SIZE;
> +		--nblocks;
> +	}
> +}
> +
> +static inline void blake2s_set_lastblock(struct blake2s_ctx *ctx)
> +{
> +	ctx->f[0] = -1;
> +}
> +
> +void blake2s_update(struct blake2s_ctx *ctx, const u8 *in, size_t inlen)
> +{
> +	const size_t fill = BLAKE2S_BLOCK_SIZE - ctx->buflen;
> +
> +	if (unlikely(!inlen))
> +		return;
> +	if (inlen > fill) {
> +		memcpy(ctx->buf + ctx->buflen, in, fill);
> +		blake2s_compress(ctx, ctx->buf, 1, BLAKE2S_BLOCK_SIZE);
> +		ctx->buflen = 0;
> +		in += fill;
> +		inlen -= fill;
> +	}
> +	if (inlen > BLAKE2S_BLOCK_SIZE) {
> +		const size_t nblocks = DIV_ROUND_UP(inlen, BLAKE2S_BLOCK_SIZE);
> +
> +		blake2s_compress(ctx, in, nblocks - 1, BLAKE2S_BLOCK_SIZE);
> +		in += BLAKE2S_BLOCK_SIZE * (nblocks - 1);
> +		inlen -= BLAKE2S_BLOCK_SIZE * (nblocks - 1);
> +	}
> +	memcpy(ctx->buf + ctx->buflen, in, inlen);
> +	ctx->buflen += inlen;
> +}
> +
> +void blake2s_final(struct blake2s_ctx *ctx, u8 *out)
> +{
> +	blake2s_set_lastblock(ctx);
> +	memset(ctx->buf + ctx->buflen, 0,
> +	       BLAKE2S_BLOCK_SIZE - ctx->buflen); /* Padding */
> +	blake2s_compress(ctx, ctx->buf, 1, ctx->buflen);
> +	cpu_to_le32_array(ctx->h, ARRAY_SIZE(ctx->h));
> +	memcpy(out, ctx->h, ctx->outlen);
> +	memset(ctx, 0, sizeof(*ctx));
> +}
> diff --git a/tools/perf/util/blake2s.h b/tools/perf/util/blake2s.h
> new file mode 100644
> index 000000000000..a1fe81a4bea8
> --- /dev/null
> +++ b/tools/perf/util/blake2s.h
> @@ -0,0 +1,73 @@
> +/* SPDX-License-Identifier: GPL-2.0 OR MIT */
> +/*
> + * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
> + */
> +
> +#ifndef _CRYPTO_BLAKE2S_H
> +#define _CRYPTO_BLAKE2S_H
> +
> +#include <string.h>
> +#include <linux/types.h>
> +
> +#define BLAKE2S_BLOCK_SIZE 64
> +
> +struct blake2s_ctx {
> +	u32 h[8];
> +	u32 t[2];
> +	u32 f[2];
> +	u8 buf[BLAKE2S_BLOCK_SIZE];
> +	unsigned int buflen;
> +	unsigned int outlen;
> +};
> +
> +enum blake2s_iv {
> +	BLAKE2S_IV0 = 0x6A09E667UL,
> +	BLAKE2S_IV1 = 0xBB67AE85UL,
> +	BLAKE2S_IV2 = 0x3C6EF372UL,
> +	BLAKE2S_IV3 = 0xA54FF53AUL,
> +	BLAKE2S_IV4 = 0x510E527FUL,
> +	BLAKE2S_IV5 = 0x9B05688CUL,
> +	BLAKE2S_IV6 = 0x1F83D9ABUL,
> +	BLAKE2S_IV7 = 0x5BE0CD19UL,
> +};
> +
> +static inline void __blake2s_init(struct blake2s_ctx *ctx, size_t outlen,
> +				  const void *key, size_t keylen)
> +{
> +	ctx->h[0] = BLAKE2S_IV0 ^ (0x01010000 | keylen << 8 | outlen);
> +	ctx->h[1] = BLAKE2S_IV1;
> +	ctx->h[2] = BLAKE2S_IV2;
> +	ctx->h[3] = BLAKE2S_IV3;
> +	ctx->h[4] = BLAKE2S_IV4;
> +	ctx->h[5] = BLAKE2S_IV5;
> +	ctx->h[6] = BLAKE2S_IV6;
> +	ctx->h[7] = BLAKE2S_IV7;
> +	ctx->t[0] = 0;
> +	ctx->t[1] = 0;
> +	ctx->f[0] = 0;
> +	ctx->f[1] = 0;
> +	ctx->buflen = 0;
> +	ctx->outlen = outlen;
> +	if (keylen) {
> +		memcpy(ctx->buf, key, keylen);
> +		memset(&ctx->buf[keylen], 0, BLAKE2S_BLOCK_SIZE - keylen);
> +		ctx->buflen = BLAKE2S_BLOCK_SIZE;
> +	}
> +}
> +
> +static inline void blake2s_init(struct blake2s_ctx *ctx, size_t outlen)
> +{
> +	__blake2s_init(ctx, outlen, NULL, 0);
> +}
> +
> +static inline void blake2s_init_key(struct blake2s_ctx *ctx, size_t outlen,
> +				    const void *key, size_t keylen)
> +{
> +	__blake2s_init(ctx, outlen, key, keylen);
> +}
> +
> +void blake2s_update(struct blake2s_ctx *ctx, const u8 *in, size_t inlen);
> +
> +void blake2s_final(struct blake2s_ctx *ctx, u8 *out);
> +
> +#endif /* _CRYPTO_BLAKE2S_H */
> diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c
> index a1cd5196f4ec..505fefdc60f3 100644
> --- a/tools/perf/util/genelf.c
> +++ b/tools/perf/util/genelf.c
> @@ -16,12 +16,12 @@
>  #include <err.h>
>  #ifdef HAVE_LIBDW_SUPPORT
>  #include <dwarf.h>
>  #endif
>  
> +#include "blake2s.h"
>  #include "genelf.h"
> -#include "sha1.h"
>  #include "../util/jitdump.h"
>  #include <linux/compiler.h>
>  
>  #ifndef NT_GNU_BUILD_ID
>  #define NT_GNU_BUILD_ID 3
> @@ -49,11 +49,11 @@ static char shd_string_table[] = {
>  };
>  
>  static struct buildid_note {
>  	Elf_Note desc;		/* descsz: size of build-id, must be multiple of 4 */
>  	char	 name[4];	/* GNU\0 */
> -	u8	 build_id[SHA1_DIGEST_SIZE];
> +	u8	 build_id[20];
>  } bnote;
>  
>  static Elf_Sym symtab[]={
>  	/* symbol 0 MUST be the undefined symbol */
>  	{ .st_name  = 0, /* index in sym_string table */
> @@ -150,13 +150,32 @@ jit_add_eh_frame_info(Elf *e, void* unwinding, uint64_t unwinding_header_size,
>  	shdr->sh_entsize = 0;
>  
>  	return 0;
>  }
>  
> +enum {
> +	TAG_CODE = 0,
> +	TAG_SYMTAB = 1,
> +	TAG_STRSYM = 2,
> +};
> +
> +/*
> + * Update the hash using the given data, also prepending a (tag, len) prefix to
> + * ensure that different input tuples result in different outputs.
> + */
> +static void blake2s_update_tagged(struct blake2s_ctx *ctx, int tag,
> +				  const void *data, size_t len)
> +{
> +	u64 prefix = ((u64)tag << 56) | len;
> +
> +	blake2s_update(ctx, (const u8 *)&prefix, sizeof(prefix));
> +	blake2s_update(ctx, data, len);
> +}
> +
>  /*
>   * fd: file descriptor open for writing for the output file
> - * load_addr: code load address (could be zero, just used for buildid)
> + * load_addr: code load address (could be zero)
>   * sym: function name (for native code - used as the symbol)
>   * code: the native code
>   * csize: the code size in bytes
>   */
>  int
> @@ -171,12 +190,11 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym,
>  	Elf_Ehdr *ehdr;
>  	Elf_Phdr *phdr;
>  	Elf_Shdr *shdr;
>  	uint64_t eh_frame_base_offset;
>  	char *strsym = NULL;
> -	void *build_id_data = NULL, *tmp;
> -	int build_id_data_len;
> +	struct blake2s_ctx ctx;
>  	int symlen;
>  	int retval = -1;
>  
>  	if (elf_version(EV_CURRENT) == EV_NONE) {
>  		warnx("ELF initialization failed");
> @@ -251,17 +269,12 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym,
>  	shdr->sh_type = SHT_PROGBITS;
>  	shdr->sh_addr = GEN_ELF_TEXT_OFFSET;
>  	shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC;
>  	shdr->sh_entsize = 0;
>  
> -	build_id_data = malloc(csize);
> -	if (build_id_data == NULL) {
> -		warnx("cannot allocate build-id data");
> -		goto error;
> -	}
> -	memcpy(build_id_data, code, csize);
> -	build_id_data_len = csize;
> +	blake2s_init(&ctx, sizeof(bnote.build_id));
> +	blake2s_update_tagged(&ctx, TAG_CODE, code, csize);
>  
>  	/*
>  	 * Setup .eh_frame_hdr and .eh_frame
>  	 */
>  	if (unwinding) {
> @@ -342,18 +355,11 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym,
>  	shdr->sh_type = SHT_SYMTAB;
>  	shdr->sh_flags = 0;
>  	shdr->sh_entsize = sizeof(Elf_Sym);
>  	shdr->sh_link = unwinding ? 6 : 4; /* index of .strtab section */
>  
> -	tmp = realloc(build_id_data, build_id_data_len + sizeof(symtab));
> -	if (tmp == NULL) {
> -		warnx("cannot allocate build-id data");
> -		goto error;
> -	}
> -	memcpy(tmp + build_id_data_len, symtab, sizeof(symtab));
> -	build_id_data = tmp;
> -	build_id_data_len += sizeof(symtab);
> +	blake2s_update_tagged(&ctx, TAG_SYMTAB, symtab, sizeof(symtab));
>  
>  	/*
>  	 * setup symbols string table
>  	 * 2 = 1 for 0 in 1st entry, 1 for the 0 at end of symbol for 2nd entry
>  	 */
> @@ -393,18 +399,11 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym,
>  	shdr->sh_name = 25; /* offset in shd_string_table */
>  	shdr->sh_type = SHT_STRTAB;
>  	shdr->sh_flags = 0;
>  	shdr->sh_entsize = 0;
>  
> -	tmp = realloc(build_id_data, build_id_data_len + symlen);
> -	if (tmp == NULL) {
> -		warnx("cannot allocate build-id data");
> -		goto error;
> -	}
> -	memcpy(tmp + build_id_data_len, strsym, symlen);
> -	build_id_data = tmp;
> -	build_id_data_len += symlen;
> +	blake2s_update_tagged(&ctx, TAG_STRSYM, strsym, symlen);
>  
>  	/*
>  	 * setup build-id section
>  	 */
>  	scn = elf_newscn(e);
> @@ -420,11 +419,11 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym,
>  	}
>  
>  	/*
>  	 * build-id generation
>  	 */
> -	sha1(build_id_data, build_id_data_len, bnote.build_id);
> +	blake2s_final(&ctx, bnote.build_id);
>  	bnote.desc.namesz = sizeof(bnote.name); /* must include 0 termination */
>  	bnote.desc.descsz = sizeof(bnote.build_id);
>  	bnote.desc.type   = NT_GNU_BUILD_ID;
>  	strcpy(bnote.name, "GNU");
>  
> @@ -465,9 +464,8 @@ jit_write_elf(int fd, uint64_t load_addr __maybe_unused, const char *sym,
>  	retval = 0;
>  error:
>  	(void)elf_end(e);
>  
>  	free(strsym);
> -	free(build_id_data);
>  
>  	return retval;
>  }
> diff --git a/tools/perf/util/sha1.c b/tools/perf/util/sha1.c
> deleted file mode 100644
> index 7032fa4ff3fd..000000000000
> --- a/tools/perf/util/sha1.c
> +++ /dev/null
> @@ -1,97 +0,0 @@
> -// SPDX-License-Identifier: GPL-2.0-only
> -/*
> - * SHA-1 message digest algorithm
> - *
> - * Copyright 2025 Google LLC
> - */
> -#include <linux/bitops.h>
> -#include <linux/kernel.h>
> -#include <linux/unaligned.h>
> -#include <string.h>
> -
> -#include "sha1.h"
> -
> -#define SHA1_BLOCK_SIZE 64
> -
> -static const u32 sha1_K[4] = { 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 };
> -
> -#define SHA1_ROUND(i, a, b, c, d, e)                                          \
> -	do {                                                                  \
> -		if ((i) >= 16)                                                \
> -			w[i] = rol32(w[(i) - 16] ^ w[(i) - 14] ^ w[(i) - 8] ^ \
> -					     w[(i) - 3],                      \
> -				     1);                                      \
> -		e += w[i] + rol32(a, 5) + sha1_K[(i) / 20];                   \
> -		if ((i) < 20)                                                 \
> -			e += (b & (c ^ d)) ^ d;                               \
> -		else if ((i) < 40 || (i) >= 60)                               \
> -			e += b ^ c ^ d;                                       \
> -		else                                                          \
> -			e += (c & d) ^ (b & (c ^ d));                         \
> -		b = rol32(b, 30);                                             \
> -		/* The new (a, b, c, d, e) is the old (e, a, b, c, d). */     \
> -	} while (0)
> -
> -#define SHA1_5ROUNDS(i)                             \
> -	do {                                        \
> -		SHA1_ROUND((i) + 0, a, b, c, d, e); \
> -		SHA1_ROUND((i) + 1, e, a, b, c, d); \
> -		SHA1_ROUND((i) + 2, d, e, a, b, c); \
> -		SHA1_ROUND((i) + 3, c, d, e, a, b); \
> -		SHA1_ROUND((i) + 4, b, c, d, e, a); \
> -	} while (0)
> -
> -#define SHA1_20ROUNDS(i)                \
> -	do {                            \
> -		SHA1_5ROUNDS((i) + 0);  \
> -		SHA1_5ROUNDS((i) + 5);  \
> -		SHA1_5ROUNDS((i) + 10); \
> -		SHA1_5ROUNDS((i) + 15); \
> -	} while (0)
> -
> -static void sha1_blocks(u32 h[5], const u8 *data, size_t nblocks)
> -{
> -	while (nblocks--) {
> -		u32 a = h[0];
> -		u32 b = h[1];
> -		u32 c = h[2];
> -		u32 d = h[3];
> -		u32 e = h[4];
> -		u32 w[80];
> -
> -		for (int i = 0; i < 16; i++)
> -			w[i] = get_unaligned_be32(&data[i * 4]);
> -		SHA1_20ROUNDS(0);
> -		SHA1_20ROUNDS(20);
> -		SHA1_20ROUNDS(40);
> -		SHA1_20ROUNDS(60);
> -
> -		h[0] += a;
> -		h[1] += b;
> -		h[2] += c;
> -		h[3] += d;
> -		h[4] += e;
> -		data += SHA1_BLOCK_SIZE;
> -	}
> -}
> -
> -/* Calculate the SHA-1 message digest of the given data. */
> -void sha1(const void *data, size_t len, u8 out[SHA1_DIGEST_SIZE])
> -{
> -	u32 h[5] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476,
> -		     0xC3D2E1F0 };
> -	u8 final_data[2 * SHA1_BLOCK_SIZE] = { 0 };
> -	size_t final_len = len % SHA1_BLOCK_SIZE;
> -
> -	sha1_blocks(h, data, len / SHA1_BLOCK_SIZE);
> -
> -	memcpy(final_data, data + len - final_len, final_len);
> -	final_data[final_len] = 0x80;
> -	final_len = round_up(final_len + 9, SHA1_BLOCK_SIZE);
> -	put_unaligned_be64((u64)len * 8, &final_data[final_len - 8]);
> -
> -	sha1_blocks(h, final_data, final_len / SHA1_BLOCK_SIZE);
> -
> -	for (int i = 0; i < 5; i++)
> -		put_unaligned_be32(h[i], &out[i * 4]);
> -}
> diff --git a/tools/perf/util/sha1.h b/tools/perf/util/sha1.h
> deleted file mode 100644
> index e92c9966e1d5..000000000000
> --- a/tools/perf/util/sha1.h
> +++ /dev/null
> @@ -1,6 +0,0 @@
> -/* SPDX-License-Identifier: GPL-2.0-only */
> -#include <linux/types.h>
> -
> -#define SHA1_DIGEST_SIZE 20
> -
> -void sha1(const void *data, size_t len, u8 out[SHA1_DIGEST_SIZE]);
> 
> base-commit: bc04acf4aeca588496124a6cf54bfce3db327039
> -- 
> 2.52.0
> 

      parent reply	other threads:[~2025-12-05 21:23 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-12-05  4:31 [PATCH] perf genelf: Switch from SHA-1 to BLAKE2s for build ID generation Eric Biggers
2025-12-05  4:39 ` Eric Biggers
2025-12-05 18:53 ` Ian Rogers
2025-12-09  1:19   ` Eric Biggers
2025-12-05 21:23 ` Namhyung Kim [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aTNNN3SjQO4CsT77@google.com \
    --to=namhyung@kernel.org \
    --cc=Jason@zx2c4.com \
    --cc=acme@kernel.org \
    --cc=adrian.hunter@intel.com \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=ebiggers@kernel.org \
    --cc=irogers@google.com \
    --cc=james.clark@linaro.org \
    --cc=jolsa@kernel.org \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=maskray@sourceware.org \
    --cc=mingo@redhat.com \
    --cc=pablogsal@gmail.com \
    --cc=peterz@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).