RFC-0244:提高使用者定義的 Zircon 例外狀況 | |
---|---|
狀態 | 已接受 |
領域 |
|
說明 | 導入系統呼叫,以引發使用者定義的 Zircon 例外狀況 |
更小鳥 | |
作者 | |
審查人員 | |
提交日期 (年月分) | 2024-03-22 |
審查日期 (年-月-日) | 2024-04-22 |
摘要
這個 RFC 導入了 zx_thread_raise_exception
syscall,用於引發使用者定義的 Zircon 例外狀況。此系統呼叫的第一個用途是 Starnix,在其中一個程序呼叫 exec()
時向偵錯工具發出信號。偵錯工具會使用這個信號來判斷開發人員是否要附加至程序。
提振精神
在 Starnix 中執行程序時,我們通常會想使用程序名稱,指定是否要將偵錯工具附加到該程序。如果程序已在執行,這個做法都能正常運作,因為偵錯工具可以檢查現有程序的 ZX_PROP_NAME
,找出需要的程序。不過,由於 Starnix 程序是由 fork()
建立,因此該程序的 ZX_PROP_NAME
與名為 fork()
的程序名稱相符時,因此這個方法不適合尚未執行的程序。Starnix 會在 exec()
期間變更程序的 ZX_PROP_NAME
,但偵錯工具一律不會通知,因此不會附加至程序。
相關人員
誰有權規範這份 RFC?(本節為選用,但建議提供)。
講師:
FEC 委任的人員透過 RFC 程序來破壞這個 RFC。
審查者:
- cpu@google.com
- jamesr@google.com
- jruthe@google.com
諮詢時間:
列出應查看 RFC,但不一定要經過核准的使用者。
社會化:
這個問題在 Zircon 聊天管道中討論過,我按照所接收的建議建立原型,以使用使用者定義的例外狀況,以名稱連接尚未執行的 Starnix 程序的端對端流程。
相關規定
- 當 Starnix 程序呼叫
exec()
時,必須通知偵錯工具,以便檢查程序是否與任何篩選器相符 (例如程序的新名稱是否與名稱篩選器相符)。 - 如果沒有任何偵錯工具正在執行,通知機制不應耗用大量資源。
- 通知機制必須處理多個偵錯代理程式同時執行的情況。
- 此設計不應要求我們變更系統的其他部分 (例如
crashsvc
)。
設計
偵錯工具會監聽 ZX_EXCEPTION_CHANNEL_TYPE_JOB_DEBUGGER
上的 ZX_EXCP_PROCESS_STARTING
例外狀況,藉此瞭解正在建立新程序。此 RFC 中的做法是透過透過 ZX_EXCEPTION_CHANNEL_TYPE_JOB_DEBUGGER
傳送其他類型的例外狀況,通知偵錯工具變更程序名稱。
可惜的是,當程序的 ZX_PROP_NAME
屬性變更時,由於任意執行緒可以變更該屬性,我們不希望 Zircon 自動產生例外狀況。相反地,我們希望從名稱變更程序的執行緒產生例外狀況。幸好,Starnix 一律會透過 exec()
或 procfs
中的檔案,變更只能在程序內寫入,藉此變更程序內執行緒的名稱。
因此,我們推出新的 Syscall,用於產生使用者定義的例外狀況。每當 Starnix 變更程序的名稱時,Starnix 就會使用這個系統呼叫引發此類例外狀況。偵錯工具會監聽這些例外狀況,並重新掃描其附加篩選器清單,看看使用者是否要根據新名稱對程序進行偵錯。
使用者定義的例外狀況
與 Zircon 物件中的使用者定義信號類似,這個 RFC 會保留部分 Zircon 例外狀況命名空間,用於使用者定義的例外狀況。此預留項目可確保使用者定義的例外狀況不會與系統定義例外狀況的日後擴充發生衝突。
具體來說,這個 RFC 透過名為 ZX_EXCP_USER
的 ZX_EXCP_SYNTH
位元集定義了新的 zx_excp_type_t
:
#define ZX_EXCP_USER ((uint32_t) 0x309u | ZX_EXCP_SYNTH)
這個 RFC 也定義了幾個已知的使用者例外狀況代碼,這些程式碼會顯示在 zx_exception_context_t
的 synth_code
欄位中。
ZX_EXCP_USER_CODE_PROCESS_NAME_CHANGED ((uint32_t) 0x0001u)
ZX_EXCP_USER_CODE_USER0 ((uint32_t) 0xF000u)
ZX_EXCP_USER_CODE_USER1 ((uint32_t) 0xF001u)
ZX_EXCP_USER_CODE_USER2 ((uint32_t) 0xF002u)
Starnix 和偵錯工具會使用 ZX_EXCP_USER_CODE_PROCESS_NAME_CHANGED
程式碼,用於上述用途。與 PA_USER0
、PA_USER1
和 PA_USER2
類似,ZX_EXCP_USER_CODE_USER0
、ZX_EXCP_USER_CODE_USER1
和 ZX_EXCP_USER_CODE_USER2
程式碼是針對特定用途定義的。
小於 ZX_EXCP_USER_CODE_USER0
的程式碼僅保留給整個系統使用,可以在後續 RFC 中定義。
提高使用者定義的例外狀況
這個 RFC 定義了會引發使用者定義例外狀況的 syscall:
zx_status_t zx_thread_raise_exception(uint32_t options,
zx_excp_type_t type,
const zx_exception_context_t* context);
這項系統呼叫會針對目前的執行緒,以指定的例外狀況結構定義引發 type
類型例外狀況。
目前 options
引數必須是 ZX_EXCEPTION_JOB_DEBUGGER
,其值為 1。如果呼叫端傳遞任何其他值,系統呼叫會傳回 ZX_ERR_INVALID_ARGS
。提供這個值時,如果工作偵錯工具管道存在,便會在工作偵錯工具管道上傳送例外狀況。
type
引數必須為 ZX_EXCP_USER
。如果呼叫端傳遞任何其他值,系統呼叫會傳回 ZX_ERR_INVALID_ARGS
。
系統會忽略 context
的 arch
欄位。context
中的 synth_code
和 synth_data
欄位目前是透過例外狀況傳達資訊的主要機制。
如果我們想要將這個 Sys 呼叫擴充為其他類型的例外狀況管道,可以在後續的 RFC 中擴充系統呼叫的語意。
實作
透過新增設計一節所述的 Syscall,即可實作這項功能。所有用來引發例外狀況的機器都存在於 Zircon 中。第二個 CL 會指示 debug_agent
監聽這些例外狀況,並重新檢查產生例外狀況的程序名稱。
概念驗證 CL 證明瞭 Zircon 和 debug_agent
中的實作相當簡單。
效能
這項設計對系統效能幾乎沒有影響。通常沒有執行中的 debug_agent
時,zx_thread_raise_exception
會在前往工作階層的根層級後提早傳回,並會發現沒有人在監聽偵錯工具例外狀況管道。
反之,如果系統中有多個 debug_agent
執行個體正在執行,此機制可有效率地將通知傳送給每個執行個體。
此程式碼路徑已針對這兩種情況進行最佳化,因為系統會使用相同的機制來通知其他常見事件 (例如啟動程序) 的 debug_agent
。
人體工學
此 RFC 中描述的方法並不是特別人體工學,舉例來說,Starnix 必須在變更程序名稱時引發適當的例外狀況類型。較符合人體工學的設計,是讓 Zircon 在每次程序名稱變更時自動觸發這項例外狀況。不過,這個方法並不容易,因為系統中如有處理序的執行緒可以變更程序名稱。Zircon 沒有能夠從遠端執行緒發出例外狀況的機制,而新增這類機制會讓 Zircon 更加複雜 (例如先檢查待處理的例外狀況,然後再返回使用者空間)。
回溯相容性
本文所述的設計與現有系統回溯相容。zx_thread_raise_exception
可能產生的例外狀況會清楚標示為使用者產生的例外狀況,並有一個與核心產生的例外狀況分開的命名空間。這項設計也將保留命名空間,供日後使用者和核心產生的例外狀況使用。
安全性考量
zx_thread_raise_exception
可讓使用者空間產生先前無法產生的例外狀況,讓攻擊者可以用來操控監聽例外狀況的軟體。本提案可以限制使用者產生的例外狀況,使其設定 ZX_EXCP_SYNTH
位元的例外狀況,並限制為保留的命名空間,藉此降低風險。
Userspace 已經可以在微架構層級產生一些例外狀況,例如分別對 ARM 和 Intel 使用 brk
和 int3
指令,這表示新增核心中介機制產生例外狀況的風險也已降低。
隱私權注意事項
雖然程序名稱可能包含隱私機密資訊,但這項新機制並不會將這些資訊的存取權提供給任何新程序。舉例來說,相較於納入新程序名稱且加上新程序名稱的設計,這項設計在設定隱私權方面的屬性略微更高。
測試
新的系統呼叫將由 Zircon 核心測試進行測試。
偵錯工具整合將以整合測試進行測試。
說明文件
就像往常的 Zircon 系統呼叫一樣,新的系統呼叫會以系統呼叫手動頁面記錄。新的例外狀況語意也會記錄在「例外狀況處理」概念頁面中。
缺點、替代項目和未知
我們考慮到以下幾個替代方案:
使用微架構例外狀況
與其新增系統呼叫來引發例外狀況,我們不如利用現有的微架構機制來引發例外狀況 (例如 brk
和 int3
操作說明)。此方法的缺點是,除非處理這些例外狀況,否則這些例外狀況將造成嚴重影響。我們可以協助 crashsvc
辨識這些例外狀況,就像處理回溯追蹤要求一樣,但建議不要向 crashsvc
教導與 crashsvc
無關的系統功能。
在程序名稱變更時自動產生例外狀況
與其要求 Starnix 在變更程序名稱後呼叫 zx_thread_raise_exception
,而是讓 Zircon 在每次程序名稱變更時自動產生例外狀況。不過,如上所述,任何具有程序處理常式的執行緒可以變更 Zircon 程序的名稱,且 Zircon 缺少在遠端執行緒上產生例外狀況的機制。
幸運的是,Starnix 實際上變更程序名稱的情況,是在該程序中的執行緒發生名稱變更的情況。也就是說,我們不必解決遠端執行緒產生例外狀況的問題,藉此處理現有的用途。