2 * declsec.c: Declarative Security support
5 * Sebastien Pouliot <sebastien@ximian.com>
7 * Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
13 * Does the methods (or it's class) as any declarative security attribute ?
14 * Is so are they applicable ? (e.g. static class constructor)
17 mono_method_has_declsec (MonoMethod *method)
19 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
20 method = mono_marshal_method_from_wrapper (method);
23 } else if (method->wrapper_type != MONO_WRAPPER_NONE)
26 if ((method->klass->flags & TYPE_ATTRIBUTE_HAS_SECURITY) || (method->flags & METHOD_ATTRIBUTE_HAS_SECURITY)) {
27 /* ignore static constructors */
28 if (strcmp (method->name, ".cctor"))
36 * Fill actions for the specific index (which may either be an encoded class token or
37 * an encoded method token) from the metadata image.
38 * Returns TRUE if some actions requiring code generation are present, FALSE otherwise.
41 mono_declsec_cache_stack_modifiers (MonoJitInfo *jinfo)
43 /* first find the stack modifiers applied to the method */
44 guint32 flags = mono_declsec_flags_from_method (jinfo->method);
45 jinfo->cas_method_assert = (flags & MONO_DECLSEC_FLAG_ASSERT) != 0;
46 jinfo->cas_method_deny = (flags & MONO_DECLSEC_FLAG_DENY) != 0;
47 jinfo->cas_method_permitonly = (flags & MONO_DECLSEC_FLAG_PERMITONLY) != 0;
49 /* then find the stack modifiers applied to the class */
50 flags = mono_declsec_flags_from_class (jinfo->method->klass);
51 jinfo->cas_class_assert = (flags & MONO_DECLSEC_FLAG_ASSERT) != 0;
52 jinfo->cas_class_deny = (flags & MONO_DECLSEC_FLAG_DENY) != 0;
53 jinfo->cas_class_permitonly = (flags & MONO_DECLSEC_FLAG_PERMITONLY) != 0;
58 mono_declsec_create_frame (MonoDomain *domain, MonoJitInfo *jinfo)
60 MonoSecurityFrame *frame = (MonoSecurityFrame*) mono_object_new (domain, mono_defaults.runtimesecurityframe_class);
62 if (!jinfo->cas_inited) {
63 if (mono_method_has_declsec (jinfo->method)) {
64 /* Cache the stack modifiers into the MonoJitInfo structure to speed up future stack walks */
65 mono_declsec_cache_stack_modifiers (jinfo);
67 jinfo->cas_inited = TRUE;
70 frame->method = mono_method_get_object (domain, jinfo->method, NULL);
72 /* stack modifiers on methods have priority on (i.e. replaces) modifiers on class */
74 if (jinfo->cas_method_assert) {
75 mono_declsec_get_method_action (jinfo->method, SECURITY_ACTION_ASSERT, &frame->assert);
76 } else if (jinfo->cas_class_assert) {
77 mono_declsec_get_class_action (jinfo->method->klass, SECURITY_ACTION_ASSERT, &frame->assert);
80 if (jinfo->cas_method_deny) {
81 mono_declsec_get_method_action (jinfo->method, SECURITY_ACTION_DENY, &frame->deny);
82 } else if (jinfo->cas_class_deny) {
83 mono_declsec_get_class_action (jinfo->method->klass, SECURITY_ACTION_DENY, &frame->deny);
86 if (jinfo->cas_method_permitonly) {
87 mono_declsec_get_method_action (jinfo->method, SECURITY_ACTION_PERMITONLY, &frame->permitonly);
88 } else if (jinfo->cas_class_permitonly) {
89 mono_declsec_get_class_action (jinfo->method->klass, SECURITY_ACTION_PERMITONLY, &frame->permitonly);
92 /* g_warning ("FRAME %s A(%p,%d) D(%p,%d) PO(%p,%d)",
93 jinfo->method->name, frame->assert.blob, frame->assert.size, frame->deny.blob, frame->deny.size, frame->permitonly.blob,frame->permitonly.size); */
100 * Execute any LinkDemand, NonCasLinkDemand, LinkDemandChoice declarative
101 * security attribute present on the called method or it's class.
103 * @domain The current application domain
104 * @caller The method calling
105 * @callee The called method.
106 * return value: TRUE if a security violation is detection, FALSE otherwise.
108 * Note: The execution is done in managed code in SecurityManager.LinkDemand
111 mono_declsec_linkdemand_standard (MonoDomain *domain, MonoMethod *caller, MonoMethod *callee)
113 MonoDeclSecurityActions linkclass, linkmethod;
115 if (mono_declsec_get_linkdemands (callee, &linkclass, &linkmethod)) {
116 MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
117 MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
118 MonoSecurityManager *secman = mono_security_manager_get_methods ();
123 args [1] = &linkclass;
124 args [2] = &linkmethod;
126 res = mono_runtime_invoke (secman->linkdemand, NULL, args, NULL);
127 return !(*(MonoBoolean *) mono_object_unbox(res));
133 * Ensure that the restrictions for partially trusted code are satisfied.
135 * @domain The current application domain
136 * @caller The method calling
137 * @callee The called method
138 * return value: TRUE if a security violation is detection, FALSE otherwise.
140 * If callee's assembly is strongnamed and doesn't have an
141 * [AllowPartiallyTrustedCallers] attribute then we must enforce a LinkDemand
142 * for FullTrust on all public/protected methods on public class.
144 * Note: APTC is only effective on stongnamed assemblies.
147 mono_declsec_linkdemand_aptc (MonoDomain *domain, MonoMethod *caller, MonoMethod *callee)
149 MonoSecurityManager* secman;
150 MonoAssembly *assembly;
153 /* A - Applicable only if we're calling into *another* assembly */
154 if (caller->klass->image == callee->klass->image)
157 /* B - Applicable if we're calling a public/protected method from a public class */
158 if (!(callee->klass->flags & TYPE_ATTRIBUTE_PUBLIC) || !(callee->flags & FIELD_ATTRIBUTE_PUBLIC))
161 /* C - Applicable if the callee's assembly is strongnamed */
162 if ((mono_image_get_public_key (callee->klass->image, &size) == NULL) || (size < MONO_ECMA_KEY_LENGTH))
165 /* D - the callee's assembly must have [AllowPartiallyTrustedCallers] */
166 assembly = mono_image_get_assembly (callee->klass->image);
167 if (!MONO_SECMAN_FLAG_INIT (assembly->aptc)) {
168 MonoCustomAttrInfo* cinfo = mono_custom_attrs_from_assembly (assembly);
169 gboolean result = FALSE;
170 secman = mono_security_manager_get_methods ();
171 if (secman && cinfo) {
172 /* look for AllowPartiallyTrustedCallersAttribute */
173 result = mono_custom_attrs_has_attr (cinfo, secman->aptc);
175 MONO_SECMAN_FLAG_SET_VALUE (assembly->aptc, result);
178 if (MONO_SECMAN_FLAG_GET_VALUE (assembly->aptc))
181 /* E - the caller's assembly must have full trust permissions */
182 if (!MONO_SECMAN_FLAG_INIT (assembly->fulltrust)) {
183 MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
185 secman = mono_security_manager_get_methods ();
187 if (secman && refass) {
192 res = mono_runtime_invoke (secman->linkdemandfulltrust, NULL, args, NULL);
193 if (*(MonoBoolean *) mono_object_unbox(res)) {
194 /* keep this value cached as it will be used very often */
195 MONO_SECMAN_FLAG_SET_VALUE (assembly->fulltrust, TRUE);
200 MONO_SECMAN_FLAG_SET_VALUE (assembly->fulltrust, FALSE);
203 if (MONO_SECMAN_FLAG_GET_VALUE (assembly->fulltrust))
206 /* g_warning ("FAILURE *** JIT LinkDemand APTC check *** %s.%s calls into %s.%s",
207 caller->klass->name, caller->name, callee->klass->name, callee->name); */
209 return TRUE; /* i.e. throw new SecurityException(); */
213 * Ensure that the restrictions for calling internal calls are satisfied.
215 * @caller The method calling
216 * @icall The internal call method
217 * return value: TRUE if a security violation is detection, FALSE otherwise.
219 * Executing internal calls (icalls) is a restricted operation. Only
220 * assemblies with an ECMA public key are allowed to call them (unless they
221 * are publicly available).
223 * This LinkDemand case is special because it can be done without calling
227 mono_declsec_linkdemand_ecma (MonoMethod *caller, MonoMethod *icall)
229 MonoAssembly *assembly;
231 /* some icall are public (i.e. they CAN be called by any code) */
232 if (((icall->klass->flags & TYPE_ATTRIBUTE_PUBLIC) == TYPE_ATTRIBUTE_PUBLIC) &&
233 ((icall->flags & FIELD_ATTRIBUTE_PUBLIC) == FIELD_ATTRIBUTE_PUBLIC)) {
237 assembly = mono_image_get_assembly (icall->klass->image);
238 if (!MONO_SECMAN_FLAG_INIT (assembly->ecma)) {
240 const char *pk = mono_image_get_public_key (caller->klass->image, &size);
241 MONO_SECMAN_FLAG_SET_VALUE (assembly->ecma, mono_is_ecma_key (pk, size));
244 if (MONO_SECMAN_FLAG_GET_VALUE (assembly->ecma))
247 /* g_warning ("FAILURE *** JIT LinkDemand for ECMA check *** %s.%s calls into %s.%s",
248 caller->klass->name, caller->name, icall->klass->name, icall->name); */
250 return TRUE; /* i.e. throw new SecurityException(); */
254 * Ensure that the restrictions for calling native code are satisfied.
256 * @domain The current application domain
257 * @caller The method calling
258 * @native The native method called
259 * return value: TRUE if a security violation is detection, FALSE otherwise.
261 * Executing Platform Invokes (P/Invoke) is a is a restricted operation.
262 * The security policy must allow (SecurityPermissionFlag.UnmanagedCode)
263 * an assembly to do this.
265 * This LinkDemand case is special because it only needs to call managed
266 * code once per assembly. Further calls on this assembly will use a cached
267 * flag for better performance. This is not done before the first call (e.g.
268 * when loading the assembly) because that would break the lazy policy
269 * evaluation that Mono use (another time saving optimization).
271 * Note: P/Invoke checks are ALWAYS (1) done at JIT time (as a LinkDemand).
272 * They are also checked at runtime, using a Demand (stack walk), unless the
273 * method or it's class has a [SuppressUnmanagedCodeSecurity] attribute.
275 * (1) well as long as the security manager is active (i.e. --security)
278 mono_declsec_linkdemand_pinvoke (MonoDomain *domain, MonoMethod *caller, MonoMethod *native)
280 MonoAssembly *assembly = mono_image_get_assembly (caller->klass->image);
282 /* Check for P/Invoke flag for the assembly */
283 if (!MONO_SECMAN_FLAG_INIT (assembly->unmanaged)) {
284 /* Check if we know (and have) or FullTrust status */
285 if (MONO_SECMAN_FLAG_INIT (assembly->fulltrust) && MONO_SECMAN_FLAG_GET_VALUE (assembly->fulltrust)) {
286 /* FullTrust includes UnmanagedCode permission */
287 MONO_SECMAN_FLAG_SET_VALUE (assembly->unmanaged, TRUE);
289 MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
290 MonoSecurityManager* secman = mono_security_manager_get_methods ();
291 if (secman && refass) {
296 res = mono_runtime_invoke (secman->linkdemandunmanaged, NULL, args, NULL);
297 if (*(MonoBoolean *) mono_object_unbox(res)) {
298 MONO_SECMAN_FLAG_SET_VALUE (assembly->unmanaged, TRUE);
304 MONO_SECMAN_FLAG_SET_VALUE (assembly->unmanaged, FALSE);
307 if (MONO_SECMAN_FLAG_GET_VALUE (assembly->unmanaged))
310 /* g_warning ("FAILURE *** JIT LinkDemand P/Invoke check *** %s.%s calls into %s.%s",
311 caller->klass->name, caller->name, native->klass->name, native->name); */
313 return TRUE; /* i.e. throw new SecurityException(); */
318 * Before the JIT can link (call) into a method the following security checks
321 * We check that the code has the permission to link when:
322 * 1. the code try to call an internal call;
323 * 2. the code try to p/invoke to unmanaged code;
324 * 3. the code try to call trusted code without being trusted itself -
325 * or without the trusted code permission (APTC);
326 * 4. the code try to call managed code protected by a LinkDemand security
329 * Failures result in a SecurityException being thrown (later in mini code).
331 * Note: Some checks are duplicated in managed code to deal when reflection is
332 * used to call the methods.
335 mono_declsec_linkdemand (MonoDomain *domain, MonoMethod *caller, MonoMethod *callee)
337 guint32 violation = MONO_JIT_SECURITY_OK;
338 /* first, the special (implied) linkdemand */
340 if (callee->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
341 /* restrict calls into the runtime to ECMA signed assemblies */
342 if (mono_declsec_linkdemand_ecma (caller, callee))
343 violation = MONO_JIT_LINKDEMAND_ECMA;
344 } else if (callee->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
345 /* CAS can restrict p/invoke calls with the assembly granted permissions */
346 if (mono_declsec_linkdemand_pinvoke (domain, caller, callee))
347 violation = MONO_JIT_LINKDEMAND_PINVOKE;
351 /* check if we allow partially trusted callers in trusted (signed) assemblies */
352 if (mono_declsec_linkdemand_aptc (domain, caller, callee))
353 violation = MONO_JIT_LINKDEMAND_APTC;
356 /* then the "normal" LinkDemand (only when called method has declarative security) */
357 if (!violation && mono_method_has_declsec (callee)) {
358 /* LinkDemand are ignored for static constructors (ensured by calling mono_method_has_declsec) */
359 if (mono_declsec_linkdemand_standard (domain, caller, callee))
360 violation = MONO_JIT_LINKDEMAND_PERMISSION;
363 /* if (violation) g_warning ("mono_declsec_linkdemand violation reported %d", violation); */