From 3d1f228ffdd987c298092baefa6de2ed3978ab50 Mon Sep 17 00:00:00 2001 From: Alexander Polyakov Date: Sat, 27 Apr 2024 13:28:43 +0300 Subject: [PATCH] Fix SIGSEGV in openssl_random_pseudo_bytes and xor_strings (#985) SIGSEGV was caused by using wrong string's constructor. The constructor we used was an optimization for single-character strings. Such strings are stored in `.rodata`. Writing to these strings' buffer led to a SIGSEGV --- runtime/openssl.cpp | 4 +-- runtime/string_decl.inl | 4 +++ runtime/string_functions.cpp | 2 +- .../openssl/9_openssl_random_pseudo_bytes.php | 33 +++++++++++++++++++ .../phpt/string_functions/010_xor_strings.php | 24 ++++++++++++++ 5 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 tests/phpt/openssl/9_openssl_random_pseudo_bytes.php create mode 100644 tests/phpt/string_functions/010_xor_strings.php diff --git a/runtime/openssl.cpp b/runtime/openssl.cpp index a85ce4c62f..cf7c91433b 100644 --- a/runtime/openssl.cpp +++ b/runtime/openssl.cpp @@ -601,7 +601,7 @@ Optional f$openssl_random_pseudo_bytes(int64_t length) { if (length <= 0 || length > string::max_size()) { return false; } - string buffer(static_cast(length), ' '); + string buffer{static_cast(length), false}; timeval tv{}; gettimeofday(&tv, nullptr); @@ -610,7 +610,7 @@ Optional f$openssl_random_pseudo_bytes(int64_t length) { if (RAND_bytes(reinterpret_cast(buffer.buffer()), static_cast(length)) <= 0) { return false; } - return std::move(buffer); + return buffer; } diff --git a/runtime/string_decl.inl b/runtime/string_decl.inl index 950f1cab41..1d5132ab3e 100644 --- a/runtime/string_decl.inl +++ b/runtime/string_decl.inl @@ -74,6 +74,8 @@ private: inline void set_size(size_type new_size); inline static char *create(const char *beg, const char *end); + // IMPORTANT: this function may return read-only strings for n == 0 and n == 1. + // Use it unless you have to manually write something into the buffer. inline static char *create(size_type req, char c); inline static char *create(size_type req, bool b); @@ -97,6 +99,8 @@ public: inline string(string &&str) noexcept; inline string(const char *s, size_type n); inline explicit string(const char *s); + // IMPORTANT: this constructor may return read-only strings for n == 0 and n == 1. + // Use it unless you have to manually operate with string's internal buffer. inline string(size_type n, char c); inline string(size_type n, bool b); inline explicit string(int64_t i); diff --git a/runtime/string_functions.cpp b/runtime/string_functions.cpp index f5eb182881..a467e36d29 100644 --- a/runtime/string_functions.cpp +++ b/runtime/string_functions.cpp @@ -2844,7 +2844,7 @@ string f$wordwrap(const string &str, int64_t width, const string &brk, bool cut) string f$xor_strings(const string &s, const string &t) { string::size_type length = min(s.size(), t.size()); - string result(length, ' '); + string result{length, false}; const char *s_str = s.c_str(); const char *t_str = t.c_str(); char *res_str = result.buffer(); diff --git a/tests/phpt/openssl/9_openssl_random_pseudo_bytes.php b/tests/phpt/openssl/9_openssl_random_pseudo_bytes.php new file mode 100644 index 0000000000..26b1a0cc36 --- /dev/null +++ b/tests/phpt/openssl/9_openssl_random_pseudo_bytes.php @@ -0,0 +1,33 @@ +@ok +