diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -2492,6 +2492,34 @@ #define INIT_GLOB64 #endif // SANITIZER_INTERCEPT_GLOB64 +#if SANITIZER_INTERCEPT___B64_TO +INTERCEPTOR(int, __b64_ntop, unsigned char const *src, SIZE_T srclength, + char *target, SIZE_T targsize) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __b64_ntop, src, srclength, target, targsize); + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, srclength); + int res = REAL(__b64_ntop)(src, srclength, target, targsize); + if (res >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, target, res); + return res; +} +INTERCEPTOR(int, __b64_pton, char const *src, char *target, SIZE_T targsize) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __b64_pton, src, target, targsize); + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, internal_strlen(src)); + int res = REAL(__b64_pton)(src, target, targsize); + if (res >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, target, res); + return res; +} +# define INIT___B64_TO \ + COMMON_INTERCEPT_FUNCTION(__b64_ntop); \ + COMMON_INTERCEPT_FUNCTION(__b64_pton); +#else // SANITIZER_INTERCEPT___B64_TO +#define INIT___B64_TO +#endif // SANITIZER_INTERCEPT___B64_TO + + #if SANITIZER_INTERCEPT_POSIX_SPAWN template @@ -10392,6 +10420,7 @@ INIT_TIME; INIT_GLOB; INIT_GLOB64; + INIT___B64_TO; INIT_POSIX_SPAWN; INIT_WAIT; INIT_WAIT4; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -235,6 +235,7 @@ #define SANITIZER_INTERCEPT_TIME SI_POSIX #define SANITIZER_INTERCEPT_GLOB (SI_GLIBC || SI_SOLARIS) #define SANITIZER_INTERCEPT_GLOB64 SI_GLIBC +#define SANITIZER_INTERCEPT___B64_TO SI_LINUX #define SANITIZER_INTERCEPT_POSIX_SPAWN SI_POSIX #define SANITIZER_INTERCEPT_WAIT SI_POSIX #define SANITIZER_INTERCEPT_INET SI_POSIX diff --git a/compiler-rt/test/msan/Linux/b64.cpp b/compiler-rt/test/msan/Linux/b64.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/msan/Linux/b64.cpp @@ -0,0 +1,89 @@ +// RUN: %clangxx_msan -O0 %s -o %t -lresolv && %run %t 2>&1 | FileCheck %s +// RUN: not %run %t NTOP_READ 2>&1 | FileCheck %s --check-prefix=NTOP_READ +// RUN: not %run %t PTON_READ 2>&1 | FileCheck %s --check-prefix=PTON_READ + +#include +#include +#include +#include +#include + +#include + +int main(int iArgc, char *szArgv[]) { + char* test = nullptr; + if (iArgc > 1) { + test = szArgv[1]; + } + + if (test == nullptr) { + // Check NTOP writing + const char *src = "base64 test data"; + size_t src_len = strlen(src); + size_t dst_len = ((src_len + 2) / 3) * 4 + 1; + char dst[dst_len]; + int res = b64_ntop(reinterpret_cast(src), src_len, + dst, dst_len); + assert(res >= 0); + __msan_check_mem_is_initialized(dst, res); + printf("%d - %s\n", res, dst); + + // Check PTON writing + unsigned char target[dst_len]; + res = b64_pton(dst, target, dst_len); + assert(res >= 0); + __msan_check_mem_is_initialized(target, res); + // not null terminated by b64_pton + target[res] = '\0'; + printf("%d - %s\n", res, target); + + // Check NTOP writing for zero length src + src = ""; + src_len = strlen(src); + assert(((src_len + 2) / 3) * 4 + 1 < dst_len); + res = b64_ntop(reinterpret_cast(src), src_len, + dst, dst_len); + assert(res >= 0); + __msan_check_mem_is_initialized(dst, res); + printf("%d - %s\n", res, dst); + + // Check PTON writing for zero length src + dst[0] = '\0'; + res = b64_pton(dst, target, dst_len); + assert(res >= 0); + __msan_check_mem_is_initialized(target, res); + // not null terminated by b64_pton + target[res] = '\0'; + printf("%d - %s\n", res, target); + + return 0; + } + + if (strcmp(test, "NTOP_READ") == 0) { + // Check NTOP reading + size_t src_len = 80; + char src[src_len]; + __msan_poison(src, src_len); + size_t dst_len = ((src_len + 2) / 3) * 4 + 1; + char dst[dst_len]; + int res = b64_ntop(reinterpret_cast(src), src_len, + dst, dst_len); + // NTOP_READ: Uninitialized bytes in __interceptor___b64_ntop + return 0; + } + + if (strcmp(test, "PTON_READ") == 0) { + // Check PTON reading + size_t src_len = 80; + char src[src_len]; + strcpy(src, "junk longer than zero"); + // pretend it is uninitialized + __msan_poison(src, src_len); + unsigned char target[src_len]; + int res = b64_pton(src, target, src_len); + // PTON_READ: Uninitialized bytes in __interceptor___b64_pton + return 0; + } + + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/b64.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/b64.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/b64.cpp @@ -0,0 +1,42 @@ +// RUN: %clangxx %s -o %t -lresolv && %run %t %p + +#include +#include +#include +#include +#include + +int main(int iArgc, char *szArgv[]) { + // Check NTOP writing + const char *src = "base64 test data"; + size_t src_len = strlen(src); + size_t dst_len = ((src_len + 2) / 3) * 4 + 1; + char dst[dst_len]; + int res = b64_ntop(reinterpret_cast(src), src_len, dst, + dst_len); + assert(res >= 0); + assert(strcmp(dst, "YmFzZTY0IHRlc3QgZGF0YQ==") == 0); + + // Check PTON writing + unsigned char target[dst_len]; + res = b64_pton(dst, target, dst_len); + assert(res >= 0); + assert(strncmp(reinterpret_cast(target), src, res) == 0); + + // Check NTOP writing for zero length src + src = ""; + src_len = strlen(src); + assert(((src_len + 2) / 3) * 4 + 1 < dst_len); + res = b64_ntop(reinterpret_cast(src), src_len, dst, + dst_len); + assert(res >= 0); + assert(strcmp(dst, "") == 0); + + // Check PTON writing for zero length src + dst[0] = '\0'; + res = b64_pton(dst, target, dst_len); + assert(res >= 0); + assert(strncmp(reinterpret_cast(target), src, res) == 0); + + return 0; +}