WINCE开发更安全可靠设备驱动的最佳实践
作者:LoongEmbedded(kandi)
時間:2011.10.04
類別:WINCE驅動開發
********************************LoongEmbedded********************************?
微軟總結了WINCE開發更安全可靠設備驅動的最佳實踐,如下所示:
1.? 根據需要使用異常處理結構(SEH)來處理異常,_try/_except模型就是我們熟知的C++的SHE處理模型,下面根據WAV_IOControl()來進一步學習這SHE處理機制。_except關鍵字后面跟著是一個各種類型的表達式,在一個函數中,可以有多個_try/_except語句,它們可以是一個平面的線性結構,可以是分層的嵌套結構,也可以是這兩種結構的混合使用。
圖1
上圖的代碼的執行流程如下:
1)? 受監控的代碼先被執行。
2)? 如果受監控代碼在執行過程中,沒有出現異常,那么控制流將轉入到_except定義的異常處理代碼模塊的后面執行,也就是直接返回FALSE。
3)? 如果受監控代碼出現執行異常,那么控制流將進入到_except后面的表達式中,也即首先計算這個表達式的指,然后再根據這個值來做出相應的處理。
下面來描述這個表達式中的相關知識。
?
1)? GetExceptionCode()
GetExceptionCode()函數用于獲取已經發生的異常的類型,該函數只能在篩選表達式(filter expression)或者try-except異常處理的異常處理阻塞(exception-handler block)中調用,它的返回值是下面的值:
EXCEPTION_ACCESS_VIOLATION
調用該函數的程序嘗試訪問一個它沒有合適權限訪問的虛擬地址產生的異常。
EXCEPTION_ARRAY_BOUNDS_EXCEEDED
調用該函數的程序嘗試訪問一個越界的數組元素,而且底層硬件支持越界檢查的情況下引發的異常。
EXCEPTION_BREAKPOINT
觸發斷點時引發的異常。
EXCEPTION_DATATYPE_MISALIGNMENT
程序嘗試讀或者寫未經對齊的數據時產生的異常。
EXCEPTION_FLT_DENORMAL_OPERAND
如果浮點數運算中的操作數的值太小,以致無法采用標準的浮點數表示時產生的異常。
EXCEPTION_FLT_DIVIDE_BY_ZERO
程序嘗試對浮點數除法的除數是0進行運算時產生的異常。
EXCEPTION_FLT_INEXACT_RESULT
浮點運算的結果不能精確表示成小數時產生的異常。
EXCEPTION_FLT_INVALID_OPERATION
此異常表示不包含在這些列舉中的浮點數異常。
EXCEPTION_FLT_OVERFLOW
浮點運算的指數超過所能表示的最大值引發的異常。
EXCEPTION_FLT_STACK_CHECK
浮點運算發生棧上溢或者下溢時引發的異常。
EXCEPTION_FLT_UNDERFLOW
浮點運算的指數超過所能表示的最小值引發的異常。
EXCEPTION_INT_DIVIDE_BY_ZERO
整數除法的除數是0時引發的異常。
EXCEPTION_INT_OVERFLOW
整數操作的結果溢出時引發的異常。
EXCEPTION_NONCONTINUABLE_EXCEPTION
發生一個不可繼續執行的異常時,如果程序繼續執行,則會引發此異常。
EXCEPTION_PRIV_INSTRUCTION
程序嘗試去執行一條當前CPU模式不支持的指令時引發該異常。
EXCEPTION_SINGLE_STEP
單步調試時,每個陷阱追蹤或單條指令執行時引發該異常。
?
要調用GetExceptionCode()函數,需要把excpt.h頭文件包含進來,其中上面代碼提到的STATUS_ACCESS_VIOLATION=EXCEPTION_ACCESS_VIOLATION,這在winbase.h中使用宏定義做了等同的定義。
?
2)? Excpt.h對異常處理except()中的合法的值定義如下
#define EXCEPTION_EXECUTE_HANDLER??????? 1
表示系統識別到此異常,并且轉移控制到異常處理代碼部分繼續執行。
#define EXCEPTION_CONTINUE_SEARCH??????? 0
當前的_except模塊不是該異常所對應的正確的異常處理模塊,系統將繼續查找合適的異常處理模塊來處理該異常。
#define EXCEPTION_CONTINUE_EXECUTION??? -1
系統停止查找異常處理并且返回到發生異常的控制流所在的地方,繼續執行,但是,如果這個異常是一個不可繼續執行的異常時,那么將引發一個EXCEPTION_NONCONTINUABLE_EXCEPTION
的異常。
?
異常分為系統異常和軟件異常,上面列舉的就是系統異常,而軟件異常通過RaiseException()函數拋出。
3)? RaiseException()
在調用的thread中可以通過調用該函數來引發一個異常,該函數的聲明如下:
VOID WINAPI RaiseException(
??? DWORD dwExceptionCode,
??? DWORD dwExceptionFlags,
??? DWORD nNumberOfArguments,
??? CONST DWORD *lpArguments
);
下面描述參數及其功能
dwExceptionCode
一個在引發異常時應用程序定義的異常代碼,篩選表達式(也即_except()中的表達式)和異常處理程序的異常處理阻塞可以調用GetExceptionCode()函數來獲得異常代碼。需要注意的一點是,系統會在顯示信息之前清除dwExceptionCode參數的第28位,該位是一個系統保留的異常位,僅供系統自身使用。比如以一個異常代碼0xFFFFFFFF調用RaiseException()函數的時候,系統會以異常代碼0xEFFFFFFF顯示。
?
dwExceptionFlags
異常標志,這可以賦值為零,表示一個可持續異常,或者使用EXCEPTION_NONCONTINUABLE標志來表示一個不可持續的異常。發生不可持續的異常后,任何企圖繼續執行的行為將導致觸EXCEPTION_NONCONTINUABLE_EXCEPTION異常。
lpArguments
nNumberOfArguments
表示lpArguments參數數組中的參數個數,這個值不能超過EXCEPTION_MAXIMUM_PARAMETERS; 如果lpArguments為NULL ,則忽略此參數。
?
lpArguments
指向32位參數的數組的長指針,這個參數可以是NULL,這些參數可以包含任何應用程序所定義的數據,而這些數據需要傳遞給異常處理程序的篩選表達式。那么在篩選表達式可以調用GetExceptionInformation()函數來獲取應用程序傳遞過來的數據。
?
一個進程可以通過調用RaiseException()函數并且使用異常處理結構來處理私有的,軟件引起的或者應用程序定義的異常。下面列出在引發一個異常的時候,調度程序如何查找合適的異常處理程序來處理此異常的步驟:
⑴如果有調試器,系統將嘗試通知進程的調試器。
⑵如果這一進程沒有被調試,或者相關的調試器沒有處理這個異常,系統將嘗試通過查找引發異常的線程的堆棧幀的來定位一個基于幀的異常處理程序。系統首先查找當前的堆棧幀,然后繼續查找先前的堆棧幀。
⑶如果沒有找到基于幀的異常處理程序,或者基于幀的異常處理程序處理該異常,系統將會第二次嘗試通知進程的調試器。
⑷如果該進程仍未被調試,或者相關的調試器不能處理該異常,系統根據異常的類型來提供默認的程序,對于大多數異常,默認的動作就是調用ExitProcess函數來退出進程。
?
2.? 在IOCTL調用中檢查對嵌套指針(nested pointers)的訪問權限(access permissions)。
3.? 在非流式接口的入口函數,比如GWES的鍵盤函數的入口函數中檢查對嵌套指針的訪問權限。
4.? 使用ceddk.dll的函數來訪問硬件,不要使用wdm.h中的宏定義,這不僅有利于標準化,更便于移植。
5.? 檢查任何函數調用的返回值,這樣可以識別調用失敗或者返回意料之外的結果,以便我們做更合理的處理。
6.? 使用DEBUGCHK宏或者相關的宏來檢查一些假設(assumptions),但要相應地處理發生的錯誤情況。
DEBUGCHK宏維護(assert)一個表達式,如果此表達式為FALSE,則會調用DebugBreak函數,DebugBreak函數使當前的進程引起一個斷點異常,這樣調用的線程可以通知調試器并且強迫它采取行動。但如果調用DebugBreak函數的線程沒有附屬的調試器,那么DebugBreak函數將被忽略,并且如果沒有其他的異常或者調用DebugBreak函數時,這個線程將繼續執行。DEBUGCHK宏的用法舉例如下:
DEBUGCHK(dwCurrentNumberOfItems < dwMaxNumberOfItems);
如果dwCurrentNumberOfItems大于或者等于dwMaxNumberOfItems,那么對于debug版本的系統來說,將會輸出下面的信息
MyProgram: DEBUGCHK failed in file C:\WINCE500\Programs\MyProgram\.\main.c at line 31
也即debug消息會把出錯的文件名和行數打印出來。
7.? 當一個內部線程訪問一個外部提供的buffer的時候,使用CeAllocAsynchronousBuffer函數和SHE,這樣可以把調用者的buffer排列(marshals)到內核的虛擬內存中。在WINCE6.0中,不需要改變線程的權限來訪問外部提供的buffer。
8.? 證實訪問設備驅動并且被設備驅動信賴的任何應用程序(Verify that any applications that call into a device driver are trusted)。
?
9.? 檢查正在調用的應用程序的信任值,這個信任值通過調用CeGetCallerTrust函數來獲得。接著,如果必要的話,Flags的值為DEVFLAGS_TRUSTEDCALLERONLY(0x00010000的)驅動有權強迫只被受信任的調用者的使用,也就是說帶有此標志值的驅動只被它信任的應用程序打開,這是相對于WINCE5.0及之前版本的操作系統的概念,對于WINCE6.0之后的就有些不一樣了。
10. 使用C/C++的代碼分析(code analysis)來編程,這部分祥看幫助文檔。
?
總結
以上是生活随笔為你收集整理的WINCE开发更安全可靠设备驱动的最佳实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WINCE源代码配置文件
- 下一篇: WINCE6.0更换桌面壁纸和图标