* TextControl.cs: Make PageUp and PageDown more like the
[mono-project.git] / mono / mini / declsec.c
blobe64286ff4c7e511d70005ae0554a8d27c196de71
1 /*
2 * declsec.c: Declarative Security support
4 * Author:
5 * Sebastien Pouliot <sebastien@ximian.com>
7 * Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
8 */
10 #include "declsec.h"
11 #include "mini.h"
14 * Does the methods (or it's class) as any declarative security attribute ?
15 * Is so are they applicable ? (e.g. static class constructor)
17 MonoBoolean
18 mono_method_has_declsec (MonoMethod *method)
20 mono_jit_stats.cas_declsec_check++;
22 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || method->wrapper_type == MONO_WRAPPER_MANAGED_TO_MANAGED) {
23 method = mono_marshal_method_from_wrapper (method);
24 if (!method)
25 return FALSE;
26 } else if (method->wrapper_type != MONO_WRAPPER_NONE)
27 return FALSE;
29 if ((method->klass->flags & TYPE_ATTRIBUTE_HAS_SECURITY) || (method->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
30 /* ignore static constructors */
31 if (strcmp (method->name, ".cctor"))
32 return TRUE;
34 return FALSE;
39 * Fill actions for the specific index (which may either be an encoded class token or
40 * an encoded method token) from the metadata image.
41 * Returns TRUE if some actions requiring code generation are present, FALSE otherwise.
43 void
44 mono_declsec_cache_stack_modifiers (MonoJitInfo *jinfo)
46 /* first find the stack modifiers applied to the method */
47 guint32 flags = mono_declsec_flags_from_method (jinfo->method);
48 jinfo->cas_method_assert = (flags & MONO_DECLSEC_FLAG_ASSERT) != 0;
49 jinfo->cas_method_deny = (flags & MONO_DECLSEC_FLAG_DENY) != 0;
50 jinfo->cas_method_permitonly = (flags & MONO_DECLSEC_FLAG_PERMITONLY) != 0;
52 /* then find the stack modifiers applied to the class */
53 flags = mono_declsec_flags_from_class (jinfo->method->klass);
54 jinfo->cas_class_assert = (flags & MONO_DECLSEC_FLAG_ASSERT) != 0;
55 jinfo->cas_class_deny = (flags & MONO_DECLSEC_FLAG_DENY) != 0;
56 jinfo->cas_class_permitonly = (flags & MONO_DECLSEC_FLAG_PERMITONLY) != 0;
60 MonoSecurityFrame*
61 mono_declsec_create_frame (MonoDomain *domain, MonoJitInfo *jinfo)
63 MonoSecurityFrame *frame = (MonoSecurityFrame*) mono_object_new (domain, mono_defaults.runtimesecurityframe_class);
65 if (!jinfo->cas_inited) {
66 if (mono_method_has_declsec (jinfo->method)) {
67 /* Cache the stack modifiers into the MonoJitInfo structure to speed up future stack walks */
68 mono_declsec_cache_stack_modifiers (jinfo);
70 jinfo->cas_inited = TRUE;
73 MONO_OBJECT_SETREF (frame, method, mono_method_get_object (domain, jinfo->method, NULL));
74 MONO_OBJECT_SETREF (frame, domain, domain->domain);
76 /* stack modifiers on methods have priority on (i.e. replaces) modifiers on class */
78 if (jinfo->cas_method_assert) {
79 mono_declsec_get_method_action (jinfo->method, SECURITY_ACTION_ASSERT, &frame->assert);
80 } else if (jinfo->cas_class_assert) {
81 mono_declsec_get_class_action (jinfo->method->klass, SECURITY_ACTION_ASSERT, &frame->assert);
84 if (jinfo->cas_method_deny) {
85 mono_declsec_get_method_action (jinfo->method, SECURITY_ACTION_DENY, &frame->deny);
86 } else if (jinfo->cas_class_deny) {
87 mono_declsec_get_class_action (jinfo->method->klass, SECURITY_ACTION_DENY, &frame->deny);
90 if (jinfo->cas_method_permitonly) {
91 mono_declsec_get_method_action (jinfo->method, SECURITY_ACTION_PERMITONLY, &frame->permitonly);
92 } else if (jinfo->cas_class_permitonly) {
93 mono_declsec_get_class_action (jinfo->method->klass, SECURITY_ACTION_PERMITONLY, &frame->permitonly);
96 /* g_warning ("FRAME %s A(%p,%d) D(%p,%d) PO(%p,%d)",
97 jinfo->method->name, frame->assert.blob, frame->assert.size, frame->deny.blob, frame->deny.size, frame->permitonly.blob,frame->permitonly.size); */
99 return frame;
104 * Execute any LinkDemand, NonCasLinkDemand, LinkDemandChoice declarative
105 * security attribute present on the called method or it's class.
107 * @domain The current application domain
108 * @caller The method calling
109 * @callee The called method.
110 * return value: TRUE if a security violation is detection, FALSE otherwise.
112 * Note: The execution is done in managed code in SecurityManager.LinkDemand
114 static gboolean
115 mono_declsec_linkdemand_standard (MonoDomain *domain, MonoMethod *caller, MonoMethod *callee)
117 MonoDeclSecurityActions linkclass, linkmethod;
119 mono_jit_stats.cas_linkdemand++;
121 if (mono_declsec_get_linkdemands (callee, &linkclass, &linkmethod)) {
122 MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
123 MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
124 MonoSecurityManager *secman = mono_security_manager_get_methods ();
125 MonoObject *res;
126 gpointer args [3];
128 args [0] = refass;
129 args [1] = &linkclass;
130 args [2] = &linkmethod;
132 res = mono_runtime_invoke (secman->linkdemand, NULL, args, NULL);
133 return !(*(MonoBoolean *) mono_object_unbox(res));
135 return FALSE;
139 * Ensure that the restrictions for partially trusted code are satisfied.
141 * @domain The current application domain
142 * @assembly The assembly to query
143 * return value: TRUE if the assembly is runnning at FullTrust, FALSE otherwise.
145 static gboolean
146 mono_declsec_is_assembly_fulltrust (MonoDomain *domain, MonoAssembly *assembly)
148 if (!MONO_SECMAN_FLAG_INIT (assembly->fulltrust)) {
149 MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
150 MonoSecurityManager *secman = mono_security_manager_get_methods ();
152 if (secman && refass) {
153 MonoObject *res;
154 gpointer args [1];
155 args [0] = refass;
157 res = mono_runtime_invoke (secman->linkdemandfulltrust, NULL, args, NULL);
158 if (*(MonoBoolean *) mono_object_unbox(res)) {
159 /* keep this value cached as it will be used very often */
160 MONO_SECMAN_FLAG_SET_VALUE (assembly->fulltrust, TRUE);
161 return TRUE;
165 MONO_SECMAN_FLAG_SET_VALUE (assembly->fulltrust, FALSE);
166 return FALSE;
169 return MONO_SECMAN_FLAG_GET_VALUE (assembly->fulltrust);
173 * Ensure that the restrictions for partially trusted code are satisfied.
175 * @domain The current application domain
176 * @caller The method calling
177 * @callee The called method
178 * return value: TRUE if a security violation is detected, FALSE otherwise.
180 * If callee's assembly is strongnamed and doesn't have an
181 * [AllowPartiallyTrustedCallers] attribute then we must enforce a LinkDemand
182 * for FullTrust on all public/protected methods on public class.
184 * Note: APTC is only effective on stongnamed assemblies.
186 static gboolean
187 mono_declsec_linkdemand_aptc (MonoDomain *domain, MonoMethod *caller, MonoMethod *callee)
189 MonoSecurityManager* secman = NULL;
190 MonoAssembly *assembly;
191 guint32 size = 0;
193 mono_jit_stats.cas_linkdemand_aptc++;
195 /* A - Applicable only if we're calling into *another* assembly */
196 if (caller->klass->image == callee->klass->image)
197 return FALSE;
199 /* B - Applicable if we're calling a public/protected method from a public class */
200 if (!(callee->klass->flags & TYPE_ATTRIBUTE_PUBLIC) || !(callee->flags & FIELD_ATTRIBUTE_PUBLIC))
201 return FALSE;
203 /* C - Applicable if the callee's assembly is strongnamed */
204 if ((mono_image_get_public_key (callee->klass->image, &size) == NULL) || (size < MONO_ECMA_KEY_LENGTH))
205 return FALSE;
207 /* D - the callee's assembly must have [AllowPartiallyTrustedCallers] */
208 assembly = mono_image_get_assembly (callee->klass->image);
209 if (!MONO_SECMAN_FLAG_INIT (assembly->aptc)) {
210 MonoCustomAttrInfo* cinfo = mono_custom_attrs_from_assembly (assembly);
211 gboolean result = FALSE;
212 secman = mono_security_manager_get_methods ();
213 if (secman && cinfo) {
214 /* look for AllowPartiallyTrustedCallersAttribute */
215 result = mono_custom_attrs_has_attr (cinfo, secman->allowpartiallytrustedcallers);
217 MONO_SECMAN_FLAG_SET_VALUE (assembly->aptc, result);
220 if (MONO_SECMAN_FLAG_GET_VALUE (assembly->aptc))
221 return FALSE;
223 /* E - the caller's assembly must have full trust permissions */
224 assembly = mono_image_get_assembly (caller->klass->image);
225 if (mono_declsec_is_assembly_fulltrust (domain, assembly))
226 return FALSE;
228 /* g_warning ("FAILURE *** JIT LinkDemand APTC check *** %s.%s calls into %s.%s",
229 caller->klass->name, caller->name, callee->klass->name, callee->name); */
231 return TRUE; /* i.e. throw new SecurityException(); */
235 * Ensure that the restrictions for calling native code are satisfied.
237 * @domain The current application domain
238 * @caller The method calling
239 * @native The native method called
240 * return value: TRUE if a security violation is detected, FALSE otherwise.
242 * Executing Platform Invokes (P/Invoke) is a is a restricted operation.
243 * The security policy must allow (SecurityPermissionFlag.UnmanagedCode)
244 * an assembly to do this.
246 * This LinkDemand case is special because it only needs to call managed
247 * code once per assembly. Further calls on this assembly will use a cached
248 * flag for better performance. This is not done before the first call (e.g.
249 * when loading the assembly) because that would break the lazy policy
250 * evaluation that Mono use (another time saving optimization).
252 * Note: P/Invoke checks are ALWAYS (1) done at JIT time (as a LinkDemand).
253 * They are also checked at runtime, using a Demand (stack walk), unless the
254 * method or it's class has a [SuppressUnmanagedCodeSecurity] attribute.
256 * (1) well as long as the security manager is active (i.e. --security)
258 static gboolean
259 mono_declsec_linkdemand_pinvoke (MonoDomain *domain, MonoMethod *caller, MonoMethod *native)
261 MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
263 mono_jit_stats.cas_linkdemand_pinvoke++;
265 /* Check for P/Invoke flag for the assembly */
266 if (!MONO_SECMAN_FLAG_INIT (assembly->unmanaged)) {
267 /* Check if we know (and have) or FullTrust status */
268 if (MONO_SECMAN_FLAG_INIT (assembly->fulltrust) && MONO_SECMAN_FLAG_GET_VALUE (assembly->fulltrust)) {
269 /* FullTrust includes UnmanagedCode permission */
270 MONO_SECMAN_FLAG_SET_VALUE (assembly->unmanaged, TRUE);
271 return FALSE;
272 } else {
273 MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
274 MonoSecurityManager* secman = mono_security_manager_get_methods ();
275 if (secman && refass) {
276 MonoObject *res;
277 gpointer args [1];
278 args [0] = refass;
280 res = mono_runtime_invoke (secman->linkdemandunmanaged, NULL, args, NULL);
281 if (*(MonoBoolean *) mono_object_unbox(res)) {
282 MONO_SECMAN_FLAG_SET_VALUE (assembly->unmanaged, TRUE);
283 return FALSE;
288 MONO_SECMAN_FLAG_SET_VALUE (assembly->unmanaged, FALSE);
291 if (MONO_SECMAN_FLAG_GET_VALUE (assembly->unmanaged))
292 return FALSE;
294 /* g_warning ("FAILURE *** JIT LinkDemand P/Invoke check *** %s.%s calls into %s.%s",
295 caller->klass->name, caller->name, native->klass->name, native->name); */
297 return TRUE; /* i.e. throw new SecurityException(); */
301 * Ensure that the restrictions for calling internal calls are satisfied.
303 * @domain The current application domain
304 * @caller The method calling
305 * @icall The internal call method
306 * return value: TRUE if a security violation is detected, FALSE otherwise.
308 * We can't trust the icall flags/iflags as it comes from the assembly
309 * that we may want to restrict and we do not have the public/restricted
310 * information about icalls in the runtime. Actually it is not so bad
311 * as the CLR 2.0 doesn't enforce that restriction anymore.
313 * So we'll limit the icalls to originate from ECMA signed assemblies
314 * (as this is required for partial trust scenarios) - or - assemblies that
315 * have FullTrust.
317 static gboolean
318 mono_declsec_linkdemand_icall (MonoDomain *domain, MonoMethod *caller, MonoMethod *icall)
320 MonoAssembly *assembly;
322 mono_jit_stats.cas_linkdemand_icall++;
324 /* check if the _icall_ is defined inside an ECMA signed assembly */
325 assembly = mono_image_get_assembly (icall->klass->image);
326 if (!MONO_SECMAN_FLAG_INIT (assembly->ecma)) {
327 guint32 size = 0;
328 const char *pk = mono_image_get_public_key (icall->klass->image, &size);
329 MONO_SECMAN_FLAG_SET_VALUE (assembly->ecma, mono_is_ecma_key (pk, size));
332 if (MONO_SECMAN_FLAG_GET_VALUE (assembly->ecma))
333 return FALSE;
335 /* else check if the _calling_ assembly is running at FullTrust */
336 assembly = mono_image_get_assembly (caller->klass->image);
337 return !mono_declsec_is_assembly_fulltrust (domain, assembly);
342 * Before the JIT can link (call) into a method the following security checks
343 * must be done:
345 * We check that the code has the permission to link when:
346 * 1. the code try to call an internal call;
347 * 2. the code try to p/invoke to unmanaged code;
348 * 3. the code try to call trusted code without being trusted itself -
349 * or without the trusted code permission (APTC);
350 * 4. the code try to call managed code protected by a LinkDemand security
351 * attribute
353 * Failures result in a SecurityException being thrown (later in mini code).
355 * Note: Some checks are duplicated in managed code to deal when reflection is
356 * used to call the methods.
358 guint32
359 mono_declsec_linkdemand (MonoDomain *domain, MonoMethod *caller, MonoMethod *callee)
361 guint32 violation = MONO_JIT_SECURITY_OK;
363 /* short-circuit corlib as it is fully trusted (within itself)
364 * and because this cause major recursion headaches */
365 if ((caller->klass->image == mono_defaults.corlib) && (callee->klass->image == mono_defaults.corlib))
366 return violation;
368 /* next, the special (implied) linkdemand */
370 if (callee->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
371 /* restrict internal calls into the runtime */
372 if (mono_declsec_linkdemand_icall (domain, caller, callee))
373 violation = MONO_JIT_LINKDEMAND_ECMA;
374 } else if (callee->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
375 /* CAS can restrict p/invoke calls with the assembly granted permissions */
376 if (mono_declsec_linkdemand_pinvoke (domain, caller, callee))
377 violation = MONO_JIT_LINKDEMAND_PINVOKE;
380 if (!violation) {
381 /* check if we allow partially trusted callers in trusted (signed) assemblies */
382 if (mono_declsec_linkdemand_aptc (domain, caller, callee))
383 violation = MONO_JIT_LINKDEMAND_APTC;
386 /* then the "normal" LinkDemand (only when called method has declarative security) */
387 if (!violation && mono_method_has_declsec (callee)) {
388 /* LinkDemand are ignored for static constructors (ensured by calling mono_method_has_declsec) */
389 if (mono_declsec_linkdemand_standard (domain, caller, callee))
390 violation = MONO_JIT_LINKDEMAND_PERMISSION;
393 /* if (violation) g_warning ("mono_declsec_linkdemand violation reported %d", violation); */
394 return violation;