Skip to content
Permalink
Browse files

Added some defences to try and ward off serialization issues, but can…

…not stop the project file being inherently unsafe due to the script contents. Thanks to Graham Sutherland for making me do some changes
  • Loading branch information...
tyranid committed Nov 29, 2014
1 parent 3dd224f commit 594381c4394b788af0ec26c81ec356eb865736cc
@@ -30,6 +30,8 @@
using CANAPE.Nodes;
using CANAPE.Utils;
using System.Text;
using System.Security;
using System.Security.Permissions;

namespace CANAPE.Documents
{
@@ -736,22 +738,102 @@ public override Type BindToType(string assemblyName, string typeName)
}
}

// A small attempt to restrict what types can be accessed
sealed class SecurityBinder : SerializationBinder
{
SerializationBinder _delegateBinder;

internal SecurityBinder(SerializationBinder delegateBinder)
{
_delegateBinder = delegateBinder;
}

private bool AllowedTypeOrAssembly(Type type)
{
// "Safe" types I guess, just let them through
if(type.IsEnum || type.IsPrimitive || type == typeof(String))
{
return true;
}

string typeNamespace = type.Namespace.ToLower();

if (typeNamespace.StartsWith("canape"))
{
return true;
}

switch(typeNamespace.ToLower())
{
case "system":
case "system.collections":
case "system.collections.generic":
case "system.text":
case "system.security.authentication":
case "system.collections.objectmodel":
case "system.reflection":
return true;
}

return false;
}

public override Type BindToType(string assemblyName, string typeName)
{
System.Diagnostics.Trace.WriteLine(String.Format("{0} {1}", assemblyName, typeName));
Type type = null;

if (_delegateBinder != null)
{
type = _delegateBinder.BindToType(assemblyName, typeName);
}
else
{
type = Type.GetType(String.Format("{0},{1}", typeName, assemblyName));
}

if (type != null)
{
if (!AllowedTypeOrAssembly(type))
{
string name = type.FullName;
if (type.IsGenericType)
{
name = type.GetGenericTypeDefinition().FullName;
}

throw new SecurityException(String.Format(Properties.Resources.CANAPEProject_InsecureType, name));
}
}

return type;
}
}

// Create the binary formatter with compat hacks for particular versions if needed
private static BinaryFormatter CreateFormatter(Version ver)
private static BinaryFormatter CreateFormatter(Version ver, bool secure)
{
BinaryFormatter ret = new BinaryFormatter(null, new StreamingContext(StreamingContextStates.File));
SerializationBinder binder = null;

if (ver.Major == 1)
{
if (ver.Minor < 3)
{
ret.Binder = new FixSerializationFrom12();
binder = new FixSerializationFrom12();
}
else if(ver.Minor == 3)
{
ret.Binder = new FixSerializationFrom13();
binder = new FixSerializationFrom13();
}
}

if (secure)
{
binder = new SecurityBinder(binder);
}

ret.Binder = binder;

return ret;
}
@@ -762,7 +844,8 @@ private static BinaryFormatter CreateFormatter(Version ver)
/// <param name="stm">The stream</param>
/// <param name="fileName">The filename to use (can be null)</param>
/// <param name="verifyVersion">Set true to verify the version being opened match this canape</param>
public static void Load(Stream stm, string fileName, bool verifyVersion)
/// <param name="secure">Attemps to make the load secure, not likely to succeed</param>
public static void Load(Stream stm, string fileName, bool verifyVersion, bool secure)
{
// If an empty stream
if (stm.Length == 0)
@@ -794,10 +877,29 @@ public static void Load(Stream stm, string fileName, bool verifyVersion)
stm.Position = stm.Position - 1;

using (Stream inStream = compressed ? new GZipStream(stm, CompressionMode.Decompress, false) : stm)
{
BinaryFormatter formatter = CreateFormatter(ver);
{
BinaryFormatter formatter = CreateFormatter(ver, secure);
CANAPEProject newProject = null;

CANAPEProject newProject = (CANAPEProject)formatter.Deserialize(inStream);
// Note that all this is going to do is prevent anything during
// direct load of objects and scripts, it won't do anything against anything else
if (secure)
{
try
{
PermissionSet ps = new PermissionSet(PermissionState.None);
ps.PermitOnly();
newProject = (CANAPEProject)formatter.UnsafeDeserialize(inStream, null);
}
finally
{
CodeAccessPermission.RevertPermitOnly();
}
}
else
{
newProject = (CANAPEProject)formatter.Deserialize(inStream);
}

newProject._fileName = fileName;
newProject._globalMeta = new MetaDictionary();
@@ -817,11 +919,12 @@ public static void Load(Stream stm, string fileName, bool verifyVersion)
/// </summary>
/// <param name="fileName">The filename to use</param>
/// <param name="verifyVersion">Set true to verify the version being opened match this canape</param>
public static void Load(string fileName, bool verifyVersion)
/// <param name="secure">Attempts to open the file securely</param>
public static void Load(string fileName, bool verifyVersion, bool secure)
{
using (Stream stm = File.Open(fileName, FileMode.Open, FileAccess.Read))
{
Load(stm, fileName, verifyVersion);
Load(stm, fileName, verifyVersion, secure);
}
}
}

Some generated files are not rendered by default. Learn more.

@@ -375,4 +375,7 @@
<data name="TextDocument_DefaultName" xml:space="preserve">
<value>Text Document</value>
</data>
<data name="CANAPEProject_InsecureType" xml:space="preserve">
<value>Type '{0}' is potentially insecure</value>
</data>
</root>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -198,7 +198,7 @@ private void frmMain_Load(object sender, EventArgs e)
}
else
{
LoadProject(newProject.FileName, true);
LoadProject(newProject.FileName, true, true);
}
}
else
@@ -210,7 +210,7 @@ private void frmMain_Load(object sender, EventArgs e)
}
else
{
LoadProject(_fileName, true);
LoadProject(_fileName, true, true);
}

if (Properties.Settings.Default.AutoSaveEnabled)
@@ -287,7 +287,7 @@ private void SaveDocument(bool bSaveAs)

if(fileName != null)
{
using (SavingLoadingForm frm = new SavingLoadingForm(fileName, true, true))
using (SavingLoadingForm frm = new SavingLoadingForm(fileName, true, true, true))
{
if (frm.ShowDialog(this) == DialogResult.OK)
{
@@ -331,9 +331,9 @@ private bool CheckDirtyFlag()
return cancel;
}

private void LoadProject(string fileName, bool verifyVersion)
private void LoadProject(string fileName, bool verifyVersion, bool secure)
{
using (SavingLoadingForm frm = new SavingLoadingForm(fileName, false, verifyVersion))
using (SavingLoadingForm frm = new SavingLoadingForm(fileName, false, verifyVersion, secure))
{
InitializeTree();

@@ -345,27 +345,36 @@ private void LoadProject(string fileName, bool verifyVersion)
}
else
{
if ((frm.Error is InvalidVersionException) && (verifyVersion))
if ((frm.Error is InvalidVersionException) && verifyVersion)
{
if (MessageBox.Show(this, String.Format(Properties.Resources.LoadProject_OpenAnyway, frm.Error.Message),
Properties.Resources.LoadProject_OpenAnywayCaption,
MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
LoadProject(fileName, false);
LoadProject(fileName, false, secure);
}
}
else if ((frm.Error is SecurityException) && secure)
{
if (MessageBox.Show(this, String.Format(Properties.Resources.LoadProject_SecurityWarning, frm.Error.Message),
Properties.Resources.LoadProject_SecurityWarningCaption,
MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
{
LoadProject(fileName, verifyVersion, false);
}
}
else
{
if (frm.Error != null)
{
MessageBox.Show(this, frm.Error.Message,
MessageBox.Show(this, frm.Error.Message,
Properties.Resources.MessageBox_ErrorString,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
MessageBox.Show(this, Properties.Resources.MainForm_UnknownError,
Properties.Resources.MessageBox_ErrorString,
Properties.Resources.MessageBox_ErrorString,
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
@@ -383,7 +392,7 @@ private void openToolStripMenuItem_Click(object sender, EventArgs e)

if (dlg.ShowDialog(this) == DialogResult.OK)
{
LoadProject(dlg.FileName, true);
LoadProject(dlg.FileName, true, true);
}
}
}
@@ -469,7 +478,8 @@ private void NewDocument(bool fromTemplate)
{
try
{
CANAPEProject.Load(template.GetStream(), null, true);
// Allow insecure load, if someone has added a template they could just add a plugin
CANAPEProject.Load(template.GetStream(), null, true, false);
}
catch (Exception ex)
{
@@ -583,7 +593,7 @@ void recentFileItem_Click(object sender, EventArgs e)
{
if (!CheckDirtyFlag())
{
LoadProject((string)item.Tag, true);
LoadProject((string)item.Tag, true, true);
}
}
}
@@ -25,13 +25,15 @@ internal partial class SavingLoadingForm : Form
string _fileName;
bool _verifyVersion;
bool _saving;
bool _secure;

public SavingLoadingForm(string fileName, bool saving, bool verifyVersion)
public SavingLoadingForm(string fileName, bool saving, bool verifyVersion, bool secure)
{
InitializeComponent();
_fileName = fileName;
_saving = saving;
_verifyVersion = verifyVersion;
_secure = secure;
}

private void SavingLoadingForm_Load(object sender, EventArgs e)
@@ -61,7 +63,7 @@ void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
}
else
{
CANAPE.Documents.CANAPEProject.Load(_fileName, _verifyVersion);
CANAPE.Documents.CANAPEProject.Load(_fileName, _verifyVersion, _secure);
}
}
catch (Exception ex)
@@ -141,6 +141,9 @@ static void Main(string[] args)

if (Properties.Settings.Default.RunOnce == false)
{
MessageBox.Show(CANAPE.Properties.Resources.Program_SecurityWarning,
CANAPE.Properties.Resources.Program_SecurityWarningCaption, MessageBoxButtons.OK, MessageBoxIcon.Stop);

Properties.Settings.Default.RunOnce = true;
Program.SaveSettings();
}

0 comments on commit 594381c

Please sign in to comment.
You can’t perform that action at this time.