diff options
author | Niels Möller <nisse@lysator.liu.se> | 2014-10-23 15:12:49 +0200 |
---|---|---|
committer | Niels Möller <nisse@lysator.liu.se> | 2014-10-23 15:12:49 +0200 |
commit | 57122465ccc89996f9f8f71e7607ee67a2860e1c (patch) | |
tree | 376f5b73c680fd7cc35db4eab1c1a17dbe92d2d9 /memxor.c | |
parent | dbcea3e4c96fcd884e9cd9ab59ac21e00c359b97 (diff) | |
download | nettle-57122465ccc89996f9f8f71e7607ee67a2860e1c.tar.gz |
Fixed out-of-bounds reads in memxor.
Diffstat (limited to 'memxor.c')
-rw-r--r-- | memxor.c | 43 |
1 files changed, 35 insertions, 8 deletions
@@ -37,6 +37,7 @@ # include "config.h" #endif +#include <assert.h> #include <limits.h> #include "memxor.h" @@ -69,29 +70,44 @@ memxor_common_alignment (word_t *dst, const word_t *src, size_t n) words, not bytes. Assumes we can read complete words at the start and end of the src operand. */ static void -memxor_different_alignment (word_t *dst, const char *src, size_t n) +memxor_different_alignment (word_t *dst, const unsigned char *src, size_t n) { int shl, shr; const word_t *src_word; unsigned offset = ALIGN_OFFSET (src); word_t s0, s1; + const unsigned char *part; + unsigned i; + assert (n > 0); shl = CHAR_BIT * offset; shr = CHAR_BIT * (sizeof(word_t) - offset); src_word = (const word_t *) ((uintptr_t) src & -sizeof(word_t)); + /* Read top offset bytes, in native byte order. */ + part = src + n*sizeof(word_t) - offset; +#if WORDS_BIGENDIAN + for (s0 = part[0], i = 1; i < offset; i++) + s0 = (s0 << CHAR_BIT) | part[i]; + s0 <<= shr; /* FIXME: Eliminate this shift? */ +#else /* !WORDS_BIGENDIAN */ + for (i = offset, s0 = part[--i]; i > 0 ; ) + s0 = (s0 << CHAR_BIT) | part[--i]; +#endif /* !WORDS_BIGENDIAN */ + + /* Do n-1 regular iterations */ if (n & 1) + s1 = s0; + else { n--; s1 = src_word[n]; - s0 = src_word[n+1]; /* FIXME: Overread */ dst[n] ^= MERGE (s1, shl, s0, shr); } - else - s1 = src_word[n]; /* FIXME: Overread */ - while (n > 0) + assert (n & 1); + while (n > 2) { n -= 2; s0 = src_word[n+1]; @@ -99,6 +115,17 @@ memxor_different_alignment (word_t *dst, const char *src, size_t n) s1 = src_word[n]; /* FIXME: Overread on last iteration */ dst[n] ^= MERGE(s1, shl, s0, shr); } + assert (n == 1); + /* Read low wordsize - offset bytes */ +#if WORDS_BIGENDIAN + for (s0 = src[0], i = 1; i < sizeof(word_t) - offset; i++) + s0 = (s0 << CHAR_BIT) | src[i]; +#else /* !WORDS_BIGENDIAN */ + for (i = sizeof(word_t) - offset, s0 = src[--i]; i > 0 ; ) + s0 = (s0 << CHAR_BIT) | src[--i]; + s0 <<= shl; /* FIXME: eliminate shift? */ +#endif /* !WORDS_BIGENDIAN */ + dst[0] ^= MERGE(s0, shl, s1, shr); } /* Performance, Intel SU1400 (x86_64): 0.25 cycles/byte aligned, 0.45 @@ -109,8 +136,8 @@ memxor_different_alignment (word_t *dst, const char *src, size_t n) void * memxor(void *dst_in, const void *src_in, size_t n) { - char *dst = dst_in; - const char *src = src_in; + unsigned char *dst = dst_in; + const unsigned char *src = src_in; if (n >= WORD_T_THRESH) { @@ -129,7 +156,7 @@ memxor(void *dst_in, const void *src_in, size_t n) n %= sizeof (word_t); if (offset) - memxor_different_alignment ((word_t *) (dst+n), (src+n), nwords); + memxor_different_alignment ((word_t *) (dst+n), src+n, nwords); else memxor_common_alignment ((word_t *) (dst+n), (const word_t *) (src+n), nwords); |