You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Should StreamMuxerBox track how many "active" substreams are still around? #2865
Whilst thinking about #2863, I noticed that it is very easy to (accidentally) circumvent the limit on inbound substreams by "leaking" them to the ConnectionHandler. We do this in various places within rust-libp2p and I am sure it happens in within code-bases of ours users too.
StreamMuxerBox already boxes up each substream as a SubstreamBox. We could extend SubstreamBox with a Weak<()> where StreamMuxerBox owns the corresponding Arc<>. This would make Arc::weak_count effectively be the count of all active (i.e. not dropped) substreams the muxer has given out.
Within Connection, we know about StreamMuxerBox so we could expose functions on it to give us the current count of active inbound and outbound streams, which would allow us to actually enforce a limit on those.
Motivation
Not limiting the number of inbound streams can cause unexpected memory and CPU growth and in the worst case, is exploitable via a DoS attack.
Downsides
Rolling out this change may negatively affect users because they will suddenly experience a limit where there wasn't one before.
Current Implementation
Are you planning to do it yourself in a pull request?
changed the title [-]RFC: Have `StreamMuxerBox` track how many "active" substreams are still around[/-][+]Should `StreamMuxerBox` track how many "active" substreams are still around?[/+]on Sep 2, 2022
I like the idea. Though instead of using the Arc::weak_count to enforce a limit, I suggest using it to build a Prometheus metric. I would imagine a Connection emits an event whenever a new stream is created. That event would as well contain the overall count of streams on that connection.
I am against using Arc::weak_count as a limit as I find it unintuitive. We pass ownership of the stream to the ConnectionHandler implementation, thus I think it is the ConnectionHandler that has to manage the resource impact.
I like the idea. Though instead of using the Arc::weak_count to enforce a limit, I suggest using it to build a Prometheus metric. I would imagine a Connection emits an event whenever a new stream is created. That event would as well contain the overall count of streams on that connection.
I am against using Arc::weak_count as a limit as I find it unintuitive. We pass ownership of the stream to the ConnectionHandler implementation, thus I think it is the ConnectionHandler that has to manage the resource impact.
The issue I see with that is that we don't know, when a stream is de-allocated unless we use some kind of shared, atomic counter that is decremented on Drop. Once we pass the stream to the ConnectionHandler, we lose control over it.
The implementation will return Arc::weak_count of an Arc that is embedded in every SubstreamBox and thus happen transparently for each muxer. What clients like swarm::Connection do with this information is up to them and not further defined in this issue. We can of course implement a metric on top of that.
The motivation for this issue was to use it in swarm::Connection as the guard for calling StreamMuxer::poll_inbound which should be more robust than the current implementation which only enforces how many substreams are concurrently upgrading. If a protocol does not perform its IO in the InboundUpgrade trait but passes the substream to the ConnectionHandler, this limit is by-passed.
I noticed that we are unnecessarily exposing the SubstreamBox::new API publicly which is currently used in a test in libp2p-swarm. That test changes with #2861 though so I am planning to remove the SubstreamBox::new API in order to not unnecessarily expose the implementation detail of tracking active streams via Arcs.
Activity
thomaseizinger commentedon Sep 2, 2022
Tagging as "help wanted" because I'd like to get people's input on this idea.
[-]RFC: Have `StreamMuxerBox` track how many "active" substreams are still around[/-][+]Should `StreamMuxerBox` track how many "active" substreams are still around?[/+]mxinden commentedon Sep 6, 2022
I like the idea. Though instead of using the
Arc::weak_countto enforce a limit, I suggest using it to build a Prometheus metric. I would imagine aConnectionemits an event whenever a new stream is created. That event would as well contain the overall count of streams on that connection.I am against using
Arc::weak_countas a limit as I find it unintuitive. We pass ownership of the stream to theConnectionHandlerimplementation, thus I think it is theConnectionHandlerthat has to manage the resource impact.thomaseizinger commentedon Sep 6, 2022
The issue I see with that is that we don't know, when a stream is de-allocated unless we use some kind of shared, atomic counter that is decremented on
Drop. Once we pass the stream to theConnectionHandler, we lose control over it.mxinden commentedon Sep 8, 2022
I think my comment was misleading @thomaseizinger. Let me rephrase:
I am against using
Arc::weak_countas a limit. I am in favor of usingArc::weak_countfor metrics.Sorry. Is the second attempt more clear?
thomaseizinger commentedon Sep 8, 2022
Sort of. I wouldn't know how to enforce a limit via
Arc::weak_count?What I am proposing in this issue is to use expose functions on
StreamMuxerBox:The implementation will return
Arc::weak_countof anArcthat is embedded in everySubstreamBoxand thus happen transparently for each muxer. What clients likeswarm::Connectiondo with this information is up to them and not further defined in this issue. We can of course implement a metric on top of that.The motivation for this issue was to use it in
swarm::Connectionas the guard for callingStreamMuxer::poll_inboundwhich should be more robust than the current implementation which only enforces how many substreams are concurrently upgrading. If a protocol does not perform its IO in theInboundUpgradetrait but passes the substream to theConnectionHandler, this limit is by-passed.thomaseizinger commentedon Sep 8, 2022
Draft implementation here: #2878
I noticed that we are unnecessarily exposing the
SubstreamBox::newAPI publicly which is currently used in a test inlibp2p-swarm. That test changes with #2861 though so I am planning to remove theSubstreamBox::newAPI in order to not unnecessarily expose the implementation detail of tracking active streams viaArcs.