From 7faf1501ea85c9bd33d7f2dee67716fafd087a2c Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Tue, 15 Oct 2024 13:36:15 +0000 Subject: [PATCH] mixclient: Avoid jitter calculation panic rand.Duration may not be called with a negative or zero upper bound, but this was seen to occur in (*Client).prDelay(). Two notable possible bugs stood out. First, if sendBefore is exactly equal to now, then it will not be incremented by another epoch duration, leading to a potential invalid rand.Duration parameter. This is corrected by also checking for the times equaling exactly. Second, time.Until() causes an additional call to time.Now(), which we have already fetched and all calculations must be based on it. If sendBefore.Sub(now) is an extremely small value, it is possible that time.Until(sendBefore) now returns a small negative or zero duration. This is corrected by replacing the time.Until call with sendBefore.Sub(now). --- mixing/mixclient/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mixing/mixclient/client.go b/mixing/mixclient/client.go index ff6fac9f8..1bac640d5 100644 --- a/mixing/mixclient/client.go +++ b/mixing/mixclient/client.go @@ -516,11 +516,11 @@ func (c *Client) prDelay(ctx context.Context, p *peer) error { sendBefore := epoch.Add(-timeoutDuration - maxJitter) sendAfter := epoch.Add(timeoutDuration) var wait time.Duration - if now.After(sendBefore) { + if now.Equal(sendBefore) || now.After(sendBefore) { wait = sendAfter.Sub(now) sendBefore = sendBefore.Add(c.epoch) } - wait += p.msgJitter() + rand.Duration(time.Until(sendBefore)) + wait += p.msgJitter() + rand.Duration(sendBefore.Sub(now)) timer := time.NewTimer(wait) select { case <-ctx.Done():