From c5c5e52c241adca15bde1e498803d182fc017480 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Wed, 3 Apr 2024 22:01:43 -0400 Subject: [PATCH] AK: Disallow calling ByteString methods that return a view on rvalues This prevents, for example: StringView view = ByteString { "foo" }.view(); This prevents a class of potential UAF. --- AK/ByteString.cpp | 8 ++++---- AK/ByteString.h | 31 ++++++++++++++++++------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/AK/ByteString.cpp b/AK/ByteString.cpp index 9ac308511f..5e7469efce 100644 --- a/AK/ByteString.cpp +++ b/AK/ByteString.cpp @@ -81,14 +81,14 @@ ByteString ByteString::substring(size_t start) const return { characters() + start, length() - start }; } -StringView ByteString::substring_view(size_t start, size_t length) const +StringView ByteString::substring_view(size_t start, size_t length) const& { VERIFY(!Checked::addition_would_overflow(start, length)); VERIFY(start + length <= m_impl->length()); return { characters() + start, length }; } -StringView ByteString::substring_view(size_t start) const +StringView ByteString::substring_view(size_t start) const& { VERIFY(start <= length()); return { characters() + start, length() - start }; @@ -123,7 +123,7 @@ Vector ByteString::split_limit(char separator, size_t limit, SplitBe return v; } -Vector ByteString::split_view(Function separator, SplitBehavior split_behavior) const +Vector ByteString::split_view(Function separator, SplitBehavior split_behavior) const& { if (is_empty()) return {}; @@ -147,7 +147,7 @@ Vector ByteString::split_view(Function separator, SplitB return v; } -Vector ByteString::split_view(char const separator, SplitBehavior split_behavior) const +Vector ByteString::split_view(char const separator, SplitBehavior split_behavior) const& { return split_view([separator](char ch) { return ch == separator; }, split_behavior); } diff --git a/AK/ByteString.h b/AK/ByteString.h index f4f5023d5c..fc859ce17b 100644 --- a/AK/ByteString.h +++ b/AK/ByteString.h @@ -166,8 +166,12 @@ public: [[nodiscard]] Vector split_limit(char separator, size_t limit, SplitBehavior = SplitBehavior::Nothing) const; [[nodiscard]] Vector split(char separator, SplitBehavior = SplitBehavior::Nothing) const; - [[nodiscard]] Vector split_view(char separator, SplitBehavior = SplitBehavior::Nothing) const; - [[nodiscard]] Vector split_view(Function separator, SplitBehavior = SplitBehavior::Nothing) const; + + [[nodiscard]] Vector split_view(char separator, SplitBehavior = SplitBehavior::Nothing) const&; + [[nodiscard]] Vector split_view(char separator, SplitBehavior = SplitBehavior::Nothing) const&& = delete; + + [[nodiscard]] Vector split_view(Function separator, SplitBehavior = SplitBehavior::Nothing) const&; + [[nodiscard]] Vector split_view(Function separator, SplitBehavior = SplitBehavior::Nothing) const&& = delete; [[nodiscard]] Optional find(char needle, size_t start = 0) const { return StringUtils::find(*this, needle, start); } [[nodiscard]] Optional find(StringView needle, size_t start = 0) const { return StringUtils::find(*this, needle, start); } @@ -177,12 +181,17 @@ public: using SearchDirection = StringUtils::SearchDirection; [[nodiscard]] Optional find_any_of(StringView needles, SearchDirection direction) const { return StringUtils::find_any_of(*this, needles, direction); } - [[nodiscard]] StringView find_last_split_view(char separator) const { return view().find_last_split_view(separator); } + [[nodiscard]] StringView find_last_split_view(char separator) const& { return view().find_last_split_view(separator); } + [[nodiscard]] StringView find_last_split_view(char separator) const&& = delete; [[nodiscard]] ByteString substring(size_t start, size_t length) const; [[nodiscard]] ByteString substring(size_t start) const; - [[nodiscard]] StringView substring_view(size_t start, size_t length) const; - [[nodiscard]] StringView substring_view(size_t start) const; + + [[nodiscard]] StringView substring_view(size_t start, size_t length) const&; + [[nodiscard]] StringView substring_view(size_t start, size_t length) const&& = delete; + + [[nodiscard]] StringView substring_view(size_t start) const&; + [[nodiscard]] StringView substring_view(size_t start) const&& = delete; [[nodiscard]] ALWAYS_INLINE bool is_empty() const { return length() == 0; } [[nodiscard]] ALWAYS_INLINE size_t length() const { return m_impl->length(); } @@ -191,10 +200,8 @@ public: [[nodiscard]] bool copy_characters_to_buffer(char* buffer, size_t buffer_size) const; - [[nodiscard]] ALWAYS_INLINE ReadonlyBytes bytes() const - { - return m_impl->bytes(); - } + [[nodiscard]] ALWAYS_INLINE ReadonlyBytes bytes() const& { return m_impl->bytes(); } + [[nodiscard]] ALWAYS_INLINE ReadonlyBytes bytes() const&& = delete; [[nodiscard]] ALWAYS_INLINE char const& operator[](size_t i) const { @@ -292,10 +299,8 @@ public: return formatted("{}", value); } - [[nodiscard]] StringView view() const - { - return { characters(), length() }; - } + [[nodiscard]] StringView view() const& { return { characters(), length() }; } + [[nodiscard]] StringView view() const&& = delete; [[nodiscard]] ByteString replace(StringView needle, StringView replacement, ReplaceMode replace_mode = ReplaceMode::All) const { return StringUtils::replace(*this, needle, replacement, replace_mode); } [[nodiscard]] size_t count(StringView needle) const { return StringUtils::count(*this, needle); }