public void VisitGraph(CallGraph graph) { string bad = string.Empty; // Iterate over each method in the assembly, foreach (KeyValuePair<MethodReference, List<MethodReference>> entry in graph.Entries()) { // if it does not have a security demand then, MethodInfo info = Cache.FindMethod(entry.Key); if (info != null && info.Method.ExternallyVisible(Cache) && !DoHasSecurityDemand(info.Method)) { foreach (MethodReference callee in entry.Value) { // if it's calling a method with a link demand then // we have a problem. Note that we won't find the // method info if the callee is in a different assembly. info = Cache.FindMethod(callee); if (info != null && DoHasLinkDemand(info.Method)) { Log.DebugLine(this, "bad: {0}", info.Method); bad = string.Format("{0} {1}", bad, info.Method); } } } } if (bad.Length > 0) { string details = "Methods: " + bad; Reporter.AssemblyFailed(Cache.Assembly, CheckID, details); } }
public void VisitGraph(CallGraph graph) { m_graph = graph; // If the assembly is mixed transparent/critical then we may have critical // methods. if (m_mixed) { List<string> lines = new List<string>(); // So, for each method, foreach (KeyValuePair<MethodReference, List<MethodReference>> entry in graph.Entries()) { MethodInfo caller = Cache.FindMethod(entry.Key); if (caller != null) { // if it's public, MethodAttributes access = caller.Method.Attributes & MethodAttributes.MemberAccessMask; if (access == MethodAttributes.Public) { // and transparent, if (!caller.Method.CustomAttributes.Has("SecurityCriticalAttribute")) { // then fail if it calls a non-public critical method. string line = DoIsBad(caller.Method, entry.Value, 1); if (line.Length > 0) { lines.Add(line); } } } } } if (lines.Count > 0) { string details = string.Join(Environment.NewLine, lines.ToArray()); // Console.WriteLine(details); Reporter.AssemblyFailed(Cache.Assembly, CheckID, details); } } }
public void VisitCallGraph(CallGraph graph) { foreach (KeyValuePair<TypeDefinition, Entry> entry1 in m_table) { foreach (KeyValuePair<Source, List<MethodReference>> entry2 in entry1.Value.Calls) { foreach (MethodReference method in entry2.Value) { List<string> chain = new List<string>(); chain.Add(entry2.Key.Method.ToString()); if (DoCallsLock(method, entry2.Key.Field, entry1.Value, graph, chain, 0)) { string details = "Field: " + entry2.Key.Field.Name + Environment.NewLine; details += "Calls: " + string.Join(" =>" + Environment.NewLine + " ", chain.ToArray()); Log.DebugLine(this, details); Reporter.TypeFailed(entry1.Key, CheckID, details); } } } } }
private bool DoCallsExternal(MethodReference method, Entry entry, CallGraph graph, List<string> chain, int depth, ref string name) { if (depth > 8) // this can't be too large or the rule takes a very long time to run return false; chain.Add(method.ToString()); if (entry.ExternalCalls.ContainsKey(method)) { name = entry.ExternalCalls[method]; return true; } foreach (MethodReference candidate in graph.Calls(method)) { if (DoCallsExternal(candidate, entry, graph, chain, depth + 1, ref name)) return true; } chain.RemoveAt(chain.Count - 1); return false; }
private bool DoFoundBadSetter(CallGraph graph, MethodReference method, List<string> chain) { if (m_visited.IndexOf(method) >= 0) return false; m_visited.Add(method); bool found = false; Log.DebugLine(this, "checking {0}", method); if (m_unlocked.IndexOf(method) >= 0 && m_setters.IndexOf(method) >= 0) { Log.DebugLine(this, "it's a setter"); found = true; } else { foreach (MethodReference callee in graph.Calls(method)) { Log.Indent(); if (DoFoundBadSetter(graph, callee, chain)) { found = true; Log.Unindent(); break; } Log.Unindent(); } } if (found) chain.Insert(0, method.ToString()); return found; }
public void VisitCallGraph(CallGraph graph) { string details = string.Empty; List<string> chain = new List<string>(); foreach (MethodReference method in m_dispatcher.ClassifyMethod.ThreadRoots()) { chain.Clear(); m_visited.Clear(); if (DoFoundBadSetter(graph, method, chain)) { details = string.Format("{0}{1}{1}{2}", ListExtensions.Accumulate( chain, string.Empty, (s, e) => s.Length > 0 ? s + " -> " + Environment.NewLine + e : e), Environment.NewLine, details); } } details = details.Trim(); if (details.Length > 0) { Log.DebugLine(this, details); Reporter.AssemblyFailed(Cache.Assembly, CheckID, details); } }
private bool DoCallsLock(MethodReference method, FieldReference field, Entry entry, CallGraph graph, List<string> chain, int depth) { if (depth > 8) // this can't be too large or the rule takes a very long time to run return false; chain.Add(method.ToString()); if (entry.Locked.ContainsKey(method) && entry.Locked[method].IndexOf(field) >= 0) { return true; } foreach (MethodReference candidate in graph.Calls(method)) { if (DoCallsLock(candidate, field, entry, graph, chain, depth + 1)) return true; } chain.RemoveAt(chain.Count - 1); return false; }
private void DoSetChains(string root, MethodDefinition caller, CallGraph graph, List<MethodDefinition> chain, bool multiple, int depth) { // if (depth > 12) // this can't be too large or the rule takes a very long time to run // return false; // For each method the caller calls, IEnumerable<MethodReference> callees = graph.GetCalls(caller); if (callees != null) { foreach (MethodReference callee in callees) { // if it's a method in the assembly we're testing, MethodState state; if (m_methods.TryGetValue(callee, out state)) { // and we haven't already called it from our root, if (!state.IsCalledFrom(root)) { // then update it's call chain and update all the methods it calls. List<MethodDefinition> schain = new List<MethodDefinition>(chain.Count + 1); schain.AddRange(chain); schain.Add(state.Method); state.SetCallChain(root, schain, multiple); DoSetChains(root, state.Method, graph, schain, multiple, depth + 1); if (m_requiredSafeTypes.IndexOf(state.Method.DeclaringType) < 0) m_requiredSafeTypes.Add(state.Method.DeclaringType); } } } } }
private string DoCheckForUnsafeMethods(CallGraph graph) { foreach (var entry in m_knownRoots) DoSetChains(entry.Value, entry.Key.Method, graph, new List<MethodDefinition>{entry.Key.Method}, entry.Key.IsThreadSafe && entry.Key.IsExternal, 0); foreach (MethodDefinition m in m_entryPoints) DoSetChains("Main", m, graph, new List<MethodDefinition>{m}, false, 0); string details = string.Empty; foreach (MethodState state in m_methods.Values) { if (state.IsCalledFromMultiple && !DoIsMarkedThreadSafe(state.Method)) { details += state.GetCallChains(" ") + Environment.NewLine; } } if (details.Length > 0) details = "Not marked as thread safe: " + Environment.NewLine + details; return details; }
public void VisitCalls(CallGraph graph) { if (!m_disabled) { string details = string.Empty; IEnumerable<MethodReference> roots = m_dispatcher.ClassifyMethod.ThreadRoots(); details += DoCheckForUnmarkedRoots(roots); if (m_knownRoots.Count > 0) details += DoCheckForUnsafeMethods(graph); details += DoCheckForBadSafe(roots); details += DoCheckForBadSafeTypes(); details = details.Trim(); if (details.Length > 0) { Log.DebugLine(this, "Details: {0}", details); Reporter.AssemblyFailed(Cache.Assembly, CheckID, details); } } }