Home All Groups Group Topic Archive Search About

SecurityException thrown when serializing custom exception class

Author
19 Oct 2006 10:22 AM
Martin Liversage
I want to create a custom exception class that contains an additional field.
However, when I test my exception class I have a problem with serialization
where a SecurityException is thrown. Since I believe I have followed all the
rules (including using FxCop on my class) I have tried to simplify my
troubleshooting by creating a new custom exception very similar to the
System.ArgumentException class. This custom exception class called
MyException has code identical to System.ArgumentException (discovered by
using Reflector) including attributes. This code passes FxCop inspection
(except for some unimportant naming issues: "param" is "misspelled"). I try
to serialize it using the following code:

MyException x = new MyException("Message", "ParamName");
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, x);
stream.Position = 0;
x = (MyException) formatter.Deserialize(stream);

When this code is executed an exception is thrown in the call to
BinaryFormatter.Serialize(). (All the code is executed locally on my computer
in a fully trusted environment.)

The interesting part of the stack trace is as follows:

       at
System.Security.CodeAccessSecurityEngine.ThrowSecurityException(Assembly asm,
PermissionSet granted, PermissionSet refused, RuntimeMethodHandle rmh,
SecurityAction action, Object demand, IPermission permThatFailed)
       at
System.Security.CodeAccessSecurityEngine.ThrowSecurityException(Object
assemblyOrString, PermissionSet granted, PermissionSet refused,
RuntimeMethodHandle rmh, SecurityAction action, Object demand, IPermission
permThatFailed)
       at
System.Security.CodeAccessSecurityEngine.CheckSetHelper(PermissionSet grants,
PermissionSet refused, PermissionSet demands, RuntimeMethodHandle rmh, Object
assemblyOrString, SecurityAction action, Boolean throwException)
       at
System.Security.CodeAccessSecurityEngine.CheckSetHelper(CompressedStack cs,
PermissionSet grants, PermissionSet refused, PermissionSet demands,
RuntimeMethodHandle rmh, Assembly asm, SecurityAction action)
       at MyException.GetObjectData(SerializationInfo info, StreamingContext
context)
       at
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object
obj, ISurrogateSelector surrogateSelector, StreamingContext context,
SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter,
ObjectWriter objectWriter)
       at
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object
obj, ISurrogateSelector surrogateSelector, StreamingContext context,
SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter,
ObjectWriter objectWriter)
       at
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object
graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
       at
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
       at
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)

The exception thrown is SecurityException and the FirstPermissionThatFailed
property of this exception is:

<IPermission class="System.Security.Permissions.SecurityPermission,
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1" Flags="SerializationFormatter"/>

Since MyException is an replica of ArgumentException
MyException.GetObjectData() is marked with the following attribute:

[SecurityPermission(SecurityAction.LinkDemand,
Flags=SecurityPermissionFlag.SerializationFormatter)]

Removing the attribute doesn't fix the problem, but upsets FxCop.

What really puzzles me is that if I replace MyException with
ArgumentException no exception is thrown. Why? What should I do to fix my
custom exception class?

Thanks in advance.

--
Martin Liversage

Author
19 Oct 2006 10:24 AM
Martin Liversage
I forgot to mention that I'm using .NET 2.0.

--
Martin Liversage
Are all your drivers up to date? click for free checkup

Author
19 Oct 2006 11:25 AM
Claus Konrad
Remember to mark your own exception class with the Serializable attribute.
and provide the protected contructor taking SerializationInfo as argument.

The below works perfectly:
--
rgds.
/Claus Konrad

using System;
using System.IO;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;


namespace ExceptionSerialization
{
   class Program
   {
      static void Main(string[] args)
      {
         MyException ex = new MyException();

         MemoryStream msSerialize= new MemoryStream();
         BinaryFormatter form = new BinaryFormatter();

         //serialize the exception
         form.Serialize(msSerialize, ex);


         //deserialize
         msSerialize.Position = 0;
         MyException myEx = (MyException)form.Deserialize(msSerialize);

         Debug.Assert(myEx != null);

         Console.ReadKey();

      }
   }

   [Serializable]
   class MyException : System.ApplicationException
   {
      public MyException()
      {}

      public MyException(string message) : base(message)
      {
      }

      protected MyException(SerializationInfo info, StreamingContext
context) : base(info, context)
      {
      }
   }
}



--
rgds.
/Claus Konrad


Show quoteHide quote
"Martin Liversage" wrote:

> I want to create a custom exception class that contains an additional field.
> However, when I test my exception class I have a problem with serialization
> where a SecurityException is thrown. Since I believe I have followed all the
> rules (including using FxCop on my class) I have tried to simplify my
> troubleshooting by creating a new custom exception very similar to the
> System.ArgumentException class. This custom exception class called
> MyException has code identical to System.ArgumentException (discovered by
> using Reflector) including attributes. This code passes FxCop inspection
> (except for some unimportant naming issues: "param" is "misspelled"). I try
> to serialize it using the following code:
>
> MyException x = new MyException("Message", "ParamName");
> MemoryStream stream = new MemoryStream();
> BinaryFormatter formatter = new BinaryFormatter();
> formatter.Serialize(stream, x);
> stream.Position = 0;
> x = (MyException) formatter.Deserialize(stream);
>
> When this code is executed an exception is thrown in the call to
> BinaryFormatter.Serialize(). (All the code is executed locally on my computer
> in a fully trusted environment.)
>
> The interesting part of the stack trace is as follows:
>
>        at
> System.Security.CodeAccessSecurityEngine.ThrowSecurityException(Assembly asm,
> PermissionSet granted, PermissionSet refused, RuntimeMethodHandle rmh,
> SecurityAction action, Object demand, IPermission permThatFailed)
>        at
> System.Security.CodeAccessSecurityEngine.ThrowSecurityException(Object
> assemblyOrString, PermissionSet granted, PermissionSet refused,
> RuntimeMethodHandle rmh, SecurityAction action, Object demand, IPermission
> permThatFailed)
>        at
> System.Security.CodeAccessSecurityEngine.CheckSetHelper(PermissionSet grants,
> PermissionSet refused, PermissionSet demands, RuntimeMethodHandle rmh, Object
> assemblyOrString, SecurityAction action, Boolean throwException)
>        at
> System.Security.CodeAccessSecurityEngine.CheckSetHelper(CompressedStack cs,
> PermissionSet grants, PermissionSet refused, PermissionSet demands,
> RuntimeMethodHandle rmh, Assembly asm, SecurityAction action)
>        at MyException.GetObjectData(SerializationInfo info, StreamingContext
> context)
>        at
> System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object
> obj, ISurrogateSelector surrogateSelector, StreamingContext context,
> SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter,
> ObjectWriter objectWriter)
>        at
> System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object
> obj, ISurrogateSelector surrogateSelector, StreamingContext context,
> SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter,
> ObjectWriter objectWriter)
>        at
> System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object
> graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
>        at
> System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
>        at
> System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)
>
> The exception thrown is SecurityException and the FirstPermissionThatFailed
> property of this exception is:
>
> <IPermission class="System.Security.Permissions.SecurityPermission,
> mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
> version="1" Flags="SerializationFormatter"/>
>
> Since MyException is an replica of ArgumentException
> MyException.GetObjectData() is marked with the following attribute:
>
> [SecurityPermission(SecurityAction.LinkDemand,
> Flags=SecurityPermissionFlag.SerializationFormatter)]
>
> Removing the attribute doesn't fix the problem, but upsets FxCop.
>
> What really puzzles me is that if I replace MyException with
> ArgumentException no exception is thrown. Why? What should I do to fix my
> custom exception class?
>
> Thanks in advance.
>
> --
> Martin Liversage
>
Author
19 Oct 2006 11:41 AM
Martin Liversage
"Claus Konrad" wrote:

> Remember to mark your own exception class with the Serializable attribute.
> and provide the protected contructor taking SerializationInfo as argument.

Thanks for you input.

My custom exception is marked Serializable and contains the protected
constructor you are refering to. I have used Reflector to "reverse engineer"
ArgumentException, and my problem is that for some reason my exception throws
a SecurityException during serialization, but ArgumentException does not.

You example does not include a private field, and the SecurityException is
thrown in the ISerializable.GetObjectData() method where the private field is
supposed to be serialized. Your example works for me too by the way.

In case you are interested I include the code for MyException below:

using System;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Runtime.InteropServices;

namespace MyNamespace {

  [Serializable, ComVisible(true)]
  public class MyException : SystemException, ISerializable {

    public MyException() : base("MyException") { }

    public MyException(String message) : base(message) { }

    protected MyException(SerializationInfo info, StreamingContext context)
      : base(info, context) {
      if (info == null)
        throw new ArgumentNullException("info");
      this.m_paramName = info.GetString("ParamName");
    }

    public MyException(String message, Exception innerException) :
base(message, innerException) { }

    public MyException(String message, String paramName)
      : base(message) {
      this.m_paramName = paramName;
    }

    public MyException(String message, String paramName, Exception
innerException)
      : base(message, innerException) {
      this.m_paramName = paramName;
    }

    [SecurityPermission(SecurityAction.LinkDemand,
Flags=SecurityPermissionFlag.SerializationFormatter)]
    public override void GetObjectData(SerializationInfo info,
StreamingContext context) {
      if (info == null)
        throw new ArgumentNullException("info");
      base.GetObjectData(info, context);
      info.AddValue("ParamName", this.m_paramName, typeof(String));
    }

    public override String Message { get { return base.Message; } }

    public virtual String ParamName { get { return this.m_paramName; } }

    String m_paramName;

  }

}

--
Martin Liversage
Author
19 Oct 2006 12:40 PM
Claus Konrad
Right.
In case you are dealing with custom parameters, you need to cater for that
by adding these to the serialization info object (to be allowed to be
descerialised).

using System;
using System.IO;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Security.Permissions;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;


namespace ExceptionSerialization
{
   class Program
   {
      static void Main(string[] args)
      {
         string myMsg = "message";
         int par = 22;

         MyException ex = new MyException(myMsg, par);

         using (MemoryStream ms = new MemoryStream())
         {
            BinaryFormatter binForm = new BinaryFormatter();

            //serialize the exception
            binForm.Serialize(ms, ex);

            //deserialize
            ms.Position = 0;
            MyException myEx = (MyException)binForm.Deserialize(ms);

            Debug.Assert(myEx != null);
            Debug.Assert(myEx.SomeParameter.Equals(par));
            Debug.Assert(myEx.Message.Equals(myMsg));
         }
         Console.ReadKey();

      }
   }


   [Serializable]
   class MyException : System.ApplicationException
   {
      public MyException(string message, int someParamenter) : base(message)
      {
         this.m_somePar = someParamenter;
      }

      private int m_somePar;

      public int SomeParameter
      {
         get { return m_somePar; }
         set { m_somePar = value; }
      }

      protected MyException(SerializationInfo info, StreamingContext
context) : base(info, context)
      {
          m_somePar = info.GetInt32("myparameter");
      }

      [SecurityPermission(SecurityAction.LinkDemand,
Flags=SecurityPermissionFlag.SerializationFormatter)]
      public override void GetObjectData(SerializationInfo info,
StreamingContext context)
      {
         base.GetObjectData(info, context);
         info.AddValue("myparameter", m_somePar);
      }
   }
}
--
rgds.
/Claus Konrad


Show quoteHide quote
"Martin Liversage" wrote:

> "Claus Konrad" wrote:
>
> > Remember to mark your own exception class with the Serializable attribute.
> > and provide the protected contructor taking SerializationInfo as argument.
>
> Thanks for you input.
>
> My custom exception is marked Serializable and contains the protected
> constructor you are refering to. I have used Reflector to "reverse engineer"
> ArgumentException, and my problem is that for some reason my exception throws
> a SecurityException during serialization, but ArgumentException does not.
>
> You example does not include a private field, and the SecurityException is
> thrown in the ISerializable.GetObjectData() method where the private field is
> supposed to be serialized. Your example works for me too by the way.
>
> In case you are interested I include the code for MyException below:
>
> using System;
> using System.Runtime.Serialization;
> using System.Security.Permissions;
> using System.Runtime.InteropServices;
>
> namespace MyNamespace {
>
>   [Serializable, ComVisible(true)]
>   public class MyException : SystemException, ISerializable {
>
>     public MyException() : base("MyException") { }
>
>     public MyException(String message) : base(message) { }
>
>     protected MyException(SerializationInfo info, StreamingContext context)
>       : base(info, context) {
>       if (info == null)
>         throw new ArgumentNullException("info");
>       this.m_paramName = info.GetString("ParamName");
>     }
>
>     public MyException(String message, Exception innerException) :
> base(message, innerException) { }
>
>     public MyException(String message, String paramName)
>       : base(message) {
>       this.m_paramName = paramName;
>     }
>
>     public MyException(String message, String paramName, Exception
> innerException)
>       : base(message, innerException) {
>       this.m_paramName = paramName;
>     }
>
>     [SecurityPermission(SecurityAction.LinkDemand,
> Flags=SecurityPermissionFlag.SerializationFormatter)]
>     public override void GetObjectData(SerializationInfo info,
> StreamingContext context) {
>       if (info == null)
>         throw new ArgumentNullException("info");
>       base.GetObjectData(info, context);
>       info.AddValue("ParamName", this.m_paramName, typeof(String));
>     }
>
>     public override String Message { get { return base.Message; } }
>
>     public virtual String ParamName { get { return this.m_paramName; } }
>
>     String m_paramName;
>
>   }
>
> }
>
> --
> Martin Liversage
>
Author
19 Oct 2006 12:57 PM
Martin Liversage
"Claus Konrad" wrote:

> Right.
> In case you are dealing with custom parameters, you need to cater for that
> by adding these to the serialization info object (to be allowed to be
> descerialised).

Again, thanks a lot for you input.

Your code works (off course). In my setup I had a test application that did
the serialization and an assembly containing the custom exception class. When
I moved your exception class to my assembly the SecurityException was thrown
again indicating that the problem was with my assembly containing the
exception class.

After some investigation I found that the culprit was these two attributes
in the assembly:

// Minimum permissions required for this assembly.
[assembly: FileIOPermission(SecurityAction.RequestOptional,
Unrestricted=true)]
[assembly: SecurityPermission(SecurityAction.RequestOptional,
UnmanagedCode=true)]

Removing them fixed the problem.

--
Martin Liversage



Post Thread options