Skip to content

Commit

Permalink
[ASM][IAST] Add source tainting for Grpc (#5473)
Browse files Browse the repository at this point in the history
* Initial commit with the CallTargetRefStruct.cs readonly struct

* Managed test

* Native code implementation

* fixes

* Fixes and test suite

* revert

* Add instrumentation on grpc request object + Visitor to track strings and taint them

* Add new sample + integration test

* Add grpc Source Type

* Update Sample to add more tests

* Add problematic instrumentation

* Implement new instrumentation for reading grpc messages strings

* Move Sample + Working integration tests

* Add the missing telemetry

* Revert debug on triming file

* Remove Security Sample

* Update integration tests on existing APM sample

* Lower the minimum version of Google.Protobuf to support older versions

* Missing integration in the group

* Exclude net fx

* Skip build on unsupported

* Update snapshot with deduplication enabled

* Scrub location

* Applied comments

---------

Co-authored-by: Tony Redondo <tony.redondo@datadoghq.com>
  • Loading branch information
e-n-0 and tonyredondo committed May 10, 2024
1 parent e24746d commit 7aad726
Show file tree
Hide file tree
Showing 26 changed files with 501 additions and 49 deletions.
1 change: 0 additions & 1 deletion Datadog.Trace.OSX.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@
"tracer\\test\\test-applications\\integrations\\Samples.GraphQL3\\Samples.GraphQL3.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.GraphQL4\\Samples.GraphQL4.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.GraphQL\\Samples.GraphQL.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.GrpcDotNet\\Samples.GrpcDotNet.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.GrpcLegacy\\Samples.GrpcLegacy.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.HotChocolate\\Samples.HotChocolate.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.HttpMessageHandler\\Samples.HttpMessageHandler.csproj",
Expand Down
3 changes: 2 additions & 1 deletion Datadog.Trace.Security.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"tracer\\test\\test-applications\\security\\Samples.Security.AspNetCoreBare\\Samples.Security.AspNetCoreBare.csproj",
"tracer\\test\\test-applications\\security\\aspnet\\Samples.Security.AspNetMvc5\\Samples.Security.AspNetMvc5.csproj",
"tracer\\test\\test-applications\\security\\aspnet\\Samples.Security.WebApi\\Samples.Security.WebApi.csproj",
"tracer\\test\\test-applications\\security\\aspnet\\Samples.Security.WebForms\\Samples.Security.WebForms.csproj"
"tracer\\test\\test-applications\\security\\aspnet\\Samples.Security.WebForms\\Samples.Security.WebForms.csproj",
"tracer\\test\\test-applications\\integrations\\Samples.GrpcDotNet\\Samples.GrpcDotNet.csproj",
]
}
}
1 change: 1 addition & 0 deletions tracer/build/_build/Honeypot/IntegrationGroups.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ static IntegrationMap()
NugetPackages.Add("Grpc.AspNetCore.Server", new string[] { "Grpc.AspNetCore" });
NugetPackages.Add("Grpc.Net.Client", new string[] { "Grpc.AspNetCore" });
NugetPackages.Add("Grpc.Core", new string[] { "Grpc" });
NugetPackages.Add("Google.Protobuf", new string[] { "Google.Protobuf" });
NugetPackages.Add("Microsoft.AspNetCore.Mvc.Core", new [] { "Microsoft.AspNetCore.Mvc.Core" });
NugetPackages.Add("Microsoft.AspNetCore.Identity", new [] { "Microsoft.AspNetCore.Identity" });
NugetPackages.Add("Microsoft.Extensions.Identity.Core", new [] { "Microsoft.Extensions.Identity.Core" });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<assembly fullname="Datadog.Trace" />
<assembly fullname="dotnet" />
<assembly fullname="Elasticsearch.Net" />
<assembly fullname="Google.Protobuf" />
<assembly fullname="GraphQL" />
<assembly fullname="GraphQL.SystemReactive" />
<assembly fullname="Grpc.AspNetCore.Server" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// <copyright file="ParsingPrimitivesReadRawStringIntegration.cs" company="Datadog">
// Unless explicitly stated otherwise all files in this repository are licensed under the Apache 2 License.
// This product includes software developed at Datadog (https://www.datadoghq.com/). Copyright 2017 Datadog, Inc.
// </copyright>
#nullable enable

using System;
using System.ComponentModel;
using System.IO;
using System.Threading;
using Datadog.Trace.ClrProfiler.CallTarget;
using Datadog.Trace.Configuration;
using Datadog.Trace.Iast;

namespace Datadog.Trace.ClrProfiler.AutoInstrumentation.Grpc.GrpcDotNet.GrpcAspNetCoreServer.IAST;

/// <summary>
/// System.String Google.Protobuf.ParsingPrimitives::ReadRawString calltarget instrumentation
/// </summary>
[InstrumentMethod(
AssemblyName = "Google.Protobuf",
TypeName = "Google.Protobuf.ParsingPrimitives",
MethodName = "ReadRawString",
ReturnTypeName = ClrNames.String,
ParameterTypeNames = ["System.ReadOnlySpan`1[System.Byte]&", "Google.Protobuf.ParserInternalState&", ClrNames.Int32],
MinimumVersion = "3.0.0",
MaximumVersion = "3.*.*",
IntegrationName = nameof(Grpc),
InstrumentationCategory = InstrumentationCategory.Iast)]
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
public class ParsingPrimitivesReadRawStringIntegration
{
internal static CallTargetReturn<string?> OnMethodEnd<TTarget>(string? returnValue, Exception? exception, in CallTargetState state)
{
if (returnValue is not null)
{
var taintedObjects = IastModule.GetIastContext()?.GetTaintedObjects();
taintedObjects?.TaintInputString(returnValue, new Source(SourceType.GrpcRequestBody, null, returnValue));
}

return new CallTargetReturn<string?>(returnValue);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal static partial class IastInstrumentedSourcesExtensions
/// The number of members in the enum.
/// This is a non-distinct count of defined names.
/// </summary>
public const int Length = 12;
public const int Length = 13;

/// <summary>
/// Returns the string representation of the <see cref="Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources"/> value.
Expand All @@ -42,6 +42,7 @@ public static string ToStringFast(this Datadog.Trace.Telemetry.Metrics.MetricTag
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.CookieValue => "source_type:http.request.cookie.value",
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.MatrixParameter => "source_type:http.request.matrix.parameter",
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.RequestUri => "source_type:http.request.uri",
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.GrpcRequestBody => "source_type:grpc.request.body",
_ => value.ToString(),
};

Expand All @@ -67,6 +68,7 @@ public static Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.CookieValue,
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.MatrixParameter,
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.RequestUri,
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.GrpcRequestBody,
};

/// <summary>
Expand All @@ -92,6 +94,7 @@ public static string[] GetNames()
nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.CookieValue),
nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.MatrixParameter),
nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.RequestUri),
nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.GrpcRequestBody),
};

/// <summary>
Expand All @@ -117,5 +120,6 @@ public static string[] GetDescriptions()
"source_type:http.request.cookie.value",
"source_type:http.request.matrix.parameter",
"source_type:http.request.uri",
"source_type:grpc.request.body",
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ static InstrumentationDefinitions()
new (NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("GraphQL.SystemReactive"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("GraphQL.Execution.SubscriptionExecutionStrategy"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("ExecuteAsync"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16StringArray("System.Threading.Tasks.Task`1<GraphQL.ExecutionResult>", "GraphQL.Execution.ExecutionContext"), 2, 4, 0, 0, 4, 65535, 65535, NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String(assemblyFullName), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("Datadog.Trace.ClrProfiler.AutoInstrumentation.GraphQL.Net.ExecuteAsyncIntegration"), 0, 1),

// Grpc
new (NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("Google.Protobuf"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("Google.Protobuf.ParsingPrimitives"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("ReadRawString"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16StringArray("System.String", "System.ReadOnlySpan`1[System.Byte]&", "Google.Protobuf.ParserInternalState&", "System.Int32"), 4, 3, 0, 0, 3, 65535, 65535, NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String(assemblyFullName), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("Datadog.Trace.ClrProfiler.AutoInstrumentation.Grpc.GrpcDotNet.GrpcAspNetCoreServer.IAST.ParsingPrimitivesReadRawStringIntegration"), 0, 4),
new (NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("Grpc.Core"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("Grpc.Core.DefaultCallInvoker"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("CreateCall"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16StringArray("Grpc.Core.CallInvocationDetails`2[!!0,!!1]", "Grpc.Core.Method`2[!!0,!!1]", "System.String", "Grpc.Core.CallOptions"), 4, 2, 0, 0, 2, 65535, 65535, NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String(assemblyFullName), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("Datadog.Trace.ClrProfiler.AutoInstrumentation.Grpc.GrpcLegacy.Client.DefaultCallInvokerInstrumentation"), 0, 1),
new (NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("Grpc.Core"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("Grpc.Core.Internal.AsyncCall`2"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("HandleFinished"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16StringArray("System.Void", "System.Boolean", "Grpc.Core.Internal.ClientSideStatus"), 3, 2, 0, 0, 2, 65535, 65535, NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String(assemblyFullName), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("Datadog.Trace.ClrProfiler.AutoInstrumentation.Grpc.GrpcLegacy.Client.AsyncCallHandleFinishedInstrumentation"), 0, 1),
new (NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("Grpc.Core"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("Grpc.Core.Internal.AsyncCall`2"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("HandleUnaryResponse"), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16StringArray("System.Void", "System.Boolean", "Grpc.Core.Internal.ClientSideStatus", "Grpc.Core.Internal.IBufferReader", "Grpc.Core.Metadata"), 5, 2, 0, 0, 2, 65535, 65535, NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String(assemblyFullName), NativeCallTargetUnmanagedMemoryHelper.AllocateAndWriteUtf16String("Datadog.Trace.ClrProfiler.AutoInstrumentation.Grpc.GrpcLegacy.Client.AsyncCallHandleUnaryResponseInstrumentation"), 0, 1),
Expand Down Expand Up @@ -549,6 +550,7 @@ internal static bool IsInstrumentedAssembly(string assemblyName)
|| assemblyName.StartsWith("coverlet.core,", StringComparison.Ordinal)
|| assemblyName.StartsWith("dotnet,", StringComparison.Ordinal)
|| assemblyName.StartsWith("Elasticsearch.Net,", StringComparison.Ordinal)
|| assemblyName.StartsWith("Google.Protobuf,", StringComparison.Ordinal)
|| assemblyName.StartsWith("GraphQL,", StringComparison.Ordinal)
|| assemblyName.StartsWith("GraphQL.SystemReactive,", StringComparison.Ordinal)
|| assemblyName.StartsWith("Grpc.Core,", StringComparison.Ordinal)
Expand Down Expand Up @@ -716,7 +718,8 @@ internal static bool IsInstrumentedAssembly(string assemblyName)
or "Datadog.Trace.ClrProfiler.AutoInstrumentation.GraphQL.Net.ValidateAsyncIntegrationV5AndV7"
or "Datadog.Trace.ClrProfiler.AutoInstrumentation.GraphQL.Net.ExecuteAsyncIntegration"
=> Datadog.Trace.Configuration.IntegrationId.GraphQL,
"Datadog.Trace.ClrProfiler.AutoInstrumentation.Grpc.GrpcLegacy.Client.DefaultCallInvokerInstrumentation"
"Datadog.Trace.ClrProfiler.AutoInstrumentation.Grpc.GrpcDotNet.GrpcAspNetCoreServer.IAST.ParsingPrimitivesReadRawStringIntegration"
or "Datadog.Trace.ClrProfiler.AutoInstrumentation.Grpc.GrpcLegacy.Client.DefaultCallInvokerInstrumentation"
or "Datadog.Trace.ClrProfiler.AutoInstrumentation.Grpc.GrpcLegacy.Client.AsyncCallHandleFinishedInstrumentation"
or "Datadog.Trace.ClrProfiler.AutoInstrumentation.Grpc.GrpcLegacy.Client.AsyncCallHandleUnaryResponseInstrumentation"
or "Datadog.Trace.ClrProfiler.AutoInstrumentation.Grpc.GrpcLegacy.Server.AsyncCallServerSendInitialMetadataAsyncInstrumentation"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
namespace Datadog.Trace.Telemetry;
internal partial class MetricsTelemetryCollector
{
private const int CountLength = 364;
private const int CountLength = 365;

/// <summary>
/// Creates the buffer for the <see cref="Datadog.Trace.Telemetry.Metrics.Count" /> values.
Expand Down Expand Up @@ -391,9 +391,10 @@ private static AggregatedMetric[] GetCountBuffer()
new(new[] { "source_type:http.request.cookie.value" }),
new(new[] { "source_type:http.request.matrix.parameter" }),
new(new[] { "source_type:http.request.uri" }),
// executed.propagation, index = 337
new(new[] { "source_type:grpc.request.body" }),
// executed.propagation, index = 338
new(null),
// executed.sink, index = 338
// executed.sink, index = 339
new(new[] { "vulnerability_type:none" }),
new(new[] { "vulnerability_type:weak_cipher" }),
new(new[] { "vulnerability_type:weak_hash" }),
Expand All @@ -419,7 +420,7 @@ private static AggregatedMetric[] GetCountBuffer()
new(new[] { "vulnerability_type:insecure_auth_protocol" }),
new(new[] { "vulnerability_type:xss" }),
new(new[] { "vulnerability_type:directory_listing_leak" }),
// request.tainted, index = 363
// request.tainted, index = 364
new(null),
};

Expand All @@ -429,7 +430,7 @@ private static AggregatedMetric[] GetCountBuffer()
/// It is equal to the cardinality of the tag combinations (or 1 if there are no tags)
/// </summary>
private static int[] CountEntryCounts { get; }
= new int[]{ 4, 73, 1, 3, 4, 2, 2, 4, 1, 1, 1, 22, 3, 2, 4, 4, 1, 22, 3, 2, 44, 6, 1, 73, 1, 22, 3, 1, 1, 5, 3, 2, 2, 2, 12, 1, 25, 1, };
= new int[]{ 4, 73, 1, 3, 4, 2, 2, 4, 1, 1, 1, 22, 3, 2, 4, 4, 1, 22, 3, 2, 44, 6, 1, 73, 1, 22, 3, 1, 1, 5, 3, 2, 2, 2, 13, 1, 25, 1, };

public void RecordCountLogCreated(Datadog.Trace.Telemetry.Metrics.MetricTags.LogLevel tag, int increment = 1)
{
Expand Down Expand Up @@ -634,17 +635,17 @@ public void RecordCountIastExecutedSources(Datadog.Trace.Telemetry.Metrics.Metri

public void RecordCountIastExecutedPropagations(int increment = 1)
{
Interlocked.Add(ref _buffer.Count[337], increment);
Interlocked.Add(ref _buffer.Count[338], increment);
}

public void RecordCountIastExecutedSinks(Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSinks tag, int increment = 1)
{
var index = 338 + (int)tag;
var index = 339 + (int)tag;
Interlocked.Add(ref _buffer.Count[index], increment);
}

public void RecordCountIastRequestTainted(int increment = 1)
{
Interlocked.Add(ref _buffer.Count[363], increment);
Interlocked.Add(ref _buffer.Count[364], increment);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal static partial class IastInstrumentedSourcesExtensions
/// The number of members in the enum.
/// This is a non-distinct count of defined names.
/// </summary>
public const int Length = 12;
public const int Length = 13;

/// <summary>
/// Returns the string representation of the <see cref="Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources"/> value.
Expand All @@ -42,6 +42,7 @@ public static string ToStringFast(this Datadog.Trace.Telemetry.Metrics.MetricTag
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.CookieValue => "source_type:http.request.cookie.value",
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.MatrixParameter => "source_type:http.request.matrix.parameter",
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.RequestUri => "source_type:http.request.uri",
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.GrpcRequestBody => "source_type:grpc.request.body",
_ => value.ToString(),
};

Expand All @@ -67,6 +68,7 @@ public static Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.CookieValue,
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.MatrixParameter,
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.RequestUri,
Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.GrpcRequestBody,
};

/// <summary>
Expand All @@ -92,6 +94,7 @@ public static string[] GetNames()
nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.CookieValue),
nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.MatrixParameter),
nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.RequestUri),
nameof(Datadog.Trace.Telemetry.Metrics.MetricTags.IastInstrumentedSources.GrpcRequestBody),
};

/// <summary>
Expand All @@ -117,5 +120,6 @@ public static string[] GetDescriptions()
"source_type:http.request.cookie.value",
"source_type:http.request.matrix.parameter",
"source_type:http.request.uri",
"source_type:grpc.request.body",
};
}
Loading

0 comments on commit 7aad726

Please sign in to comment.