From 17b296a11839ac63279b89e40cecb4c114c229b2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 7 Dec 2022 18:32:38 +0100 Subject: [PATCH 1/5] sha256: external headers should be included with <> --- src/fundamental/sha256.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fundamental/sha256.h b/src/fundamental/sha256.h index 31790c2ebd..7c29c785cb 100644 --- a/src/fundamental/sha256.h +++ b/src/fundamental/sha256.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include "stdint.h" +#include #define SHA256_DIGEST_SIZE 32 From d8007e7aacdadc57d2fd9ee3f80f620be781248e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 7 Dec 2022 18:10:42 +0100 Subject: [PATCH 2/5] fundamental: split out unaligned_{read|write}_ne{16,32,64}() helpers into unaligned-fundamental.h Let's allow using this in code shared between userspace and EFI mode. Also, don't implement these functions via endianness conversions given we don't actually want to convert endianess here. --- src/basic/unaligned.h | 20 ++----------- src/fundamental/unaligned-fundamental.h | 40 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 18 deletions(-) create mode 100644 src/fundamental/unaligned-fundamental.h diff --git a/src/basic/unaligned.h b/src/basic/unaligned.h index 4100be0803..04580cfb63 100644 --- a/src/basic/unaligned.h +++ b/src/basic/unaligned.h @@ -4,6 +4,8 @@ #include #include +#include "unaligned-fundamental.h" + /* BE */ static inline uint16_t unaligned_read_be16(const void *_u) { @@ -79,21 +81,3 @@ static inline void unaligned_write_le64(void *_u, uint64_t a) { u->x = le64toh(a); } - -#if __BYTE_ORDER == __BIG_ENDIAN -#define unaligned_read_ne16 unaligned_read_be16 -#define unaligned_read_ne32 unaligned_read_be32 -#define unaligned_read_ne64 unaligned_read_be64 - -#define unaligned_write_ne16 unaligned_write_be16 -#define unaligned_write_ne32 unaligned_write_be32 -#define unaligned_write_ne64 unaligned_write_be64 -#else -#define unaligned_read_ne16 unaligned_read_le16 -#define unaligned_read_ne32 unaligned_read_le32 -#define unaligned_read_ne64 unaligned_read_le64 - -#define unaligned_write_ne16 unaligned_write_le16 -#define unaligned_write_ne32 unaligned_write_le32 -#define unaligned_write_ne64 unaligned_write_le64 -#endif diff --git a/src/fundamental/unaligned-fundamental.h b/src/fundamental/unaligned-fundamental.h new file mode 100644 index 0000000000..a4c810a5fc --- /dev/null +++ b/src/fundamental/unaligned-fundamental.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +static inline uint16_t unaligned_read_ne16(const void *_u) { + const struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u; + + return u->x; +} + +static inline uint32_t unaligned_read_ne32(const void *_u) { + const struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u; + + return u->x; +} + +static inline uint64_t unaligned_read_ne64(const void *_u) { + const struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u; + + return u->x; +} + +static inline void unaligned_write_ne16(void *_u, uint16_t a) { + struct __attribute__((__packed__, __may_alias__)) { uint16_t x; } *u = _u; + + u->x = a; +} + +static inline void unaligned_write_ne32(void *_u, uint32_t a) { + struct __attribute__((__packed__, __may_alias__)) { uint32_t x; } *u = _u; + + u->x = a; +} + +static inline void unaligned_write_ne64(void *_u, uint64_t a) { + struct __attribute__((__packed__, __may_alias__)) { uint64_t x; } *u = _u; + + u->x = a; +} From 22e339761be66ae5b7c92b27b4e2b59074ebfbb1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 7 Dec 2022 18:13:12 +0100 Subject: [PATCH 3/5] sha256: move to unaligned_write_ne32() --- src/fundamental/sha256.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/fundamental/sha256.c b/src/fundamental/sha256.c index 9b717645b3..fcbf531bd2 100644 --- a/src/fundamental/sha256.c +++ b/src/fundamental/sha256.c @@ -30,6 +30,7 @@ #include "macro-fundamental.h" #include "sha256.h" +#include "unaligned-fundamental.h" #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ # define SWAP(n) \ @@ -128,11 +129,7 @@ uint8_t *sha256_finish_ctx(struct sha256_ctx *ctx, uint8_t resbuf[static SHA256_ /* Put result from CTX in first 32 bytes following RESBUF. */ for (size_t i = 0; i < 8; ++i) - if (UNALIGNED_P(resbuf)) - memcpy(resbuf + i * sizeof(uint32_t), (uint32_t[]) { SWAP(ctx->H[i]) }, sizeof(uint32_t)); - else - ((uint32_t *) resbuf)[i] = SWAP(ctx->H[i]); - + unaligned_write_ne32(resbuf + i * sizeof(uint32_t), SWAP(ctx->H[i])); return resbuf; } From 4f07388360a3513b9fc8d2773568b8def941f4a4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 7 Dec 2022 18:31:27 +0100 Subject: [PATCH 4/5] macro: add generic IS_ALIGNED32() anf friends Let's generalize (and invert) the UNALIGNED32_P() macro from the sha256 code, and let's add a test for it. --- src/fundamental/macro-fundamental.h | 9 +++++ src/test/test-macro.c | 53 +++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h index c11a5b15f4..65c9e042cd 100644 --- a/src/fundamental/macro-fundamental.h +++ b/src/fundamental/macro-fundamental.h @@ -327,14 +327,23 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) { return ((l + ali - 1) & ~(ali - 1)); } +#define ALIGN2(l) ALIGN_TO(l, 2) #define ALIGN4(l) ALIGN_TO(l, 4) #define ALIGN8(l) ALIGN_TO(l, 8) +#define ALIGN2_PTR(p) ((void*) ALIGN2((uintptr_t) p)) +#define ALIGN4_PTR(p) ((void*) ALIGN4((uintptr_t) p)) +#define ALIGN8_PTR(p) ((void*) ALIGN8((uintptr_t) p)) #ifndef SD_BOOT /* libefi also provides ALIGN, and we do not use them in sd-boot explicitly. */ #define ALIGN(l) ALIGN_TO(l, sizeof(void*)) #define ALIGN_PTR(p) ((void*) ALIGN((uintptr_t) (p))) #endif +/* Checks if the specified pointer is aligned as appropriate for the specific type */ +#define IS_ALIGNED16(p) (((uintptr_t) p) % __alignof__(uint16_t) == 0) +#define IS_ALIGNED32(p) (((uintptr_t) p) % __alignof__(uint32_t) == 0) +#define IS_ALIGNED64(p) (((uintptr_t) p) % __alignof__(uint64_t) == 0) + /* Same as ALIGN_TO but callable in constant contexts. */ #define CONST_ALIGN_TO(l, ali) \ __builtin_choose_expr( \ diff --git a/src/test/test-macro.c b/src/test/test-macro.c index 001166d0dc..d4f32496b7 100644 --- a/src/test/test-macro.c +++ b/src/test/test-macro.c @@ -531,4 +531,57 @@ TEST(ISPOWEROF2) { assert_se(!ISPOWEROF2(u)); } +TEST(ALIGNED) { + assert_se(IS_ALIGNED16(NULL)); + assert_se(IS_ALIGNED32(NULL)); + assert_se(IS_ALIGNED64(NULL)); + + uint64_t u64; + uint32_t u32; + uint16_t u16; + + assert_se(IS_ALIGNED16(&u16)); + assert_se(IS_ALIGNED16(&u32)); + assert_se(IS_ALIGNED16(&u64)); + assert_se(IS_ALIGNED32(&u32)); + assert_se(IS_ALIGNED32(&u64)); + assert_se(IS_ALIGNED64(&u64)); + + _align_(32) uint8_t ua256; + _align_(8) uint8_t ua64; + _align_(4) uint8_t ua32; + _align_(2) uint8_t ua16; + + assert_se(IS_ALIGNED16(&ua256)); + assert_se(IS_ALIGNED32(&ua256)); + assert_se(IS_ALIGNED64(&ua256)); + + assert_se(IS_ALIGNED16(&ua64)); + assert_se(IS_ALIGNED32(&ua64)); + assert_se(IS_ALIGNED64(&ua64)); + + assert_se(IS_ALIGNED16(&ua32)); + assert_se(IS_ALIGNED32(&ua32)); + + assert_se(IS_ALIGNED16(&ua16)); + +#ifdef __x86_64__ + /* Conditionalized on x86-64, since there we know for sure that all three types are aligned to + * their size. Too lazy to figure it out for other archs */ + void *p = UINT_TO_PTR(1); /* definitely not aligned */ + assert_se(!IS_ALIGNED16(p)); + assert_se(!IS_ALIGNED32(p)); + assert_se(!IS_ALIGNED64(p)); + + assert_se(IS_ALIGNED16(ALIGN2_PTR(p))); + assert_se(IS_ALIGNED32(ALIGN4_PTR(p))); + assert_se(IS_ALIGNED64(ALIGN8_PTR(p))); + + p = UINT_TO_PTR(-1); /* also definitely not aligned */ + assert_se(!IS_ALIGNED16(p)); + assert_se(!IS_ALIGNED32(p)); + assert_se(!IS_ALIGNED64(p)); +#endif +} + DEFINE_TEST_MAIN(LOG_INFO); From a0ccc18e89a9cb04b4177a0f5bbf3bb571397ca6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 7 Dec 2022 18:19:29 +0100 Subject: [PATCH 5/5] sha256: port to new generic IS_ALIGNED32() macro This drops the special casing for s390 and other archs, which was cargo-culted from glibc. Given it's not obvious why it exists, and is at best an optimization let's simply avoid it, in particular as the archs are relatively non-mainstream. Inspired by: #25636 --- src/fundamental/sha256.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/fundamental/sha256.c b/src/fundamental/sha256.c index fcbf531bd2..307f672507 100644 --- a/src/fundamental/sha256.c +++ b/src/fundamental/sha256.c @@ -49,14 +49,6 @@ # define SWAP64(n) (n) #endif -/* The condition below is from glibc's string/string-inline.c. - * See definition of _STRING_INLINE_unaligned. */ -#if !defined(__mc68020__) && !defined(__s390__) && !defined(__i386__) -# define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__(uint32_t) != 0) -#else -# define UNALIGNED_P(p) false -#endif - /* This array contains the bytes used to pad the buffer to the next 64-byte boundary. (FIPS 180-2:5.1.1) */ static const uint8_t fillbuf[64] = { @@ -162,18 +154,17 @@ void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx /* Process available complete blocks. */ if (len >= 64) { - if (UNALIGNED_P(buffer)) + if (IS_ALIGNED32(buffer)) { + sha256_process_block(buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } else while (len > 64) { memcpy(ctx->buffer, buffer, 64); sha256_process_block(ctx->buffer, 64, ctx); buffer = (const char *) buffer + 64; len -= 64; } - else { - sha256_process_block(buffer, len & ~63, ctx); - buffer = (const char *) buffer + (len & ~63); - len &= 63; - } } /* Move remaining bytes into internal buffer. */