summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Security/PermissionListSet.cs
blob: 093542ad4e212df3b51b0a2825d128e745b165ef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

/*=============================================================================
**
** 
** 
** 
**
** Purpose: Holds state about A/G/R permissionsets in a callstack or appdomain
**          (Replacement for PermissionListSet)
**
=============================================================================*/

namespace System.Security
{
    using System.Globalization;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Security.Permissions;
    using System.Threading;
    using System.Collections;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Diagnostics.Contracts;

    [Serializable]
    sealed internal class PermissionListSet
    {
        // Only internal (public) methods are creation methods and demand evaluation methods.
        // Scroll down to the end to see them.
        private PermissionSetTriple m_firstPermSetTriple;
        private ArrayList m_permSetTriples;
#if FEATURE_COMPRESSEDSTACK
        private ArrayList m_zoneList;
        private ArrayList m_originList;
#endif // FEATURE_COMPRESSEDSTACK

        internal PermissionListSet() {}

        private void EnsureTriplesListCreated()
        {
            if (m_permSetTriples == null)
            {
                m_permSetTriples = new ArrayList();
                if (m_firstPermSetTriple != null)
                {
                    m_permSetTriples.Add(m_firstPermSetTriple);
                    m_firstPermSetTriple = null;
                }
            }
        }

#if FEATURE_PLS
        internal void UpdateDomainPLS (PermissionListSet adPLS) {
            if (adPLS != null && adPLS.m_firstPermSetTriple != null)
                UpdateDomainPLS(adPLS.m_firstPermSetTriple.GrantSet, adPLS.m_firstPermSetTriple.RefusedSet);
        }

        internal void UpdateDomainPLS (PermissionSet grantSet, PermissionSet deniedSet) {
            Debug.Assert(m_permSetTriples == null, "m_permSetTriples != null");
            if (m_firstPermSetTriple == null)
                m_firstPermSetTriple = new PermissionSetTriple();

            // update the grant and denied sets
            m_firstPermSetTriple.UpdateGrant(grantSet);
            m_firstPermSetTriple.UpdateRefused(deniedSet);
        }
#endif // FEATURE_PLS

        private void Terminate(PermissionSetTriple currentTriple)
        {
            UpdateTripleListAndCreateNewTriple(currentTriple, null);
        }

        private void Terminate(PermissionSetTriple currentTriple, PermissionListSet pls)
        {
#if FEATURE_COMPRESSEDSTACK
            this.UpdateZoneAndOrigin(pls);
#endif // FEATURE_COMPRESSEDSTACK
            this.UpdatePermissions(currentTriple, pls);
            this.UpdateTripleListAndCreateNewTriple(currentTriple, null);
        }

        private bool Update(PermissionSetTriple currentTriple, PermissionListSet pls)
        {
#if FEATURE_COMPRESSEDSTACK
            this.UpdateZoneAndOrigin(pls);
#endif // FEATURE_COMPRESSEDSTACK
            return this.UpdatePermissions(currentTriple, pls);
        }

        private bool Update(PermissionSetTriple currentTriple, FrameSecurityDescriptor fsd)
        {
#if FEATURE_COMPRESSEDSTACK
           FrameSecurityDescriptorWithResolver fsdWithResolver = fsd as FrameSecurityDescriptorWithResolver;
           if (fsdWithResolver != null)
           {
               return Update2(currentTriple, fsdWithResolver);
           }
#endif // FEATURE_COMPRESSEDSTACK

           // check imperative
           bool fHalt = Update2(currentTriple, fsd, false);
           if (!fHalt)            
           {
                // then declarative
                fHalt = Update2(currentTriple, fsd, true);
           }
           return fHalt;
        }

#if FEATURE_COMPRESSEDSTACK
        private bool Update2(PermissionSetTriple currentTriple, FrameSecurityDescriptorWithResolver fsdWithResolver)
        {
            System.Reflection.Emit.DynamicResolver resolver = fsdWithResolver.Resolver;
            CompressedStack dynamicCompressedStack = resolver.GetSecurityContext();
            dynamicCompressedStack.CompleteConstruction(null);
            return this.Update(currentTriple, dynamicCompressedStack.PLS);
        }
#endif // FEATURE_COMPRESSEDSTACK

        private bool Update2(PermissionSetTriple currentTriple, FrameSecurityDescriptor fsd, bool fDeclarative)
        {
            // Deny
            PermissionSet deniedPset = fsd.GetDenials(fDeclarative);
            if (deniedPset != null)
            {
                currentTriple.UpdateRefused(deniedPset);
            }

            // permit only
            PermissionSet permitOnlyPset = fsd.GetPermitOnly(fDeclarative);
            if (permitOnlyPset != null)
            {
                currentTriple.UpdateGrant(permitOnlyPset);
            }

            // Assert all possible
            if (fsd.GetAssertAllPossible())
            {
                // If we have no grant set, it means that the only assembly we've seen on the stack so
                // far is mscorlib. Since mscorlib will always be fully trusted, the grant set of the
                // compressed stack is also FullTrust.
                if (currentTriple.GrantSet == null)
                    currentTriple.GrantSet = PermissionSet.s_fullTrust;

                UpdateTripleListAndCreateNewTriple(currentTriple, m_permSetTriples);
                currentTriple.GrantSet = PermissionSet.s_fullTrust;
                currentTriple.UpdateAssert(fsd.GetAssertions(fDeclarative));
                return true;
            }
                
            // Assert
            PermissionSet assertPset = fsd.GetAssertions(fDeclarative);
            if (assertPset != null)
            {
                if (assertPset.IsUnrestricted())
                {
                    // If we have no grant set, it means that the only assembly we've seen on the stack so
                    // far is mscorlib. Since mscorlib will always be fully trusted, the grant set of the
                    // compressed stack is also FullTrust.
                    if (currentTriple.GrantSet == null)
                        currentTriple.GrantSet = PermissionSet.s_fullTrust;

                    UpdateTripleListAndCreateNewTriple(currentTriple, m_permSetTriples);
                    currentTriple.GrantSet = PermissionSet.s_fullTrust;
                    currentTriple.UpdateAssert(assertPset);
                    return true;
                }

                PermissionSetTriple retTriple = currentTriple.UpdateAssert(assertPset);
                if (retTriple != null)
                {
                    EnsureTriplesListCreated();
                    m_permSetTriples.Add(retTriple);
                }
            }

            return false;
        }
        private void Update(PermissionSetTriple currentTriple, PermissionSet in_g, PermissionSet in_r)
        {
#if FEATURE_COMPRESSEDSTACK
            ZoneIdentityPermission z;
            UrlIdentityPermission u;
            currentTriple.UpdateGrant(in_g, out z, out u);
            currentTriple.UpdateRefused(in_r);
            AppendZoneOrigin(z, u);
#else // !FEATURE_COMPRESEDSTACK
            currentTriple.UpdateGrant(in_g);
            currentTriple.UpdateRefused(in_r);
#endif // FEATURE_COMPRESSEDSTACK
        }

        // Called from the VM for HG CS construction        
        private void Update(PermissionSet in_g)
        {
            if (m_firstPermSetTriple == null)
                m_firstPermSetTriple = new PermissionSetTriple();
            Update(m_firstPermSetTriple, in_g, null);
        }
        
#if FEATURE_COMPRESSEDSTACK
        private void UpdateZoneAndOrigin(PermissionListSet pls)
        {
            if (pls != null)
            {
                if (this.m_zoneList == null && pls.m_zoneList != null && pls.m_zoneList.Count > 0)
                    this.m_zoneList = new ArrayList();
                UpdateArrayList(this.m_zoneList, pls.m_zoneList);
                if (this.m_originList == null && pls.m_originList != null && pls.m_originList.Count > 0)
                    this.m_originList = new ArrayList();                                
                UpdateArrayList(this.m_originList, pls.m_originList);
            }
        }
#endif // FEATURE_COMPRESSEDSTACK

        private bool UpdatePermissions(PermissionSetTriple currentTriple, PermissionListSet pls)
        {
            if (pls != null)
            {
                if (pls.m_permSetTriples != null)
                {
                    // DCS has an AGR List. So we need to add the AGR List
                    UpdateTripleListAndCreateNewTriple(currentTriple,pls.m_permSetTriples);
                }
                else
                {
                    // Common case: One AGR set
                    
                    PermissionSetTriple tmp_psTriple = pls.m_firstPermSetTriple;
                    PermissionSetTriple retTriple;
                    // First try and update currentTriple. Return value indicates if we can stop construction
                    if (currentTriple.Update(tmp_psTriple, out retTriple))
                        return true;
                    // If we got a non-null retTriple, what it means is that compression failed,
                    // and we now have 2 triples to deal with: retTriple and currentTriple.
                    // retTriple has to be appended first. then currentTriple.
                    if (retTriple != null)
                    {
                        EnsureTriplesListCreated();
                        // we just created a new triple...add the previous one (returned) to the list
                        m_permSetTriples.Add(retTriple);
                    }
                }
            }
            else
            {
                // pls can be null only outside the loop in CreateCompressedState
                UpdateTripleListAndCreateNewTriple(currentTriple, null);
            }
            

            return false;
            
        }


        private void UpdateTripleListAndCreateNewTriple(PermissionSetTriple currentTriple, ArrayList tripleList)
        {
            if (!currentTriple.IsEmpty())
            {
                if (m_firstPermSetTriple == null && m_permSetTriples == null)
                {
                    m_firstPermSetTriple = new PermissionSetTriple(currentTriple);
                }
                else
                {
                    EnsureTriplesListCreated();
                    m_permSetTriples.Add(new PermissionSetTriple(currentTriple));
                }
                currentTriple.Reset();
            }
            if (tripleList != null)
            {
                EnsureTriplesListCreated();
                m_permSetTriples.AddRange(tripleList);
            }
        }

        private static void UpdateArrayList(ArrayList current, ArrayList newList)
        {
            if (newList == null)
                return;

            for(int i=0;i < newList.Count; i++)
            {
                if (!current.Contains(newList[i]))
                    current.Add(newList[i]);
            }

        }

#if FEATURE_COMPRESSEDSTACK
        private void AppendZoneOrigin(ZoneIdentityPermission z, UrlIdentityPermission u)
        {

            if (z != null)
            {
                if (m_zoneList == null)
                    m_zoneList = new ArrayList();
                z.AppendZones(m_zoneList);
            }

            if (u != null)
            {
                if (m_originList == null)
                    m_originList = new ArrayList();
                u.AppendOrigin(m_originList);
            }
        }

[System.Runtime.InteropServices.ComVisible(true)]
        // public(internal) interface begins...
        // Creation functions
        static internal PermissionListSet CreateCompressedState(CompressedStack cs, CompressedStack innerCS)
        {
            // function that completes the construction of the compressed stack if not done so already (bottom half for demand evaluation)
            
            bool bHaltConstruction = false;
            if (cs.CompressedStackHandle == null)
                return null; //  FT case or Security off
   
            PermissionListSet pls = new PermissionListSet();
            PermissionSetTriple currentTriple = new PermissionSetTriple();
            int numDomains = CompressedStack.GetDCSCount(cs.CompressedStackHandle);
            for (int i=numDomains-1; (i >= 0 && !bHaltConstruction) ; i--)
            {
                DomainCompressedStack dcs = CompressedStack.GetDomainCompressedStack(cs.CompressedStackHandle, i);
                if (dcs == null)
                    continue; // we hit a FT Domain
                if (dcs.PLS == null)
                {
                    // We failed on some DCS
                    throw new SecurityException(String.Format(CultureInfo.InvariantCulture, Environment.GetResourceString("Security_Generic")));
                }
                pls.UpdateZoneAndOrigin(dcs.PLS);
                pls.Update(currentTriple, dcs.PLS); 
                bHaltConstruction = dcs.ConstructionHalted;
            }
            if (!bHaltConstruction)
            {
                PermissionListSet tmp_pls = null;
                // Construction did not halt. 
                if (innerCS != null)
                {
                    innerCS.CompleteConstruction(null);
                    tmp_pls = innerCS.PLS;
                }
                pls.Terminate(currentTriple, tmp_pls);
            }
            else
            {
                pls.Terminate(currentTriple);
            }

            return pls;
        }

        static internal PermissionListSet CreateCompressedState(IntPtr unmanagedDCS, out bool bHaltConstruction)
        {
            PermissionListSet pls = new PermissionListSet();
            PermissionSetTriple currentTriple = new PermissionSetTriple();

            PermissionSet tmp_g, tmp_r;
            // Construct the descriptor list
            int descCount = DomainCompressedStack.GetDescCount(unmanagedDCS);
            bHaltConstruction = false;
            for(int i=0; (i < descCount && !bHaltConstruction); i++)
            {
                FrameSecurityDescriptor fsd;
                Assembly assembly;
                if (DomainCompressedStack.GetDescriptorInfo(unmanagedDCS, i, out tmp_g, out tmp_r, out assembly, out fsd))
                {
                    // Got an FSD
                    bHaltConstruction = pls.Update(currentTriple, fsd);
                }
                else
                {
                    pls.Update(currentTriple, tmp_g, tmp_r);
                }
                
            }
            if (!bHaltConstruction)
            {
                // domain
                if (!DomainCompressedStack.IgnoreDomain(unmanagedDCS))
                {
                    DomainCompressedStack.GetDomainPermissionSets(unmanagedDCS, out tmp_g, out tmp_r);
                    pls.Update(currentTriple, tmp_g, tmp_r);
                }
            }
            pls.Terminate(currentTriple);


            // return the created object
            return pls;
            
        }
        static internal PermissionListSet CreateCompressedState_HG()
        {
            PermissionListSet pls = new PermissionListSet();
            CompressedStack.GetHomogeneousPLS(pls);
            return pls;
        }
#endif // #if FEATURE_COMPRESSEDSTACK
        // Private Demand evaluation functions - only called from the VM
        internal bool CheckDemandNoThrow(CodeAccessPermission demand)
        {
            // AppDomain permissions - no asserts. So there should only be one triple to work with
            Debug.Assert(m_permSetTriples == null && m_firstPermSetTriple != null, "More than one PermissionSetTriple encountered in AD PermissionListSet");
            

            
            PermissionToken permToken = null;
            if (demand != null)
                permToken = PermissionToken.GetToken(demand);

            return m_firstPermSetTriple.CheckDemandNoThrow(demand, permToken);
                

        }
        internal bool CheckSetDemandNoThrow(PermissionSet pSet)
        {
            // AppDomain permissions - no asserts. So there should only be one triple to work with
            Debug.Assert(m_permSetTriples == null && m_firstPermSetTriple != null, "More than one PermissionSetTriple encountered in AD PermissionListSet");

            
            return m_firstPermSetTriple.CheckSetDemandNoThrow(pSet);
        }

        // Demand evauation functions
        internal bool CheckDemand(CodeAccessPermission demand, PermissionToken permToken, RuntimeMethodHandleInternal rmh)
        {
            bool bRet = SecurityRuntime.StackContinue;
            if (m_permSetTriples != null)
            {
                for (int i=0; (i < m_permSetTriples.Count && bRet != SecurityRuntime.StackHalt) ; i++)
                {
                    PermissionSetTriple psTriple = (PermissionSetTriple)m_permSetTriples[i];
                    bRet = psTriple.CheckDemand(demand, permToken, rmh);
                }
            }
            else if (m_firstPermSetTriple != null)
            {
                bRet = m_firstPermSetTriple.CheckDemand(demand, permToken, rmh);
            }

            return bRet;
        }

        internal bool CheckSetDemand(PermissionSet pset , RuntimeMethodHandleInternal rmh)
        {
            PermissionSet unused;
            CheckSetDemandWithModification(pset, out unused, rmh);
            return SecurityRuntime.StackHalt; //  CS demand check always terminates the stackwalk    
        }

        internal bool CheckSetDemandWithModification(PermissionSet pset, out PermissionSet alteredDemandSet, RuntimeMethodHandleInternal rmh)
        {
            bool bRet = SecurityRuntime.StackContinue;
            PermissionSet demandSet = pset;
            alteredDemandSet = null;
            if (m_permSetTriples != null)
            {
                for (int i=0; (i < m_permSetTriples.Count && bRet != SecurityRuntime.StackHalt) ; i++)
                {
                    PermissionSetTriple psTriple = (PermissionSetTriple)m_permSetTriples[i];
                    bRet = psTriple.CheckSetDemand(demandSet, out alteredDemandSet, rmh);
                    if (alteredDemandSet != null)
                        demandSet = alteredDemandSet;
                }
            }
            else if (m_firstPermSetTriple != null)
            {
                bRet = m_firstPermSetTriple.CheckSetDemand(demandSet, out alteredDemandSet, rmh);
            }

            return bRet;
        }

        /// <summary>
        ///     Check to see if the PLS satisfies a demand for the special permissions encoded in flags
        /// </summary>
        /// <param name="flags">set of flags to check (See PermissionType)</param>
        private bool CheckFlags(int flags)
        {
            Debug.Assert(flags != 0, "Invalid permission flag demand");

            bool check = true;

            if (m_permSetTriples != null)
            {
                for (int i = 0; i < m_permSetTriples.Count && check && flags != 0; i++)
                {
                    check &= ((PermissionSetTriple)m_permSetTriples[i]).CheckFlags(ref flags);
                }
            }
            else if (m_firstPermSetTriple != null)
            {
                check = m_firstPermSetTriple.CheckFlags(ref flags);
            }
            
            return check;
        }

        /// <summary>
        ///     Demand which succeeds if either a set of special permissions or a permission set is granted
        ///     to the call stack
        /// </summary>
        /// <param name="flags">set of flags to check (See PermissionType)</param>
        /// <param name="grantSet">alternate permission set to check</param>
        internal void DemandFlagsOrGrantSet(int flags, PermissionSet grantSet)
        {
            if (CheckFlags(flags))
                return;

            CheckSetDemand(grantSet, RuntimeMethodHandleInternal.EmptyHandle);
        }

#if FEATURE_COMPRESSEDSTACK
        internal void GetZoneAndOrigin(ArrayList zoneList, ArrayList originList, PermissionToken zoneToken, PermissionToken originToken)
        {
            if (m_zoneList != null)
                zoneList.AddRange(m_zoneList);
            if (m_originList != null)
                originList.AddRange(m_originList);
        }
#endif
    }

}