Skip to content

Hollowed out public types extending from System.Security.Permissions types #869

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

Merged
merged 11 commits into from
Jun 13, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public static XamlAccessLevel PrivateAccessTo(string assemblyQualifiedTypeName)
int nameBoundary = assemblyQualifiedTypeName.IndexOf(',');
if (nameBoundary < 0)
{
throw new ArgumentException(SR.Get(SRID.ExpectedQualifiedTypeName, assemblyQualifiedTypeName), nameof(assemblyQualifiedTypeName));
throw new ArgumentException("", nameof(assemblyQualifiedTypeName));
}

string typeName = assemblyQualifiedTypeName.Substring(0, nameBoundary).Trim();
Expand Down Expand Up @@ -94,13 +94,13 @@ internal static XamlAccessLevel FromXml(SecurityElement elem)
{
if (elem.Tag != XmlConstants.XamlAccessLevel)
{
throw new ArgumentException(SR.Get(SRID.SecurityXmlUnexpectedTag, elem.Tag, XmlConstants.XamlAccessLevel), nameof(elem));
throw new ArgumentException("", nameof(elem));
}

string assemblyNameString = elem.Attribute(XmlConstants.AssemblyName);
if (assemblyNameString == null)
{
throw new ArgumentException(SR.Get(SRID.SecurityXmlMissingAttribute, XmlConstants.AssemblyName), nameof(elem));
throw new ArgumentException("", nameof(elem));
}
AssemblyName assemblyName = new AssemblyName(assemblyNameString);
ValidateAssemblyName(assemblyName, "elem");
Expand Down Expand Up @@ -136,7 +136,7 @@ private static void ValidateAssemblyName(AssemblyName assemblyName, string argNa
if (assemblyName.Name == null || assemblyName.Version == null ||
assemblyName.CultureInfo == null || assemblyName.GetPublicKeyToken() == null)
{
throw new ArgumentException(SR.Get(SRID.ExpectedQualifiedAssemblyName, assemblyName.FullName), argName);
throw new ArgumentException("", argName);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
Expand All @@ -14,327 +13,33 @@ namespace System.Xaml.Permissions
[Serializable]
public sealed class XamlLoadPermission : CodeAccessPermission, IUnrestrictedPermission
{
private static IList<XamlAccessLevel> s_emptyAccessLevel;
private bool _isUnrestricted;

public XamlLoadPermission(PermissionState state)
{
Init(state == PermissionState.Unrestricted, null);
}

public XamlLoadPermission(XamlAccessLevel allowedAccess)
{
if (allowedAccess == null)
{
throw new ArgumentNullException(nameof(allowedAccess));
}
Init(false, new XamlAccessLevel[] { allowedAccess });
}

public XamlLoadPermission(IEnumerable<XamlAccessLevel> allowedAccess)
{
if (allowedAccess == null)
{
throw new ArgumentNullException(nameof(allowedAccess));
}
List<XamlAccessLevel> accessList = new List<XamlAccessLevel>(allowedAccess);
foreach (XamlAccessLevel accessLevel in allowedAccess)
{
if (accessLevel == null)
{
throw new ArgumentException(SR.Get(SRID.CollectionCannotContainNulls, "allowedAccess"));
}
accessList.Add(accessLevel);
}
Init(false, accessList);
}

private IList<XamlAccessLevel> _emptyAccessLevel = new ReadOnlyCollection<XamlAccessLevel>(Array.Empty<XamlAccessLevel>());
public XamlLoadPermission(PermissionState state) { }
public XamlLoadPermission(XamlAccessLevel allowedAccess) { }
public XamlLoadPermission(IEnumerable<XamlAccessLevel> allowedAccess) { }
#if NETCOREAPP3_0

[ComVisible(false)]
public override bool Equals(object obj)
{
IPermission perm = obj as IPermission;
if (obj != null && perm == null)
{
return false;
}

try
{
if (!IsSubsetOf(perm))
{
return false;
}

if (perm != null && !perm.IsSubsetOf(this))
{
return false;
}
}
catch (ArgumentException)
{
// Any argument exception implies inequality
// Note that we require a try/catch here because we have to deal with
// custom permissions that may throw exceptions indiscriminately
return false;
}

return true;
}

public override bool Equals(object obj) { return false; }
Copy link

@weltkante weltkante Jun 13, 2019

Choose a reason for hiding this comment

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

This is not a valid implementation because x.Equals(x) returns false, which will cause all sorts of bugs if anyone calls this method. You should use ReferenceEquals(this, obj) or throw an exception if you don't want to support equality.

Copy link
Member

Choose a reason for hiding this comment

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

This impl. will get deleted from dotnet/wpf shortly, and we'll consume the one from dotnet/corefx#38405. Let's make sure we get the corefx PR right.

[ComVisible(false)]
public override int GetHashCode()
{
// This implementation is only to silence a compiler warning
return base.GetHashCode();
}

public override int GetHashCode() { return base.GetHashCode(); }
#endif

// copy ctor. We can reuse the list of the existing instance, because it is a
// ReadOnlyCollection over a privately created array, hence is never mutated,
// even if the other instance is mutated via FromXml().
private XamlLoadPermission(XamlLoadPermission other)
{
_isUnrestricted = other._isUnrestricted;
AllowedAccess = other.AllowedAccess;
}

private void Init(bool isUnrestricted, IList<XamlAccessLevel> allowedAccess)
{
_isUnrestricted = isUnrestricted;
if (allowedAccess == null)
{
if (s_emptyAccessLevel == null)
{
s_emptyAccessLevel = new ReadOnlyCollection<XamlAccessLevel>(Array.Empty<XamlAccessLevel>());
}
AllowedAccess = s_emptyAccessLevel;
}
else
{
Debug.Assert(!isUnrestricted);
AllowedAccess = new ReadOnlyCollection<XamlAccessLevel>(allowedAccess);
}
}

public IList<XamlAccessLevel> AllowedAccess { get; private set; } // ReadOnlyCollection

public override IPermission Copy()
{
return new XamlLoadPermission(this);
}

public override void FromXml(SecurityElement elem)
{
if (elem == null)
{
throw new ArgumentNullException(nameof(elem));
}
if (elem.Tag != XmlConstants.IPermission)
public IList<XamlAccessLevel> AllowedAccess
{
get
{
throw new ArgumentException(SR.Get(SRID.SecurityXmlUnexpectedTag, elem.Tag, XmlConstants.IPermission), nameof(elem));
return _emptyAccessLevel;
}

string className = elem.Attribute(XmlConstants.Class);
if (!className.StartsWith(GetType().FullName, false, TypeConverterHelper.InvariantEnglishUS))
private set
{
throw new ArgumentException(SR.Get(SRID.SecurityXmlUnexpectedValue, className, XmlConstants.Class, GetType().FullName), nameof(elem));
}

string version = elem.Attribute(XmlConstants.Version);
if (version != null && version != XmlConstants.VersionNumber)
{
throw new ArgumentException(SR.Get(SRID.SecurityXmlUnexpectedValue, className, XmlConstants.Version, XmlConstants.VersionNumber), nameof(elem));
}

string unrestricted = elem.Attribute(XmlConstants.Unrestricted);
if (unrestricted != null && bool.Parse(unrestricted))
{
Init(true, null);
}
else
{
List<XamlAccessLevel> allowedAccess = null;
if (elem.Children != null)
{
allowedAccess = new List<XamlAccessLevel>(elem.Children.Count);
foreach (SecurityElement child in elem.Children)
{
allowedAccess.Add(XamlAccessLevel.FromXml(child));
}
}
Init(false, allowedAccess);
}
}

public bool Includes(XamlAccessLevel requestedAccess)
{
if (requestedAccess == null)
{
throw new ArgumentNullException(nameof(requestedAccess));
}
if (_isUnrestricted)
{
return true;
}
foreach (XamlAccessLevel allowedAccess in AllowedAccess)
{
if (allowedAccess.Includes(requestedAccess))
{
return true;
}
}
return false;
}

public override IPermission Intersect(IPermission target)
{
if (target == null)
{
return null;
}
XamlLoadPermission other = CastPermission(target, "target");
if (other.IsUnrestricted())
{
return Copy();
}
if (IsUnrestricted())
{
return other.Copy();
}

List<XamlAccessLevel> result = new List<XamlAccessLevel>();
// We could optimize this with a hash, but we don't expect people to be creating
// large unions of access levels.
foreach (XamlAccessLevel accessLevel in AllowedAccess)
{
// First try the full access level
if (other.Includes(accessLevel))
{
result.Add(accessLevel);
}
// Then try the assembly subset
else if (accessLevel.PrivateAccessToTypeName != null)
{
XamlAccessLevel assemblyAccess = accessLevel.AssemblyOnly();
if (other.Includes(assemblyAccess))
{
result.Add(assemblyAccess);
}
}
}
return new XamlLoadPermission(result);
}

public override bool IsSubsetOf(IPermission target)
{
if (target == null)
{
bool isEmpty = !IsUnrestricted() && AllowedAccess.Count == 0;
return isEmpty;
}
XamlLoadPermission other = CastPermission(target, "target");
if (other.IsUnrestricted())
{
return true;
}
if (IsUnrestricted())
{
return false;
}

foreach (XamlAccessLevel accessLevel in AllowedAccess)
{
if (!other.Includes(accessLevel))
{
return false;
}
}
return true;
}

public override SecurityElement ToXml()
{
SecurityElement securityElement = new SecurityElement(XmlConstants.IPermission);
securityElement.AddAttribute(XmlConstants.Class, GetType().AssemblyQualifiedName);
securityElement.AddAttribute(XmlConstants.Version, XmlConstants.VersionNumber);

if (IsUnrestricted())
{
securityElement.AddAttribute(XmlConstants.Unrestricted, Boolean.TrueString);
}
else
{
foreach (XamlAccessLevel accessLevel in AllowedAccess)
{
securityElement.AddChild(accessLevel.ToXml());
}
}

return securityElement;
}

public override IPermission Union(IPermission other)
{
if (other == null)
{
return Copy();
}
XamlLoadPermission xamlOther = CastPermission(other, "other");
if (IsUnrestricted() || xamlOther.IsUnrestricted())
{
return new XamlLoadPermission(PermissionState.Unrestricted);
}

List<XamlAccessLevel> mergedAccess = new List<XamlAccessLevel>(AllowedAccess);
foreach (XamlAccessLevel accessLevel in xamlOther.AllowedAccess)
{
if (!Includes(accessLevel))
{
mergedAccess.Add(accessLevel);
if (accessLevel.PrivateAccessToTypeName != null)
{
// If we have an entry for access to just the assembly of this type, it is now redundant
for (int i = 0; i < mergedAccess.Count; i++)
{
if (mergedAccess[i].PrivateAccessToTypeName == null &&
mergedAccess[i].AssemblyNameString == accessLevel.AssemblyNameString)
{
mergedAccess.RemoveAt(i);
break;
}
}
}
}
}
return new XamlLoadPermission(mergedAccess);
}

public bool IsUnrestricted()
{
return _isUnrestricted;
}

private static XamlLoadPermission CastPermission(IPermission other, string argName)
{
XamlLoadPermission result = other as XamlLoadPermission;
if (result == null)
{
throw new ArgumentException(SR.Get(SRID.ExpectedLoadPermission), argName);
}
return result;
}

private static class XmlConstants
{
public const string IPermission = "IPermission";
public const string Class = "class";
public const string Version = "version";
public const string VersionNumber = "1";
public const string Unrestricted = "Unrestricted";
}
public override IPermission Copy() { return default(IPermission); }
public override void FromXml(SecurityElement elem) { }
public bool Includes(XamlAccessLevel requestedAccess) { return false; }
public override IPermission Intersect(IPermission target) { return default(IPermission); }
public override bool IsSubsetOf(IPermission target) { return false; }
public override SecurityElement ToXml() { return default(SecurityElement); }
public override IPermission Union(IPermission other) { return default(IPermission); }
public bool IsUnrestricted() { return true; }
}

}
Loading