Skip to content

Commit 8692580

Browse files
cjen1-msfteddyashtonachamayou
authored
[release/6.x] Port curlm to 6.x (#7103, #7102, #7219, #7213) (#7293)
Co-authored-by: Eddy Ashton <ashton.eddy@gmail.com> Co-authored-by: Amaury Chamayou <amaury@xargs.fr> Co-authored-by: Amaury Chamayou <amchamay@microsoft.com> Co-authored-by: Eddy Ashton <edashton@microsoft.com>
1 parent 653a05d commit 8692580

File tree

20 files changed

+1928
-404
lines changed

20 files changed

+1928
-404
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1212
### Added
1313

1414
- Validate endorsement metadata (tcb version and chip id) against attestation (#7240)
15+
- Curl multi based fetching of quote endorsements and snapshots
16+
17+
### Fixed
18+
19+
- Fixed quote endorsements retry logic
1520

1621
### Removed
1722

CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,8 @@ if(COMPILE_TARGET STREQUAL "snp")
617617
ccf_kv.snp
618618
nghttp2
619619
${CMAKE_THREAD_LIBS_INIT}
620+
curl
621+
uv
620622
ccf_pal.snp
621623
)
622624

@@ -670,6 +672,8 @@ elseif(COMPILE_TARGET STREQUAL "virtual")
670672
ccf_kv.host
671673
nghttp2
672674
${CMAKE_THREAD_LIBS_INIT}
675+
curl
676+
uv
673677
ccf_pal.host
674678
)
675679

@@ -1515,6 +1519,17 @@ if(BUILD_TESTS)
15151519
NAME historical_query_cache_test
15161520
PYTHON_SCRIPT ${CMAKE_SOURCE_DIR}/tests/historical_query_cache.py
15171521
)
1522+
1523+
add_test_bin(
1524+
curl_test ${CMAKE_CURRENT_SOURCE_DIR}/src/http/test/curl_test.cpp
1525+
)
1526+
target_link_libraries(curl_test PRIVATE curl uv http_parser.host)
1527+
1528+
if(LONG_TESTS)
1529+
add_e2e_test(
1530+
NAME e2e_curl PYTHON_SCRIPT ${CMAKE_SOURCE_DIR}/tests/e2e_curl.py
1531+
)
1532+
endif()
15181533
endif()
15191534
endif()
15201535

cmake/common.cmake

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ endfunction()
4545
function(add_test_bin name)
4646
add_executable(${name} ${CCF_DIR}/src/enclave/thread_local.cpp ${ARGN})
4747
target_compile_options(${name} PRIVATE ${COMPILE_LIBCXX})
48-
target_include_directories(${name} PRIVATE src ${CCFCRYPTO_INC})
48+
target_include_directories(
49+
${name} PRIVATE src ${CCFCRYPTO_INC} ${CCF_DIR}/3rdparty/test
50+
)
4951
enable_coverage(${name})
5052
target_link_libraries(${name} PRIVATE ${LINK_LIBCXX} ccfcrypto.host)
5153
add_san(${name})

include/ccf/pal/attestation_sev_snp.h

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "ccf/ds/enum_formatter.h"
66
#include "ccf/ds/json.h"
7+
#include "ccf/ds/unit_strings.h"
78
#include "ccf/pal/attestation_sev_snp_endorsements.h"
89
#include "ccf/pal/measurement.h"
910
#include "ccf/pal/report_data.h"
@@ -459,6 +460,8 @@ pRb21iI1NlNCfOGUPIhVpWECAwEAAQ==
459460
auto reported_tcb = fmt::format("{:0x}", *(uint64_t*)(&quote.reported_tcb));
460461

461462
constexpr size_t default_max_retries_count = 10;
463+
static const ds::SizeString default_max_client_response_size =
464+
ds::SizeString("100mb");
462465

463466
if (endorsements_servers.empty())
464467
{
@@ -467,22 +470,30 @@ pRb21iI1NlNCfOGUPIhVpWECAwEAAQ==
467470
default_azure_endorsements_endpoint,
468471
chip_id_hex,
469472
reported_tcb,
470-
default_max_retries_count));
473+
default_max_retries_count,
474+
default_max_client_response_size));
471475
return config;
472476
}
473477

474478
for (auto const& server : endorsements_servers)
475479
{
476480
size_t max_retries_count =
477481
server.max_retries_count.value_or(default_max_retries_count);
482+
size_t max_client_response_size =
483+
server.max_client_response_size.value_or(
484+
default_max_client_response_size);
478485
switch (server.type)
479486
{
480487
case EndorsementsEndpointType::Azure:
481488
{
482489
auto loc =
483490
get_endpoint_loc(server, default_azure_endorsements_endpoint);
484491
config.servers.emplace_back(make_azure_endorsements_server(
485-
loc, chip_id_hex, reported_tcb, max_retries_count));
492+
loc,
493+
chip_id_hex,
494+
reported_tcb,
495+
max_retries_count,
496+
max_client_response_size));
486497
break;
487498
}
488499
case EndorsementsEndpointType::AMD:
@@ -532,15 +543,20 @@ pRb21iI1NlNCfOGUPIhVpWECAwEAAQ==
532543
snp,
533544
microcode,
534545
product,
535-
max_retries_count));
546+
max_retries_count,
547+
max_client_response_size));
536548
break;
537549
}
538550
case EndorsementsEndpointType::THIM:
539551
{
540552
auto loc =
541553
get_endpoint_loc(server, default_thim_endorsements_endpoint);
542554
config.servers.emplace_back(make_thim_endorsements_server(
543-
loc, chip_id_hex, reported_tcb, max_retries_count));
555+
loc,
556+
chip_id_hex,
557+
reported_tcb,
558+
max_retries_count,
559+
max_client_response_size));
544560
break;
545561
}
546562
default:

include/ccf/pal/attestation_sev_snp_endorsements.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,14 @@ namespace ccf::pal::snp
7676
EndorsementsEndpointType type = Azure;
7777
std::optional<std::string> url = std::nullopt;
7878
std::optional<size_t> max_retries_count = std::nullopt;
79+
std::optional<ccf::ds::SizeString> max_client_response_size = std::nullopt;
7980

8081
bool operator==(const EndorsementsServer&) const = default;
8182
};
8283
DECLARE_JSON_TYPE_WITH_OPTIONAL_FIELDS(EndorsementsServer);
8384
DECLARE_JSON_REQUIRED_FIELDS(EndorsementsServer);
8485
DECLARE_JSON_OPTIONAL_FIELDS(
85-
EndorsementsServer, type, url, max_retries_count);
86+
EndorsementsServer, type, url, max_retries_count, max_client_response_size);
8687
using EndorsementsServers = std::vector<EndorsementsServer>;
8788

8889
struct HostPort
@@ -99,17 +100,20 @@ namespace ccf::pal::snp
99100
const HostPort& endpoint,
100101
const std::string& chip_id_hex,
101102
const std::string& reported_tcb,
102-
size_t max_retries_count)
103+
size_t max_retries_count,
104+
size_t max_client_response_size)
103105
{
104106
std::map<std::string, std::string> params;
105107
params["api-version"] = "2020-10-15-preview";
106108
EndorsementEndpointsConfiguration::EndpointInfo info{
107109
endpoint.host,
108110
endpoint.port,
109111
fmt::format("/SevSnpVM/certificates/{}/{}", chip_id_hex, reported_tcb),
110-
params};
112+
params,
113+
};
111114

112115
info.max_retries_count = max_retries_count;
116+
info.max_client_response_size = max_client_response_size;
113117

114118
return {info};
115119
}
@@ -127,7 +131,8 @@ namespace ccf::pal::snp
127131
const std::string& snp,
128132
const std::string& microcode,
129133
const ProductName& product_name,
130-
size_t max_retries_count)
134+
size_t max_retries_count,
135+
size_t max_client_response_size)
131136
{
132137
std::map<std::string, std::string> params;
133138
params["blSPL"] = boot_loader;
@@ -144,12 +149,14 @@ namespace ccf::pal::snp
144149
true // DER
145150
};
146151
leaf.max_retries_count = max_retries_count;
152+
leaf.max_client_response_size = max_client_response_size;
147153
EndorsementEndpointsConfiguration::EndpointInfo chain{
148154
endpoint.host,
149155
endpoint.port,
150156
fmt::format("/vcek/v1/{}/cert_chain", to_string(product_name)),
151157
{}};
152158
chain.max_retries_count = max_retries_count;
159+
chain.max_client_response_size = max_client_response_size;
153160

154161
server.push_back(leaf);
155162
server.push_back(chain);
@@ -164,7 +171,8 @@ namespace ccf::pal::snp
164171
const HostPort& endpoint,
165172
const std::string& chip_id_hex,
166173
const std::string& reported_tcb,
167-
size_t max_retries_count)
174+
size_t max_retries_count,
175+
size_t max_client_response_size)
168176
{
169177
std::map<std::string, std::string> params;
170178
params["tcbVersion"] = reported_tcb;
@@ -180,6 +188,7 @@ namespace ccf::pal::snp
180188
false // No TLS
181189
};
182190
info.max_retries_count = max_retries_count;
191+
info.max_client_response_size = max_client_response_size;
183192

184193
return {info};
185194
}

include/ccf/service/tables/jsengine.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace ccf
1414
{
1515
static constexpr size_t max_heap_bytes = 100 * 1024 * 1024;
1616
static constexpr size_t max_stack_bytes = 1024 * 1024;
17-
static constexpr uint64_t max_execution_time_ms = 1000;
17+
static constexpr uint64_t max_execution_time_ms = 5000;
1818
static constexpr bool log_exception_details = false;
1919
static constexpr bool return_exception_details = false;
2020
static constexpr size_t max_cached_interpreters = 10;

src/common/configuration.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "common/enclave_interface_types.h"
1717
#include "consensus/consensus_types.h"
1818
#include "ds/oversized.h"
19+
#include "http/curl.h"
1920
#include "service/tables/config.h"
2021

2122
#include <optional>
@@ -39,6 +40,8 @@ struct EnclaveConfig
3940
ringbuffer::Offsets* from_enclave_buffer_offsets;
4041

4142
oversized::WriterConfig writer_config = {};
43+
44+
std::shared_ptr<ccf::curl::CurlmLibuvContext> curlm_libuv_context_instance;
4245
};
4346

4447
static constexpr auto node_to_node_interface_name = "node_to_node_interface";

src/enclave/main.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,14 @@ extern "C"
8181
auto ringbuffer_logger = new_logger.get();
8282
ccf::logger::config::loggers().push_back(std::move(new_logger));
8383

84+
if (ec.curlm_libuv_context_instance == nullptr)
85+
{
86+
LOG_FAIL_FMT("CurlmLibuvContext instance is null");
87+
return CreateNodeStatus::EnclaveInitFailed;
88+
}
89+
ccf::curl::CurlmLibuvContextSingleton::set_instance(
90+
ec.curlm_libuv_context_instance);
91+
8492
{
8593
auto ccf_version_string = std::string(ccf::ccf_version);
8694
if (ccf_version_string.size() > enclave_version_size)

src/host/main.cpp

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,11 @@ int main(int argc, char** argv) // NOLINT(bugprone-exception-escape)
537537
rpc_udp->behaviour.register_udp_message_handlers(
538538
buffer_processor.get_dispatcher());
539539

540+
// Initialise the curlm singleton
541+
curl_global_init(CURL_GLOBAL_DEFAULT);
542+
auto curl_libuv_context =
543+
ccf::curl::CurlmLibuvContextSingleton(uv_default_loop());
544+
540545
ResolvedAddresses resolved_rpc_addresses;
541546
for (auto& [name, interface] : config.network.rpc_interfaces)
542547
{
@@ -602,6 +607,9 @@ int main(int argc, char** argv) // NOLINT(bugprone-exception-escape)
602607

603608
enclave_config.writer_config = writer_config;
604609

610+
enclave_config.curlm_libuv_context_instance =
611+
curl_libuv_context.get_context();
612+
605613
ccf::StartupConfig startup_config(config);
606614

607615
if (startup_config.attestation.snp_security_policy_file.has_value())
@@ -1010,25 +1018,38 @@ int main(int argc, char** argv) // NOLINT(bugprone-exception-escape)
10101018

10111019
process_launcher.stop();
10121020

1013-
// Continue running the loop long enough for the on_close
1014-
// callbacks to be despatched, so as to avoid memory being
1015-
// leaked by handles. Capped out of abundance of caution.
1016-
constexpr size_t max_iterations = 1000;
1017-
size_t close_iterations = max_iterations;
1018-
while ((uv_loop_alive(uv_default_loop()) != 0) && (close_iterations > 0))
1021+
constexpr size_t max_close_iterations = 1000;
1022+
size_t close_iterations = max_close_iterations;
1023+
int loop_close_rc = 0;
1024+
while (close_iterations > 0)
10191025
{
1026+
loop_close_rc = uv_loop_close(uv_default_loop());
1027+
if (loop_close_rc != UV_EBUSY)
1028+
{
1029+
break;
1030+
}
10201031
uv_run(uv_default_loop(), UV_RUN_NOWAIT);
1021-
close_iterations--;
1032+
--close_iterations;
1033+
std::this_thread::sleep_for(10ms);
10221034
}
10231035
LOG_INFO_FMT(
1024-
"Ran an extra {} cleanup iteration(s)", max_iterations - close_iterations);
1025-
1026-
auto loop_close_rc = uv_loop_close(uv_default_loop());
1036+
"Ran an extra {} cleanup iteration(s)",
1037+
max_close_iterations - close_iterations);
10271038
if (loop_close_rc != 0)
10281039
{
10291040
LOG_FAIL_FMT(
10301041
"Failed to close uv loop cleanly: {}", uv_err_name(loop_close_rc));
1042+
// walk loop to diagnose unclosed handles
1043+
auto cb = [](uv_handle_t* handle, void* arg) {
1044+
(void)arg;
1045+
LOG_FAIL_FMT(
1046+
"Leaked handle: type={}, ptr={}",
1047+
uv_handle_type_name(handle->type),
1048+
fmt::ptr(handle));
1049+
};
1050+
uv_walk(uv_default_loop(), cb, nullptr);
10311051
}
1052+
curl_global_cleanup();
10321053
ccf::crypto::openssl_sha256_shutdown();
10331054

10341055
return loop_close_rc;

src/host/proxy.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace asynchost
2525
{
2626
raw = new T(std::forward<Args>(args)...);
2727
}
28+
close_ptr(T* that) : raw(that) {}
2829

2930
~close_ptr()
3031
{
@@ -56,6 +57,7 @@ namespace asynchost
5657
proxy_ptr(const proxy_ptr<T>& that) : internal(that.internal) {}
5758
proxy_ptr(proxy_ptr<T>&& that) : internal(std::move(that.internal)) {}
5859
proxy_ptr(std::nullptr_t that) : internal(that) {}
60+
proxy_ptr(T* that) : internal(std::make_shared<close_ptr<T>>(that)) {}
5961

6062
template <typename... Args>
6163
proxy_ptr(Args&&... args) :

0 commit comments

Comments
 (0)