-
Notifications
You must be signed in to change notification settings - Fork 5k
Obsolete XmlSecureResolver #73676
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
Obsolete XmlSecureResolver #73676
Conversation
…te all call sites to the new API
Note regarding the This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, to please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change. |
Tagging subscribers to this area: @dotnet/area-system-xml Issue DetailsResolves #73636. Obsoletes the
|
Added When you commit this breaking change:
Tagging @dotnet/compat for awareness of the breaking change. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make Singelton fields readonly?
// An XmlResolver that forbids all external entity resolution. | ||
private sealed class XmlThrowingResolver : XmlResolver | ||
{ | ||
internal static XmlThrowingResolver Singleton = new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
internal static XmlThrowingResolver Singleton = new(); | |
internal static readonly XmlThrowingResolver Singleton = new(); |
// (Copied from XmlResolver.ThrowingResolver.cs.) | ||
private sealed class XmlThrowingResolver : XmlResolver | ||
{ | ||
internal static XmlThrowingResolver Singleton = new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
internal static XmlThrowingResolver Singleton = new(); | |
internal static readonly XmlThrowingResolver Singleton = new(); |
src/libraries/System.Private.Xml/src/System/Xml/XmlResolver.ThrowingResolver.cs
Outdated
Show resolved
Hide resolved
...s/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlResolverHelper.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.Xml/src/System/Xml/XmlResolver.ThrowingResolver.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.Xml/src/System/Xml/XmlResolver.ThrowingResolver.cs
Show resolved
Hide resolved
if (xmlResolver == null || xmlResolver == XmlResolver.ThrowingResolver) | ||
origResolver = new XmlUrlResolver(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems a bit weird, if user explicitly chooses throwing resolver we will still go with XmlUrlResolver?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, thought the same. It looks like a bug, but perhaps I was being too deferential to preserving back-compat. Maybe killing that clause is the best option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I'd honestly go with just:
xmlResolver ??= XmlResolver.ThrowingResolver
or xmlResolver ??= new XmlUrlResolver()
depending if we expect unsafe inputs in those API
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like that line is meant to override whatever the "default" resolver is. For example, if you call XslCompiledTransform.Load(string)
, it will eventually hit:
runtime/src/libraries/System.Private.Xml/src/System/Xml/Xslt/XslTransform.cs
Lines 259 to 269 in e71a958
private static XmlResolver CreateDefaultResolver() | |
{ | |
if (LocalAppContextSwitches.AllowDefaultResolver) | |
{ | |
return new XmlUrlResolver(); | |
} | |
else | |
{ | |
return XmlNullResolver.Singleton; | |
} | |
} |
And the "ignore the null resolver" logic was apparently meant to work around this. This seems completely broken to me, since why bother putting in a secure default if we're just going to ignore it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it was added because the URL to the stylesheet itself (the arg passed to XslCompiledTransform.Load(string)
) also goes through the resolver for some reason. The system needs to strip it off temporarily - just while loading the outermost stylesheet - so that resolution can take place.
...s/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlResolverHelper.cs
Show resolved
Hide resolved
...s/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlResolverHelper.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Jeremy Barton <jbarton@microsoft.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has my approval once the build errors are resolved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than the test compilation issues, LGTM.
- Also improves error message on failure
Note to reviewers (@bartonjs @krwq) - the latest iteration does three things.
That third point really helped me with debugging the issues here, and if we're concerned that real-world customers might run into this as a regression then the improved error message can help them as well. (I'll merge once CI is green and there's an additional affirmative review.) |
(matches existing code patterns in this file)
|
||
public override Task<object> GetEntityAsync(Uri absoluteUri, string? role, Type? ofObjectToReturn) | ||
{ | ||
throw new XmlException(SR.Format(SR.Xml_NullResolver, absoluteUri)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we care about inside vs outside the task here?
It looks like other implementations are throwing XmlException "outside" the task, so I guess this isn't entirely wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's one of those weird edge cases that doesn't cleanly fit into any bucket. If I squint I can kinda claim that it's a usage error, since the caller shouldn't be invoking it in the first place. But ultimately I followed the pattern that the previous implementation threw the exception synchronously rather than wrapped within a task.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, LGTM
Resolves #73636.
Resolves #73637.
Resolves CVE-2022-34716.
Obsoletes the
System.Xml.XmlSecureResolver
type and introduces a new acceleratorXmlResolver.ThrowingResolver
for callers who need to forbid external entity resolution.