0

It is possible to restrict specific classes, such as Random or DateTime, or the use of float in an AppDomain. Is it possible to detect it by reflection if you use them? or should we look at the IL code?

I would like to make a plugin system, but I have to make sure that the executed code is deterministic. Any other ideas on how to deal with it?

Thanks.

  • So, if I write ``int localInt = 0;`` somewhere in my code, and you "restricted" the usage of int you would like to say `Sorry, but no ints permitted` ? – Rand Random Nov 20 '17 at 07:47
  • 6
    The number of restrictions you'd need to put in place to ensure determinism is so high that I think that starting from C# and taking things away would be the wrong approach. Just the number of things inside mscorlib and System.Core that could be leveraged to achieve non-determinism is huge. – Damien_The_Unbeliever Nov 20 '17 at 07:51
  • Following @Damien_The_Unbeliever, it might be possible to find or develop a deterministic scripting language. However, a plugin system that doesn't allow file access (non-deterministic contents), user interaction (non-deterministic input) and a lot more doesn't sound very interesting to me. – grek40 Nov 20 '17 at 07:55
  • 1
    Out of curiosity - what's the idea behind doing thus? – Evk Nov 20 '17 at 07:56
  • Why the negative vote? – Fernando Diaz Toledano Dec 08 '17 at 17:50

2 Answers2

1

You could look at the IL with something like Cecil[*]. But then again, it is possible to get access to those things via reflection.

[*]: Which would take some time, prompting you to cache the results..., which would introduce a vulnerability in which the attacker mimic a valid entry in the cache.

On the other hand, you could use a sandbox without Reflection. You will have to combine that with the above approach.

Then, there are ways to mimic the behavior of what you describe... for example, you can create your own Random Number Generator (which is something totally deterministic, by the way) and seed it with the current time or other source of entropy (you probably want to deny access to the file system and the network, and even to peripherals and other system status - for example an script could yield a different result depending on the pointer position).

Thus, I would suggest to have a whitelist instead of blacklist as Damien_The_Unbeliever suggests.

Theraot
  • 31,890
  • 5
  • 57
  • 86
0

Creating Type white list is possible to do that job

 readonly static List<string> WhiteList = new List<string>()
    {
        #region Basics
        typeof(Boolean).FullName,
        typeof(Char).FullName,
        typeof(String).FullName,
        typeof(Byte).FullName,
        typeof(SByte).FullName,
        typeof(UInt16).FullName,
        typeof(Int16).FullName,
        typeof(UInt32).FullName,
        typeof(Int32).FullName,
        typeof(UInt64).FullName,
        typeof(Int64).FullName,
        typeof(Decimal).FullName,
        typeof(Double).FullName,
        typeof(Single).FullName,
        typeof(TimeSpan).FullName,

        typeof(Array).FullName,
        typeof(Enum).FullName,
        #endregion

        #region Exceptions
        typeof(Exception).FullName,
        typeof(NotImplementedException).FullName,
        typeof(IOException).FullName,
        #endregion

        #region Delegates
        typeof(Delegate).FullName,
        #endregion

        #region Parallel
        typeof(Parallel).FullName,
        #endregion

        #region Conversions
        typeof(Convert).FullName,
        typeof(BitConverter).FullName,
        #endregion

        #region Streams
        typeof(Stream).FullName,
        typeof(MemoryStream).FullName,
        typeof(BinaryReader).FullName,
        typeof(BinaryWriter).FullName,
        #endregion

        #region Interfaces
        typeof(IDisposable).FullName,
        typeof(IComparable).FullName,
        typeof(IConvertible).FullName,
        typeof(IFormatProvider).FullName,
        typeof(IFormattable).FullName,
        typeof(IOrderedQueryable).FullName,
        #endregion

        #region Attributes
        typeof(Attribute).FullName,

        // Compilation JIT
        typeof(CompilationRelaxationsAttribute).FullName,
        typeof(RuntimeCompatibilityAttribute).FullName,
        typeof(CompilerGeneratedAttribute).FullName,
        #endregion

        #region Generic Types
        typeof(IDictionary<object,object>).Namespace+"."+typeof(IDictionary<object,object>).Name,
        typeof(Dictionary<object,object>).Namespace+"."+typeof(Dictionary<object,object>).Name,
        typeof(List<object>).Namespace+"."+typeof(List<object>).Name,
        typeof(IList<object>).Namespace+"."+typeof(IList<object>).Name,
        typeof(IEnumerable<object>).Namespace+"."+typeof(IEnumerable<object>).Name,
        typeof(IEnumerator<object>).Namespace+"."+typeof(IEnumerator<object>).Name,
        typeof(IOrderedEnumerable<object>).Namespace+"."+typeof(IOrderedEnumerable<object>).Name,
        typeof(IOrderedQueryable<object>).Namespace+"."+typeof(IOrderedQueryable<object>).Name,
        typeof(ICollection<object>).Namespace+"."+typeof(ICollection<object>).Name,
        typeof(IComparable<object>).Namespace+"."+typeof(IComparable<object>).Name,
        typeof(IEquatable<object>).Namespace+"."+typeof(IEquatable<object>).Name,
        typeof(IObservable<object>).Namespace+"."+typeof(IObservable<object>).Name,
        #endregion
    };

    const string WhiteListedNamespace = "XX.XXXXXXXXXX.";

    /// <summary>
    /// Check white list
    /// </summary>
    /// <param name="binary">Binary</param>
    public static void CheckWhiteList(byte[] binary)
    {
        using (MemoryStream ms = new MemoryStream(binary))
        {
            AssemblyDefinition def = AssemblyDefinition.ReadAssembly(ms, new ReaderParameters(ReadingMode.Immediate));

            List<string> ls = new List<string>();
            foreach (ModuleDefinition mdef in def.Modules)
                foreach (TypeReference tdef in mdef.GetTypeReferences())
                {
                    if (!WhiteList.Contains(tdef.FullName) &&
                        !tdef.FullName.StartsWith(WhiteListedNamespace, StringComparison.InvariantCulture))
                        ls.Add(tdef.FullName);
                }

            if (ls.Count > 0)
                throw (new TypeNotAllowedException(ls.ToArray()));
        }
    }