From 5b8987ae46512b5550d15fafd54b270ec913422d Mon Sep 17 00:00:00 2001 From: Jeremy Compostella Date: Tue, 11 Jul 2017 14:08:37 -0700 Subject: libpayload: Support unaligned pointer for memcpy, memmove and memcmp The memcpy(), memmove() and memcmp() functions use word by word operations regardless of the pointer alignment. Depending on the platform, this could lead to a crash. This patch makes the memcpy(), memmove() or memcmp() operate byte per byte if they are supplied with unaligned pointers. Change-Id: I0b668739b7b58d47266f10f2dff2dc9cbf38577e Signed-off-by: Jeremy Compostella Reviewed-on: https://review.coreboot.org/20535 Tested-by: build bot (Jenkins) Reviewed-by: Nico Huber Reviewed-by: Julius Werner --- payloads/libpayload/libc/memory.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'payloads/libpayload') diff --git a/payloads/libpayload/libc/memory.c b/payloads/libpayload/libc/memory.c index 1adfb3207f..2c44764edb 100644 --- a/payloads/libpayload/libc/memory.c +++ b/payloads/libpayload/libc/memory.c @@ -66,13 +66,17 @@ static void *default_memcpy(void *dst, const void *src, size_t n) size_t i; void *ret = dst; - for(i = 0; i < n / sizeof(unsigned long); i++) - ((unsigned long *)dst)[i] = ((unsigned long *)src)[i]; + if (IS_ALIGNED((uintptr_t)dst, sizeof(unsigned long)) && + IS_ALIGNED((uintptr_t)src, sizeof(unsigned long))) { + for (i = 0; i < n / sizeof(unsigned long); i++) + ((unsigned long *)dst)[i] = ((unsigned long *)src)[i]; - src += i * sizeof(unsigned long); - dst += i * sizeof(unsigned long); + src += i * sizeof(unsigned long); + dst += i * sizeof(unsigned long); + n -= i * sizeof(unsigned long); + } - for(i = 0; i < n % sizeof(unsigned long); i++) + for (i = 0; i < n; i++) ((u8 *)dst)[i] = ((u8 *)src)[i]; return ret; @@ -89,6 +93,13 @@ static void *default_memmove(void *dst, const void *src, size_t n) if (src > dst) return memcpy(dst, src, n); + if (!IS_ALIGNED((uintptr_t)dst, sizeof(unsigned long)) || + !IS_ALIGNED((uintptr_t)src, sizeof(unsigned long))) { + for (i = n - 1; i >= 0; i--) + ((u8 *)dst)[i] = ((u8 *)src)[i]; + return dst; + } + offs = n - (n % sizeof(unsigned long)); for (i = (n % sizeof(unsigned long)) - 1; i >= 0; i--) @@ -116,11 +127,14 @@ void *memmove(void *dst, const void *src, size_t n) static int default_memcmp(const void *s1, const void *s2, size_t n) { - size_t i; - - for (i = 0; i < n / sizeof(unsigned long); i++) - if (((unsigned long *)s1)[i] != ((unsigned long *)s2)[i]) - break; /* fall through to find differing byte */ + size_t i = 0; + const unsigned long *w1 = s1, *w2 = s2; + + if (IS_ALIGNED((uintptr_t)s1, sizeof(unsigned long)) && + IS_ALIGNED((uintptr_t)s2, sizeof(unsigned long))) + for (; i < n / sizeof(unsigned long); i++) + if (w1[i] != w2[i]) + break; /* fall through to find differing byte */ for (i *= sizeof(unsigned long); i < n; i++) if (((u8 *)s1)[i] != ((u8 *)s2)[i]) -- cgit v1.2.3