2 // InjectSecurityAttributes.cs
5 // Jb Evain (jbevain@novell.com)
7 // (C) 2009 Novell, Inc.
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.
30 using System.Collections;
36 using Mono.Linker.Steps;
40 namespace Mono.Tuner {
42 public class InjectSecurityAttributes : BaseStep {
49 protected enum AttributeType {
54 const string _safe_critical = "System.Security.SecuritySafeCriticalAttribute";
55 const string _critical = "System.Security.SecurityCriticalAttribute";
57 const string sec_attr_folder = "secattrs";
59 protected AssemblyDefinition _assembly;
61 MethodDefinition _safe_critical_ctor;
62 MethodDefinition _critical_ctor;
66 protected override bool ConditionToProcess ()
68 if (!Context.HasParameter (sec_attr_folder)) {
69 Console.Error.WriteLine ("Warning: no secattrs folder specified.");
73 data_folder = Context.GetParameter (sec_attr_folder);
77 protected override void ProcessAssembly (AssemblyDefinition assembly)
79 if (Annotations.GetAction (assembly) != AssemblyAction.Link)
82 string secattr_file = Path.Combine (
84 assembly.Name.Name + ".secattr");
86 if (!File.Exists (secattr_file)) {
87 Console.Error.WriteLine ("Warning: file '{0}' not found, skipping.", secattr_file);
93 // remove existing [SecurityCritical] and [SecuritySafeCritical]
94 RemoveSecurityAttributes ();
96 // add [SecurityCritical] and [SecuritySafeCritical] from the data file
97 ProcessSecurityAttributeFile (secattr_file);
100 protected void RemoveSecurityAttributes ()
102 foreach (TypeDefinition type in _assembly.MainModule.Types) {
103 if (RemoveSecurityAttributes (type))
104 type.HasSecurity = false;
106 if (type.HasMethods) {
107 foreach (MethodDefinition method in type.Methods) {
108 if (RemoveSecurityAttributes (method))
109 method.HasSecurity = false;
115 static bool RemoveSecurityDeclarations (ISecurityDeclarationProvider provider)
117 // also remove already existing CAS security declarations
119 if (provider == null)
122 if (!provider.HasSecurityDeclarations)
125 provider.SecurityDeclarations.Clear ();
129 static bool RemoveSecurityAttributes (ICustomAttributeProvider provider)
131 bool result = RemoveSecurityDeclarations (provider as ISecurityDeclarationProvider);
133 if (!provider.HasCustomAttributes)
136 var attributes = provider.CustomAttributes;
137 for (int i = 0; i < attributes.Count; i++) {
138 CustomAttribute attribute = attributes [i];
139 switch (attribute.Constructor.DeclaringType.FullName) {
142 attributes.RemoveAt (i--);
149 void ProcessSecurityAttributeFile (string file)
151 using (StreamReader reader = File.OpenText (file)) {
153 while ((line = reader.ReadLine ()) != null)
158 void ProcessLine (string line)
160 if (line == null || line.Length < 6)
163 int sep = line.IndexOf (": ");
167 string marker = line.Substring (0, sep);
168 string target = line.Substring (sep + 2);
170 ProcessSecurityAttributeEntry (
171 DecomposeAttributeType (marker),
172 DecomposeTargetKind (marker),
176 static AttributeType DecomposeAttributeType (string marker)
178 if (marker.StartsWith ("SC"))
179 return AttributeType.Critical;
180 else if (marker.StartsWith ("SSC"))
181 return AttributeType.SafeCritical;
183 throw new ArgumentException ();
186 static TargetKind DecomposeTargetKind (string marker)
188 switch (marker [marker.Length - 1]) {
190 return TargetKind.Type;
192 return TargetKind.Method;
194 throw new ArgumentException ();
198 void ProcessSecurityAttributeEntry (AttributeType type, TargetKind kind, string target)
200 ICustomAttributeProvider provider = GetTarget (kind, target);
201 if (provider == null)
205 case AttributeType.Critical:
206 AddCriticalAttribute (provider);
208 case AttributeType.SafeCritical:
209 AddSafeCriticalAttribute (provider);
214 protected void AddCriticalAttribute (ICustomAttributeProvider provider)
216 // a [SecurityCritical] replaces a [SecuritySafeCritical]
217 if (HasSecurityAttribute (provider, AttributeType.SafeCritical))
218 RemoveSecurityAttributes (provider);
220 AddSecurityAttribute (provider, AttributeType.Critical);
223 void AddSafeCriticalAttribute (ICustomAttributeProvider provider)
225 // a [SecuritySafeCritical] is ignored if a [SecurityCritical] is present
226 if (HasSecurityAttribute (provider, AttributeType.Critical))
229 AddSecurityAttribute (provider, AttributeType.SafeCritical);
232 void AddSecurityAttribute (ICustomAttributeProvider provider, AttributeType type)
234 if (HasSecurityAttribute (provider, type))
237 var attributes = provider.CustomAttributes;
239 case AttributeType.Critical:
240 attributes.Add (CreateCriticalAttribute ());
242 case AttributeType.SafeCritical:
243 attributes.Add (CreateSafeCriticalAttribute ());
248 protected static bool HasSecurityAttribute (ICustomAttributeProvider provider, AttributeType type)
250 if (!provider.HasCustomAttributes)
253 foreach (CustomAttribute attribute in provider.CustomAttributes) {
254 switch (attribute.Constructor.DeclaringType.Name) {
256 if (type == AttributeType.Critical)
261 if (type == AttributeType.SafeCritical)
271 ICustomAttributeProvider GetTarget (TargetKind kind, string target)
274 case TargetKind.Type:
275 return GetType (target);
276 case TargetKind.Method:
277 return GetMethod (target);
279 throw new ArgumentException ();
283 TypeDefinition GetType (string fullname)
285 return _assembly.MainModule.GetType (fullname);
288 MethodDefinition GetMethod (string signature)
290 int pos = signature.IndexOf (" ");
292 throw new ArgumentException ();
294 string tmp = signature.Substring (pos + 1);
296 pos = tmp.IndexOf ("::");
298 throw new ArgumentException ();
300 string type_name = tmp.Substring (0, pos);
302 int parpos = tmp.IndexOf ("(");
304 throw new ArgumentException ();
306 string method_name = tmp.Substring (pos + 2, parpos - pos - 2);
308 TypeDefinition type = GetType (type_name);
312 return GetMethod (type.Methods, signature);
315 static MethodDefinition GetMethod (IEnumerable methods, string signature)
317 foreach (MethodDefinition method in methods)
318 if (GetFullName (method) == signature)
324 static string GetFullName (MethodReference method)
326 var sentinel = method.Parameters.FirstOrDefault (p => p.ParameterType.IsSentinel);
327 var sentinel_pos = -1;
328 if (sentinel != null)
329 sentinel_pos = method.Parameters.IndexOf (sentinel);
331 StringBuilder sb = new StringBuilder ();
332 sb.Append (method.ReturnType.FullName);
334 sb.Append (method.DeclaringType.FullName);
336 sb.Append (method.Name);
337 if (method.HasGenericParameters) {
339 for (int i = 0; i < method.GenericParameters.Count; i++ ) {
342 sb.Append (method.GenericParameters [i].Name);
347 if (method.HasParameters) {
348 for (int i = 0; i < method.Parameters.Count; i++) {
352 if (i == sentinel_pos)
355 sb.Append (method.Parameters [i].ParameterType.FullName);
359 return sb.ToString ();
362 static MethodDefinition GetDefaultConstructor (TypeDefinition type)
364 foreach (MethodDefinition ctor in type.Methods.Where (m => m.IsConstructor))
365 if (ctor.Parameters.Count == 0)
371 MethodDefinition GetSafeCriticalCtor ()
373 if (_safe_critical_ctor != null)
374 return _safe_critical_ctor;
376 TypeDefinition safe_critical_type = Context.GetType (_safe_critical);
377 if (safe_critical_type == null)
378 throw new InvalidOperationException (String.Format ("{0} type not found", _safe_critical));
380 _safe_critical_ctor = GetDefaultConstructor (safe_critical_type);
381 return _safe_critical_ctor;
384 MethodDefinition GetCriticalCtor ()
386 if (_critical_ctor != null)
387 return _critical_ctor;
389 TypeDefinition critical_type = Context.GetType (_critical);
390 if (critical_type == null)
391 throw new InvalidOperationException (String.Format ("{0} type not found", _critical));
393 _critical_ctor = GetDefaultConstructor (critical_type);
394 return _critical_ctor;
397 MethodReference Import (MethodDefinition method)
399 return _assembly.MainModule.Import (method);
402 CustomAttribute CreateSafeCriticalAttribute ()
404 return new CustomAttribute (Import (GetSafeCriticalCtor ()));
407 CustomAttribute CreateCriticalAttribute ()
409 return new CustomAttribute (Import (GetCriticalCtor ()));