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);
				}
			}
		}
Beispiel #3
0
		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);
						}
					}
				}
			}
		}
Beispiel #4
0
		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;
		}
Beispiel #5
0
		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;
		}
Beispiel #6
0
		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);
			}
		}
Beispiel #7
0
		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;
		}
Beispiel #8
0
		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);
						}
					}
				}
			}
		}
Beispiel #9
0
		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;
		}
Beispiel #10
0
		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);
				}
			}
		}