/// <summary> /// Start Pipe server /// </summary> /// <param name="connection">Connection</param> public void Start(FuzzerConnectionBase connection) { if (IsStarted) { throw new Exception("Already started"); } try { _cancel = new CancellationTokenSource(); _disposables = new ConcurrentBag <IDisposable>(); if (connection is FuzzerNamedPipeConnection pipe) { _tasks = new Task[5]; _tasks[0] = new Task(() => ProcessLogBagAsync(_cancel.Token)); for (int x = 1; x < _tasks.Length; x++) { _tasks[x] = new Task(() => { var client = new FuzzerClientInfo() { Id = Guid.NewGuid(), Description = "." + pipe.PipeName, InternalName = "." + pipe.PipeName }; while (!_cancel.Token.IsCancellationRequested) { NamedPipeServerStream server = null; try { _cancel.Token.ThrowIfCancellationRequested(); server = new NamedPipeServerStream(pipe.PipeName, PipeDirection.InOut, _tasks.Length, PipeTransmissionMode.Byte); _disposables.Add(server); server.WaitForConnection(); UpdateFromStream(new FuzzerStat <FuzzerClientInfo>(client), server, _cancel.Token); } catch // (Exception ex) { // Pipe error } finally { try { server?.Dispose(); } catch { } _cancel?.Token.ThrowIfCancellationRequested(); } Thread.Sleep(50); } }, _cancel.Token); } } else if (connection is FuzzerTcpConnection tcp) { _tasks = new Task[] { new Task(() => ProcessLogBagAsync(_cancel.Token)), new Task(() => { var server = new TcpListener(tcp.EndPoint); _disposables.Add(server.Server); server.Start(); server.BeginAcceptTcpClient(OnNewTcpClient, server); //var res = server.BeginAcceptTcpClient(OnNewTcpClient, server); //_disposables.Add(res.AsyncWaitHandle); }, _cancel.Token) }; } else { if (connection == null) { throw new NullReferenceException(nameof(connection)); } throw new ArgumentException(nameof(connection)); } _tasks.All(u => { u.Start(); return(true); }); } catch (Exception e) { Stop(); throw e; } }
private void Test(FuzzerConnectionBase serverConnection, FuzzerConnectionBase clientConnection) { Fuzzer.Client.ExecutionTimeOut = TimeSpan.FromMilliseconds(5_000); using (var server = new FuzzerServer()) using (var client = new FuzzerClient()) { // Change name client.PublicName = "TestClient_" + Guid.NewGuid().ToString(); // Ensure no error client.SendLog(null); // Dummy input var entryIBuffer = new byte[100]; RandomHelper.FillWithRandomBytes(entryIBuffer); var entryI = new FuzzerStat <FuzzingInputBase>(new ManualFuzzingInput(entryIBuffer) { Description = "1" }); server.Inputs.Add(entryI.Source.Id, entryI); entryI = new FuzzerStat <FuzzingInputBase>(new RandomFuzzingInput(new FromToValue <long>(100, 200)) { Description = "2" }); server.Inputs.Add(entryI.Source.Id, entryI); // Dummy configurations var entryC = new FuzzerStat <FuzzingConfigBase>(new PatchConfig("1", new PatchChange("1", 1, 1, new byte[0]))); server.Configurations.Add(entryC.Source.Id, entryC); entryC = new FuzzerStat <FuzzingConfigBase>(new PatchConfig("2", new PatchChange("2", 2, 2, new byte[0]))); server.Configurations.Add(entryC.Source.Id, entryC); // Check server CheckConfig(() => ((IRandomValue <FuzzingConfigBase>)server).Get(), server.Configurations.Select(u => u.Value.Source).ToArray()); CheckConfig(() => ((IRandomValue <FuzzingInputBase>)server).Get(), server.Inputs.Select(u => u.Value.Source).ToArray()); CheckConfig(() => server.GetConfig(), server.Configurations.Select(u => u.Value.Source).ToArray()); CheckConfig(() => server.GetInput(), server.Inputs.Select(u => u.Value.Source).ToArray()); // Start Assert.IsFalse(server.IsStarted); Assert.IsFalse(client.IsStarted); if (serverConnection == null && clientConnection == null) { Assert.Catch <NullReferenceException>(() => server.Start(serverConnection)); Assert.Catch <NullReferenceException>(() => client.Start(clientConnection)); return; } else { if (serverConnection is TestDummyConnection && clientConnection is TestDummyConnection) { Assert.Catch <ArgumentException>(() => server.Start(serverConnection)); Assert.Catch <ArgumentException>(() => client.Start(clientConnection)); return; } } var waitInput = new ManualResetEvent(false); var waitConfigs = new ManualResetEvent(false); var waitLog = new ManualResetEvent(false); var waitLogError = new ManualResetEvent(false); client.OnReceiveInputs += (s, e) => waitInput.Set(); client.OnReceiveConfigurations += (s, e) => waitConfigs.Set(); server.OnReceiveLog += (s, e) => (e.Any(u => u.Error != null) ? waitLogError : waitLog).Set(); server.Start(serverConnection); Thread.Sleep(250); // Wait for server client.Start(clientConnection); Assert.IsTrue(server.IsStarted); Assert.IsTrue(client.IsStarted); // Already started Assert.Catch <Exception>(() => server.Start(serverConnection)); Assert.Catch <Exception>(() => client.Start(clientConnection)); // Check client Assert.IsTrue(waitConfigs.WaitOne(TimeSpan.FromSeconds(10)), "Waiting for configs"); Assert.IsTrue(waitInput.WaitOne(TimeSpan.FromSeconds(10)), "Waiting for inputs"); Assert.AreEqual(1, server.Connections.Count); Assert.IsTrue(server.Connections.Values.FirstOrDefault()?.Source.Description.Contains(client.PublicName)); Assert.AreNotEqual(Guid.Empty, server.Connections.Values.FirstOrDefault()?.Source.Id); Assert.AreNotEqual(Guid.Empty, server.Connections.Values.FirstOrDefault()?.Id); var speedInit = server.Connections.Values.FirstOrDefault().Source.Speed; CheckConfig(() => ((IRandomValue <FuzzingConfigBase>)client).Get(), server.Configurations.Select(u => u.Value.Source).ToArray()); CheckConfig(() => ((IRandomValue <FuzzingInputBase>)client).Get(), server.Inputs.Select(u => u.Value.Source).ToArray()); CheckConfig(() => client.GetConfig(), server.Configurations.Select(u => u.Value.Source).ToArray()); CheckConfig(() => client.GetInput(), server.Inputs.Select(u => u.Value.Source).ToArray()); // Send log var cfg = client.GetConfig(); var input = client.GetInput(); var log = new FuzzerLog() { ConfigId = cfg.Id, InputId = input.Id, Coverage = 10, }; var sIn = server.Inputs.Select(u => u.Value).Where(u => u.Source.Id == log.InputId).FirstOrDefault(); var sCfg = server.Configurations.Select(u => u.Value).Where(u => u.Source.Id == log.ConfigId).FirstOrDefault(); Assert.AreEqual(0, server.Logs.Count); Assert.AreEqual(0, server.UniqueErrors); Assert.AreEqual(0, server.TotalErrors); client.SendLog(log); Assert.IsTrue(waitLog.WaitOne(TimeSpan.FromSeconds(10)), "Waiting for log"); Assert.AreEqual(0, server.Logs.Count); Assert.AreEqual(0, server.UniqueErrors); Assert.AreEqual(0, server.TotalErrors); Thread.Sleep(250); Assert.IsTrue(server.Connections.Values.FirstOrDefault().Source.Speed > speedInit); Assert.AreEqual(log.Coverage, server.Connections.Values.FirstOrDefault().Source.Coverage); // Check stats Assert.AreEqual(1, sIn.Tests); Assert.AreEqual(1, sCfg.Tests); Assert.AreEqual(0, sIn.Crashes); Assert.AreEqual(0, sCfg.Crashes); Assert.AreEqual(0, sIn.Errors); Assert.AreEqual(0, sCfg.Errors); // Send error log = new FuzzerLog() { ConfigId = cfg.Id, InputId = input.Id, Error = new FuzzerError() { ErrorId = Guid.NewGuid(), Error = FuzzerError.EFuzzingErrorType.Crash, ExplotationResult = FuzzerError.EExplotationResult.Exploitable, ReplicationData = new byte[0], } }; Assert.AreEqual(0, server.UniqueErrors); Assert.AreEqual(0, server.TotalErrors); client.SendLog(log); waitLogError.Reset(); Assert.IsTrue(waitLogError.WaitOne(TimeSpan.FromSeconds(10)), "Waiting for error"); Assert.AreEqual(1, server.Logs.Count); Assert.IsTrue(server.Logs.TryGetValue(log.Error.ErrorId, out var peekLog)); Assert.IsTrue(log.Equals(peekLog)); Assert.AreEqual(1, server.UniqueErrors); Assert.AreEqual(1, server.TotalErrors); // Check stats Assert.AreEqual(2, sIn.Tests); Assert.AreEqual(2, sCfg.Tests); Assert.AreEqual(1, sIn.Crashes); Assert.AreEqual(1, sCfg.Crashes); Assert.AreEqual(0, sIn.Errors); Assert.AreEqual(0, sCfg.Errors); // Generic MultiClient FuzzerLog gerr = null; Fuzzer.Client.Stop(); if (serverConnection != clientConnection) { // Test default Fuzzer.Client.Start(clientConnection); } waitLogError.Reset(); Fuzzer.Run(FuzWERSample, new FuzzerRunArgs() { OnLog = (l, c) => { if (l.Error != null) { c.Cancel = true; gerr = l; } } }); // Could spend more time because are more tests Assert.IsTrue(waitLogError.WaitOne(TimeSpan.FromSeconds(30)), "Waiting for error"); Assert.AreEqual(2, server.Logs.Count); Assert.IsTrue(server.Logs.TryGetValue(gerr.Error.ErrorId, out peekLog)); Assert.IsTrue(gerr.Equals(peekLog)); Assert.IsTrue(gerr.Error.ReplicationData.Length > 0); Assert.AreEqual(FuzzerError.EExplotationResult.Exploitable, gerr.Error.ExplotationResult); Assert.AreEqual(FuzzerError.EFuzzingErrorType.Crash, gerr.Error.Error); Assert.AreEqual(2, server.UniqueErrors); Assert.AreEqual(2, server.TotalErrors); // Generic MultiThread Client gerr = null; Fuzzer.Client.Stop(); Thread.Sleep(250); // Wait some time for pipes if (serverConnection != clientConnection) { // Test default Fuzzer.Client.Start(clientConnection); } waitLogError.Reset(); Fuzzer.Run(1, FuzMultiThreadSample, new FuzzerRunArgs() { OnLog = (l, c) => { if (l.Error != null) { c.Cancel = true; gerr = l; } } }); // Could spend more time because are more tests Assert.IsTrue(waitLogError.WaitOne(TimeSpan.FromSeconds(30)), "Waiting for error"); Assert.AreEqual(3, server.Logs.Count); Assert.IsTrue(server.Logs.TryGetValue(gerr.Error.ErrorId, out peekLog)); Assert.IsTrue(gerr.Equals(peekLog)); Assert.IsTrue(gerr.Error.ReplicationData.Length > 0); Assert.AreEqual(3, server.UniqueErrors); Assert.AreEqual(3, server.TotalErrors); // Test timeout gerr = null; waitLogError.Reset(); Fuzzer.Client.ExecutionTimeOut = TimeSpan.FromMilliseconds(250); Fuzzer.Run(FuzTimeoutSample, new FuzzerRunArgs() { OnLog = (l, c) => { c.Cancel = true; if (l.Error != null) { gerr = l; } } }); Assert.IsTrue(waitLogError.WaitOne(TimeSpan.FromSeconds(5)), "Waiting for error"); Assert.AreEqual(4, server.Logs.Count); Assert.IsTrue(server.Logs.TryGetValue(gerr.Error.ErrorId, out peekLog)); Assert.IsTrue(gerr.Equals(peekLog)); Assert.IsTrue(gerr.Error.ReplicationData.Length > 0); Assert.AreEqual(4, server.UniqueErrors); Assert.AreEqual(4, server.TotalErrors); // Current stream var logReaded = new byte[255]; var current = new byte[logReaded.Length]; FuzzingStream fuzStream = null; Fuzzer.Run((stream) => { Array.Resize(ref current, stream.Read(current, 0, current.Length)); fuzStream = (FuzzingStream)stream; Assert.IsNotNull(fuzStream.CurrentStream); }, new FuzzerRunArgs() { StoreCurrent = true, OnLog = (l, c) => { // Read current file var fCurrent = ((FileStream)fuzStream.CurrentStream); fCurrent.Seek(0, SeekOrigin.Begin); Array.Resize(ref logReaded, fCurrent.Read(logReaded, 0, logReaded.Length)); c.Cancel = true; }, }); Assert.IsNotNull(fuzStream); Assert.IsNotNull(fuzStream.CurrentStream); CollectionAssert.AreEqual(current, logReaded); // Clean Fuzzer.Client.Stop(); waitInput.Dispose(); waitConfigs.Dispose(); waitLog.Dispose(); waitLogError.Dispose(); } }
/// <summary> /// Start Pipe connection /// </summary> /// <param name="connection">Connection</param> public void Start(FuzzerConnectionBase connection) { if (IsStarted) { throw new Exception("Already started"); } if (connection is FuzzerNamedPipeConnection pipe) { var client = new NamedPipeClientStream(".", pipe.PipeName, PipeDirection.InOut, PipeOptions.Asynchronous); client.Connect(10_000); _client = client; } else if (connection is FuzzerTcpConnection tcp) { #pragma warning disable IDE0067 // Dispose objects before losing scope var client = new TcpClient(); #pragma warning restore IDE0067 // Dispose objects before losing scope client.Connect(tcp.EndPoint); _client = client.GetStream(); } else { if (connection == null) { throw new NullReferenceException(nameof(connection)); } throw new ArgumentException(nameof(connection)); } _cancel = new CancellationTokenSource(); _tasks = new Task[] { new Task(() => UpdateFromStream(_client, _cancel.Token), _cancel.Token), new Task(() => FlushBuffer(_cancel.Token), _cancel.Token) }; _tasks.All(u => { u.Start(); return(true); }); // Request Configs and inputs var send = new List <byte>(new byte[] { (byte)EFuzzerMessageType.GetAvailableConfigs, (byte)EFuzzerMessageType.GetAvailableInputs }); if (!string.IsNullOrWhiteSpace(PublicName)) { send.AddRange(GetMessage(EFuzzerMessageType.PushPublicName, PublicName)); } lock (_client) { _client.Write(send.ToArray(), 0, send.Count); _client.Flush(); } }