diff --git a/SConstruct b/SConstruct index e60a7f350c8..5e02f368632 100644 --- a/SConstruct +++ b/SConstruct @@ -1718,6 +1718,29 @@ def doConfigure(myenv): conf.Finish() + def CheckMemset_s(context): + test_body = """ + #define __STDC_WANT_LIB_EXT1__ 1 + #include + int main(int argc, char* argv[]) { + void* data = nullptr; + return memset_s(data, 0, 0, 0); + } + """ + + context.Message('Checking for memset_s... ') + ret = context.TryLink(textwrap.dedent(test_body), ".cpp") + context.Result(ret) + return ret + + conf = Configure(env, custom_tests = { + 'CheckMemset_s' : CheckMemset_s, + }) + if conf.CheckMemset_s(): + conf.env.SetConfigHeaderDefine("MONGO_CONFIG_HAVE_MEMSET_S") + + conf.Finish() + # If we are using libstdc++, check to see if we are using a libstdc++ that is older than # our GCC minimum of 4.8.2. This is primarly to help people using clang on OS X but # forgetting to use --libc++ (or set the target OS X version high enough to get it as the diff --git a/src/mongo/SConscript b/src/mongo/SConscript index 1b5c3426cfd..ad0067476cc 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -225,6 +225,7 @@ config_header_substs = ( ('@mongo_config_have_execinfo_backtrace@', 'MONGO_CONFIG_HAVE_EXECINFO_BACKTRACE'), ('@mongo_config_have_fips_mode_set@', 'MONGO_CONFIG_HAVE_FIPS_MODE_SET'), ('@mongo_config_have_header_unistd_h@', 'MONGO_CONFIG_HAVE_HEADER_UNISTD_H'), + ('@mongo_config_have_memset_s@', 'MONGO_CONFIG_HAVE_MEMSET_S'), ('@mongo_config_have_posix_monotonic_clock@', 'MONGO_CONFIG_HAVE_POSIX_MONOTONIC_CLOCK'), ('@mongo_config_have_std_is_trivially_copyable@', 'MONGO_CONFIG_HAVE_STD_IS_TRIVIALLY_COPYABLE'), ('@mongo_config_have_std_make_unique@', 'MONGO_CONFIG_HAVE_STD_MAKE_UNIQUE'), diff --git a/src/mongo/config.h.in b/src/mongo/config.h.in index 1ae9c83b84e..07e95406b80 100644 --- a/src/mongo/config.h.in +++ b/src/mongo/config.h.in @@ -52,6 +52,9 @@ // Defined if unitstd.h is available @mongo_config_have_header_unistd_h@ +// Defined if memset_s is available +@mongo_config_have_memset_s@ + // Defined if a POSIX monotonic clock is available @mongo_config_have_posix_monotonic_clock@ diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript index 3e382a0b564..1b01b59310a 100644 --- a/src/mongo/util/SConscript +++ b/src/mongo/util/SConscript @@ -320,6 +320,24 @@ quick_exit_env.Library( ] ) +env.Library( + target="secure_zero_memory", + source=[ + 'secure_zero_memory.cpp', + ], + LIBDEPS=[ + "$BUILD_DIR/mongo/base", + ], +) + +env.CppUnitTest( + target='secure_zero_memory_test', + source=['secure_zero_memory_test.cpp'], + LIBDEPS=[ + 'secure_zero_memory' + ], +) + if not env.TargetOSIs('windows'): env.CppUnitTest( target='signal_handlers_synchronous_test', diff --git a/src/mongo/util/secure_zero_memory.cpp b/src/mongo/util/secure_zero_memory.cpp new file mode 100644 index 00000000000..ee7bb48218e --- /dev/null +++ b/src/mongo/util/secure_zero_memory.cpp @@ -0,0 +1,63 @@ +/* Copyright 2014 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#include "mongo/config.h" + +#if defined(MONGO_CONFIG_HAVE_MEMSET_S) +#define __STDC_WANT_LIB_EXT1__ 1 +#endif + +#include "mongo/platform/basic.h" + +#include + +#include "mongo/util/assert_util.h" + +namespace mongo { + +void secureZeroMemory(void* mem, size_t size) { + if (mem == nullptr) { + fassert(28751, size == 0); + return; + } + +#if defined(_WIN32) + // Windows provides a simple function for zeroing memory + SecureZeroMemory(mem, size); +#elif defined(MONGO_CONFIG_HAVE_MEMSET_S) + // Some C11 libraries provide a variant of memset which is guaranteed to not be optimized away + fassert(28752, memset_s(mem, size, 0, size) == 0); +#else + // fall back to using volatile pointer + volatile char* p = reinterpret_cast(mem); + while (size--) { + *p++ = 0; + } +#endif +} + +} // namespace mongo diff --git a/src/mongo/util/secure_zero_memory.h b/src/mongo/util/secure_zero_memory.h new file mode 100644 index 00000000000..03b78c8d272 --- /dev/null +++ b/src/mongo/util/secure_zero_memory.h @@ -0,0 +1,43 @@ +/* Copyright 2015 10gen Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#pragma once + +namespace mongo { + +/** + * Wrapper around several platform specific methods for zeroing memory + * Memory zeroing is complicated by the fact that compilers will try to optimize it away, as the + * memory frequently will not be later read. + * + * This function will, if available, perform a platform specific operation to zero memory. If no + * platform specific operation is available, memory will be zeroed using volatile pointers. + */ +void secureZeroMemory(void* ptr, size_t size); + + +} // namespace mongo diff --git a/src/mongo/util/secure_zero_memory_test.cpp b/src/mongo/util/secure_zero_memory_test.cpp new file mode 100644 index 00000000000..fbdc81590a3 --- /dev/null +++ b/src/mongo/util/secure_zero_memory_test.cpp @@ -0,0 +1,64 @@ +/* Copyright 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#include "mongo/unittest/death_test.h" +#include "mongo/unittest/unittest.h" +#include "mongo/util/assert_util.h" +#include "mongo/util/secure_zero_memory.h" + +namespace mongo { + +TEST(SecureZeroMemoryTest, zeroZeroLengthNull) { + void* ptr = nullptr; + secureZeroMemory(ptr, 0); + ASSERT_TRUE(true); +} + +DEATH_TEST(SecureZeroMemoryTest, zeroNonzeroLengthNull, "Fatal Assertion") { + void* ptr = nullptr; + secureZeroMemory(ptr, 1000); +} + +TEST(SecureZeroMemoryTest, dataZeroed) { + static const size_t dataSize = 100; + std::uint8_t data[dataSize]; + + // Populate array + for (size_t i = 0; i < dataSize; ++i) { + data[i] = i; + } + + // Zero array + secureZeroMemory(data, dataSize); + + // Check contents + for (size_t i = 0; i < dataSize; ++i) { + ASSERT_FALSE(data[i]); + } +} + +} // namespace mongo