Skip to content
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

Microsoft.Extensions.Configuration.ConfigurationBinder.BindProperty(PropertyInfo,object, IConfiguration, BinderOptions) – harmful call to PropertyInfo.GetValue(object) #52905

Closed
deep-outcome opened this issue May 18, 2021 · 5 comments · Fixed by #60415, #63586 or #66723
Labels
area-Extensions-Configuration help wanted [up-for-grabs] Good issue for external contributors
Milestone

Comments

@deep-outcome
Copy link

deep-outcome commented May 18, 2021

Description

The ConfigurationBinder.BindProperty seems to be

private static void BindProperty(PropertyInfo property, object instance, IConfiguration config, BinderOptions options)
{
    // We don't support set only, non public, or indexer properties
    if (property.GetMethod == null ||
        (!options.BindNonPublicProperties && !property.GetMethod.IsPublic) ||
        property.GetMethod.GetParameters().Length > 0)
    {
        return;
    }

    object propertyValue = property.GetValue(instance);
    bool hasSetter = property.SetMethod != null && (property.SetMethod.IsPublic || options.BindNonPublicProperties);

    if (propertyValue == null && !hasSetter)
    {
        // Property doesn't have a value and we cannot set it so there is no
        // point in going further down the graph
        return;
    }

    propertyValue = GetPropertyValue(property, instance, config, options);

    if (propertyValue != null && hasSetter)
    {
        property.SetValue(instance, propertyValue);
    }
}

Lines object propertyValue = property.GetValue(instance); ,

if (propertyValue == null && !hasSetter)
{
  // Property doesn't have a value and we cannot set it so there is no
  // point in going further down the graph
  return;
}

are obviously some debris somebody forgotten to remove. The line object propertyValue = property.GetValue(instance); can call to properties with not setter – like static properties – forcing them to execute.

Moreover, why to obtain any property value before asking if it can be passed to existing setter. 👎🏻

Configuration

Microsoft.Extensions.Configuration.Binder 5.0.0 on .NET 5.0

Area

area-Extensions-Configuration

@dotnet-issue-labeler dotnet-issue-labeler bot added the untriaged New issue has not been triaged by the area owner label May 18, 2021
@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@deep-outcome deep-outcome changed the title Microsoft.Extensions.Configuration.ConfigurationBinder.BindProperty(PropertyInfo,object, IConfiguration, BinderOptions) – useless call to PropertyInfo.GetValue(object) Microsoft.Extensions.Configuration.ConfigurationBinder.BindProperty(PropertyInfo,object, IConfiguration, BinderOptions) – harmful call to PropertyInfo.GetValue(object) May 18, 2021
@ghost
Copy link

ghost commented May 18, 2021

Tagging subscribers to this area: @maryamariyan, @safern
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

The ConfigurationBinder.BindProperty seems to be

private static void BindProperty(PropertyInfo property, object instance, IConfiguration config, BinderOptions options)
{
    // We don't support set only, non public, or indexer properties
    if (property.GetMethod == null ||
        (!options.BindNonPublicProperties && !property.GetMethod.IsPublic) ||
        property.GetMethod.GetParameters().Length > 0)
    {
        return;
    }

    object propertyValue = property.GetValue(instance);
    bool hasSetter = property.SetMethod != null && (property.SetMethod.IsPublic || options.BindNonPublicProperties);

    if (propertyValue == null && !hasSetter)
    {
        // Property doesn't have a value and we cannot set it so there is no
        // point in going further down the graph
        return;
    }

    propertyValue = GetPropertyValue(property, instance, config, options);

    if (propertyValue != null && hasSetter)
    {
        property.SetValue(instance, propertyValue);
    }
}

Lines object propertyValue = property.GetValue(instance); ,

if (propertyValue == null && !hasSetter)
{
  // Property doesn't have a value and we cannot set it so there is no
  // point in going further down the graph
  return;
}

are obviously some debris somebody forgotten to remove. The line object propertyValue = property.GetValue(instance); can call to properties with not setter – like static properties – forcing them to execute.

Moreover, why to obtain any property value before asking if it can be passed to existing setter. 👎🏻

Configuration

Microsoft.Extensions.Configuration.Binder 5.0.0 on .NET 5.0

Area

area-Extensions-Configuration

Author: Uzivatel919
Assignees: -
Labels:

area-Extensions-Configuration, untriaged

Milestone: -

@maryamariyan maryamariyan removed the untriaged New issue has not been triaged by the area owner label Jun 5, 2021
@maryamariyan maryamariyan added this to the Future milestone Jun 5, 2021
@david-jarman
Copy link

This is currently biting me, where I have a read-only property on one of my objects that can potentially throw an exception if called before some extra setup is executed. This forces me to modify the behavior of the property so it doesn't throw while the binding process is happening.

example:

public class BindingObject
{
    public string BindThisString { get; set; }

    public OtherObject ThisIsNotSetDuringBinding { get; set; }

    // This will throw an exception during binding, because the get is called for no good reason
    public string DerivedPropertyString => $"DerivedProperty={ThisIsNotSetDuringBinding .Id}"
}

@safern safern modified the milestones: Future, 7.0.0 Oct 1, 2021
@safern safern added the help wanted [up-for-grabs] Good issue for external contributors label Oct 1, 2021
danielmpetrov added a commit to danielmpetrov/runtime that referenced this issue Oct 14, 2021
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Oct 14, 2021
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Oct 14, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Nov 14, 2021
@ericstj ericstj reopened this Jan 10, 2022
@ericstj
Copy link
Member

ericstj commented Jan 10, 2022

Reopening since the fix introduced a regression and will be reverted.

@ericstj
Copy link
Member

ericstj commented Jan 10, 2022

Make sure that any fix for this in the future accounts for the scenario here: #63479

@ericstj ericstj reopened this Jan 10, 2022
madelson added a commit to madelson/runtime that referenced this issue Mar 16, 2022
Previously, ConfigurationBinder would eagerly read properties it
encountered and initialize/bind objects for them even when those
reads/initializations could lead to thrown exceptions or unnecessary
work. Now, we defer work until we determine that it will actually
contribute to the final binding result.

Fix dotnet#52905
Fix dotnet#65710
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.