mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
Fix critical security vulnerability and state-machine wedge in BwuManager.
PiperOrigin-RevId: 923367474
This commit is contained in:
committed by
Copybara-Service
parent
7c31996db2
commit
54c155389c
@@ -572,9 +572,19 @@ void BwuManager::OnBwuNegotiationFrame(
|
||||
OperationResultCode::NEARBY_GENERIC_REMOTE_UPGRADE_FAILURE);
|
||||
break;
|
||||
case BandwidthUpgradeNegotiationFrame::LAST_WRITE_TO_PRIOR_CHANNEL:
|
||||
if (!in_progress_upgrades_.contains(endpoint_id)) {
|
||||
LOG(ERROR) << "Received LAST_WRITE_TO_PRIOR_CHANNEL for endpoint "
|
||||
<< endpoint_id << " but no upgrade is in progress.";
|
||||
return;
|
||||
}
|
||||
ProcessLastWriteToPriorChannelEvent(client, endpoint_id);
|
||||
break;
|
||||
case BandwidthUpgradeNegotiationFrame::SAFE_TO_CLOSE_PRIOR_CHANNEL:
|
||||
if (!in_progress_upgrades_.contains(endpoint_id)) {
|
||||
LOG(ERROR) << "Received SAFE_TO_CLOSE_PRIOR_CHANNEL for endpoint "
|
||||
<< endpoint_id << " but no upgrade is in progress.";
|
||||
return;
|
||||
}
|
||||
ProcessSafeToClosePriorChannelEvent(client, endpoint_id);
|
||||
break;
|
||||
default:
|
||||
@@ -1205,9 +1215,8 @@ void BwuManager::ProcessLastWriteToPriorChannelEvent(
|
||||
// loss). But now that we've received this definitive final write over that
|
||||
// prior EndpointChannel, we can let the remote device that they can safely
|
||||
// close their end of this now-dormant EndpointChannel.
|
||||
EndpointChannel* previous_endpoint_channel =
|
||||
previous_endpoint_channels_[endpoint_id].get();
|
||||
if (!previous_endpoint_channel) {
|
||||
auto it = previous_endpoint_channels_.find(endpoint_id);
|
||||
if (it == previous_endpoint_channels_.end()) {
|
||||
LOG(ERROR)
|
||||
<< "BwuManager received a BWU_NEGOTIATION.LAST_WRITE_TO_PRIOR_CHANNEL "
|
||||
"OfflineFrame for unknown endpoint "
|
||||
@@ -1215,6 +1224,12 @@ void BwuManager::ProcessLastWriteToPriorChannelEvent(
|
||||
successfully_upgraded_endpoints_.emplace(endpoint_id);
|
||||
return;
|
||||
}
|
||||
EndpointChannel* previous_endpoint_channel = it->second.get();
|
||||
if (!previous_endpoint_channel) {
|
||||
LOG(ERROR) << "previous_endpoint_channel is null for endpoint "
|
||||
<< endpoint_id;
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(INFO) << "ProcessLastWriteToPriorChannelEvent: service_id="
|
||||
<< previous_endpoint_channel->GetServiceId()
|
||||
@@ -1267,6 +1282,13 @@ void BwuManager::ProcessSafeToClosePriorChannelEvent(
|
||||
// or not (as is the case with Android's Bluetooth sockets, where closing
|
||||
// instantly throws an IOException on the remote device).
|
||||
auto item = previous_endpoint_channels_.extract(endpoint_id);
|
||||
if (item.empty()) {
|
||||
LOG(ERROR)
|
||||
<< "BwuManager received a BWU_NEGOTIATION.SAFE_TO_CLOSE_PRIOR_CHANNEL "
|
||||
"OfflineFrame for unknown endpoint "
|
||||
<< endpoint_id << ", can't complete the upgrade protocol.";
|
||||
return;
|
||||
}
|
||||
auto& previous_endpoint_channel = item.mapped();
|
||||
if (previous_endpoint_channel == nullptr) {
|
||||
LOG(ERROR)
|
||||
|
||||
@@ -1089,6 +1089,91 @@ TEST_F(BwuManagerTest, BlockBwuFrameFromAdvertiser) {
|
||||
UnRegisterChannelForEndpoint(kEndpointId2);
|
||||
}
|
||||
|
||||
TEST_F(BwuManagerTest, ReceiveUnexpectedSafeToClose_NoCrash) {
|
||||
ExceptionOr<OfflineFrame> safe_to_close_frame =
|
||||
parser::FromBytes(parser::ForBwuSafeToClose());
|
||||
bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(),
|
||||
std::string(kEndpointId1), &client_,
|
||||
Medium::BLUETOOTH);
|
||||
}
|
||||
|
||||
TEST_F(BwuManagerTest, ReceiveUnexpectedLastWrite_NoCrashOrWedge) {
|
||||
ExceptionOr<OfflineFrame> last_write_frame =
|
||||
parser::FromBytes(parser::ForBwuLastWrite());
|
||||
bwu_manager_->OnIncomingFrame(last_write_frame.result(),
|
||||
std::string(kEndpointId1), &client_,
|
||||
Medium::BLUETOOTH);
|
||||
}
|
||||
|
||||
TEST_F(BwuManagerTest, ReceiveEarlyLastWrite_Success) {
|
||||
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
|
||||
std::shared_ptr<EndpointChannel> shared_initial_channel =
|
||||
ecm_.GetChannelForEndpoint(std::string(kEndpointId1));
|
||||
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WEB_RTC);
|
||||
ASSERT_TRUE(bwu_manager_->IsUpgradeOngoing(std::string(kEndpointId1)));
|
||||
|
||||
ExceptionOr<OfflineFrame> last_write_frame =
|
||||
parser::FromBytes(parser::ForBwuLastWrite());
|
||||
bwu_manager_->OnIncomingFrame(last_write_frame.result(),
|
||||
std::string(kEndpointId1), &client_,
|
||||
Medium::BLUETOOTH);
|
||||
|
||||
FakeEndpointChannel* upgraded_channel =
|
||||
fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection(
|
||||
/*initialize_call_index=*/0u, bwu_manager_.get());
|
||||
|
||||
ExceptionOr<OfflineFrame> safe_to_close_frame =
|
||||
parser::FromBytes(parser::ForBwuSafeToClose());
|
||||
bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(),
|
||||
std::string(kEndpointId1), &client_,
|
||||
Medium::BLUETOOTH);
|
||||
|
||||
auto old_channel =
|
||||
dynamic_cast<FakeEndpointChannel*>(shared_initial_channel.get());
|
||||
EXPECT_FALSE(upgraded_channel->IsPaused());
|
||||
EXPECT_TRUE(old_channel->is_closed());
|
||||
EXPECT_EQ(location::nearby::proto::connections::DisconnectionReason::UPGRADED,
|
||||
old_channel->disconnection_reason());
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
}
|
||||
|
||||
TEST_F(BwuManagerTest, ReceiveUnexpectedLastWriteBeforeUpgrade_NoWedge) {
|
||||
ExceptionOr<OfflineFrame> last_write_frame =
|
||||
parser::FromBytes(parser::ForBwuLastWrite());
|
||||
bwu_manager_->OnIncomingFrame(last_write_frame.result(),
|
||||
std::string(kEndpointId1), &client_,
|
||||
Medium::BLUETOOTH);
|
||||
|
||||
CreateInitialEndpoint(&client_, kServiceIdA, kEndpointId1, Medium::BLUETOOTH);
|
||||
std::shared_ptr<EndpointChannel> shared_initial_channel =
|
||||
ecm_.GetChannelForEndpoint(std::string(kEndpointId1));
|
||||
|
||||
bwu_manager_->InitiateBwuForEndpoint(&client_, std::string(kEndpointId1),
|
||||
Medium::WEB_RTC);
|
||||
|
||||
FakeEndpointChannel* upgraded_channel =
|
||||
fake_web_rtc_bwu_handler_->NotifyBwuManagerOfIncomingConnection(
|
||||
/*initialize_call_index=*/0u, bwu_manager_.get());
|
||||
|
||||
bwu_manager_->OnIncomingFrame(last_write_frame.result(),
|
||||
std::string(kEndpointId1), &client_,
|
||||
Medium::BLUETOOTH);
|
||||
|
||||
ExceptionOr<OfflineFrame> safe_to_close_frame =
|
||||
parser::FromBytes(parser::ForBwuSafeToClose());
|
||||
bwu_manager_->OnIncomingFrame(safe_to_close_frame.result(),
|
||||
std::string(kEndpointId1), &client_,
|
||||
Medium::BLUETOOTH);
|
||||
|
||||
auto old_channel =
|
||||
dynamic_cast<FakeEndpointChannel*>(shared_initial_channel.get());
|
||||
EXPECT_FALSE(upgraded_channel->IsPaused());
|
||||
EXPECT_TRUE(old_channel->is_closed());
|
||||
UnRegisterChannelForEndpoint(kEndpointId1);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(BwuManagerTestParam, BwuManagerTestParam,
|
||||
testing::Bool());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user