Added tests for Task.WhenAll w/ empty list
[mono.git] / mono / mini / declsec.c
1 /*
2  * declsec.c:  Declarative Security support
3  *
4  * Author:
5  *      Sebastien Pouliot  <sebastien@ximian.com>
6  *
7  * Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
8  */
9 #include <config.h>
10
11 #include "declsec.h"
12 #include "mini.h"
13
14 #ifndef DISABLE_SECURITY
15
16 /*
17  * Does the methods (or it's class) as any declarative security attribute ?
18  * Is so are they applicable ? (e.g. static class constructor)
19  */
20 MonoBoolean
21 mono_method_has_declsec (MonoMethod *method)
22 {
23         InterlockedIncrement (&mono_jit_stats.cas_declsec_check);
24
25         if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || method->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
26                 method = mono_marshal_method_from_wrapper (method);
27                 if (!method)
28                         return FALSE;
29         } else if (method->wrapper_type != MONO_WRAPPER_NONE)
30                 return FALSE;
31
32         if ((method->klass->flags & TYPE_ATTRIBUTE_HAS_SECURITY) || (method->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
33                 /* ignore static constructors */
34                 if (strcmp (method->name, ".cctor"))
35                         return TRUE;
36         }
37         return FALSE;
38 }
39
40
41 /*
42  * Fill actions for the specific index (which may either be an encoded class token or
43  * an encoded method token) from the metadata image.
44  * Returns TRUE if some actions requiring code generation are present, FALSE otherwise.
45  */
46 void
47 mono_declsec_cache_stack_modifiers (MonoJitInfo *jinfo)
48 {
49         MonoMethodCasInfo *info = mono_jit_info_get_cas_info (jinfo);
50         guint32 flags;
51
52         if (!info)
53                 return;
54
55         /* first find the stack modifiers applied to the method */
56         flags = mono_declsec_flags_from_method (jinfo->method);
57         info->cas_method_assert = (flags & MONO_DECLSEC_FLAG_ASSERT) != 0;
58         info->cas_method_deny = (flags & MONO_DECLSEC_FLAG_DENY) != 0;
59         info->cas_method_permitonly = (flags & MONO_DECLSEC_FLAG_PERMITONLY) != 0;
60
61         /* then find the stack modifiers applied to the class */
62         flags = mono_declsec_flags_from_class (jinfo->method->klass);
63         info->cas_class_assert = (flags & MONO_DECLSEC_FLAG_ASSERT) != 0;
64         info->cas_class_deny = (flags & MONO_DECLSEC_FLAG_DENY) != 0;
65         info->cas_class_permitonly = (flags & MONO_DECLSEC_FLAG_PERMITONLY) != 0;
66 }
67
68
69 MonoSecurityFrame*
70 mono_declsec_create_frame (MonoDomain *domain, MonoJitInfo *jinfo)
71 {
72         MonoSecurityFrame *frame = (MonoSecurityFrame*) mono_object_new (domain, mono_defaults.runtimesecurityframe_class);
73         MonoMethodCasInfo *info;
74
75         info = mono_jit_info_get_cas_info (jinfo);
76         if (info && !info->cas_inited) {
77                 if (mono_method_has_declsec (jinfo->method)) {
78                         /* Cache the stack modifiers into the MonoJitInfo structure to speed up future stack walks */
79                         mono_declsec_cache_stack_modifiers (jinfo);
80                 }
81                 info->cas_inited = TRUE;
82         }
83
84         MONO_OBJECT_SETREF (frame, method, mono_method_get_object (domain, jinfo->method, NULL));
85         MONO_OBJECT_SETREF (frame, domain, domain->domain);
86
87         /* stack modifiers on methods have priority on (i.e. replaces) modifiers on class */
88
89         if (info && info->cas_method_assert) {
90                 mono_declsec_get_method_action (jinfo->method, SECURITY_ACTION_ASSERT, &frame->assert);
91         } else if (info && info->cas_class_assert) {
92                 mono_declsec_get_class_action (jinfo->method->klass, SECURITY_ACTION_ASSERT, &frame->assert);
93         }
94
95         if (info && info->cas_method_deny) {
96                 mono_declsec_get_method_action (jinfo->method, SECURITY_ACTION_DENY, &frame->deny);
97         } else if (info && info->cas_class_deny) {
98                 mono_declsec_get_class_action (jinfo->method->klass, SECURITY_ACTION_DENY, &frame->deny);
99         }
100
101         if (info && info->cas_method_permitonly) {
102                 mono_declsec_get_method_action (jinfo->method, SECURITY_ACTION_PERMITONLY, &frame->permitonly);
103         } else if (info && info->cas_class_permitonly) {
104                 mono_declsec_get_class_action (jinfo->method->klass, SECURITY_ACTION_PERMITONLY, &frame->permitonly);
105         }
106
107         /* g_warning ("FRAME %s A(%p,%d) D(%p,%d) PO(%p,%d)", 
108         jinfo->method->name, frame->assert.blob, frame->assert.size, frame->deny.blob, frame->deny.size, frame->permitonly.blob,frame->permitonly.size); */
109
110         return frame;
111 }
112
113
114 /*
115  * Execute any LinkDemand, NonCasLinkDemand, LinkDemandChoice declarative
116  * security attribute present on the called method or it's class.
117  *
118  * @domain      The current application domain
119  * @caller      The method calling
120  * @callee      The called method.
121  * return value: TRUE if a security violation is detection, FALSE otherwise.
122  *
123  * Note: The execution is done in managed code in SecurityManager.LinkDemand
124  */
125 static gboolean
126 mono_declsec_linkdemand_standard (MonoDomain *domain, MonoMethod *caller, MonoMethod *callee)
127 {
128         MonoDeclSecurityActions linkclass, linkmethod;
129
130         InterlockedIncrement (&mono_jit_stats.cas_linkdemand);
131
132         if (mono_declsec_get_linkdemands (callee, &linkclass, &linkmethod)) {
133                 MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
134                 MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
135                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
136                 MonoObject *res;
137                 gpointer args [3];
138
139                 args [0] = refass;
140                 args [1] = &linkclass;
141                 args [2] = &linkmethod;
142
143                 res = mono_runtime_invoke (secman->linkdemand, NULL, args, NULL);
144                 return !(*(MonoBoolean *) mono_object_unbox(res));
145         }
146         return FALSE;
147 }
148
149 /*
150  * Ensure that the restrictions for partially trusted code are satisfied.
151  *
152  * @domain      The current application domain
153  * @assembly    The assembly to query
154  * return value: TRUE if the assembly is runnning at FullTrust, FALSE otherwise.
155  */
156 static gboolean
157 mono_declsec_is_assembly_fulltrust (MonoDomain *domain, MonoAssembly *assembly)
158 {
159         if (!MONO_SECMAN_FLAG_INIT (assembly->fulltrust)) {
160                 MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
161                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
162
163                 if (secman && refass) {
164                         MonoObject *res;
165                         gpointer args [1];
166                         args [0] = refass;
167
168                         res = mono_runtime_invoke (secman->linkdemandfulltrust, NULL, args, NULL);
169                         if (*(MonoBoolean *) mono_object_unbox(res)) {
170                                 /* keep this value cached as it will be used very often */
171                                 MONO_SECMAN_FLAG_SET_VALUE (assembly->fulltrust, TRUE);
172                                 return TRUE;
173                         }
174                 }
175
176                 MONO_SECMAN_FLAG_SET_VALUE (assembly->fulltrust, FALSE);
177                 return FALSE;
178         }
179
180         return MONO_SECMAN_FLAG_GET_VALUE (assembly->fulltrust);
181 }
182
183 /*
184  * Ensure that the restrictions for partially trusted code are satisfied.
185  *
186  * @domain      The current application domain
187  * @caller      The method calling
188  * @callee      The called method
189  * return value: TRUE if a security violation is detected, FALSE otherwise.
190  *
191  * If callee's assembly is strongnamed and doesn't have an 
192  * [AllowPartiallyTrustedCallers] attribute then we must enforce a LinkDemand
193  * for FullTrust on all public/protected methods on public class.
194  *
195  * Note: APTC is only effective on stongnamed assemblies.
196  */
197 static gboolean
198 mono_declsec_linkdemand_aptc (MonoDomain *domain, MonoMethod *caller, MonoMethod *callee)
199 {
200         MonoSecurityManager* secman = NULL;
201         MonoAssembly *assembly;
202         guint32 size = 0;
203
204         InterlockedIncrement (&mono_jit_stats.cas_linkdemand_aptc);
205
206         /* A - Applicable only if we're calling into *another* assembly */
207         if (caller->klass->image == callee->klass->image)
208                 return FALSE;
209
210         /* B - Applicable if we're calling a public/protected method from a public class */
211         if (!(callee->klass->flags & TYPE_ATTRIBUTE_PUBLIC) || !(callee->flags & FIELD_ATTRIBUTE_PUBLIC))
212                 return FALSE;
213
214         /* C - Applicable if the callee's assembly is strongnamed */
215         if ((mono_image_get_public_key (callee->klass->image, &size) == NULL) || (size < MONO_ECMA_KEY_LENGTH))
216                 return FALSE;
217
218         /* D - the callee's assembly must have [AllowPartiallyTrustedCallers] */
219         assembly = mono_image_get_assembly (callee->klass->image);
220         if (!MONO_SECMAN_FLAG_INIT (assembly->aptc)) {
221                 MonoCustomAttrInfo* cinfo = mono_custom_attrs_from_assembly (assembly);
222                 gboolean result = FALSE;
223                 secman = mono_security_manager_get_methods ();
224                 if (secman && cinfo) {
225                         /* look for AllowPartiallyTrustedCallersAttribute */
226                         result = mono_custom_attrs_has_attr (cinfo, secman->allowpartiallytrustedcallers);
227                 }
228                 if (cinfo)
229                         mono_custom_attrs_free (cinfo);
230                 MONO_SECMAN_FLAG_SET_VALUE (assembly->aptc, result);
231         }
232
233         if (MONO_SECMAN_FLAG_GET_VALUE (assembly->aptc))
234                 return FALSE;
235
236         /* E - the caller's assembly must have full trust permissions */
237         assembly = mono_image_get_assembly (caller->klass->image);
238         if (mono_declsec_is_assembly_fulltrust (domain, assembly))
239                 return FALSE;
240
241         /* g_warning ("FAILURE *** JIT LinkDemand APTC check *** %s.%s calls into %s.%s",
242                 caller->klass->name, caller->name, callee->klass->name, callee->name); */
243
244         return TRUE;    /* i.e. throw new SecurityException(); */
245 }
246
247 /*
248  * Ensure that the restrictions for calling native code are satisfied.
249  *
250  * @domain      The current application domain
251  * @caller      The method calling
252  * @native      The native method called
253  * return value: TRUE if a security violation is detected, FALSE otherwise.
254  *
255  * Executing Platform Invokes (P/Invoke) is a is a restricted operation.
256  * The security policy must allow (SecurityPermissionFlag.UnmanagedCode)
257  * an assembly to do this.
258  *
259  * This LinkDemand case is special because it only needs to call managed
260  * code once per assembly. Further calls on this assembly will use a cached
261  * flag for better performance. This is not done before the first call (e.g.
262  * when loading the assembly) because that would break the lazy policy
263  * evaluation that Mono use (another time saving optimization).
264  *
265  * Note: P/Invoke checks are ALWAYS (1) done at JIT time (as a LinkDemand). 
266  * They are also checked at runtime, using a Demand (stack walk), unless the 
267  * method or it's class has a [SuppressUnmanagedCodeSecurity] attribute.
268  *
269  * (1) well as long as the security manager is active (i.e. --security)
270  */
271 static gboolean
272 mono_declsec_linkdemand_pinvoke (MonoDomain *domain, MonoMethod *caller, MonoMethod *native)
273 {
274         MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
275
276         InterlockedIncrement (&mono_jit_stats.cas_linkdemand_pinvoke);
277
278         /* Check for P/Invoke flag for the assembly */
279         if (!MONO_SECMAN_FLAG_INIT (assembly->unmanaged)) {
280                 /* Check if we know (and have) or FullTrust status */
281                 if (MONO_SECMAN_FLAG_INIT (assembly->fulltrust) && MONO_SECMAN_FLAG_GET_VALUE (assembly->fulltrust)) {
282                         /* FullTrust includes UnmanagedCode permission */
283                         MONO_SECMAN_FLAG_SET_VALUE (assembly->unmanaged, TRUE);
284                         return FALSE;
285                 } else {
286                         MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
287                         MonoSecurityManager* secman = mono_security_manager_get_methods ();
288                         if (secman && refass) {
289                                 MonoObject *res;
290                                 gpointer args [1];
291                                 args [0] = refass;
292
293                                 res = mono_runtime_invoke (secman->linkdemandunmanaged, NULL, args, NULL);
294                                 if (*(MonoBoolean *) mono_object_unbox(res)) {
295                                         MONO_SECMAN_FLAG_SET_VALUE (assembly->unmanaged, TRUE);
296                                         return FALSE;
297                                 }
298                         }
299                 }
300
301                 MONO_SECMAN_FLAG_SET_VALUE (assembly->unmanaged, FALSE);
302         }
303
304         if (MONO_SECMAN_FLAG_GET_VALUE (assembly->unmanaged))
305                 return FALSE;
306
307         /* g_warning ("FAILURE *** JIT LinkDemand P/Invoke check *** %s.%s calls into %s.%s",
308                 caller->klass->name, caller->name, native->klass->name, native->name); */
309
310         return TRUE;    /* i.e. throw new SecurityException(); */
311 }
312
313 /*
314  * Ensure that the restrictions for calling internal calls are satisfied.
315  *
316  * @domain      The current application domain
317  * @caller      The method calling
318  * @icall       The internal call method
319  * return value: TRUE if a security violation is detected, FALSE otherwise.
320  *
321  * We can't trust the icall flags/iflags as it comes from the assembly
322  * that we may want to restrict and we do not have the public/restricted
323  * information about icalls in the runtime. Actually it is not so bad 
324  * as the CLR 2.0 doesn't enforce that restriction anymore.
325  * 
326  * So we'll limit the icalls to originate from ECMA signed assemblies 
327  * (as this is required for partial trust scenarios) - or - assemblies that 
328  * have FullTrust.
329  */
330 static gboolean
331 mono_declsec_linkdemand_icall (MonoDomain *domain, MonoMethod *caller, MonoMethod *icall)
332 {
333         MonoAssembly *assembly;
334
335         InterlockedIncrement (&mono_jit_stats.cas_linkdemand_icall);
336
337         /* check if the _icall_ is defined inside an ECMA signed assembly */
338         assembly = mono_image_get_assembly (icall->klass->image);
339         if (!MONO_SECMAN_FLAG_INIT (assembly->ecma)) {
340                 guint32 size = 0;
341                 const char *pk = mono_image_get_public_key (icall->klass->image, &size);
342                 MONO_SECMAN_FLAG_SET_VALUE (assembly->ecma, mono_is_ecma_key (pk, size));
343         }
344
345         if (MONO_SECMAN_FLAG_GET_VALUE (assembly->ecma))
346                 return FALSE;
347
348         /* else check if the _calling_ assembly is running at FullTrust */
349         assembly = mono_image_get_assembly (caller->klass->image);
350         return !mono_declsec_is_assembly_fulltrust (domain, assembly);
351 }
352
353
354 /*
355  * Before the JIT can link (call) into a method the following security checks
356  * must be done:
357  *
358  * We check that the code has the permission to link when:
359  * 1. the code try to call an internal call;
360  * 2. the code try to p/invoke to unmanaged code;
361  * 3. the code try to call trusted code without being trusted itself -
362  *    or without the trusted code permission (APTC);
363  * 4. the code try to call managed code protected by a LinkDemand security 
364  *    attribute
365  *
366  * Failures result in a SecurityException being thrown (later in mini code).
367  *
368  * Note: Some checks are duplicated in managed code to deal when reflection is
369  * used to call the methods.
370  */
371 guint32
372 mono_declsec_linkdemand (MonoDomain *domain, MonoMethod *caller, MonoMethod *callee)
373 {
374         guint32 violation = MONO_JIT_SECURITY_OK;
375
376         /* short-circuit corlib as it is fully trusted (within itself)
377          * and because this cause major recursion headaches */
378         if ((caller->klass->image == mono_defaults.corlib) && (callee->klass->image == mono_defaults.corlib))
379                 return violation;
380
381         /* next, the special (implied) linkdemand */
382
383         if (callee->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
384                 /* restrict internal calls into the runtime */
385                 if (mono_declsec_linkdemand_icall (domain, caller, callee))
386                         violation = MONO_JIT_LINKDEMAND_ECMA;
387         } else if (callee->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
388                 /* CAS can restrict p/invoke calls with the assembly granted permissions */
389                 if (mono_declsec_linkdemand_pinvoke (domain, caller, callee))
390                         violation = MONO_JIT_LINKDEMAND_PINVOKE;
391         }
392
393         if (!violation) {
394                 /* check if we allow partially trusted callers in trusted (signed) assemblies */
395                 if (mono_declsec_linkdemand_aptc (domain, caller, callee))
396                         violation = MONO_JIT_LINKDEMAND_APTC;
397         }
398
399         /* then the "normal" LinkDemand (only when called method has declarative security) */
400         if (!violation && mono_method_has_declsec (callee)) {
401                 /* LinkDemand are ignored for static constructors (ensured by calling mono_method_has_declsec) */
402                 if (mono_declsec_linkdemand_standard (domain, caller, callee))
403                         violation = MONO_JIT_LINKDEMAND_PERMISSION;
404         }
405
406         /* if (violation) g_warning ("mono_declsec_linkdemand violation reported %d", violation); */
407         return violation;
408 }
409
410 #else /* DISABLE_SECURITY */
411
412 void
413 mono_declsec_cache_stack_modifiers (MonoJitInfo *jinfo)
414 {
415 }
416
417 MonoSecurityFrame*
418 mono_declsec_create_frame (MonoDomain *domain, MonoJitInfo *jinfo)
419 {
420         return NULL;
421 }
422
423 guint32
424 mono_declsec_linkdemand (MonoDomain *domain, MonoMethod *caller, MonoMethod *callee)
425 {
426         return MONO_JIT_SECURITY_OK;
427 }
428
429 MonoBoolean
430 mono_method_has_declsec (MonoMethod *method)
431 {
432         return FALSE;
433 }
434
435 #endif