Пример #1
0
        public bool Rewrite(Instruction instruction, MemberRewriterContext context)
        {
            var il = context.IL;

            var method = ((MethodReference)instruction.Operand).Resolve();

            if (method.ReturnType.FullName != typeof(string).FullName)
            {
                return(false);
            }

            var getLength = il.Body.Method.Module.ImportReference(
                method.ReturnType.Resolve().GetProperty(nameof(string.Length)).GetMethod
                );
            var pop = il.Create(OpCodes.Pop);

            context.IL.InsertAfter(instruction,
                                   il.Create(OpCodes.Dup),
                                   il.Create(OpCodes.Dup),
                                   il.Create(OpCodes.Brfalse, pop),
                                   il.CreateCall(getLength),
                                   il.CreateLdlocBest(context.RuntimeGuardVariable),
                                   il.CreateCall(context.RuntimeGuardReferences.FlowThroughGuardCountIntPtrMethod),
                                   pop
                                   );
            return(true);
        }
Пример #2
0
        bool IMemberRewriterInternal.Rewrite(Instruction instruction, MemberRewriterContext context)
        {
            var method = (MethodReference)instruction.Operand;
            var il     = context.IL;

            if (method.Parameters.Count == 1)
            {
                var enumerableType = method.Parameters[0].ParameterType.ResolveGenericParameters(method as GenericInstanceMethod, method.DeclaringType as GenericInstanceType);
                if (!IsIEnumerable(enumerableType))
                {
                    return(false);
                }
                InsertEnumerableGuard(instruction, context, enumerableType);
                return(true);
            }

            var parameterTypes = new TypeReference[method.Parameters.Count];
            var hasIEnumerable = false;

            for (var i = 0; i < method.Parameters.Count; i++)
            {
                var parameterType = method.Parameters[i].ParameterType.ResolveGenericParameters(method as GenericInstanceMethod, method.DeclaringType as GenericInstanceType);
                if (IsIEnumerable(parameterType))
                {
                    hasIEnumerable = true;
                }
                parameterTypes[i] = parameterType;
            }
            if (!hasIEnumerable)
            {
                return(false);
            }

            // we need to eat the stack and put it somewhere (vars), so that we can
            // process the enumerables without messing up other values
            var variables = new VariableDefinition[method.Parameters.Count];

            for (var i = method.Parameters.Count - 1; i >= 0; i--)
            {
                var variable = new VariableDefinition(parameterTypes[i]);
                variables[i] = variable;
                il.Body.Variables.Add(variable);
                il.InsertBeforeAndRetargetJumps(instruction, il.CreateStlocBest(variable));
                // technically we don't have to eat last parameter if it's not enumerable,
                // but trying to keep things simple
            }

            foreach (var variable in variables)
            {
                il.InsertBefore(instruction, il.CreateLdlocBest(variable));
                if (IsIEnumerable(variable.VariableType))
                {
                    InsertEnumerableGuard(instruction, context, variable.VariableType);
                }
            }

            return(true);
        }
Пример #3
0
        bool IMemberRewriterInternal.Rewrite(Instruction instruction, MemberRewriterContext context)
        {
            var writeWarning = context.IL.Body.Method.Module.ImportReference(WriteWarningMethod);

            var ldstr = context.IL.Create(OpCodes.Ldstr, _warning);

            context.IL.InsertAfter(instruction, ldstr);
            context.IL.InsertAfter(ldstr, context.IL.CreateCall(writeWarning));
            return(true);
        }
Пример #4
0
        bool IMemberRewriterInternal.Rewrite(Instruction instruction, MemberRewriterContext context)
        {
            var il = context.IL;

            il.InsertAfter(instruction,
                           il.CreateLdlocBest(context.RuntimeGuardVariable),
                           il.Create(OpCodes.Ldc_I8, 1L),
                           il.CreateCall(context.RuntimeGuardReferences.GuardCountMethod)
                           );
            return(true);
        }
Пример #5
0
        private void InsertEnumerableGuard(Instruction instruction, MemberRewriterContext context, TypeReference enumerableType)
        {
            var il                  = context.IL;
            var elementType         = ((GenericInstanceType)enumerableType).GenericArguments[0];
            var guardMethodInstance = new GenericInstanceMethod(context.RuntimeGuardReferences.FlowThroughGuardEnumerableCollectedMethod)
            {
                GenericArguments = { elementType }
            };

            il.InsertBeforeAndRetargetJumps(instruction, il.CreateLdlocBest(context.RuntimeGuardVariable));
            il.InsertBefore(instruction, il.CreateCall(guardMethodInstance));
        }
        bool IMemberRewriterInternal.Rewrite(Instruction instruction, MemberRewriterContext context)
        {
            var il            = context.IL;
            var method        = ((MethodReference)instruction.Operand).Resolve();
            var collectedType = (method.IsConstructor) ? method.DeclaringType : method.ReturnType;
            var collect       = new GenericInstanceMethod(context.RuntimeGuardReferences.FlowThroughCollectDisposableMethod)
            {
                GenericArguments = { il.Body.Method.Module.ImportReference(collectedType) }
            };

            il.InsertAfter(instruction,
                           il.CreateLdlocBest(context.RuntimeGuardVariable),
                           il.CreateCall(collect)
                           );
            return(true);
        }
Пример #7
0
        bool IMemberRewriterInternal.Rewrite(Instruction instruction, MemberRewriterContext context)
        {
            var method = ((MethodReference)instruction.Operand).Resolve();

            if (!MethodDetailsByMetadataToken.Value.TryGetValue(method.MetadataToken.ToInt32(), out var details))
            {
                throw new AssemblyGuardException($"Regex method {method.Name} is not allowed.");
            }

            if (details.ReasonIfNotAllowed != null)
            {
                throw new AssemblyGuardException(details.ReasonIfNotAllowed);
            }

            if (details.HasRegexOptionsAsLastParameter)
            {
                var guardRegexOptions = context.Module.ImportReference(KnownMethods.GuardRegexOptions);
                context.IL.InsertBeforeAndRetargetJumps(instruction, context.IL.CreateCall(guardRegexOptions));
            }

            if (!method.IsStatic && !method.IsConstructor)
            {
                return(true);
            }

            if (details.MethodWithTimeout == null)
            {
                throw new AssemblyGuardException($"Could not find a timeout variant for this overload of Regex.{method.Name}. Please try another overload.");
            }

            if (details.MethodWithTimeoutNeedsRegexOptions)
            {
                // 0 = RegexOptions.None
                context.IL.InsertBeforeAndRetargetJumps(instruction, context.IL.Create(OpCodes.Ldc_I4_0));
            }

            var getTimeUntilLimit = context.Module.ImportReference(KnownMethods.GetTimeUntilLimit);

            context.IL.InsertBeforeAndRetargetJumps(instruction, context.IL.CreateLdlocBest(context.RuntimeGuardVariable));
            context.IL.InsertBefore(instruction, context.IL.CreateCall(getTimeUntilLimit));

            var importedTimeoutMethod = context.Module.ImportReference(details.MethodWithTimeout);

            instruction.Operand = importedTimeoutMethod;
            return(true);
        }
Пример #8
0
        bool IMemberRewriterInternal.Rewrite(Instruction instruction, MemberRewriterContext context)
        {
            var method         = ((MethodReference)instruction.Operand).Resolve();
            var countParameter = GetCountParameter(method);

            if (countParameter == null)
            {
                return(false);
            }
            if (countParameter.Index < method.Parameters.Count - 1)
            {
                throw new NotSupportedException($"{nameof(CountArgumentRewriter)} does not support method {method} because count is not the last argument.");
            }

            var il = context.IL;

            il.InsertBeforeAndRetargetJumps(instruction, il.CreateLdlocBest(context.RuntimeGuardVariable));
            il.InsertBefore(instruction, il.CreateCall(context.RuntimeGuardReferences.FlowThroughGuardCountInt32Method));
            return(true);
        }
Пример #9
0
        public bool Rewrite(Instruction instruction, MemberRewriterContext context)
        {
            var il = context.IL;

            var method = ((MethodReference)instruction.Operand).Resolve();

            if (!method.ReturnType.IsArray)
            {
                return(false);
            }

            var dup   = il.Create(OpCodes.Dup);
            var ldlen = il.Create(OpCodes.Ldlen);
            var ldloc = il.CreateLdlocBest(context.RuntimeGuardVariable);
            var call  = il.CreateCall(context.RuntimeGuardReferences.FlowThroughGuardCountIntPtrMethod);
            var pop   = il.Create(OpCodes.Pop);

            context.IL.InsertAfter(instruction, dup);
            context.IL.InsertAfter(dup, ldlen);
            context.IL.InsertAfter(ldlen, ldloc);
            context.IL.InsertAfter(ldloc, call);
            context.IL.InsertAfter(call, pop);
            return(true);
        }
Пример #10
0
 bool IMemberRewriterInternal.Rewrite(Instruction instruction, MemberRewriterContext context) => true;
Пример #11
0
        private static void ValidateAndRewriteMethod(MethodDefinition method, RuntimeGuardReferences guard, AssemblyValidator validator, AssemblyGuardSettings settings)
        {
            if (method.DeclaringType == guard.InstanceField.DeclaringType)
            {
                return;
            }

            validator.ValidateDefinition(method);
            if (!method.HasBody)
            {
                return;
            }

            if (method.Body.Instructions.Count == 0)
            {
                return; // weird, but happens with 'extern'
            }
            var isStaticConstructor = method.Name == ".cctor" && method.IsStatic && method.IsRuntimeSpecialName;
            var il            = method.Body.GetILProcessor();
            var guardVariable = new VariableDefinition(guard.InstanceField.FieldType);

            il.Body.Variables.Add(guardVariable);

            var instructions = il.Body.Instructions;
            var start        = instructions[0];
            var skipFirst    = 4;

            il.InsertBefore(start, il.Create(OpCodes.Ldsfld, guard.InstanceField));
            il.InsertBefore(start, il.Create(OpCodes.Dup));
            il.InsertBefore(start, il.CreateStlocBest(guardVariable));
            il.InsertBefore(start, il.Create(OpCodes.Call, isStaticConstructor ? guard.GuardEnterStaticConstructorMethod : guard.GuardEnterMethod));

            for (var i = skipFirst; i < instructions.Count; i++)
            {
                var instruction = instructions[i];
                var memberRule  = validator.ValidateInstructionAndGetPolicy(instruction, method);
                var code        = instruction.OpCode.Code;
                if (code == Code.Newarr)
                {
                    il.InsertBeforeAndRetargetJumps(instruction, il.CreateLdlocBest(guardVariable));
                    il.InsertBefore(instruction, il.CreateCall(guard.FlowThroughGuardCountIntPtrMethod));
                    i += 2;
                    continue;
                }

                if (memberRule != null && memberRule.Rewriters.Count > 0)
                {
                    var instructionCountBefore = instructions.Count;
                    var rewritten = false;
                    var context   = new MemberRewriterContext(il, guardVariable, guard);
                    foreach (var rewriter in memberRule.InternalRewriters)
                    {
                        rewritten = rewriter.Rewrite(instruction, context) || rewritten;
                    }
                    if (rewritten)
                    {
                        i += instructions.Count - instructionCountBefore;
                        continue;
                    }
                }

                if (isStaticConstructor && instruction.OpCode.Code == Code.Ret)
                {
                    il.InsertBeforeAndRetargetJumps(instruction, il.CreateLdlocBest(guardVariable));
                    il.InsertBefore(instruction, il.CreateCall(guard.GuardExitStaticConstructorMethod));
                    i += 2;
                    continue;
                }

                if (!ShouldInsertJumpGuardBefore(instruction))
                {
                    continue;
                }

                il.InsertBeforeAndRetargetJumps(instruction, il.CreateLdlocBest(guardVariable));
                il.InsertBefore(instruction, il.Create(OpCodes.Call, guard.GuardJumpMethod));
                i += 2;
            }

            il.CorrectAllAfterChanges();
        }
Пример #12
0
        private static void ValidateAndRewriteMethod(MethodDefinition method, RuntimeGuardReferences guard, AssemblyValidator validator, AssemblyGuardSettings settings)
        {
            if (method.DeclaringType == guard.InstanceField.DeclaringType)
            {
                return;
            }

            validator.ValidateDefinition(method);
            if (!method.HasBody)
            {
                return;
            }

            if (method.Body.Instructions.Count == 0)
            {
                return; // weird, but happens with 'extern'
            }
            var isStaticConstructor = method.Name == ".cctor" && method.IsStatic && method.IsRuntimeSpecialName;
            var il = method.Body.GetILProcessor();
            // IAsyncStateMachine.MoveNext has special rules, but to be safe, only apply them when its type is compiler-generated
            // which is checked by verifying that it has unspeakable name
            var isStateMachineMoveNext =
                method.Name == "MoveNext" &&
                method.Overrides.Count == 1 &&
                method.Overrides[0].FullName == "System.Void System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext()" &&
                method.DeclaringType.Name.Contains("<") &&
                il.Body.ExceptionHandlers.Count >= 1;
            var guardVariable = new VariableDefinition(guard.InstanceField.FieldType);

            il.Body.Variables.Add(guardVariable);

            var instructions = il.Body.Instructions;
            var start        = instructions[0];
            var skipStart    = 0;
            var skipCount    = 4;
            ExceptionHandler?stateMachineExceptionHandler = null;

            if (isStateMachineMoveNext)
            {
                // in IAsyncStateMachine.MoveNext, the GuardEnter call has to be inside the try block, so that the exception is propagated to the Task
                stateMachineExceptionHandler = il.Body.ExceptionHandlers.OrderBy(eh => eh.TryStart.Offset).First();
                start     = stateMachineExceptionHandler.TryStart;
                skipStart = instructions.IndexOf(start);
            }

            il.InsertBeforeAndRetargetJumps(start, il.Create(OpCodes.Ldsfld, guard.InstanceField));
            il.InsertBefore(start, il.Create(OpCodes.Dup));
            il.InsertBefore(start, il.CreateStlocBest(guardVariable));
            il.InsertBefore(start, il.Create(OpCodes.Call, isStaticConstructor ? guard.GuardEnterStaticConstructorMethod : guard.GuardEnterMethod));

            for (var i = 0; i < instructions.Count; i++)
            {
                if (i >= skipStart && i < skipStart + skipCount)
                {
                    continue;
                }

                // in IAsyncStateMachine.MoveNext, guard calls are only allowed inside the try block
                if (stateMachineExceptionHandler != null &&
                    (i < instructions.IndexOf(stateMachineExceptionHandler.TryStart) || i > instructions.IndexOf(stateMachineExceptionHandler.TryEnd)))
                {
                    continue;
                }

                var instruction = instructions[i];
                var memberRule  = validator.ValidateInstructionAndGetPolicy(instruction, method);
                var code        = instruction.OpCode.Code;
                if (code == Code.Newarr)
                {
                    il.InsertBeforeAndRetargetJumps(instruction, il.CreateLdlocBest(guardVariable));
                    il.InsertBefore(instruction, il.CreateCall(guard.FlowThroughGuardCountIntPtrMethod));
                    i += 2;
                    continue;
                }

                if (memberRule != null && memberRule.Rewriters.Count > 0)
                {
                    var instructionCountBefore = instructions.Count;
                    var rewritten = false;
                    var context   = new MemberRewriterContext(il, guardVariable, guard);
                    foreach (var rewriter in memberRule.InternalRewriters)
                    {
                        rewritten = rewriter.Rewrite(instruction, context) || rewritten;
                    }
                    if (rewritten)
                    {
                        i += instructions.Count - instructionCountBefore;
                        continue;
                    }
                }

                if (isStaticConstructor && instruction.OpCode.Code == Code.Ret)
                {
                    il.InsertBeforeAndRetargetJumps(instruction, il.CreateLdlocBest(guardVariable));
                    il.InsertBefore(instruction, il.CreateCall(guard.GuardExitStaticConstructorMethod));
                    i += 2;
                    continue;
                }

                if (!ShouldInsertJumpGuardBefore(instruction))
                {
                    continue;
                }

                il.InsertBeforeAndRetargetJumps(instruction, il.CreateLdlocBest(guardVariable));
                il.InsertBefore(instruction, il.Create(OpCodes.Call, guard.GuardJumpMethod));
                i += 2;
            }

            il.CorrectAllAfterChanges();
        }