From 629a0b72dd8d45dfcd22aa294022fe3d9b3e1776 Mon Sep 17 00:00:00 2001 From: J-D-K Date: Mon, 8 Sep 2025 22:15:11 -0400 Subject: [PATCH] remote::URL & remote::Form: Prevent buffer overflows. --- include/remote/Form.hpp | 6 +++--- include/remote/URL.hpp | 12 ++++++------ source/remote/Form.cpp | 11 ++++++++--- source/remote/URL.cpp | 28 ++++++++++++++++++++-------- 4 files changed, 37 insertions(+), 20 deletions(-) diff --git a/include/remote/Form.hpp b/include/remote/Form.hpp index 0716ba5..ea37d25 100644 --- a/include/remote/Form.hpp +++ b/include/remote/Form.hpp @@ -12,7 +12,7 @@ namespace remote /// @brief Appends a parameter to the form/URL encoded text. /// @param param Parameter to append. /// @param value Value to append. - Form &append_parameter(std::string_view param, std::string_view value); + Form &append_parameter(std::string_view param, std::string_view value) noexcept; /// @brief Returns m_form.length() size_t length() const noexcept; @@ -23,10 +23,10 @@ namespace remote private: /// @brief Size used for the buffer. - static inline constexpr int SIZE_FORM_BUFFER = 0x800; + static inline constexpr size_t SIZE_FORM_BUFFER = 0x800; /// @brief Current offset if the form. - int m_offset{}; + size_t m_offset{}; /// @brief Buffer for the form. char m_formBuffer[SIZE_FORM_BUFFER] = {0}; diff --git a/include/remote/URL.hpp b/include/remote/URL.hpp index 54f9f0f..7563faf 100644 --- a/include/remote/URL.hpp +++ b/include/remote/URL.hpp @@ -13,30 +13,30 @@ namespace remote /// @brief Constructs a URL with a base URL already in place. /// @param base String_view containing the base URL. - URL(std::string_view base); + URL(std::string_view base) noexcept; /// @brief Appends the string passed as a path to the URL /// @param path Path to append; - URL &append_path(std::string_view path); + URL &append_path(std::string_view path) noexcept; /// @brief Appends a string parameter /// @param param Parameter to append. /// @param value Value of the parameter to append. - URL &append_parameter(std::string_view param, std::string_view value); + URL &append_parameter(std::string_view param, std::string_view value) noexcept; /// @brief Appends a trailing slash if needed. - URL &append_slash(); + URL &append_slash() noexcept; /// @brief Returns the C string of the url string. const char *get() const noexcept; private: - static inline constexpr int SIZE_URL_BUFFER = 0x800; + static inline constexpr size_t SIZE_URL_BUFFER = 0x800; /// @brief This is where the actual URL is held. char m_urlBuffer[SIZE_URL_BUFFER] = {0}; // Current offset in the buffer. - int m_offset{}; + size_t m_offset{}; }; } // namespace remote diff --git a/source/remote/Form.cpp b/source/remote/Form.cpp index 37d81d3..898a3e2 100644 --- a/source/remote/Form.cpp +++ b/source/remote/Form.cpp @@ -3,17 +3,22 @@ #include #include -remote::Form &remote::Form::append_parameter(std::string_view param, std::string_view value) +remote::Form &remote::Form::append_parameter(std::string_view param, std::string_view value) noexcept { + const size_t paramLength = param.length(); + const size_t valueLength = value.length(); + const size_t endLength = m_offset + paramLength + valueLength + 1; + if (endLength >= SIZE_FORM_BUFFER) { return *this; } + if (m_offset > 0 && m_formBuffer[m_offset] != '&') { m_formBuffer[m_offset++] = '&'; } std::copy(param.begin(), param.end(), &m_formBuffer[m_offset]); - m_offset += param.length(); + m_offset += paramLength; m_formBuffer[m_offset++] = '='; std::copy(value.begin(), value.end(), &m_formBuffer[m_offset]); - m_offset += value.length(); + m_offset += valueLength; return *this; } diff --git a/source/remote/URL.cpp b/source/remote/URL.cpp index 1fb0486..37e75d9 100644 --- a/source/remote/URL.cpp +++ b/source/remote/URL.cpp @@ -2,44 +2,56 @@ #include -remote::URL::URL(std::string_view base) +remote::URL::URL(std::string_view base) noexcept { + const size_t baseLength = base.length(); + if (baseLength >= SIZE_URL_BUFFER) { return; } + std::copy(base.begin(), base.end(), &m_urlBuffer[m_offset]); m_offset += base.length(); } -remote::URL &remote::URL::append_path(std::string_view path) +remote::URL &remote::URL::append_path(std::string_view path) noexcept { if (path.empty()) { return *this; } + const size_t pathLength = path.length(); + if (m_offset + pathLength >= SIZE_URL_BUFFER) { return *this; } + if (m_urlBuffer[m_offset] != '/' && path.front() != '/') { m_urlBuffer[m_offset++] = '/'; } std::copy(path.begin(), path.end(), &m_urlBuffer[m_offset]); - m_offset += path.length(); + m_offset += pathLength; return *this; } -remote::URL &remote::URL::append_parameter(std::string_view param, std::string_view value) +remote::URL &remote::URL::append_parameter(std::string_view param, std::string_view value) noexcept { + const size_t paramLength = param.length(); + const size_t valueLength = value.length(); + const size_t endLength = m_offset + paramLength + valueLength + 2; + if (endLength >= SIZE_URL_BUFFER) { return *this; } + const char *find = std::char_traits::find(m_urlBuffer, m_offset, '?'); if (!find) { m_urlBuffer[m_offset++] = '?'; } else { m_urlBuffer[m_offset++] = '&'; } std::copy(param.begin(), param.end(), &m_urlBuffer[m_offset]); - m_offset += param.length(); + m_offset += paramLength; m_urlBuffer[m_offset++] = '='; std::copy(value.begin(), value.end(), &m_urlBuffer[m_offset]); - m_offset += value.length(); + m_offset += valueLength; return *this; } -remote::URL &remote::URL::append_slash() +remote::URL &remote::URL::append_slash() noexcept { - if (m_urlBuffer[m_offset] != '/') { m_urlBuffer[m_offset++] = '/'; } + if (m_offset >= SIZE_URL_BUFFER) { return *this; } + else if (m_urlBuffer[m_offset] != '/') { m_urlBuffer[m_offset++] = '/'; } return *this; }