forked from microsoft/SymCrypt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
env_windowsKernelModeWin7.c
258 lines (202 loc) · 6.75 KB
/
env_windowsKernelModeWin7.c
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
//
// env_windowsKernelModeWin7.c
// Platform-specific code for windows kernel mode, Windows 7 and later
//
// This requires saving the XMM registers on X86, but does not require
// a guarded region.
//
// Note: we no longer support the use of a guarded region. That is only needed
// on XP and Vista, and we simply don't use XMM
//
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
//
//
// Define _NTSYSTEM_ to supress some __declspec(dllimport) definitions, which under some circumstance lead
// to an additional indirect function call, which adds some attack surface to kernel mode.
//
#define _NTSYSTEM_
#include <ntddk.h>
#include "symcrypt.h"
#include "sc_lib.h"
#if SYMCRYPT_CPU_AMD64
//
// KeGetCurrentIrql must be inlined on AMD64 to prevent linking errors with winload.sys, which
// runs in an environment that does not define/implement KeGetCurrentIrql.
//
#define KeGetCurrentIrql() ((KIRQL)ReadCR8())
#endif
SYMCRYPT_CPU_FEATURES SYMCRYPT_CALL SymCryptCpuFeaturesNeverPresentEnvWindowsKernelmodeWin7nLater()
{
return 0;
}
VOID
SYMCRYPT_CALL
SymCryptInitEnvWindowsKernelmodeWin7nLater( UINT32 version )
{
RTL_OSVERSIONINFOW verInfo;
if( g_SymCryptFlags & SYMCRYPT_FLAG_LIB_INITIALIZED )
{
return;
}
//
// Check that we are on Win7 or later and not something earlier
//
verInfo.dwOSVersionInfoSize = sizeof( verInfo );
if( !NT_SUCCESS( RtlGetVersion( &verInfo ) ) )
{
SymCryptFatal( 'nsrv' );
}
if( verInfo.dwMajorVersion < 6 || (verInfo.dwMajorVersion == 6 && verInfo.dwMinorVersion < 1 ) )
{
SymCryptFatal( 'nsrv' );
}
#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64
//
// First we detect what the CPU has
//
SymCryptDetectCpuFeaturesByCpuid( SYMCRYPT_CPUID_DETECT_FLAG_CHECK_OS_SUPPORT_FOR_YMM );
//
// We also need to be sure that the OS supports the extended registers.
//
{
ULONGLONG FeatureMask = RtlGetEnabledExtendedFeatures( (ULONGLONG) -1 );
if( !(FeatureMask & XSTATE_MASK_AVX) )
{
g_SymCryptCpuFeaturesNotPresent |= SYMCRYPT_CPU_FEATURE_AVX2;
}
if( !(FeatureMask & XSTATE_MASK_AVX512) )
{
g_SymCryptCpuFeaturesNotPresent |= SYMCRYPT_CPU_FEATURE_AVX512;
}
}
#elif SYMCRYPT_CPU_ARM | SYMCRYPT_CPU_ARM64
SymCryptDetectCpuFeaturesFromRegisters();
#endif
SymCryptInitEnvCommon( version );
}
_Analysis_noreturn_
VOID
SYMCRYPT_CALL
SymCryptFatalEnvWindowsKernelmodeWin7nLater( UINT32 fatalCode )
{
SymCryptFatalIntercept( fatalCode );
#pragma prefast( disable:28159 ) // PreFast complains about use of BugCheckEx.
KeBugCheckEx( CRYPTO_LIBRARY_INTERNAL_ERROR, fatalCode, 0, 0, 0 );
SymCryptFatalHang( fatalCode );
}
VOID
SYMCRYPT_CALL
SymCryptTestInjectErrorEnvWindowsKernelmodeWin7nLater( PBYTE pbBuf, SIZE_T cbBuf )
{
//
// This feature is only used during testing. In production it is always
// an empty function that the compiler can optimize away.
//
UNREFERENCED_PARAMETER( pbBuf );
UNREFERENCED_PARAMETER( cbBuf );
}
#if SYMCRYPT_CPU_X86
C_ASSERT( sizeof( XSTATE_SAVE ) <= SYMCRYPT_XSTATE_SAVE_SIZE );
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptSaveXmmEnvWindowsKernelmodeWin7nLater( _Out_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
SYMCRYPT_ERROR result = SYMCRYPT_NO_ERROR;
// KeSaveExtendedProcessorState must only be called at IRQL <= DISPATCH_LEVEL
if( KeGetCurrentIrql() > DISPATCH_LEVEL )
{
result = SYMCRYPT_EXTERNAL_FAILURE;
goto cleanup;
}
if( !NT_SUCCESS( KeSaveExtendedProcessorState( XSTATE_MASK_LEGACY_SSE, (PXSTATE_SAVE)&pSaveData->data[0] ) ) )
{
result = SYMCRYPT_EXTERNAL_FAILURE;
goto cleanup;
}
SYMCRYPT_SET_MAGIC( pSaveData );
cleanup:
return result;
}
VOID
SYMCRYPT_CALL
SymCryptRestoreXmmEnvWindowsKernelmodeWin7nLater( _Inout_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
SYMCRYPT_CHECK_MAGIC( pSaveData );
KeRestoreExtendedProcessorState( (PXSTATE_SAVE)&pSaveData->data[0] );
SYMCRYPT_WIPE_MAGIC( pSaveData );
}
#elif SYMCRYPT_CPU_AMD64
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptSaveXmmEnvWindowsKernelmodeWin7nLater( _Out_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveArea )
{
//
// In amd64 kernel mode there is no need to save XMM registers.
// The compiler should inline this function and optimize it away.
//
UNREFERENCED_PARAMETER( pSaveArea );
return SYMCRYPT_NO_ERROR;
}
VOID
SYMCRYPT_CALL
SymCryptRestoreXmmEnvWindowsKernelmodeWin7nLater( _Inout_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveArea )
{
//
// In amd64 kernel mode there is no need to save XMM registers.
// The compiler should inline this function and optimize it away.
//
UNREFERENCED_PARAMETER( pSaveArea );
}
#endif
#if SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_X86
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptSaveYmmEnvWindowsKernelmodeWin7nLater( _Out_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
SYMCRYPT_ERROR result = SYMCRYPT_NO_ERROR;
C_ASSERT( sizeof( pSaveData->data ) >= sizeof( XSTATE_SAVE ) );
C_ASSERT( sizeof( pSaveData->data ) == sizeof( XSTATE_SAVE ) );
//
// A rare error check. If we are called without AVX2 enabled something is badly
// wrong, and it could create a corrupted CPU state which is impossible to debug.
//
if( !SYMCRYPT_CPU_FEATURES_PRESENT( SYMCRYPT_CPU_FEATURE_AVX2 ) )
{
SymCryptFatal( ' mmy' );
}
// KeSaveExtendedProcessorState must only be called at IRQL <= DISPATCH_LEVEL
if( KeGetCurrentIrql() > DISPATCH_LEVEL )
{
result = SYMCRYPT_EXTERNAL_FAILURE;
goto cleanup;
}
//
// Our init routine disabled AVX2 if the XSTATE_MASK_AVX isn't supported, so we don't have to check
// for that anymore.
//
if( !NT_SUCCESS( KeSaveExtendedProcessorState( XSTATE_MASK_AVX, (PXSTATE_SAVE)&pSaveData->data[0] ) ) )
{
result = SYMCRYPT_EXTERNAL_FAILURE;
goto cleanup;
}
SYMCRYPT_SET_MAGIC( pSaveData );
cleanup:
return result;
}
VOID
SYMCRYPT_CALL
SymCryptRestoreYmmEnvWindowsKernelmodeWin7nLater( _Inout_ PSYMCRYPT_EXTENDED_SAVE_DATA pSaveData )
{
SYMCRYPT_CHECK_MAGIC( pSaveData );
KeRestoreExtendedProcessorState( (PXSTATE_SAVE)&pSaveData->data[0] );
SYMCRYPT_WIPE_MAGIC( pSaveData );
}
#endif
#if SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_X86
VOID
SYMCRYPT_CALL
SymCryptCpuidExFuncEnvWindowsKernelmodeWin7nLater( int cpuInfo[4], int function_id, int subfunction_id )
{
__cpuidex( cpuInfo, function_id, subfunction_id );
}
#endif