這兩天 Tianocore 更新了最新版的 edk2-stable-202411,然後地獄的 build error 又莫名地出現了。不出所料,又是 secirity 的更新造成的 ….
又來了,一更新就壞
照慣例我會把我自己寫的一些小 tool 用最新的 code base 重新 build 一次看看會不會有什麼問題,而最近感覺 UEFI 沒什麼能玩了,近期不管改什麼都可以扯到 security,在我更新了 edk2-stable-202411 之後,出現了如下的 errors。
1
2
3
4
|
BaseLib.lib(SafeString.obj) : error LNK2001: unresolved external symbol __security_check_cookie
BaseLib.lib(SafeString.obj) : error LNK2001: unresolved external symbol __GSHandlerCheck
BaseLib.lib(SafeString.obj) : error LNK2001: unresolved external symbol __security_cookie
UefiDevicePathLib.lib(DevicePathToText.obj) : error LNK2001: unresolved external symbol __report_rangecheckfailure
|
經過了一連串的 git log 搜尋,看起來問題是出在 StackCheckLib 這個新增加的 stack cookie 實作。經過了一點點學習,簡單說它就是在 stack 中插入一個亂數值,然後在 return 前檢查該值是否改變來以避免有人竄改 stack。
這造成了 compiler 會在編譯的時候會嘗試取得上述 error 內提及的 symbol,若找不到當然就會 build error。
Tianocore 也寫了一份完整的 Readme.md 來描述該新增的機制,文件連結如下:
https://github.com/tianocore/edk2/tree/master/MdePkg/Library/StackCheckLib
基本上該文件已經寫得很清楚了,不過我這邊再記錄一下我大概改了什麼東西。
StackCheckLib 實作分類
依照文件建議,目前有三種 StackCheckLib 實作,分別建議在不同的 phase 中使用。
-
MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
SEC, PEI_CORE 中使用
-
MdePkg/Library/StackCheckLib/StackCheckLibStaticInit.inf
PEIM 中使用
-
MdePkg/Library/StackCheckLib/StackCheckLibDynamicInit.inf
注意,這個 DynamicInit 實際上還沒有在這一版 edk2-stable-202411 中實現,所以我自己是先改成用 StackCheckLibNull(因為 Shell 也沒換用 StackCheckLibStaticInit 所以我就假設官方建議先不要開)
如果你有自己寫的 package,請跟我這樣改
你應該有已經有一個現成的 dsc 檔
- 加上 MdeLibs.dsc.inc
在 MdePkg/MdeLibs.dsc.inc 已經有預先拉進一些 library, 你可以 review 一下是否跟現在的 dsc 檔內容有重複,若有重複可以刪除。
1
|
!include MdePkg/MdeLibs.dsc.inc
|
這邊要注意的是下面這段,如果你沒有 define CUSTOM_STACK_CHECK_LIB 代表直接使用 StackCheckLibNull,這樣可以修復 build error 問題,但不會打開 stack cookie 保護。
也就是說只要加上 MdeLibs.dsc.inc 其實你就 build 的過了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
StackCheckFailureHookLib|MdePkg/Library/StackCheckFailureHookLibNull/StackCheckFailureHookLibNull.inf
!ifndef CUSTOM_STACK_CHECK_LIB
# If CUSTOM_STACK_CHECK_LIB is set, MdeLibs.dsc.inc will not link StackCheckLibNull and it is expected that the
# DSC being built is providing it's own implementation of StackCheckLib.
NULL|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
!endif
[LibraryClasses.ARM, LibraryClasses.AARCH64]
#
# It is not possible to prevent the ARM/AARCH64 compilers from inserting generic intrinsic functions.
# This library provides the intrinsic functions generated by these compilers.
#
# Linking this here as a null library will cause all ARM/AARCH64 files to link against it and have
# definitions for the intrinsic functions.
#
NULL|MdePkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
|
- 加上 define DEFINE CUSTOM_STACK_CHECK_LIB 來使用指定的 StackCheckLib
若想要開啟保護,接著在 dsc 宣告 CUSTOM_STACK_CHECK_LIB,然後補上文件建議的實作。
1
|
DEFINE CUSTOM_STACK_CHECK_LIB = TRUE
|
根據 Tianocore 提供的 StackCheckLib Readmd.md 來加上你所需的 StackCheckLib
1
2
3
4
5
6
7
8
9
10
|
[LibraryClasses.common.SEC, LibraryClasses.common.PEI_CORE]
NULL|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
[LibraryClasses.common.PEIM]
NULL|MdePkg/Library/StackCheckLib/StackCheckLibStaticInit.inf
# Refer to edk2\MdePkg\Library\StackCheckLib\Readme.md, StackCheckLibDynamicInit is not finished yet.
[LibraryClasses.common.MM_CORE_STANDALONE, LibraryClasses.common.MM_STANDALONE, LibraryClasses.common.DXE_CORE, LibraryClasses.common.SMM_CORE, LibraryClasses.common.DXE_SMM_DRIVER, LibraryClasses.common.DXE_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.DXE_SAL_DRIVER, LibraryClasses.common.UEFI_DRIVER, LibraryClasses.common.UEFI_APPLICATION]
# NULL|MdePkg/Library/StackCheckLib/StackCheckLibDynamicInit.inf
NULL|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf
|
這樣就大功告成了。
參考