Skip to content

Commit 19dcf98

Browse files
authored
udp_proxy_filter: Fix crash when accepting dynamic cds for UDP. Fixes #34195. (#37151)
Please see #34195 and #26206 for details. This change fixes a usage of cluster info resource after the udp cluster be destroyed. I've got an approval from envoy-security list for the fix. Risk Level: Low Testing: mentioned in both tickets Docs Changes: N/A --------- Signed-off-by: sinxccc <[email protected]>
1 parent 6878af7 commit 19dcf98

File tree

3 files changed

+29
-22
lines changed

3 files changed

+29
-22
lines changed

source/extensions/filters/udp/udp_proxy/udp_proxy_filter.cc

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ PerPacketLoadBalancingUdpProxyFilter::onDataInternal(Network::UdpRecvData& data)
133133
auto host = cluster->chooseHost(data.addresses_.peer_, nullptr);
134134
if (host == nullptr) {
135135
ENVOY_LOG(debug, "cannot find any valid host.");
136-
cluster->cluster_.info()->trafficStats()->upstream_cx_none_healthy_.inc();
136+
cluster->cluster_info_->trafficStats()->upstream_cx_none_healthy_.inc();
137137
return Network::FilterStatus::StopIteration;
138138
}
139139

@@ -204,7 +204,7 @@ void UdpProxyFilter::removeSession(ActiveSession* session) {
204204
UdpProxyFilter::ClusterInfo::ClusterInfo(UdpProxyFilter& filter,
205205
Upstream::ThreadLocalCluster& cluster,
206206
absl::flat_hash_set<ActiveSession*>&& sessions)
207-
: filter_(filter), cluster_(cluster),
207+
: filter_(filter), cluster_(cluster), cluster_info_(cluster.info()),
208208
cluster_stats_(generateStats(cluster.info()->statsScope())), sessions_(std::move(sessions)),
209209
member_update_cb_handle_(cluster.prioritySet().addMemberUpdateCb(
210210
[this](const Upstream::HostVector&, const Upstream::HostVector& hosts_removed) {
@@ -269,7 +269,7 @@ UdpProxyFilter::createSession(Network::UdpRecvData::LocalPeerAddresses&& address
269269
auto host = cluster->chooseHost(addresses.peer_, nullptr);
270270
if (host == nullptr) {
271271
ENVOY_LOG(debug, "cannot find any valid host.");
272-
cluster->cluster_.info()->trafficStats()->upstream_cx_none_healthy_.inc();
272+
cluster->cluster_info_->trafficStats()->upstream_cx_none_healthy_.inc();
273273
return nullptr;
274274
}
275275

@@ -345,8 +345,7 @@ void UdpProxyFilter::ActiveSession::onSessionComplete() {
345345

346346
filter_.config_->stats().downstream_sess_active_.dec();
347347
if (cluster_connections_inc_) {
348-
cluster_->cluster_.info()
349-
->resourceManager(Upstream::ResourcePriority::Default)
348+
cluster_->cluster_info_->resourceManager(Upstream::ResourcePriority::Default)
350349
.connections()
351350
.dec();
352351
}
@@ -385,7 +384,7 @@ void UdpProxyFilter::ActiveSession::fillSessionStreamInfo() {
385384
ProtobufWkt::Struct stats_obj;
386385
auto& fields_map = *stats_obj.mutable_fields();
387386
if (cluster_ != nullptr) {
388-
fields_map["cluster_name"] = ValueUtil::stringValue(cluster_->cluster_.info()->name());
387+
fields_map["cluster_name"] = ValueUtil::stringValue(cluster_->cluster_info_->name());
389388
}
390389
fields_map["bytes_sent"] = ValueUtil::numberValue(session_stats_.downstream_sess_tx_bytes_);
391390
fields_map["bytes_received"] = ValueUtil::numberValue(session_stats_.downstream_sess_rx_bytes_);
@@ -551,7 +550,7 @@ void UdpProxyFilter::UdpActiveSession::writeUpstream(Network::UdpRecvData& data)
551550
cluster_->cluster_stats_.sess_tx_errors_.inc();
552551
} else {
553552
cluster_->cluster_stats_.sess_tx_datagrams_.inc();
554-
cluster_->cluster_.info()->trafficStats()->upstream_cx_tx_bytes_total_.add(tx_buffer_length);
553+
cluster_->cluster_info_->trafficStats()->upstream_cx_tx_bytes_total_.add(tx_buffer_length);
555554
}
556555
}
557556

@@ -592,7 +591,7 @@ bool UdpProxyFilter::UdpActiveSession::createUpstream() {
592591
host_ = cluster_->chooseHost(addresses_.peer_, &udp_session_info_);
593592
if (host_ == nullptr) {
594593
ENVOY_LOG(debug, "cannot find any valid host.");
595-
cluster_->cluster_.info()->trafficStats()->upstream_cx_none_healthy_.inc();
594+
cluster_->cluster_info_->trafficStats()->upstream_cx_none_healthy_.inc();
596595
return false;
597596
}
598597
}
@@ -687,7 +686,7 @@ void UdpProxyFilter::UdpActiveSession::processPacket(
687686
host_ != nullptr ? host_->address()->asStringView() : "unknown");
688687

689688
cluster_->cluster_stats_.sess_rx_datagrams_.inc();
690-
cluster_->cluster_.info()->trafficStats()->upstream_cx_rx_bytes_total_.add(rx_buffer_length);
689+
cluster_->cluster_info_->trafficStats()->upstream_cx_rx_bytes_total_.add(rx_buffer_length);
691690

692691
Network::UdpRecvData recv_data{{std::move(local_address), std::move(peer_address)},
693692
std::move(buffer),
@@ -784,20 +783,16 @@ bool UdpProxyFilter::ActiveSession::setClusterInfo() {
784783
return false;
785784
}
786785

787-
if (!cluster_->cluster_.info()
788-
->resourceManager(Upstream::ResourcePriority::Default)
786+
if (!cluster_->cluster_info_->resourceManager(Upstream::ResourcePriority::Default)
789787
.connections()
790788
.canCreate()) {
791789
ENVOY_LOG(debug, "cannot create new connection.");
792790
udp_session_info_.setResponseFlag(StreamInfo::CoreResponseFlag::UpstreamOverflow);
793-
cluster_->cluster_.info()->trafficStats()->upstream_cx_overflow_.inc();
791+
cluster_->cluster_info_->trafficStats()->upstream_cx_overflow_.inc();
794792
return false;
795793
}
796794

797-
cluster_->cluster_.info()
798-
->resourceManager(Upstream::ResourcePriority::Default)
799-
.connections()
800-
.inc();
795+
cluster_->cluster_info_->resourceManager(Upstream::ResourcePriority::Default).connections().inc();
801796

802797
cluster_connections_inc_ = true;
803798
return true;
@@ -1003,21 +998,20 @@ bool UdpProxyFilter::TunnelingActiveSession::createConnectionPool() {
1003998

1004999
// Check this here because the TCP conn pool will queue our request waiting for a connection that
10051000
// will never be released.
1006-
if (!cluster_->cluster_.info()
1007-
->resourceManager(Upstream::ResourcePriority::Default)
1001+
if (!cluster_->cluster_info_->resourceManager(Upstream::ResourcePriority::Default)
10081002
.connections()
10091003
.canCreate()) {
10101004
udp_session_info_.setResponseFlag(StreamInfo::CoreResponseFlag::UpstreamOverflow);
1011-
cluster_->cluster_.info()->trafficStats()->upstream_cx_overflow_.inc();
1005+
cluster_->cluster_info_->trafficStats()->upstream_cx_overflow_.inc();
10121006
return false;
10131007
}
10141008

10151009
if (connect_attempts_ >= filter_.config_->tunnelingConfig()->maxConnectAttempts()) {
10161010
udp_session_info_.setResponseFlag(StreamInfo::CoreResponseFlag::UpstreamRetryLimitExceeded);
1017-
cluster_->cluster_.info()->trafficStats()->upstream_cx_connect_attempts_exceeded_.inc();
1011+
cluster_->cluster_info_->trafficStats()->upstream_cx_connect_attempts_exceeded_.inc();
10181012
return false;
10191013
} else if (connect_attempts_ >= 1) {
1020-
cluster_->cluster_.info()->trafficStats()->upstream_rq_retry_.inc();
1014+
cluster_->cluster_info_->trafficStats()->upstream_rq_retry_.inc();
10211015
}
10221016

10231017
conn_pool_ = conn_pool_factory_->createConnPool(cluster_->cluster_, load_balancer_context_.get(),
@@ -1170,7 +1164,7 @@ void UdpProxyFilter::TunnelingActiveSession::onUpstreamData(Buffer::Instance& da
11701164

11711165
ASSERT(cluster_);
11721166
cluster_->cluster_stats_.sess_rx_datagrams_.inc();
1173-
cluster_->cluster_.info()->trafficStats()->upstream_cx_rx_bytes_total_.add(rx_buffer_length);
1167+
cluster_->cluster_info_->trafficStats()->upstream_cx_rx_bytes_total_.add(rx_buffer_length);
11741168
resetIdleTimer();
11751169

11761170
Network::UdpRecvData recv_data{{addresses_.local_, addresses_.peer_},

source/extensions/filters/udp/udp_proxy/udp_proxy_filter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,7 @@ class UdpProxyFilter : public Network::UdpListenerReadFilter,
862862

863863
UdpProxyFilter& filter_;
864864
Upstream::ThreadLocalCluster& cluster_;
865+
Upstream::ClusterInfoConstSharedPtr cluster_info_;
865866
UdpProxyUpstreamStats cluster_stats_;
866867
absl::flat_hash_set<ActiveSession*> sessions_;
867868

test/extensions/filters/udp/udp_proxy/udp_proxy_filter_test.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,18 @@ stat_prefix: foo
927927
expectSessionCreate(upstream_address_);
928928
test_sessions_[0].expectWriteToUpstream("hello", 0, nullptr, true);
929929
recvDataFromDownstream("10.0.0.1:1000", "10.0.0.2:80", "hello");
930+
931+
// Push a new cluster again, we expect this to trigger active session removal.
932+
{
933+
NiceMock<Upstream::MockThreadLocalCluster> other_thread_local_cluster;
934+
other_thread_local_cluster.cluster_.info_->name_ = "fake_cluster";
935+
Upstream::ThreadLocalClusterCommand command =
936+
[&other_thread_local_cluster]() -> Upstream::ThreadLocalCluster& {
937+
return other_thread_local_cluster;
938+
};
939+
cluster_update_callbacks_->onClusterAddOrUpdate(other_thread_local_cluster.info()->name(),
940+
command);
941+
}
930942
}
931943

932944
// Hitting the maximum per-cluster connection/session circuit breaker.

0 commit comments

Comments
 (0)