00001 /*++ 00002 00003 Copyright (c) 1990 Microsoft Corporation 00004 00005 Module Name: 00006 00007 raisexcp.c 00008 00009 Abstract: 00010 00011 This module implements the internal kernel code to continue execution 00012 and raise a exception. 00013 00014 Author: 00015 00016 David N. Cutler (davec) 8-Aug-1990 00017 00018 Environment: 00019 00020 Kernel mode only. 00021 00022 Revision History: 00023 00024 18-Oct-1997 Neillc 00025 00026 Fix for bug #98981. KiRaiseException referenced the users exception record before probeing. 00027 It also had a range check that was incorrect for the number of exception parameters because 00028 it used a signed temp to make a later calculation of the size work. The exception record 00029 was also subject to changes to the number of parameters after validation. This might cause 00030 lower levels to fail. 00031 00032 --*/ 00033 00034 #include "ki.h" 00035 00036 VOID 00037 KiContinuePreviousModeUser( 00038 IN PCONTEXT ContextRecord, 00039 IN PKEXCEPTION_FRAME ExceptionFrame, 00040 IN PKTRAP_FRAME TrapFrame, 00041 IN KPROCESSOR_MODE PreviousMode 00042 ) 00043 00044 /*++ 00045 00046 Routine Description: 00047 00048 This function is called from KiContinue if PreviousMode is 00049 not KernelMode. In this case a kernel mode copy of the 00050 ContextRecord is made before calling KeContextToKframes. 00051 This is done in a seperate routine to save stack space for 00052 the common case which is PreviousMode == Kernel. 00053 00054 N.B. This routine is called from within a try/except block 00055 that will be used to handle errors like invalid context. 00056 00057 Arguments: 00058 00059 00060 ContextRecord - Supplies a pointer to a context record. 00061 00062 ExceptionFrame - Supplies a pointer to an exception frame. 00063 00064 TrapFrame - Supplies a pointer to a trap frame. 00065 00066 PreviousMode - Not KernelMode. 00067 00068 Return Value: 00069 00070 None. 00071 00072 --*/ 00073 00074 { 00075 CONTEXT ContextRecord2; 00076 00077 // 00078 // Copy the context record to kernel mode space. 00079 // 00080 00081 ProbeForRead(ContextRecord, sizeof(CONTEXT), CONTEXT_ALIGN); 00082 RtlMoveMemory(&ContextRecord2, ContextRecord, sizeof(CONTEXT)); 00083 ContextRecord = &ContextRecord2; 00084 00085 // 00086 // Move information from the context record to the exception 00087 // and trap frames. 00088 // 00089 00090 KeContextToKframes(TrapFrame, 00091 ExceptionFrame, 00092 &ContextRecord2, 00093 ContextRecord2.ContextFlags, 00094 PreviousMode); 00095 } 00096 00097 00098 NTSTATUS 00099 KiContinue ( 00100 IN PCONTEXT ContextRecord, 00101 IN PKEXCEPTION_FRAME ExceptionFrame, 00102 IN PKTRAP_FRAME TrapFrame 00103 ) 00104 00105 /*++ 00106 00107 Routine Description: 00108 00109 This function is called to copy the specified context frame to the 00110 specified exception and trap frames for the continue system service. 00111 00112 Arguments: 00113 00114 ContextRecord - Supplies a pointer to a context record. 00115 00116 ExceptionFrame - Supplies a pointer to an exception frame. 00117 00118 TrapFrame - Supplies a pointer to a trap frame. 00119 00120 Return Value: 00121 00122 STATUS_ACCESS_VIOLATION is returned if the context record is not readable 00123 from user mode. 00124 00125 STATUS_DATATYPE_MISALIGNMENT is returned if the context record is not 00126 properly aligned. 00127 00128 STATUS_SUCCESS is returned if the context frame is copied successfully 00129 to the specified exception and trap frames. 00130 00131 --*/ 00132 00133 { 00134 KPROCESSOR_MODE PreviousMode; 00135 NTSTATUS Status; 00136 KIRQL OldIrql; 00137 BOOLEAN IrqlChanged = FALSE; 00138 00139 // 00140 // Synchronize with other context operations. 00141 // 00142 00143 Status = STATUS_SUCCESS; 00144 if (KeGetCurrentIrql() < APC_LEVEL) { 00145 00146 // 00147 // To support try-except and ExRaiseStatus in device driver code we 00148 // need to check if we are already at raised level. 00149 // 00150 00151 IrqlChanged = TRUE; 00152 KeRaiseIrql(APC_LEVEL, &OldIrql); 00153 } 00154 00155 // 00156 // Establish an exception handler and probe and capture the specified 00157 // context record if the previous mode is user. If the probe or copy 00158 // fails, then return the exception code as the function value. Else 00159 // copy the context record to the specified exception and trap frames, 00160 // and return success as the function value. 00161 // 00162 00163 try { 00164 00165 // 00166 // Get the previous processor mode. If the previous processor mode is 00167 // user, then probe and copy the specified context record. 00168 // 00169 00170 PreviousMode = KeGetPreviousMode(); 00171 if (PreviousMode != KernelMode) { 00172 KiContinuePreviousModeUser(ContextRecord, 00173 ExceptionFrame, 00174 TrapFrame, 00175 PreviousMode); 00176 } else { 00177 00178 // 00179 // Move information from the context record to the exception 00180 // and trap frames. 00181 // 00182 00183 KeContextToKframes(TrapFrame, 00184 ExceptionFrame, 00185 ContextRecord, 00186 ContextRecord->ContextFlags, 00187 PreviousMode); 00188 } 00189 00190 // 00191 // If an exception occurs during the probe or copy of the context 00192 // record, then always handle the exception and return the exception 00193 // code as the status value. 00194 // 00195 00196 } except(EXCEPTION_EXECUTE_HANDLER) { 00197 Status = GetExceptionCode(); 00198 } 00199 00200 if (IrqlChanged) { 00201 KeLowerIrql (OldIrql); 00202 } 00203 00204 return Status; 00205 } 00206 00207 NTSTATUS 00208 KiRaiseException ( 00209 IN PEXCEPTION_RECORD ExceptionRecord, 00210 IN PCONTEXT ContextRecord, 00211 IN PKEXCEPTION_FRAME ExceptionFrame, 00212 IN PKTRAP_FRAME TrapFrame, 00213 IN BOOLEAN FirstChance 00214 ) 00215 00216 /*++ 00217 00218 Routine Description: 00219 00220 This function is called to raise an exception. The exception can be 00221 raised as a first or second chance exception. 00222 00223 Arguments: 00224 00225 ExceptionRecord - Supplies a pointer to an exception record. 00226 00227 ContextRecord - Supplies a pointer to a context record. 00228 00229 ExceptionFrame - Supplies a pointer to an exception frame. 00230 00231 TrapFrame - Supplies a pointer to a trap frame. 00232 00233 FirstChance - Supplies a boolean value that specifies whether this is 00234 the first (TRUE) or second (FALSE) chance for the exception. 00235 00236 Return Value: 00237 00238 STATUS_ACCESS_VIOLATION is returned if either the exception or the context 00239 record is not readable from user mode. 00240 00241 STATUS_DATATYPE_MISALIGNMENT is returned if the exception record or the 00242 context record are not properly aligned. 00243 00244 STATUS_INVALID_PARAMETER is returned if the number of exception parameters 00245 is greater than the maximum allowable number of exception parameters. 00246 00247 STATUS_SUCCESS is returned if the exception is dispatched and handled. 00248 00249 --*/ 00250 00251 { 00252 00253 CONTEXT ContextRecord2; 00254 EXCEPTION_RECORD ExceptionRecord2; 00255 ULONG Length; 00256 ULONG Params; 00257 KPROCESSOR_MODE PreviousMode; 00258 00259 // 00260 // Establish an exception handler and probe the specified exception and 00261 // context records for read accessibility. If the probe fails, then 00262 // return the exception code as the service status. Else call the exception 00263 // dispatcher to dispatch the exception. 00264 // 00265 00266 try { 00267 00268 // 00269 // Get the previous processor mode. If the previous processor mode 00270 // is user, then probe and copy the specified exception and context 00271 // records. 00272 // 00273 00274 PreviousMode = KeGetPreviousMode(); 00275 if (PreviousMode != KernelMode) { 00276 ProbeForRead(ContextRecord, sizeof(CONTEXT), CONTEXT_ALIGN); 00277 ProbeForRead(ExceptionRecord, 00278 FIELD_OFFSET (EXCEPTION_RECORD, NumberParameters) + 00279 sizeof (ExceptionRecord->NumberParameters), sizeof(ULONG)); 00280 Params = ExceptionRecord->NumberParameters; 00281 if (Params > EXCEPTION_MAXIMUM_PARAMETERS) { 00282 return STATUS_INVALID_PARAMETER; 00283 } 00284 00285 // 00286 // The exception record structure is defined unlike others with trailing 00287 // information as being its maximum size rather than just a single trailing 00288 // element. 00289 // 00290 Length = (sizeof(EXCEPTION_RECORD) - 00291 ((EXCEPTION_MAXIMUM_PARAMETERS - Params) * 00292 sizeof(ExceptionRecord->ExceptionInformation[0]))); 00293 00294 // 00295 // The structure is currently less that 64k so we don't really need this probe. 00296 // 00297 ProbeForRead(ExceptionRecord, Length, sizeof(ULONG)); 00298 00299 // 00300 // Copy the exception and context record to local storage so an 00301 // access violation cannot occur during exception dispatching. 00302 // 00303 00304 RtlMoveMemory(&ContextRecord2, ContextRecord, sizeof(CONTEXT)); 00305 RtlMoveMemory(&ExceptionRecord2, ExceptionRecord, Length); 00306 ContextRecord = &ContextRecord2; 00307 ExceptionRecord = &ExceptionRecord2; 00308 // 00309 // The number of parameters might have changed after we validated but before we 00310 // copied the structure. Fix this up as lower levels might not like this. 00311 // 00312 ExceptionRecord->NumberParameters = Params; 00313 } 00314 00315 // 00316 // If an exception occurs during the probe of the exception or context 00317 // record, then always handle the exception and return the exception code 00318 // as the status value. 00319 // 00320 00321 } except(EXCEPTION_EXECUTE_HANDLER) { 00322 return GetExceptionCode(); 00323 } 00324 00325 // 00326 // Move information from the context record to the exception and 00327 // trap frames. 00328 // 00329 00330 KeContextToKframes(TrapFrame, 00331 ExceptionFrame, 00332 ContextRecord, 00333 ContextRecord->ContextFlags, 00334 PreviousMode); 00335 00336 // 00337 // Make sure the reserved bit is clear in the exception code and 00338 // perform exception dispatching. 00339 // 00340 // N.B. The reserved bit is used to differentiate internally gerarated 00341 // codes from codes generated by application programs. 00342 // 00343 00344 ExceptionRecord->ExceptionCode &= 0xefffffff; 00345 KiDispatchException(ExceptionRecord, 00346 ExceptionFrame, 00347 TrapFrame, 00348 PreviousMode, 00349 FirstChance); 00350 00351 return STATUS_SUCCESS; 00352 }