Skip to content

Commit 567d8f2

Browse files
authored
fix(rest): prevent libcurl callback from reading bad address (#14626)
1 parent aaf88be commit 567d8f2

File tree

3 files changed

+32
-0
lines changed

3 files changed

+32
-0
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
breaking changes in the upcoming 3.x release. This release is scheduled for
55
2024-12 or 2025-01.
66

7+
## v2.25.1 - 2024-08
8+
9+
- fix(rest): prevent libcurl callback from reading bad address ([#14615](https://github.com/googleapis/google-cloud-cpp/pull/14615), [#14617](https://github.com/googleapis/google-cloud-cpp/pull/14617))
10+
711
## v2.25.0 - 2024-06
812

913
### New Libraries

google/cloud/internal/curl_impl.cc

+27
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ static std::size_t ReadFunction( // NOLINT(misc-use-anonymous-namespace)
114114
return writev->MoveTo(absl::MakeSpan(buffer, size * nitems));
115115
}
116116

117+
// Instead of trying to send any more bytes from userdata, aborts.
118+
static std::size_t ReadFunctionAbort( // NOLINT(misc-use-anonymous-namespace)
119+
char*, std::size_t, std::size_t, void*) {
120+
return CURL_READFUNC_ABORT;
121+
}
122+
117123
static int SeekFunction( // NOLINT(misc-use-anonymous-namespace)
118124
void* userdata, curl_off_t offset, int origin) {
119125
auto* const writev = reinterpret_cast<WriteVector*>(userdata);
@@ -482,6 +488,22 @@ std::size_t CurlImpl::HeaderCallback(absl::Span<char> response) {
482488
response.size());
483489
}
484490

491+
class CurlImpl::ReadFunctionAbortGuard {
492+
public:
493+
explicit ReadFunctionAbortGuard(CurlImpl& impl) : impl_(impl) {}
494+
~ReadFunctionAbortGuard() {
495+
// If curl_closed_ is true, then the handle has already been recycled and
496+
// attempting to set an option on it will error.
497+
if (!impl_.curl_closed_) {
498+
impl_.handle_.SetOptionUnchecked(CURLOPT_READFUNCTION,
499+
&ReadFunctionAbort);
500+
}
501+
}
502+
503+
private:
504+
CurlImpl& impl_;
505+
};
506+
485507
Status CurlImpl::MakeRequestImpl(RestContext& context) {
486508
TRACE_STATE() << ", url_=" << url_;
487509

@@ -504,6 +526,11 @@ Status CurlImpl::MakeRequestImpl(RestContext& context) {
504526
handle_.SetOptionUnchecked(CURLOPT_HTTP_VERSION,
505527
VersionToCurlCode(http_version_));
506528

529+
// All data in the WriteVector should be written after ReadImpl returns unless
530+
// an error, typically a timeout, has occurred. Use ReadFunctionAbortGuard to
531+
// leverage RAII to instruct curl to not attempt to send anymore data on this
532+
// handle regardless if an error or exception is encountered.
533+
ReadFunctionAbortGuard guard(*this);
507534
auto error = curl_multi_add_handle(multi_.get(), handle_.handle_.get());
508535

509536
// This indicates that we are using the API incorrectly. The application

google/cloud/internal/curl_impl.h

+1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ class CurlImpl {
107107
std::size_t HeaderCallback(absl::Span<char> response);
108108

109109
private:
110+
class ReadFunctionAbortGuard;
110111
Status MakeRequestImpl(RestContext& context);
111112
StatusOr<std::size_t> ReadImpl(RestContext& context, absl::Span<char> output);
112113

0 commit comments

Comments
 (0)