diff --git a/tracer/src/Datadog.Trace/Iast/VulnerabilityBatch.cs b/tracer/src/Datadog.Trace/Iast/VulnerabilityBatch.cs index 6fc3bf58a90a..e9fe31869e5e 100644 --- a/tracer/src/Datadog.Trace/Iast/VulnerabilityBatch.cs +++ b/tracer/src/Datadog.Trace/Iast/VulnerabilityBatch.cs @@ -7,15 +7,10 @@ using System; using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; using Datadog.Trace.AppSec.Rasp; using Datadog.Trace.Iast.SensitiveData; using Datadog.Trace.Iast.Settings; using Datadog.Trace.Logging; -using Datadog.Trace.Util.Http; -using Datadog.Trace.Vendors.dnlib; using Datadog.Trace.Vendors.Newtonsoft.Json; using Datadog.Trace.Vendors.Newtonsoft.Json.Serialization; @@ -31,6 +26,8 @@ internal class VulnerabilityBatch private static Lazy _truncatedSettings = new(() => CreateTruncatedSettings()); private readonly int _truncationMaxValueLength; + private readonly List _vulnerabilities = new List(); + private List? _sources = null; private EvidenceRedactor? _evidenceRedactor; private JsonSerializerSettings _serializerSettings; private string? _vulnerabilitiesJson; @@ -52,9 +49,9 @@ public VulnerabilityBatch(int truncationMaxValueLength = IastSettings.Truncation } } - public List Vulnerabilities { get; } = new List(); + public ICollection Vulnerabilities => _vulnerabilities; - public List? Sources { get; private set; } = null; + public ICollection? Sources => _sources; public bool IsTruncated() => _isTruncated; @@ -87,27 +84,30 @@ private static JsonSerializerSettings CreateTruncatedSettings() public void Add(Vulnerability vulnerability) { - _vulnerabilitiesJson = null; - var ranges = vulnerability.Evidence?.Ranges; - - if (ranges != null) + lock (_vulnerabilities) { - foreach (var range in ranges) + _vulnerabilitiesJson = null; + var ranges = vulnerability.Evidence?.Ranges; + + if (ranges != null) { - if (Sources is null) + foreach (var range in ranges) { - Sources = new List(); - } + if (Sources is null) + { + _sources = new List(); + } - if (range.Source != null && !Sources.Contains(range.Source)) - { - range.Source.SetInternalId(Sources.Count); - Sources.Add(range.Source); + if (range.Source != null && _sources is not null && !_sources.Contains(range.Source)) + { + range.Source.SetInternalId(_sources.Count); + _sources.Add(range.Source); + } } } - } - Vulnerabilities.Add(vulnerability); + _vulnerabilities.Add(vulnerability); + } } public string ToJson() @@ -116,32 +116,35 @@ public string ToJson() { if (_vulnerabilitiesJson == null) { - if (_evidenceRedactor == null) - { - _vulnerabilitiesJson = JsonConvert.SerializeObject(this, Formatting.Indented, _serializerSettings); - } - else + lock (_vulnerabilities) { - if (Sources != null) + if (_evidenceRedactor == null) { - foreach (var source in Sources) + _vulnerabilitiesJson = JsonConvert.SerializeObject(this, Formatting.Indented, _serializerSettings); + } + else + { + if (Sources != null) { - _evidenceRedactor.Process(source); + foreach (var source in Sources) + { + _evidenceRedactor.Process(source); + } + } + + for (int x = 0; x < _vulnerabilities.Count; x++) + { + _vulnerabilities[x] = _evidenceRedactor.RedactVulnerability(_vulnerabilities[x]); } + + _vulnerabilitiesJson = JsonConvert.SerializeObject(this, Formatting.Indented, _serializerSettings); } - for (int x = 0; x < Vulnerabilities.Count; x++) + if (System.Text.ASCIIEncoding.Unicode.GetByteCount(_vulnerabilitiesJson) > MaxSpanTagSize) { - Vulnerabilities[x] = _evidenceRedactor.RedactVulnerability(Vulnerabilities[x]); + _vulnerabilitiesJson = ToTruncatedJson(); + _isTruncated = true; } - - _vulnerabilitiesJson = JsonConvert.SerializeObject(this, Formatting.Indented, _serializerSettings); - } - - if (System.Text.ASCIIEncoding.Unicode.GetByteCount(_vulnerabilitiesJson) > MaxSpanTagSize) - { - _vulnerabilitiesJson = ToTruncatedJson(); - _isTruncated = true; } } @@ -158,40 +161,43 @@ public byte[] ToMessagePack() { try { - byte[] result; - Dictionary toSerialize; - - if (_evidenceRedactor == null) - { - toSerialize = MetaStructHelper.VulnerabilityBatchToDictionary(this); - result = MetaStructHelper.ObjectToByteArray(toSerialize); - } - else + lock (_vulnerabilities) { - if (Sources != null) + byte[] result; + Dictionary toSerialize; + + if (_evidenceRedactor == null) + { + toSerialize = MetaStructHelper.VulnerabilityBatchToDictionary(this); + result = MetaStructHelper.ObjectToByteArray(toSerialize); + } + else { - foreach (var source in Sources) + if (Sources != null) + { + foreach (var source in Sources) + { + _evidenceRedactor.Process(source); + } + } + + for (var x = 0; x < _vulnerabilities.Count; x++) { - _evidenceRedactor.Process(source); + _vulnerabilities[x] = _evidenceRedactor.RedactVulnerability(_vulnerabilities[x]); } + + toSerialize = MetaStructHelper.VulnerabilityBatchToDictionary(this); + result = MetaStructHelper.ObjectToByteArray(toSerialize); } - for (var x = 0; x < Vulnerabilities.Count; x++) + if (result.Length > MaxSpanTagSize) { - Vulnerabilities[x] = _evidenceRedactor.RedactVulnerability(Vulnerabilities[x]); + result = ToTruncatedMessagePack(toSerialize); + _isTruncated = true; } - toSerialize = MetaStructHelper.VulnerabilityBatchToDictionary(this); - result = MetaStructHelper.ObjectToByteArray(toSerialize); - } - - if (result.Length > MaxSpanTagSize) - { - result = ToTruncatedMessagePack(toSerialize); - _isTruncated = true; + return result; } - - return result; } catch (Exception ex) { @@ -202,26 +208,32 @@ public byte[] ToMessagePack() internal string ToTruncatedJson() { - return JsonConvert.SerializeObject(new TruncatedVulnerabilities(Vulnerabilities), Formatting.Indented, _truncatedSettings.Value); + lock (_vulnerabilities) + { + return JsonConvert.SerializeObject(new TruncatedVulnerabilities(_vulnerabilities), Formatting.Indented, _truncatedSettings.Value); + } } internal byte[] ToTruncatedMessagePack(Dictionary vulnerabilityBatchDictionary) { - if (vulnerabilityBatchDictionary["vulnerabilities"] is List> vulnerabilities) + lock (_vulnerabilities) { - foreach (var vulnerability in vulnerabilities) + if (vulnerabilityBatchDictionary["vulnerabilities"] is List> vulnerabilities) { - if (vulnerability["evidence"] is Dictionary evidence) + foreach (var vulnerability in vulnerabilities) { - evidence.Clear(); - evidence["value"] = TruncatedVulnerabilities.MaxSizeExceeded; + if (vulnerability["evidence"] is Dictionary evidence) + { + evidence.Clear(); + evidence["value"] = TruncatedVulnerabilities.MaxSizeExceeded; + } } } - } - vulnerabilityBatchDictionary.Remove("sources"); + vulnerabilityBatchDictionary.Remove("sources"); - return MetaStructHelper.ObjectToByteArray(vulnerabilityBatchDictionary); + return MetaStructHelper.ObjectToByteArray(vulnerabilityBatchDictionary); + } } public override string ToString() diff --git a/tracer/test/Datadog.Trace.Security.Unit.Tests/IAST/Tainted/VulnerabilityBatchTests.cs b/tracer/test/Datadog.Trace.Security.Unit.Tests/IAST/Tainted/VulnerabilityBatchTests.cs index 2cb14de381e5..2b1e17dfeb5b 100644 --- a/tracer/test/Datadog.Trace.Security.Unit.Tests/IAST/Tainted/VulnerabilityBatchTests.cs +++ b/tracer/test/Datadog.Trace.Security.Unit.Tests/IAST/Tainted/VulnerabilityBatchTests.cs @@ -3,6 +3,7 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc. // +using System.Linq; using System.Text; using Datadog.Trace.AppSec.Rasp; using Datadog.Trace.Iast; @@ -166,9 +167,10 @@ public void GivenAVulnerabilityBatch_WhenAddTwoVulnerabilities_VulnerabilitiesAr batch.Add(vulnerability2); batch.Vulnerabilities.Count.Should().Be(2); - batch.Sources.Count.Should().Be(2); - batch.Sources[0].GetInternalId().Should().Be(0); - batch.Sources[1].GetInternalId().Should().Be(1); + var sources = batch.Sources.ToList(); + sources.Count.Should().Be(2); + sources[0].GetInternalId().Should().Be(0); + sources[1].GetInternalId().Should().Be(1); var json = batch.ToJson(); var metaStructJson = VulnerabilityBatchMetaStructToJson(batch);