-
Notifications
You must be signed in to change notification settings - Fork 144
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ASM] iast: Tainting of DefaultInterpolatedStringHandler (#6340)
## Summary of changes This PR introduce the support of `DefaultInterpolatedStringHandler` for IAST. The resulting strings of `DefaultInterpolatedStringHandler` will now be tainted. ## Reason for change Since the release of .NET Core 6, interpolated strings got a performance optimisation and now use [DefaultInterpolatedStringHandler](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.defaultinterpolatedstringhandler?view=net-6.0) to build strings. Some vulnerabilities couldn't be detected because strings built with `DefaultInterpolatedStringHandler` weren't tainted. ## Implementation details As `DefaultInterpolatedStringHandler` is a ref struct, we call some IL to get it's own stack pointer value and taint it. We need to get that pointer value to track it and its tainted sources. ## Test coverage - New unit tests were added: - testing all aspects with an explicit call to the `DefaultInterpolatedStringHandler` ref struct - testing implicit interpolated strings (`$""`) in various complex cases - Aspects tests added for `IastInstrumentationUnitTests` ## Other details This PR don't handle the correct values for `start` and `length` of tainted Sources. --------- Co-authored-by: Daniel Romano <108014683+daniel-romano-DD@users.noreply.github.com>
- Loading branch information
1 parent
57b69bb
commit b677deb
Showing
10 changed files
with
821 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
233 changes: 233 additions & 0 deletions
233
...r/src/Datadog.Trace/Iast/Aspects/System.Runtime/DefaultInterpolatedStringHandlerAspect.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
// <copyright file="DefaultInterpolatedStringHandlerAspect.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> | ||
|
||
#if NET6_0_OR_GREATER | ||
|
||
#nullable enable | ||
|
||
using System; | ||
using System.Reflection.Emit; | ||
using System.Runtime.CompilerServices; | ||
using Datadog.Trace.Iast.Dataflow; | ||
using Datadog.Trace.Iast.Propagation; | ||
using InlineIL; | ||
using static InlineIL.IL.Emit; | ||
|
||
namespace Datadog.Trace.Iast.Aspects.System.Runtime; | ||
|
||
/// <summary> DefaultInterpolatedString class aspect </summary> | ||
[AspectClass("System.Runtime")] | ||
[global::System.ComponentModel.Browsable(false)] | ||
[global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] | ||
public class DefaultInterpolatedStringHandlerAspect | ||
{ | ||
/// <summary> | ||
/// System.Runtime DefaultInterpolatedStringHandler.AppendFormatted(String) aspect | ||
/// </summary> | ||
/// <param name="target"> the ref DefaultInterpolatedStringHandler </param> | ||
/// <param name="value"> the string value </param> | ||
[AspectMethodReplace("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::AppendFormatted(System.String)")] | ||
public static void AppendFormatted1(ref DefaultInterpolatedStringHandler target, string value) | ||
{ | ||
target.AppendFormatted(value); | ||
try | ||
{ | ||
DefaultInterpolatedStringHandlerModuleImpl.Append(ToPointer(ref target), value); | ||
} | ||
catch (Exception ex) | ||
{ | ||
IastModule.Log.Warning(ex, $"Error invoking {nameof(DefaultInterpolatedStringHandlerAspect)}.{nameof(AppendFormatted1)}"); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// System.Runtime DefaultInterpolatedStringHandler.AppendFormatted(String, Int32, String) aspect | ||
/// </summary> | ||
/// <param name="target"> the ref DefaultInterpolatedStringHandler </param> | ||
/// <param name="value"> the string value </param> | ||
/// <param name="alignment"> the alignment value </param> | ||
/// <param name="format"> the format value </param> | ||
[AspectMethodReplace("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::AppendFormatted(System.String,System.Int32,System.String)")] | ||
public static void AppendFormatted2(ref DefaultInterpolatedStringHandler target, string? value, int alignment, string? format) | ||
{ | ||
target.AppendFormatted(value, alignment, format); | ||
try | ||
{ | ||
DefaultInterpolatedStringHandlerModuleImpl.Append(ToPointer(ref target), value); | ||
} | ||
catch (Exception ex) | ||
{ | ||
IastModule.Log.Warning(ex, $"Error invoking {nameof(DefaultInterpolatedStringHandlerAspect)}.{nameof(AppendFormatted2)}"); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// System.Runtime DefaultInterpolatedStringHandler.AppendFormatted(Object, Int32, String) aspect | ||
/// </summary> | ||
/// <param name="target"> the ref DefaultInterpolatedStringHandler </param> | ||
/// <param name="value"> the object value </param> | ||
/// <param name="alignment"> the alignment value </param> | ||
/// <param name="format"> the format value </param> | ||
[AspectMethodReplace("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::AppendFormatted(System.Object,System.Int32,System.String)")] | ||
public static void AppendFormatted3(ref DefaultInterpolatedStringHandler target, object? value, int alignment, string? format) | ||
{ | ||
target.AppendFormatted(value, alignment, format); | ||
try | ||
{ | ||
if (value is string str) | ||
{ | ||
DefaultInterpolatedStringHandlerModuleImpl.Append(ToPointer(ref target), str); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
IastModule.Log.Warning(ex, $"Error invoking {nameof(DefaultInterpolatedStringHandlerAspect)}.{nameof(AppendFormatted3)}"); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// System.Runtime DefaultInterpolatedStringHandler.AppendFormatted(T) aspect | ||
/// </summary> | ||
/// <typeparam name="T">The first generic type parameter.</typeparam> | ||
/// <param name="target"> the ref DefaultInterpolatedStringHandler </param> | ||
/// <param name="value"> the string value </param> | ||
[AspectMethodReplace("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::AppendFormatted(!!0)")] | ||
public static void AppendFormatted4<T>(ref DefaultInterpolatedStringHandler target, T value) | ||
{ | ||
target.AppendFormatted<T>(value); | ||
try | ||
{ | ||
if (value is string str) | ||
{ | ||
DefaultInterpolatedStringHandlerModuleImpl.Append(ToPointer(ref target), str); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
IastModule.Log.Warning(ex, $"Error invoking {nameof(DefaultInterpolatedStringHandlerAspect)}.{nameof(AppendFormatted4)}"); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// System.Runtime DefaultInterpolatedStringHandler.AppendFormatted(T, String) aspect | ||
/// </summary> | ||
/// <typeparam name="T">The first generic type parameter.</typeparam> | ||
/// <param name="target"> the ref DefaultInterpolatedStringHandler </param> | ||
/// <param name="value"> the string value </param> | ||
/// <param name="alignment"> the alignment value </param> | ||
[AspectMethodReplace("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::AppendFormatted(!!0,System.Int32)")] | ||
public static void AppendFormatted5<T>(ref DefaultInterpolatedStringHandler target, T value, int alignment) | ||
{ | ||
target.AppendFormatted(value, alignment); | ||
try | ||
{ | ||
if (value is string str) | ||
{ | ||
DefaultInterpolatedStringHandlerModuleImpl.Append(ToPointer(ref target), str); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
IastModule.Log.Warning(ex, $"Error invoking {nameof(DefaultInterpolatedStringHandlerAspect)}.{nameof(AppendFormatted5)}"); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// System.Runtime DefaultInterpolatedStringHandler.AppendFormatted(T, String) aspect | ||
/// </summary> | ||
/// <typeparam name="T">The first generic type parameter.</typeparam> | ||
/// <param name="target"> the ref DefaultInterpolatedStringHandler </param> | ||
/// <param name="value"> the string value </param> | ||
/// <param name="format"> the format value </param> | ||
[AspectMethodReplace("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::AppendFormatted(!!0,System.String)")] | ||
public static void AppendFormatted6<T>(ref DefaultInterpolatedStringHandler target, T value, string? format) | ||
{ | ||
target.AppendFormatted(value, format); | ||
try | ||
{ | ||
if (value is string str) | ||
{ | ||
DefaultInterpolatedStringHandlerModuleImpl.Append(ToPointer(ref target), str); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
IastModule.Log.Warning(ex, $"Error invoking {nameof(DefaultInterpolatedStringHandlerAspect)}.{nameof(AppendFormatted6)}"); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// System.Runtime DefaultInterpolatedStringHandler.AppendFormatted(T, String) aspect | ||
/// </summary> | ||
/// <typeparam name="T">The first generic type parameter.</typeparam> | ||
/// <param name="target"> the ref DefaultInterpolatedStringHandler </param> | ||
/// <param name="value"> the string value </param> | ||
/// <param name="alignment"> the alignment value </param> | ||
/// <param name="format"> the format value </param> | ||
[AspectMethodReplace("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::AppendFormatted(!!0,System.Int32,System.String)")] | ||
public static void AppendFormatted7<T>(ref DefaultInterpolatedStringHandler target, T value, int alignment, string? format) | ||
{ | ||
target.AppendFormatted(value, alignment, format); | ||
try | ||
{ | ||
if (value is string str) | ||
{ | ||
DefaultInterpolatedStringHandlerModuleImpl.Append(ToPointer(ref target), str); | ||
} | ||
} | ||
catch (Exception ex) | ||
{ | ||
IastModule.Log.Warning(ex, $"Error invoking {nameof(DefaultInterpolatedStringHandlerAspect)}.{nameof(AppendFormatted7)}"); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// System.Runtime DefaultInterpolatedStringHandler.AppendLiteral(String) aspect | ||
/// </summary> | ||
/// <param name="target"> the ref DefaultInterpolatedStringHandler </param> | ||
/// <param name="value"> the string value </param> | ||
[AspectMethodReplace("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::AppendLiteral(System.String)")] | ||
public static void AppendLiteral(ref DefaultInterpolatedStringHandler target, string value) | ||
{ | ||
target.AppendLiteral(value); | ||
try | ||
{ | ||
DefaultInterpolatedStringHandlerModuleImpl.Append(ToPointer(ref target), value); | ||
} | ||
catch (Exception ex) | ||
{ | ||
IastModule.Log.Warning(ex, $"Error invoking {nameof(DefaultInterpolatedStringHandlerAspect)}.{nameof(AppendLiteral)}"); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// System.Runtime DefaultInterpolatedStringHandler.ToStringAndClear aspect | ||
/// </summary> | ||
/// <param name="target"> the ref DefaultInterpolatedStringHandler </param> | ||
/// <returns> the string value </returns> | ||
[AspectMethodReplace("System.Runtime.CompilerServices.DefaultInterpolatedStringHandler::ToStringAndClear()")] | ||
public static string ToStringAndClear(ref DefaultInterpolatedStringHandler target) | ||
{ | ||
var result = target.ToStringAndClear(); | ||
try | ||
{ | ||
DefaultInterpolatedStringHandlerModuleImpl.PropagateTaint(ToPointer(ref target), result); | ||
} | ||
catch (Exception ex) | ||
{ | ||
IastModule.Log.Warning(ex, $"Error invoking {nameof(DefaultInterpolatedStringHandlerAspect)}.{nameof(ToStringAndClear)}"); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
private static IntPtr ToPointer(ref DefaultInterpolatedStringHandler ts) | ||
{ | ||
Ldarg(nameof(ts)); | ||
return IL.Return<IntPtr>(); | ||
} | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
110 changes: 110 additions & 0 deletions
110
tracer/src/Datadog.Trace/Iast/Propagation/DefaultInterpolatedStringHandlerModuleImpl.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// <copyright file="DefaultInterpolatedStringHandlerModuleImpl.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> | ||
|
||
#if NET6_0_OR_GREATER | ||
|
||
#nullable enable | ||
|
||
using System; | ||
using System.Runtime.CompilerServices; | ||
using System.Runtime.InteropServices; | ||
using System.Text; | ||
using Datadog.Trace.VendoredMicrosoftCode.System.Runtime.InteropServices; | ||
|
||
namespace Datadog.Trace.Iast.Propagation; | ||
|
||
internal static class DefaultInterpolatedStringHandlerModuleImpl | ||
{ | ||
public static unsafe void Append(IntPtr target, string? value) | ||
{ | ||
FullTaintIfAnyTainted(target, value); | ||
} | ||
|
||
public static unsafe void FullTaintIfAnyTainted(IntPtr target, string? input) | ||
{ | ||
try | ||
{ | ||
IastModule.OnExecutedPropagationTelemetry(); | ||
|
||
if (input is null) | ||
{ | ||
return; | ||
} | ||
|
||
var iastContext = IastModule.GetIastContext(); | ||
if (iastContext is null) | ||
{ | ||
return; | ||
} | ||
|
||
var taintedObjects = iastContext.GetTaintedObjects(); | ||
var tainted = PropagationModuleImpl.GetTainted(taintedObjects, target); | ||
var targetIsTainted = tainted is not null; | ||
|
||
if (!targetIsTainted && (tainted = GetTaintedWithRanges(taintedObjects, input)) is null) | ||
{ | ||
return; | ||
} | ||
|
||
var rangesResult = new[] { new Range(0, 0, tainted!.Ranges[0].Source, tainted.Ranges[0].SecureMarks) }; | ||
if (!targetIsTainted) | ||
{ | ||
taintedObjects.Taint(target, rangesResult); | ||
} | ||
else | ||
{ | ||
tainted.Ranges = rangesResult; | ||
} | ||
} | ||
catch (Exception error) | ||
{ | ||
IastModule.Log.Error(error, $"{nameof(DefaultInterpolatedStringHandlerModuleImpl)}.{nameof(FullTaintIfAnyTainted)} exception"); | ||
} | ||
} | ||
|
||
public static object? PropagateTaint(object? input, string? result) | ||
{ | ||
try | ||
{ | ||
IastModule.OnExecutedPropagationTelemetry(); | ||
|
||
if (result is null || input is null) | ||
{ | ||
return result; | ||
} | ||
|
||
var iastContext = IastModule.GetIastContext(); | ||
if (iastContext == null) | ||
{ | ||
return result; | ||
} | ||
|
||
var taintedObjects = iastContext.GetTaintedObjects(); | ||
var taintedSelf = taintedObjects.Get(input); | ||
|
||
if (taintedSelf == null) | ||
{ | ||
return result; | ||
} | ||
|
||
var range = new Range(0, result.Length, taintedSelf.Ranges[0].Source, taintedSelf.Ranges[0].SecureMarks); | ||
taintedObjects.Taint(result, [range]); | ||
} | ||
catch (Exception err) | ||
{ | ||
IastModule.Log.Error(err, $"{nameof(DefaultInterpolatedStringHandlerModuleImpl)}.{nameof(PropagateTaint)} exception"); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
private static TaintedObject? GetTaintedWithRanges(TaintedObjects taintedObjects, object? value) | ||
{ | ||
var tainted = PropagationModuleImpl.GetTainted(taintedObjects, value); | ||
return tainted is not null && tainted?.Ranges.Length > 0 ? tainted : null; | ||
} | ||
} | ||
|
||
#endif |
Oops, something went wrong.