ipcz: Validate new router sublinks
This fixes a bug where it was possible to craft a parcel which routes
itself to one of its own attached routers, thus creating an unreachable
circular Router reference and leaking memory.
Fixed: 380927241
Change-Id: I5263f9cf808028aa31fd7bcad6cc140fc2d865c3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6055325
Commit-Queue: Ken Rockot <rockot@google.com>
Reviewed-by: Alex Gough <ajgo@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1389513}
NOKEYCHECK=True
GitOrigin-RevId: 45f8235319dfbe42eddbf363526e5a9e7e240afb
diff --git a/src/ipcz/node_link.cc b/src/ipcz/node_link.cc
index 0a6ea32..250cd25 100644
--- a/src/ipcz/node_link.cc
+++ b/src/ipcz/node_link.cc
@@ -528,6 +528,7 @@
accept.GetArrayView<HandleType>(accept.v0()->handle_types);
absl::Span<const RouterDescriptor> new_routers =
accept.GetArrayView<RouterDescriptor>(accept.v0()->new_routers);
+ const SublinkId for_sublink = accept.v0()->sublink;
auto driver_objects = accept.driver_objects();
// Note that on any validation failure below, we defer rejection at least
@@ -544,7 +545,8 @@
continue;
}
- Ref<Router> new_router = Router::Deserialize(new_routers[0], *this);
+ Ref<Router> new_router =
+ Router::Deserialize(new_routers[0], *this, for_sublink);
if (!new_router) {
parcel_valid = false;
continue;
@@ -597,7 +599,6 @@
return false;
}
- const SublinkId for_sublink = accept.v0()->sublink;
auto parcel = std::make_unique<Parcel>(accept.v0()->sequence_number);
parcel->set_num_subparcels(num_subparcels);
parcel->set_subparcel_index(subparcel_index);
diff --git a/src/ipcz/router.cc b/src/ipcz/router.cc
index bcd1970..a84f055 100644
--- a/src/ipcz/router.cc
+++ b/src/ipcz/router.cc
@@ -700,7 +700,21 @@
// static
Ref<Router> Router::Deserialize(const RouterDescriptor& descriptor,
- NodeLink& from_node_link) {
+ NodeLink& from_node_link,
+ SublinkId receiving_sublink) {
+ std::optional<SublinkId> new_decaying_sublink;
+ if (descriptor.proxy_already_bypassed) {
+ new_decaying_sublink = descriptor.new_decaying_sublink;
+ }
+
+ if (descriptor.new_sublink == receiving_sublink ||
+ descriptor.new_sublink == new_decaying_sublink ||
+ new_decaying_sublink == receiving_sublink) {
+ // New sublink IDs must be unique among each other, and must not identify
+ // the new Router as its own recipient.
+ return nullptr;
+ }
+
auto router = MakeRefCounted<Router>();
Ref<RemoteRouterLink> new_outward_link;
{
@@ -721,7 +735,7 @@
}
}
- if (descriptor.proxy_already_bypassed) {
+ if (new_decaying_sublink) {
// When split from a local peer, our remote counterpart (our remote peer's
// former local peer) will use this link to forward parcels it already
// received from our peer. This link decays like any other decaying link
@@ -732,9 +746,9 @@
// The sequence length from the link is whatever had already been sent
// to our counterpart back on the peer's node.
Ref<RemoteRouterLink> new_decaying_link =
- from_node_link.AddRemoteRouterLink(
- descriptor.new_decaying_sublink, nullptr,
- LinkType::kPeripheralOutward, LinkSide::kB, router);
+ from_node_link.AddRemoteRouterLink(*new_decaying_sublink, nullptr,
+ LinkType::kPeripheralOutward,
+ LinkSide::kB, router);
if (!new_decaying_link) {
return nullptr;
}
@@ -766,7 +780,7 @@
<< from_node_link.remote_node_name().ToString() << " to "
<< from_node_link.local_node_name().ToString() << " via sublink "
<< descriptor.new_sublink << " and decaying sublink "
- << descriptor.new_decaying_sublink;
+ << *new_decaying_sublink;
} else {
if (!descriptor.new_link_state_fragment.is_null()) {
// No RouterLinkState fragment should be provided for this new
diff --git a/src/ipcz/router.h b/src/ipcz/router.h
index 5d414d5..3c537f4 100644
--- a/src/ipcz/router.h
+++ b/src/ipcz/router.h
@@ -168,9 +168,11 @@
// via Put or Get APIs.
IpczResult MergeRoute(const Ref<Router>& other);
- // Deserializes a new Router from `descriptor` received over `from_node_link`.
+ // Deserializes a new Router from `descriptor` received over `from_node_link`
+ // on `receiving_sublink`.
static Ref<Router> Deserialize(const RouterDescriptor& descriptor,
- NodeLink& from_node_link);
+ NodeLink& from_node_link,
+ SublinkId receiving_sublink);
// Serializes a description of a new Router which will be used to extend this
// Router's route across `to_node_link` by introducing a new Router on the