summaryrefslogtreecommitdiff
path: root/src/inc/iilfingerprint.h
blob: e5a26986e87a8d45646492fd445b58cb7632029a (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
// 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.
// ===========================================================================
// File: IILFingerprint.h
// ===========================================================================

#ifndef __IILFingerprint_h__
#define __IILFingerprint_h__

#include "cor.h"

//**********************************************************************
// IILFingerprint:
//
// When ngen images are present, the CLR often avoids opening IL files altogether while
// still making assumptions about their contents (in particular when binding native images.)
// This raise a vulnerability where someone may overwrite the IL during a running process.
// Should the runtime need to delay-load the IL file (e.g. in an IJW app), it may find to
// its dismay that the IL file's contents have changed, or were out of sync with the native image
// cache's data all along.
//
// To address this, the CLR maintains a process-wide "ILFingerprint" object for each IL file with a unique path.
// As the process runs, and components (i.e. native binder) makes assumptions about the contents
// of the unopened IL file, the fingerprint collects these assumptions and ensures that everyone
// work off the same assumptions.
//
// If the file is ever opened, the fingerprint reads the actual data from the IL file and compares
// it to the stored assumptions. If they are conflict, the runtime raises a torn state condition
// and refuses to load the file.
//
// Data model:
//
//   The fingerprint is conceptually a property bag. For efficiency purposes, each property type
//   is associated with a fixed-size memory blob with non-customizable copy and compare operations
//   (they are memcpy and memcmp, respectively.)
//
//   This allows for efficient operation (native binding is perf sensitive) at the expense of
//   some flexibility. (Given the free-for-all that IAssemblyNames became when it became too accomodating a
//   property bag, that inflexibility is by design, actually.)
//
// Implementation:
//   The actual implementation of ILFingerprint is the PEFingerprint class, implemented in VM\PEFingerprint.cpp.
//   Since PEImages are already memoized by pathname, they serve as the fingerprint custodian.


typedef enum
{
    ILFTagTimestamp           = 0,   // datatype == FILETIME (8 bytes)
    ILFTagSize                = 1,   // datatype == DWORD (4 bytes)
    ILFTagMvid                = 2,   // datatype == GUID (16 bytes)

    // NB: If you add or change constants here, you must update PEFingerprint::s_offsets and PEFingerprint::s_sizes in PEFingerprint.cpp

    ILFTagCount               = 3,   // used for range verification
} ILFingerprintTag;

typedef struct
{
    ILFingerprintTag _tag;
    LPCVOID          _data;
} ILFingerprintComponent;

interface IILFingerprint
{
  public:
    //---------------------------------------------------------------------------------------------
    // Lifetime management methods.
    //---------------------------------------------------------------------------------------------
    STDMETHOD_(ULONG, AddRef)() = 0;
    STDMETHOD_(ULONG, Release)() = 0;

    //---------------------------------------------------------------------------------------------
    // Convenience fcn: equivalent to calling CommitAndCompareMulti() with one component.
    //---------------------------------------------------------------------------------------------
    STDMETHOD_(BOOL, CommitAndCompare)(
        ILFingerprintTag componentType,
        LPCVOID data) = 0;

    //---------------------------------------------------------------------------------------------
    // CommitAndCompareMulti(): Atomically commits one or more fingerprint components into
    // the fingerprint. Once a component is committed, its value can never change.
    //
    // An attempt to commit a component succeeds only if the component was not already committed
    // or the prior value maches the new one exactly.
    //
    // Calling CommitAndCompare() multiple times is not equivalent to calling CommitAndCompareMulti().
    // CommitAndCompareMulti() is atomic - either all the commits happen or none of them do.
    //
    // Returns:
    //    TRUE:  All passed components committed successful.
    //    FALSE: At leat one component failed to commit successfully.
    //---------------------------------------------------------------------------------------------
    STDMETHOD_(BOOL, CommitAndCompareMulti)(
        UINT numComponents,
        const ILFingerprintComponent *pComponents) = 0;


    //---------------------------------------------------------------------------------------------
    // LockAndLoadIL()
    //
    //   Forces the runtime to open the IL file and lock it against future overwrites. This
    //   is bad for working set so this should be avoided.
    //
    //   Once opened and locked, this method extracts the actual fingerprint from the IL file
    //   and attempts to commit it into the ILFingerprint. If successful, all future commits
    //   will now be compared against this trusted data. If unsuccessful, this is a torn state
    //   situation and LockAndLoadIL() throws the torn state exception.
    //---------------------------------------------------------------------------------------------
    STDMETHOD_(VOID, LockAndLoadIL)() = 0;
};

interface IILFingerprintFactory
{
  public:
    //---------------------------------------------------------------------------------------------
    // Lifetime management methods.
    //---------------------------------------------------------------------------------------------
    STDMETHOD_(ULONG, AddRef)() = 0;
    STDMETHOD_(ULONG, Release)() = 0;

    STDMETHOD(GetILFingerprintForPath)(
        LPCWSTR path, 
        IILFingerprint **ppFingerprint) = 0;
};

#endif // __IILFingerprint_h__