diff options
author | komels <komels@yandex-team.ru> | 2022-04-14 13:10:53 +0300 |
---|---|---|
committer | komels <komels@yandex-team.ru> | 2022-04-14 13:10:53 +0300 |
commit | 21c9b0e6b039e9765eb414c406c2b86e8cea6850 (patch) | |
tree | f40ebc18ff8958dfbd189954ad024043ca983ea5 /library/cpp/string_utils/secret_string | |
parent | 9a4effa852abe489707139c2b260dccc6f4f9aa9 (diff) | |
download | ydb-21c9b0e6b039e9765eb414c406c2b86e8cea6850.tar.gz |
Final part on compatibility layer: LOGBROKER-7215
ref:777c67aadbf705d19034a09a792b2df61ba53697
Diffstat (limited to 'library/cpp/string_utils/secret_string')
4 files changed, 307 insertions, 0 deletions
diff --git a/library/cpp/string_utils/secret_string/CMakeLists.txt b/library/cpp/string_utils/secret_string/CMakeLists.txt new file mode 100644 index 0000000000..e801dca812 --- /dev/null +++ b/library/cpp/string_utils/secret_string/CMakeLists.txt @@ -0,0 +1,18 @@ + +# This file was gererated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(cpp-string_utils-secret_string) +target_link_libraries(cpp-string_utils-secret_string PUBLIC + contrib-libs-cxxsupp + yutil + cpp-string_utils-ztstrbuf +) +target_sources(cpp-string_utils-secret_string PRIVATE + ${CMAKE_SOURCE_DIR}/library/cpp/string_utils/secret_string/secret_string.cpp +) diff --git a/library/cpp/string_utils/secret_string/secret_string.cpp b/library/cpp/string_utils/secret_string/secret_string.cpp new file mode 100644 index 0000000000..3b68d3cd27 --- /dev/null +++ b/library/cpp/string_utils/secret_string/secret_string.cpp @@ -0,0 +1,68 @@ +#include "secret_string.h" + +#include <util/system/madvise.h> + +namespace NSecretString { + TSecretString::TSecretString(TStringBuf value) { + Init(value); + } + + TSecretString::~TSecretString() { + try { + Clear(); + } catch (...) { + } + } + + TSecretString& TSecretString::operator=(const TSecretString& o) { + if (&o == this) { + return *this; + } + + Init(o.Value_); + + return *this; + } + + /** + * It is not honest "move". Actually it is copy-assignment with cleaning of other instance. + * This way allowes to avoid side effects of string optimizations: + * Copy-On-Write or Short-String-Optimization + */ + TSecretString& TSecretString::operator=(TSecretString&& o) { + if (&o == this) { + return *this; + } + + Init(o.Value_); + o.Clear(); + + return *this; + } + + TSecretString& TSecretString::operator=(const TStringBuf o) { + Init(o); + + return *this; + } + + void TSecretString::Init(TStringBuf value) { + Clear(); + if (value.empty()) { + return; + } + + Value_ = value; + MadviseExcludeFromCoreDump(Value_); + } + + void TSecretString::Clear() { + if (Value_.empty()) { + return; + } + + SecureZero((void*)Value_.data(), Value_.size()); + MadviseIncludeIntoCoreDump(Value_); + Value_.clear(); + } +} diff --git a/library/cpp/string_utils/secret_string/secret_string.h b/library/cpp/string_utils/secret_string/secret_string.h new file mode 100644 index 0000000000..fdb9f6a85c --- /dev/null +++ b/library/cpp/string_utils/secret_string/secret_string.h @@ -0,0 +1,74 @@ +#pragma once + +#include <library/cpp/string_utils/ztstrbuf/ztstrbuf.h> + +#include <util/generic/string.h> + +namespace NSecretString { + /** + * TSecretString allowes to store some long lived secrets in "secure" storage in memory. + * Common usage: + * 1) read secret value from disk/env/etc + * 2) put it into TSecretString + * 3) destory secret copy from 1) + * + * Useful scenerios for TSecretString: + * - in memory only tasks: using key to create crypto signature; + * - rare network cases: db password on connection or OAuth token in background tasks. + * These cases disclosure the secret + * because of sending it over network with some I/O frameworks. + * Usually such frameworks copy input params to provide network protocol: gRPC, for example. + * + * Supported features: + * 1. Exclude secret from core dump. + * madvise(MADV_DONTDUMP) in ctor excludes full memory page from core dump. + * madvise(MADV_DODUMP) in dtor reverts previous action. + * 2. Zero memory before free. + * + * Code dump looks like this: +(gdb) print s +$1 = (const TSecretString &) @0x7fff23c4c560: { + Value_ = {<TStringBase<TBasicString<char, std::__y1::char_traits<char> >, char, std::__y1::char_traits<char> >> = { + static npos = <optimized out>}, Data_ = 0x107c001d8 <error: Cannot access memory at address 0x107c001d8>}} + */ + + class TSecretString { + public: + TSecretString() = default; + TSecretString(TStringBuf value); + ~TSecretString(); + + TSecretString(const TSecretString& o) + : TSecretString(o.Value()) + { + } + + TSecretString(TSecretString&& o) + : TSecretString(o.Value()) + { + o.Clear(); + } + + TSecretString& operator=(const TSecretString& o); + TSecretString& operator=(TSecretString&& o); + + TSecretString& operator=(const TStringBuf o); + + operator TZtStringBuf() const { + return Value(); + } + + // Provides zero terminated string + TZtStringBuf Value() const { + return TZtStringBuf(Value_); + } + + private: + // TStringBuf breaks Copy-On-Write to provide correct copy-ctor and copy-assignment + void Init(TStringBuf value); + void Clear(); + + private: + TString Value_; + }; +} diff --git a/library/cpp/string_utils/secret_string/ut/secret_string_ut.cpp b/library/cpp/string_utils/secret_string/ut/secret_string_ut.cpp new file mode 100644 index 0000000000..681b75368f --- /dev/null +++ b/library/cpp/string_utils/secret_string/ut/secret_string_ut.cpp @@ -0,0 +1,147 @@ +#include <library/cpp/string_utils/secret_string/secret_string.h> + +#include <library/cpp/testing/unittest/registar.h> + +using namespace NSecretString; + +Y_UNIT_TEST_SUITE(SecretTest) { + Y_UNIT_TEST(Common) { + TSecretString s; + UNIT_ASSERT_VALUES_EQUAL("", s.Value()); + UNIT_ASSERT_VALUES_EQUAL("", (TStringBuf)s); + + TSecretString s2("qwerty"); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s2.Value()); + UNIT_ASSERT_VALUES_EQUAL("qwerty", (TStringBuf)s2); + } + + Y_UNIT_TEST(CopyCtor1) { + TSecretString s1("qwerty"); + + UNIT_ASSERT_VALUES_EQUAL("qwerty", s1.Value()); + + { + TSecretString s2(s1); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s1.Value()); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s2.Value()); + } + + UNIT_ASSERT_VALUES_EQUAL("qwerty", s1.Value()); + } + + Y_UNIT_TEST(CopyCtor2) { + auto s1 = MakeHolder<TSecretString>("qwerty"); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s1->Value()); + + TSecretString s2(*s1); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s1->Value()); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s2.Value()); + + s1.Reset(); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s2.Value()); + } + + Y_UNIT_TEST(MoveCtor1) { + TSecretString s1("qwerty"); + + UNIT_ASSERT_VALUES_EQUAL("qwerty", s1.Value()); + + { + TSecretString s2(std::move(s1)); + UNIT_ASSERT_VALUES_EQUAL("", s1.Value()); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s2.Value()); + } + + UNIT_ASSERT_VALUES_EQUAL("", s1.Value()); + } + + Y_UNIT_TEST(MoveCtor2) { + auto s1 = MakeHolder<TSecretString>("qwerty"); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s1->Value()); + + TSecretString s2(std::move(*s1)); + UNIT_ASSERT_VALUES_EQUAL("", s1->Value()); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s2.Value()); + + s1.Reset(); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s2.Value()); + } + + Y_UNIT_TEST(CopyAssignment1) { + TSecretString s1("qwerty"); + + UNIT_ASSERT_VALUES_EQUAL("qwerty", s1.Value()); + + { + TSecretString s2; + UNIT_ASSERT_VALUES_EQUAL("", s2.Value()); + + s2 = s1; + UNIT_ASSERT_VALUES_EQUAL("qwerty", s1.Value()); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s2.Value()); + } + + UNIT_ASSERT_VALUES_EQUAL("qwerty", s1.Value()); + } + + Y_UNIT_TEST(CopyAssignment2) { + auto s1 = MakeHolder<TSecretString>("qwerty"); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s1->Value()); + + TSecretString s2; + UNIT_ASSERT_VALUES_EQUAL("", s2.Value()); + + s2 = *s1; + UNIT_ASSERT_VALUES_EQUAL("qwerty", s1->Value()); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s2.Value()); + + s1.Reset(); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s2.Value()); + + TSecretString s3; + s2 = s3; + UNIT_ASSERT_VALUES_EQUAL("", s2.Value()); + } + + Y_UNIT_TEST(MoveAssignment1) { + TSecretString s1("qwerty"); + + UNIT_ASSERT_VALUES_EQUAL("qwerty", s1.Value()); + + { + TSecretString s2; + UNIT_ASSERT_VALUES_EQUAL("", s2.Value()); + + s2 = std::move(s1); + UNIT_ASSERT_VALUES_EQUAL("", s1.Value()); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s2.Value()); + } + + UNIT_ASSERT_VALUES_EQUAL("", s1.Value()); + } + + Y_UNIT_TEST(MoveAssignment2) { + auto s1 = MakeHolder<TSecretString>("qwerty"); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s1->Value()); + + TSecretString s2; + UNIT_ASSERT_VALUES_EQUAL("", s2.Value()); + + s2 = std::move(*s1); + UNIT_ASSERT_VALUES_EQUAL("", s1->Value()); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s2.Value()); + + s1.Reset(); + UNIT_ASSERT_VALUES_EQUAL("qwerty", s2.Value()); + + TSecretString s3; + s2 = std::move(s3); + UNIT_ASSERT_VALUES_EQUAL("", s2.Value()); + } + + Y_UNIT_TEST(ZeroTerminated) { + TSecretString s("qwerty"); + + UNIT_ASSERT_VALUES_EQUAL(s.Value().size(), strlen(s.Value().data())); + } +} |