Find the bugThe case of the degrading system
The following code contains a bug, can you spot it?
class Program { private Timer nextcheck; public event EventHandler ServerSigFailed; static void Main(string[] args) { var program = new Program(); if(program.ValidateServerSig() == false) return; program.DoOtherStuff(); } public bool ValidateServerSig() { nextcheck = new Timer(state => ValidateServerSig()); var response = DoRequest("http://remote-srv/signature"); if(response.Failed) { var copy = ServerSigFailed; if(copy!=null) copy(this, EventArgs.Empty); return false; } var result = Utils.CheckPublic KeySignatureMatches(response); if(result.Valid) if(response.Failed) { var copy = ServerSigFailed; if(copy!=null) copy(this, EventArgs.Empty); return false; } // setup next check nextcheck.Change(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); return true; } }
What are the implications of this bug?
More posts in "Find the bug" series:
- (29 Feb 2016) When you can't rely on your own identity
- (05 Jan 2016) The case of the degrading system–Answer
- (04 Jan 2016) The case of the degrading system
- (11 Sep 2015) The concurrent memory buster
- (20 Apr 2011) Why do I get a Null Reference Exception?
- (25 Nov 2010) A broken tree
- (13 Aug 2010) RavenDB HiLo implementation
- (25 Jul 2010) Accidental code reviews

Comments
I am not that familiar with the
System.Threading.Timerclass, but should it not be disposed before being replaced? SincedueTimeandperiodare specified in the call toChange, it looks likeValidateServerSigshould be called every 15 seconds (starting 15s after the call to change) and sinceValidateServerSigalways sets up a new timer when it's called - without ever disposing an existing timer - that could lead to infinite timers as long as the result istrue?Checking for
response.Failedafterresult.Validshould be useless, because the previous check should have ended the method call. I suppose the real check should have been for!result.Valid?Look like the issue with a timer life-cycle. It's being recreated each time. The old instance of timer is not disposed - thus it may fire for a long time (until garbage collected). Additionally the timer is configured to run many times. In this case it should be configured to run once nextcheck.Change(TimeSpan.FromSeconds(15), TimeSpan.FromMilliseconds(-1));
The biggest issue with this code is that ValidateServerSig creates a new timer object to call itself again every 15 seconds. So the initial call will setup the timer, then 15 seconds later it will setup a new timer, then 15 seconds later it will setup 2 new timers (since both the old timers fire), then 15 seconds later it will setup 4 new timers and so on. The system will run out of some sort of resource, possibly network, or outbound ports, or timer kernel objects. CPU and memory will fall as well over since this is an exponential failure, however other failures might prevent the exponential nature of the bug taking full effect. The remote server will be getting dos'd quite nicely.
If the signature is retrieved successfully but is invalid, the method will nonetheless return true, as the conditional logic around
result.validis way off. An attacker may trivially impersonate the remote server.It looks like the bug is that, after the first call to "ValidateServerSig()", there is no checking of the return value for that function. Thus, each time the timer kicks in and executes "ValidateServerSig()", it's a waste of time become nothing is acting on it's return value.
To add to my comment - since nothing checks for "false" after the first time, "ValidateServerSig()" will continue to execute, causing a degrade in system resources.
Adding a new timer every 15 sec
Error in KeySignatureMatches result validation
ServerSigFailed event can be called but nobody will be notified
It will return true, even though CheckPublicKeySignatureMatches result is not Valid. The whole "if(response.Failed)..." will never be called after "if(result.Valid)" since it has already been checked. Unless of course CheckPublicKeySignatureMatches changes "response" which would be idiotic...
One bug not mentioned so far is that timer ticks can be concurrent.
Also there should not be a timer at all. A sleep loop would be much simpler.
Comment preview