2010-06-21 Atsushi Enomoto <atsushi@ximian.com>
[mcs.git] / tools / tuner / Mono.Tuner / InjectSecurityAttributes.cs
blob0d4bac44e1e88b4103c2e87bf1592fe7c8b5ad95
1 //
2 // InjectSecurityAttributes.cs
3 //
4 // Author:
5 // Jb Evain (jbevain@novell.com)
6 //
7 // (C) 2009 Novell, Inc.
8 //
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.
29 using System;
30 using System.Collections;
31 using System.IO;
32 using System.Text;
34 using Mono.Linker;
35 using Mono.Linker.Steps;
37 using Mono.Cecil;
39 namespace Mono.Tuner {
41 public class InjectSecurityAttributes : BaseStep {
43 enum TargetKind {
44 Type,
45 Method,
48 protected enum AttributeType {
49 Critical,
50 SafeCritical,
53 const string _safe_critical = "System.Security.SecuritySafeCriticalAttribute";
54 const string _critical = "System.Security.SecurityCriticalAttribute";
56 const string sec_attr_folder = "secattrs";
58 protected AssemblyDefinition _assembly;
60 MethodDefinition _safe_critical_ctor;
61 MethodDefinition _critical_ctor;
63 string data_folder;
65 protected override bool ConditionToProcess ()
67 if (!Context.HasParameter (sec_attr_folder)) {
68 Console.Error.WriteLine ("Warning: no secattrs folder specified.");
69 return false;
72 data_folder = Context.GetParameter (sec_attr_folder);
73 return true;
76 protected override void ProcessAssembly (AssemblyDefinition assembly)
78 if (Annotations.GetAction (assembly) != AssemblyAction.Link)
79 return;
81 string secattr_file = Path.Combine (
82 data_folder,
83 assembly.Name.Name + ".secattr");
85 if (!File.Exists (secattr_file)) {
86 Console.Error.WriteLine ("Warning: file '{0}' not found, skipping.", secattr_file);
87 return;
90 _assembly = assembly;
92 // remove existing [SecurityCritical] and [SecuritySafeCritical]
93 RemoveSecurityAttributes ();
95 // add [SecurityCritical] and [SecuritySafeCritical] from the data file
96 ProcessSecurityAttributeFile (secattr_file);
99 protected void RemoveSecurityAttributes ()
101 foreach (TypeDefinition type in _assembly.MainModule.Types) {
102 RemoveSecurityAttributes (type);
104 if (type.HasConstructors)
105 foreach (MethodDefinition ctor in type.Constructors)
106 RemoveSecurityAttributes (ctor);
108 if (type.HasMethods)
109 foreach (MethodDefinition method in type.Methods)
110 RemoveSecurityAttributes (method);
114 static void RemoveSecurityDeclarations (IHasSecurity provider)
116 // also remove already existing CAS security declarations
118 if (provider == null)
119 return;
121 if (!provider.HasSecurityDeclarations)
122 return;
124 provider.SecurityDeclarations.Clear ();
127 static void RemoveSecurityAttributes (ICustomAttributeProvider provider)
129 RemoveSecurityDeclarations (provider as IHasSecurity);
131 if (!provider.HasCustomAttributes)
132 return;
134 CustomAttributeCollection attributes = provider.CustomAttributes;
135 for (int i = 0; i < attributes.Count; i++) {
136 CustomAttribute attribute = attributes [i];
137 switch (attribute.Constructor.DeclaringType.FullName) {
138 case _safe_critical:
139 case _critical:
140 attributes.RemoveAt (i--);
141 break;
146 void ProcessSecurityAttributeFile (string file)
148 using (StreamReader reader = File.OpenText (file)) {
149 string line;
150 while ((line = reader.ReadLine ()) != null)
151 ProcessLine (line);
155 void ProcessLine (string line)
157 if (line == null || line.Length < 6)
158 return;
160 int sep = line.IndexOf (": ");
161 if (sep == -1)
162 return;
164 string marker = line.Substring (0, sep);
165 string target = line.Substring (sep + 2);
167 ProcessSecurityAttributeEntry (
168 DecomposeAttributeType (marker),
169 DecomposeTargetKind (marker),
170 target);
173 static AttributeType DecomposeAttributeType (string marker)
175 if (marker.StartsWith ("SC"))
176 return AttributeType.Critical;
177 else if (marker.StartsWith ("SSC"))
178 return AttributeType.SafeCritical;
179 else
180 throw new ArgumentException ();
183 static TargetKind DecomposeTargetKind (string marker)
185 switch (marker [marker.Length - 1]) {
186 case 'T':
187 return TargetKind.Type;
188 case 'M':
189 return TargetKind.Method;
190 default:
191 throw new ArgumentException ();
195 void ProcessSecurityAttributeEntry (AttributeType type, TargetKind kind, string target)
197 ICustomAttributeProvider provider = GetTarget (kind, target);
198 if (provider == null)
199 return;
201 switch (type) {
202 case AttributeType.Critical:
203 AddCriticalAttribute (provider);
204 break;
205 case AttributeType.SafeCritical:
206 AddSafeCriticalAttribute (provider);
207 break;
211 protected void AddCriticalAttribute (ICustomAttributeProvider provider)
213 // a [SecurityCritical] replaces a [SecuritySafeCritical]
214 if (HasSecurityAttribute (provider, AttributeType.SafeCritical))
215 RemoveSecurityAttributes (provider);
217 AddSecurityAttribute (provider, AttributeType.Critical);
220 void AddSafeCriticalAttribute (ICustomAttributeProvider provider)
222 // a [SecuritySafeCritical] is ignored if a [SecurityCritical] is present
223 if (HasSecurityAttribute (provider, AttributeType.Critical))
224 return;
226 AddSecurityAttribute (provider, AttributeType.SafeCritical);
229 void AddSecurityAttribute (ICustomAttributeProvider provider, AttributeType type)
231 if (HasSecurityAttribute (provider, type))
232 return;
234 CustomAttributeCollection attributes = provider.CustomAttributes;
235 switch (type) {
236 case AttributeType.Critical:
237 attributes.Add (CreateCriticalAttribute ());
238 break;
239 case AttributeType.SafeCritical:
240 attributes.Add (CreateSafeCriticalAttribute ());
241 break;
245 protected static bool HasSecurityAttribute (ICustomAttributeProvider provider, AttributeType type)
247 if (!provider.HasCustomAttributes)
248 return false;
250 foreach (CustomAttribute attribute in provider.CustomAttributes) {
251 switch (attribute.Constructor.DeclaringType.Name) {
252 case _critical:
253 if (type == AttributeType.Critical)
254 return true;
256 break;
257 case _safe_critical:
258 if (type == AttributeType.SafeCritical)
259 return true;
261 break;
265 return false;
268 ICustomAttributeProvider GetTarget (TargetKind kind, string target)
270 switch (kind) {
271 case TargetKind.Type:
272 return GetType (target);
273 case TargetKind.Method:
274 return GetMethod (target);
275 default:
276 throw new ArgumentException ();
280 TypeDefinition GetType (string fullname)
282 return _assembly.MainModule.Types [fullname];
285 MethodDefinition GetMethod (string signature)
287 int pos = signature.IndexOf (" ");
288 if (pos == -1)
289 throw new ArgumentException ();
291 string tmp = signature.Substring (pos + 1);
293 pos = tmp.IndexOf ("::");
294 if (pos == -1)
295 throw new ArgumentException ();
297 string type_name = tmp.Substring (0, pos);
299 int parpos = tmp.IndexOf ("(");
300 if (parpos == -1)
301 throw new ArgumentException ();
303 string method_name = tmp.Substring (pos + 2, parpos - pos - 2);
305 TypeDefinition type = GetType (type_name);
306 if (type == null)
307 return null;
309 return method_name.StartsWith (".c") ?
310 GetMethod (type.Constructors, signature) :
311 GetMethod (type.Methods, signature);
314 static MethodDefinition GetMethod (IEnumerable methods, string signature)
316 foreach (MethodDefinition method in methods)
317 if (GetFullName (method) == signature)
318 return method;
320 return null;
323 static string GetFullName (MethodReference method)
325 int sentinel = method.GetSentinel ();
327 StringBuilder sb = new StringBuilder ();
328 sb.Append (method.ReturnType.ReturnType.FullName);
329 sb.Append (" ");
330 sb.Append (method.DeclaringType.FullName);
331 sb.Append ("::");
332 sb.Append (method.Name);
333 if (method.HasGenericParameters) {
334 sb.Append ("<");
335 for (int i = 0; i < method.GenericParameters.Count; i++ ) {
336 if (i > 0)
337 sb.Append (",");
338 sb.Append (method.GenericParameters [i].Name);
340 sb.Append (">");
342 sb.Append ("(");
343 if (method.HasParameters) {
344 for (int i = 0; i < method.Parameters.Count; i++) {
345 if (i > 0)
346 sb.Append (",");
348 if (i == sentinel)
349 sb.Append ("...,");
351 sb.Append (method.Parameters [i].ParameterType.FullName);
354 sb.Append (")");
355 return sb.ToString ();
358 static MethodDefinition GetDefaultConstructor (TypeDefinition type)
360 foreach (MethodDefinition ctor in type.Constructors)
361 if (ctor.Parameters.Count == 0)
362 return ctor;
364 return null;
367 MethodDefinition GetSafeCriticalCtor ()
369 if (_safe_critical_ctor != null)
370 return _safe_critical_ctor;
372 TypeDefinition safe_critical_type = Context.GetType (_safe_critical);
373 if (safe_critical_type == null)
374 throw new InvalidOperationException (String.Format ("{0} type not found", _safe_critical));
376 _safe_critical_ctor = GetDefaultConstructor (safe_critical_type);
377 return _safe_critical_ctor;
380 MethodDefinition GetCriticalCtor ()
382 if (_critical_ctor != null)
383 return _critical_ctor;
385 TypeDefinition critical_type = Context.GetType (_critical);
386 if (critical_type == null)
387 throw new InvalidOperationException (String.Format ("{0} type not found", _critical));
389 _critical_ctor = GetDefaultConstructor (critical_type);
390 return _critical_ctor;
393 MethodReference Import (MethodDefinition method)
395 return _assembly.MainModule.Import (method);
398 CustomAttribute CreateSafeCriticalAttribute ()
400 return new CustomAttribute (Import (GetSafeCriticalCtor ()));
403 CustomAttribute CreateCriticalAttribute ()
405 return new CustomAttribute (Import (GetCriticalCtor ()));