5 // Rodrigo Kumpera (rkumpera@novell.com)
7 // Copyright (C) 2007 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Diagnostics;
32 using System.Security;
33 using System.Security.Policy;
34 using System.Security.Permissions;
35 using System.Threading;
38 namespace AssemblyRunner {
40 public enum RunResult {
49 private static string program = "\"%COMSPEC%\"";
51 static String ExecuteAndFetchStderr (String command) {
52 ProcessStartInfo psi = new ProcessStartInfo (Environment.ExpandEnvironmentVariables (program), "/c " + command);
53 psi.CreateNoWindow = true;
54 psi.UseShellExecute = false;
55 psi.RedirectStandardError = true;
58 Process activeProcess=null;
60 Thread stderrThread = new Thread (new ThreadStart (delegate {
61 if (activeProcess != null)
62 stderr = activeProcess.StandardError.ReadToEnd ();
64 activeProcess = Process.Start (psi);
66 stderrThread.Start ();
67 activeProcess.WaitForExit();
69 activeProcess.Close ();
73 static int ExecuteAndFetchReturnCode (String command) {
74 ProcessStartInfo psi = new ProcessStartInfo (Environment.ExpandEnvironmentVariables (program), "/c " + command);
75 psi.CreateNoWindow = true;
76 psi.UseShellExecute = false;
77 psi.RedirectStandardError = true;
79 Process activeProcess = Process.Start (psi);
81 activeProcess.WaitForExit();
82 int res = activeProcess.ExitCode;
83 activeProcess.Close ();
88 static AppDomain NewDomain () {
89 PolicyStatement statement = new PolicyStatement(new PermissionSet(PermissionState.None),PolicyStatementAttribute.Nothing);
90 PermissionSet ps = new PermissionSet(PermissionState.None);
91 ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
92 ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.Assertion));
93 ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.ControlAppDomain));
94 ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.ControlDomainPolicy));
95 ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.ControlEvidence));
96 ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.ControlPolicy));
97 ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.ControlPrincipal));
98 ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.ControlThread));
99 ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.Infrastructure));
100 ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.RemotingConfiguration));
101 ps.AddPermission(new SecurityPermission(SecurityPermissionFlag.SerializationFormatter));
102 ps.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
103 ps.AddPermission(new EnvironmentPermission(PermissionState.Unrestricted));
104 ps.AddPermission(new ReflectionPermission(PermissionState.Unrestricted));
105 ps.AddPermission(new RegistryPermission(PermissionState.Unrestricted));
106 ps.AddPermission(new IsolatedStorageFilePermission(PermissionState.Unrestricted));
107 ps.AddPermission(new EventLogPermission(PermissionState.Unrestricted));
108 ps.AddPermission(new PerformanceCounterPermission(PermissionState.Unrestricted));
109 ps.AddPermission(new DnsPermission(PermissionState.Unrestricted));
110 ps.AddPermission(new UIPermission(PermissionState.Unrestricted));
111 PolicyStatement statement1 = new PolicyStatement(ps,PolicyStatementAttribute.Exclusive);
113 group = new UnionCodeGroup(new AllMembershipCondition(),statement);
114 group.AddChild(new UnionCodeGroup(new ZoneMembershipCondition(SecurityZone.MyComputer),statement1));
115 PolicyLevel level = PolicyLevel.CreateAppDomainLevel();
116 level.RootCodeGroup = group;
118 AppDomain domain = AppDomain.CreateDomain ("test");
119 domain.SetAppDomainPolicy(level);
123 static RunResult testWithAppDomain (String path, String assemblyName) {
124 AppDomain domain = NewDomain ();
126 domain.ExecuteAssembly (path);
127 return RunResult.valid;
128 } catch (InvalidProgramException) {
129 return RunResult.invalid;
130 } catch (FileLoadException) {
131 return RunResult.invalid;
132 } catch (VerificationException) {
133 return RunResult.unverifiable;
134 } catch (TypeInitializationException ve) {
135 if (ve.InnerException is VerificationException)
136 return RunResult.unverifiable;
137 Console.WriteLine ("Warning: test {0} thrown exception: {1} ", assemblyName, ve.InnerException);
138 return RunResult.invalid;
139 } catch (MissingMemberException) {
140 return RunResult.invalid;
141 } catch (MemberAccessException) {
142 return RunResult.unverifiable;
143 } catch (TypeLoadException) {
144 return RunResult.invalid;
145 } catch (BadImageFormatException) {
146 return RunResult.invalid;
147 } catch (Exception e) {
148 Console.WriteLine ("Warning: test {0} thrown exception {1}", assemblyName, e);
149 return RunResult.valid;
151 AppDomain.Unload (domain);
156 * This test with runtime is usefull to assert if the code is unverifiable but not invalid.
157 * This test should be used to diagnose if it's the case of code that was reported as invalid but actually is unverifiable.
159 static RunResult testWithRuntime (String path) {
160 String stderr = ExecuteAndFetchStderr (path);
161 String[] knownErrors = new String[] {
162 "MissingMethodException",
163 "InvalidProgramException",
165 "BadImageFormatException",
167 "VerificationException"
170 foreach (String str in knownErrors) {
171 if (stderr.IndexOf (str) >= 0)
172 return RunResult.invalid;
174 return RunResult.valid;
178 * This test can only assert if the code is unverifiable or not. Use it
179 * to check if it's the case for a strict check or the code is verifiable.
181 static RunResult testWithPeverify (String path) {
182 if (ExecuteAndFetchReturnCode ("peverify "+path) == 0)
183 return RunResult.valid;
184 return RunResult.unverifiable;
187 static RunResult decide (RunResult ad, RunResult rt, RunResult pv, String testName) {
188 if (ad == RunResult.valid) {
189 if (rt != RunResult.valid) {
190 Console.WriteLine ("Warning: test {0} returned valid under AD but {1} under runtime. PV said {2}, using runtime choice", testName, rt, pv);
193 if (pv != RunResult.valid)
194 return RunResult.strict;
195 return RunResult.valid;
198 if (ad == RunResult.unverifiable) {
199 //the rt test cannot complain about unverifiable
201 if (pv == RunResult.valid)
202 Console.WriteLine ("Warning: test {0} returned unverifiable under AD but {1} under PV, using AD choice", testName, pv);
204 if (rt == RunResult.invalid) {
205 /*This warning doesn't help a lot since there are cases which this happens
206 Console.WriteLine ("Warning: test {0} returned unverifiable under AD but {1} under runtime. PV said {2}, using runtime choice", testName, rt, pv);
212 return RunResult.unverifiable;
215 if (ad == RunResult.invalid) {
216 //in some cases the runtime throws exceptions meant for invalid code but the code is only unverifiable
217 //we double check that by checking if rt returns ok
219 if (pv == RunResult.valid)
220 Console.WriteLine ("Warning: test {0} returned invalid under AD but {1} under PV, using AD choice", testName, pv);
222 if (rt == RunResult.valid)
223 return RunResult.unverifiable;
225 return RunResult.invalid;
227 Console.WriteLine ("ERROR: test {0} returned an unknown result under ad {1}, runtime said {2} and PV {3} -- FIXME --", testName, ad, rt, pv);
228 return RunResult.none;
231 static void executeTest (String path, String assemblyName, RunResult expected) {
232 RunResult ad = testWithAppDomain (path, assemblyName);
233 RunResult rt = testWithRuntime (path);
234 RunResult pv = testWithPeverify (path);
236 RunResult veredict = decide (ad, rt, pv, assemblyName);
237 if (veredict != expected)
238 Console.WriteLine ("ERROR: test {0} expected {1} but got {2} AD {3} RT {4} PV {5}", assemblyName, expected, veredict, ad, rt, pv);
241 public static void Main (String[] args) {
242 String dirName = ".";
245 DirectoryInfo dir = new DirectoryInfo (dirName);
246 foreach (FileInfo file in dir.GetFiles ()) {
248 RunResult rr = RunResult.none;
249 if (file.Name.StartsWith ("strict_"))
250 rr = RunResult.strict;
251 else if (file.Name.StartsWith ("valid_"))
252 rr = RunResult.valid;
253 else if (file.Name.StartsWith ("unverifiable_"))
254 rr = RunResult.unverifiable;
255 else if (file.Name.StartsWith ("invalid_"))
256 rr = RunResult.invalid;
258 if (file.Name.EndsWith (".exe") && rr != RunResult.none)
259 executeTest (file.FullName, file.Name, rr);
260 } catch (Exception e) {
261 Console.WriteLine ("Warning: test {0} thrown exception {1}", file.FullName, e);