#37148 [BC-Insight] `wantedPeerDials()` branch will never be executed
Submitted on Nov 26th 2024 at 19:59:03 UTC by @br0nz3p1ck4x3 for Attackathon | Ethereum Protocol
Report ID: #37148
Report Type: Blockchain/DLT
Report severity: Insight
Target: https://github.com/prysmaticlabs/prysm
Impacts:
(Specifications) A bug in specifications with no direct impact on client implementations
Description
Hey Triagers, Ethereum Foundation, Prysm!
We encountered the following during our research and we think it can add value to the Prysm team.
Description
Inside prysm/beacon-chain/p2p/discovery.go::listenForNodes() we can find the following:
func (s *Service) listenForNewNodes() {
//..
if s.isPeerAtLimit(false /* inbound */) {
// Pause the main loop for a period to stop looking
// for new peers.
log.Trace("Not looking for peers, at peer limit")
time.Sleep(pollingPeriod)
continue
}
wantedCount := s.wantedPeerDials()
if wantedCount == 0 {
log.Trace("Not looking for peers, at peer limit")
time.Sleep(pollingPeriod)
continue
}
//..
}There is a problem here though in the logic.
To showcase this, we will first explain it with arbitrary values. After reading this, please run the Proof of Concept attached to the report.
Alright.
If we look at isPeerAtLimit(), we see the following:
Let's take the following arbitrary values that maximize the numbers such that the return statement will return true:
numOfConns = 9maxPeers = 10activePeers = 9
These values will evaluate to true in this return statement:
activePeers >= maxPeers || numOfConns >= maxPeers
Now, we go back to listenForNewNodes():
Now, wantedPeerDials() is called. If we look at the implementation:
The problem here is the following if-statement:
if maxPeers > activePeers {
As we saw in isPeerAtLimit(), which was called before wantedPeerDials(), maxPeers will always be bigger than activePeers. If it was not bigger than activePeers, it would enter the if-statement and continue:
Thus, wantedPeerDials() will always return a non-nil value and thus, this if-statement inside listenForNewNodes() will never be executed:
Proof of Concept
Proof of Concept
cd prysm/beacon-chain/p2pvim discovery_test.goPaste the following test in this file:
Run using:
go test -timeout 30s -run ^TestPoc
The output will be:
As we can see, the only way to get 0wanted peers is for activePeers == maxPeers, but as shown, this can never happen because the for-loop inside listenForNewNodes() will return early because of:
Recommended Patch
Consider removing the wantedPeerDials() usage since it can not be invoked right now.
Was this helpful?