aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/string_utils/secret_string
diff options
context:
space:
mode:
authorkomels <komels@yandex-team.ru>2022-04-14 13:10:53 +0300
committerkomels <komels@yandex-team.ru>2022-04-14 13:10:53 +0300
commit21c9b0e6b039e9765eb414c406c2b86e8cea6850 (patch)
treef40ebc18ff8958dfbd189954ad024043ca983ea5 /library/cpp/string_utils/secret_string
parent9a4effa852abe489707139c2b260dccc6f4f9aa9 (diff)
downloadydb-21c9b0e6b039e9765eb414c406c2b86e8cea6850.tar.gz
Final part on compatibility layer: LOGBROKER-7215
ref:777c67aadbf705d19034a09a792b2df61ba53697
Diffstat (limited to 'library/cpp/string_utils/secret_string')
-rw-r--r--library/cpp/string_utils/secret_string/CMakeLists.txt18
-rw-r--r--library/cpp/string_utils/secret_string/secret_string.cpp68
-rw-r--r--library/cpp/string_utils/secret_string/secret_string.h74
-rw-r--r--library/cpp/string_utils/secret_string/ut/secret_string_ut.cpp147
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()));
+ }
+}