From 41e4d11d118973969f494c8a4ae9ccbff2684d4a Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 1 Mar 2021 11:41:25 +0000 Subject: [PATCH] Fix CopyMem() not handling overlaps Per https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/BaseMemoryLib.h "(CopyMem) must handle the case where SourceBuffer overlaps DestinationBuffer". Having the gnu-efi version of CopyMem differ from the EDK2 version can lead to extremely hard to troubleshoot issues as well as very unexpected results. So make sure our version follows the same guidelines. --- lib/runtime/efirtlib.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/runtime/efirtlib.c b/lib/runtime/efirtlib.c index f782e4c..434db91 100644 --- a/lib/runtime/efirtlib.c +++ b/lib/runtime/efirtlib.c @@ -46,7 +46,7 @@ RUNTIMEFUNCTION RtSetMem ( IN VOID *Buffer, IN UINTN Size, - IN UINT8 Value + IN UINT8 Value ) { INT8 *pt; @@ -63,16 +63,26 @@ RtSetMem ( VOID RUNTIMEFUNCTION RtCopyMem ( - IN VOID *Dest, - IN CONST VOID *Src, - IN UINTN len + IN VOID *Dest, + IN CONST VOID *Src, + IN UINTN len ) { - CHAR8 *d; - CONST CHAR8 *s = Src; - d = Dest; - while (len--) { - *(d++) = *(s++); + CHAR8 *d = (CHAR8*)Dest; + CHAR8 *s = (CHAR8*)Src; + + if (d == NULL || s == NULL || s == d) + return; + + // If the beginning of the destination range overlaps with the end of + // the source range, make sure to start the copy from the end so that + // we don't end up overwriting source data that we need for the copy. + if ((d > s) && (d < s + len)) { + for (d += len, s += len; len--; ) + *--d = *--s; + } else { + while (len--) + *d++ = *s++; } }