Skip to content

Fix: Rabbitmq7 header injection overwrites user supplied basic properties #6730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

johang88
Copy link

Note: Created as draft as I have not actually run or tested the changes 😶

Summary of changes

Fixes the header injection so that basic properties are preserved from the supplied argument list in case PopulateBasicPropertiesHeaders returns null which happens if the basic properties argument is writable or if no changes had to be made to it.

Reason for change

Fixes a bug that would remove all user supplied basic properties.

Implementation details

Stores the basicproperties argument in the active scope and retrieves it a null return value is encountered. Changed CachedBasicPropertiesHelper to call the copy constructor that takes a IReadOnlyBasicProperties as argument.

Test coverage

Added basic properties to one of the rabbitmq7 test methods as well as assertions.

Other details

Fixes #6723

@johang88 johang88 requested review from a team as code owners February 28, 2025 13:15
@lucaspimentel
Copy link
Member

@johang88: Thanks for this! We'll take a look, run all tests, and merge it if all goes well.

Copy link
Collaborator

@bouwkast bouwkast left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey thanks a lot @johang88

I ran the CI against this and am seeing test failures for 7.1.0 related to the new Activator code

Comment on lines 22 to 38
var targetType = typeof(TBasicProperties).Assembly.GetType("RabbitMQ.Client.BasicProperties")!;
var parameterType = typeof(TBasicProperties).Assembly.GetType("RabbitMQ.Client.IReadOnlyBasicProperties")!;

var constructor = targetType.GetConstructor([parameterType])!;

var createBasicPropertiesMethod = new DynamicMethod(
$"TypeActivator_{targetType.Name}_{parameterType.Name}",
targetType,
[parameterType],
typeof(DuckType).Module,
true);

var il = createBasicPropertiesMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Newobj, constructor);
il.Emit(OpCodes.Ret);
Activator = (Func<object, object>)createBasicPropertiesMethod.CreateDelegate(typeof(Func<object, object>), targetType);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately it looks like this is throwing an exception when attempting to run the tests / sample

[ERR] Exception occurred when calling the CallTarget integration continuation. System.TypeInitializationException: The type initializer for 'Datadog.Trace.ClrProfiler.AutoInstrumentation.RabbitMQ.CachedBasicPropertiesHelper`1' threw an exception.
 ---> System.ArgumentException: Cannot bind to the target method because its signature is not compatible with that of the delegate type.
   at System.Delegate.CreateDelegateNoSecurityCheck(Type type, Object target, RuntimeMethodHandle method)
   at System.Reflection.Emit.DynamicMethod.CreateDelegate(Type delegateType, Object target)
   at Datadog.Trace.ClrProfiler.AutoInstrumentation.RabbitMQ.CachedBasicPropertiesHelper`1..cctor() 

}
else if (state.State.DuckIs<IReadOnlyBasicProperties>())
{
returnValue = CachedBasicPropertiesHelper<TReturn>.CreateHeaders(state.State!);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we need to preserve / copy headers here?
Haven't tested it out if that is necessary though

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll take a look and see if I can sort it out. We definitely need to copy the basic properties and headers as they will be dropped completely from the message otherwise. For example the current implementation completely breaks our rabbitmq message sender if instrumentation is enabled as the messageid, timestame, persistance settings will be removed.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!
And let us know if need help on this as we definitely want to fix this

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a commit that should fix the activator, not super happy about the cast but also not sure how to get rid of it. But I suppose optimizations can come after it's working properly :)

il.Emit(OpCodes.Castclass, parameterType); // Cast to IReadOnlyBasicProperties
il.Emit(OpCodes.Newobj, constructor);
il.Emit(OpCodes.Ret);
Activator = (Func<object, object>)createBasicPropertiesMethod.CreateDelegate(typeof(Func<object, object>), targetType);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@johang88: After some debugging, we figured out that the call to CreateDelegate() here was throwing an exception about the method signatures not matching. I fixed the issue by removing the targetType parameter, since the dynamic method will not be bound to a type (i.e. it acts like a static method, not an instance method).

We had to copy your commits into a new branch in the repository to run all our tests: see #6753. Once we get that new PR reviewed and approved, and all tests pass, we will merge that one in favor of this one. Your commits are still attributed to you as the author, though. Thanks for your help with this issue.

andrewlock added a commit that referenced this pull request Mar 20, 2025
…c properties [from external PR #6730] (#6753)

Based on #6730 by @johang88.

## Summary of changes
Fixes the header injection so that basic properties are preserved from
the supplied argument list in case `PopulateBasicPropertiesHeaders`
returns null which happens if the basic properties argument is writable
or if no changes had to be made to it.

## Reason for change
Fixes a bug that would remove all user supplied basic properties.

## Implementation details
Stores the basicproperties argument in the active scope and retrieves it
a null return value is encountered. Changed
`CachedBasicPropertiesHelper` to call the copy constructor that takes a
`IReadOnlyBasicProperties` as argument.

## Test coverage
Added basic properties to one of the rabbitmq7 test methods as well as
assertions.

## Other details
Fixes #6723

---------

Co-authored-by: Andrew Lock <[email protected]>
Co-authored-by: Johan Gustafsson <[email protected]>
@andrewlock
Copy link
Member

Hi @johang88, thanks for the effort on this - it took longer than we hoped to resolve some issues in the tests, and we had to create a separate PR #6753 which has just been merged. Thanks again for raising it and proposing the fix, it's much appreciated!

@andrewlock andrewlock closed this Mar 20, 2025
@lucaspimentel lucaspimentel added this to the vNext-v3 milestone Mar 21, 2025
ddyurchenko pushed a commit that referenced this pull request Mar 31, 2025
…c properties [from external PR #6730] (#6753)

Based on #6730 by @johang88.

## Summary of changes
Fixes the header injection so that basic properties are preserved from
the supplied argument list in case `PopulateBasicPropertiesHeaders`
returns null which happens if the basic properties argument is writable
or if no changes had to be made to it.

## Reason for change
Fixes a bug that would remove all user supplied basic properties.

## Implementation details
Stores the basicproperties argument in the active scope and retrieves it
a null return value is encountered. Changed
`CachedBasicPropertiesHelper` to call the copy constructor that takes a
`IReadOnlyBasicProperties` as argument.

## Test coverage
Added basic properties to one of the rabbitmq7 test methods as well as
assertions.

## Other details
Fixes #6723

---------

Co-authored-by: Andrew Lock <[email protected]>
Co-authored-by: Johan Gustafsson <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG]: RabbitMQ Basic Properties overwritten to default values
4 participants