成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Linux 內核 API 的復雜歷史

系統 Linux
由于用戶通常不會運行最新的頂層 Linux 內核,因此從用戶的角度來看,它也是一個非常分散的代碼庫,這對安全性有重要影響。

Linux 內核是一個不斷迭代的代碼庫,截至 2021 年,其代碼行數已超過 3000 萬行。然而,由于用戶通常不會運行最新的頂層 Linux 內核,因此從用戶的角度來看,它也是一個非常分散的代碼庫,這對安全性有重要影響。一致的安全屬性(跨內核版本、處理器架構、編譯器版本)是grsecurity一個重要目標,但頂層通常不會將添加的預防性安全檢查或功能向后移植到舊支持的內核,并且這些措施的狀態沒有很快被最終用戶采用,實際上,必須是有經驗的專注于安全的內核開發人員才能確定他們自己系統的狀態。

作為系統管理員,我們首先要擔心的問題是一個系統的安全性和穩定性,其次才是它的效能和效率。一個系統是否安全,一般來說與系統的復雜性有直接關系。對于必須開放訪問的系統來說,成熟而可靠的系統保護措施是十分重要的。而對作為各種程序運行平臺的操作系統而言,系統越復雜可能隱藏的攻擊面也就越多。

受 copy_*_user 中的檢查影響的漏洞類型在過去已經出現過幾次,例如, Mathias Krause 在 2013 年的修復報告。在討論這些檢查時,最有意義的是談論當前的頂層狀態,之后我們可以討論代碼的歷史以及它是如何隨著時間的推移而演變的。

當前頂層 copy_*_user() 檢查

在當前的頂層內核中,copy_from_user(用于將數據從用戶級復制到內核)和copy_to_user(用于將數據從內核復制到用戶級)實現如下:

因此,如果 check_copy_size() 通過,則將調用較低級別的 copy_*_user 例程。這些較低級別的例程可以內聯或不內聯,具體取決于處理器架構,但它們的實現方式保持不變:

access_ok() 是一個古老的例程,其目的是驗證用戶空間中提供的范圍(作為 copy_from_user 的源,copy_to_user 的目標)是否實際駐留在用戶空間中。這個 API 最近發生了變化,從 thread_info 結構中刪除了 addr_limit 并將內核拆分為內核副本到它自己的 API。以前,在 addr_limit 恢復之前的 set_fs(KERNEL_DS) 或惡意修改的 addr_limit(過去幾年的常見漏洞利用技術)之后運行的代碼可以(ab)使用 copy*user 進行任意內核讀/寫。

should_fail_usercopy() 與錯誤注入(模糊增強)有關,可以忽略。 instrument_* 同樣可以忽略,因為它與 KASAN(調試/模糊測試增強)有關。出于生產安全目的,我們感興趣的唯一代碼是 access_ok() 和 check_copy_size()。

讓我們稍微解釋一下這里顯示的內容:__compiletime_object_size()是一個宏,它利用了編譯器的__builtin_object_size()。如果內核中用于復制的源或目標(適當)的對象的大小能夠在編譯時確定,這將返回該對象的大小。否則,編譯器版本不支持__builtin_object_size(),它返回-1。

當內核對象的大小是靜態已知的并且要復制的長度也是恒定的時,__bad_copy_from() 和 __bad_copy_to() 都是編譯時出現的錯誤,這種情況在實踐中不太可能會變成安全問題,除非代碼從未測試/使用過。當對象大小靜態已知但復制長度不是編譯時常量時,Copy_overflow()是一個運行時警告。

如果復制長度大于 INT_MAX,“WARN_ON_ONCE(bytes > INT_MAX)”檢查將產生運行時警告。由于這是在無符號 size_t 類型上計算的,因此當在有符號 int 或 long 類型上解釋時(即 oss-sec 上報告的錯誤的情況),這具有拒絕負長度的附加效果。稍后會詳細介紹此檢查。

check_object_size() 來自頂層的USERCOPY 功能的有限版本。不會對其返回值進行檢查,因為它不會像其他檢查那樣簡單地使復制失敗,而是在 usercopy_abort() 中執行 BUG() ,這在簡單的情況下將簡單地終止所涉及的進程,但在更復雜的場景中,例如在用戶空間副本周圍保留互斥鎖可能會導致某些代碼路徑鎖定,或者在 panic_on_oops 場景中,會導致系統崩潰。

關于 oss-sec 報告中討論的漏洞的實際影響,由于 2018 年 6 月的"fsi: Add cfam char devices " 中針對 Linux 4.19 引入了錯誤的 CFAM 更改,因此 cfam_write() 案例將進入 copy_from_user()使用負長度,到達 check_copy_size() ,其中 __compiletime_object_size() 將返回 4 用于復制到的 __be32 數據變量,然后由于字節不是編譯時常量,將調用 copy_overflow(),觸發其中包含的WARN(),并錯誤地中止復制操作。

為了簡潔起見,我們將把分析限制在這些方面,而不會深入raw_copy_*_user()本身的實現,它已經看到了自己的體系結構特定的發展,包括SMAP/PAN/等的引入和Spectre的發現。

在繼續之前要注意的最后一點是memset()只存在于_copy_from_user()中,內核注釋如下:

注意:1.只有 copy_from_user() 在短復制的情況下將目標置零。2.__copy_from_user() 和 __copy_from_user_inatomic() 都不為零。3.他們的調用者絕對必須檢查返回值。

注意__copy_*_user(兩個下劃線)和_copy_*_user(一個下劃線)是不同的。這個memset()的原因大概是為了解決Linux歷史上copy_*_user被標記為__must_check屬性之前的情況,要求調用者檢查返回值是否錯誤。考慮一種常見的情況,即從用戶級復制結構,內核更改了某些字段,然后將結構復制回用戶級。如果來自用戶級的副本或內核設置字段沒有寫入的區域被復制回用戶級,且未初始化,它們可能會將之前的內存內容泄漏到用戶級(信息泄漏)。用戶級還可以通過使部分復制范圍包括未映射的地址或操作的無效權限來強制低級復制例程中的部分失敗。

check_object_size() 的歷史

這個檢查第一次出現在2016年6月的Linux 4.8版本中,通過commit“mm: Hardened usercopy”。它的提交信息如下:

“這是將PAX_USERCOPY移植到主線內核的開始。這是由CONFIG_HARDENED_USERCOPY控制的第一組特性。這項工作是基于PaX Team和Brad Spengler的代碼,以及Casey Schaufler的早期移植。其他非平板頁面測試來自Rik van Riel。”

check_object_size() 通過引用堆和其他元數據來工作,以便在運行時盡可能驗證復制操作是否發生在單個對象的范圍內。

盡管上面提到的提交消息是移植完整功能的開始,但在5年里,除了禁用上述添加的頁面測試(grsecurity中不存在)以外,該功能沒有出現其他重大變化,這破壞了內核的幾個方面。PAX_USERCOPY最初發布于2009年,比有限的上游版本早了大約7年。強化后的用戶復制代碼沒有向后移植到早期版本,包括當時的活動 LTS 版本。因此,頂層 4.4 XLTS。

__compiletime_object_size()/__builtin_object_size() 的歷史

__builtin_object_size()在2005年Arjan van de Ven編寫的FORTIFY_SOURCE補丁中首次使用。它最初關注的是FORTIFY_SOURCE在用戶級中也涵蓋的典型的str*和mem* api。2009 年,在研究 FORTIFY_SOURCE 在內核中的實際覆蓋范圍時,我將 Arjan 的工作擴展到對更多函數執行檢查,并增加了它對一些 [k|v]malloc 對象大小的編譯時知識,發現它只檢測了約 30% 的涵蓋 API 實例,不過從安全角度來看,是不太可能出現被攻擊的。

這些 str* 和 mem* API 的覆蓋范圍是在 2017 年 7 月為 4.13 內核提交“include/linux/string.h: add the option of fortified string.h functions ”,但沒有提及早期的工作,或者任何使用一些動態分配對象大小的改進知識,將其有效覆蓋率降低到我最初調查的 30% 以下。

2009 年 Arjan van de Ven 通過提交“x86: Use __builtin_object_size() to validate the buffer size for copy_from_user()”為 x86 頂層添加了用于 copy__*_user 的 __builtin_object_size()。這個Linux 2.6.34的初始版本只覆蓋了copy_from_user,僅從 2013 年 10 月開始涵蓋 copy_to_user,其中 Jan Beulich 為 Linux 3.13 提交了"x86: Unify copy_to_user() and add size checking to it "。它看到了許多重構,最終通過 Al Viro 在 2017 年 3 月為 4.12 版本的 Linux 提交"generic ...copy_..._user primitives"產生了一個獨立于架構的變體。

正如我們之前提到的,__builtin_object_size() 是由編譯器提供的。 2013 年 4 月,為了響應內核在某些 GCC 版本上現有使用內置函數產生的編譯時錯誤,Guenter Roeck 合并了“gcc4: disable __compiletime_object_size for GCC 4.6+”,使得整個練習對受影響的編譯器毫無用處版本(當時,最新發布的 GCC 版本是 4.8.0)。

“我想指出,盡管 __compiletime_object_size() 在 4.6 之前被限制為 gcc,但整個構造將變得越來越沒有意義。 然而,我會質疑 commit 2fb0815c9ee6b9ac50e15dd8360ec76d9fa46a2 ("gcc4: disable__compiletime_object_size for GCC 4.6+") 確實是必要的,相反,這應該像從一開始就在這里做的那樣處理。”

然而,直到2016年8月Josh Poimboeuf的Linux 4.8 commit:“mm/usercopy: get rid of CONFIG_DEBUG_STRICT_USER_COPY_CHECKS”,對GCC >= 4.1和< 4.6使用__builtin_object_size()的限制被更改為GCC >= 4.1。在這次提交時,GCC 6.2是最新的編譯器版本。Josh的提交也消除了啟用調試選項以獲得功能的需要。

綜上所述,在大約三年的時間里,除了少數內核開發人員對內核進行檢查之外,用戶都沒有進行過有關操作。還應該注意的是,放寬對 __builtin_object_size() 版本限制的 4.8 提交從未向后移植到早期的內核,這意味著即使對于今天最新的 4.4 XLTS 版本,任何涉及此的檢查對于幾乎任何現代用戶都是完全無實操可能性的。

你可能想知道,Clang在構建Linux時是如何發揮作用的,盡管谷歌在 2018 年底開始使用 Clang 構建內核的 4.4 內核。 Clang 歷史上(甚至在最新版本中)偽造了 4.2.1 的 GCC 版本,因此不受這些更改的影響。

WARN_ON_ONCE 的歷史(bytes > INT_MAX)

這種檢查最早是 Linus Torvalds 本人在 2005 年 2 月對2.6.11 內核通過BUG_ON() 對 i386 進行的檢查。由于Andi Kleen 的提交“[PATCH] i386: Remove copy_*_user BUG_ONs for (size < 0)”,兩年多后,這些檢查在2.6.22版本的內核中被刪除,并錯誤地解釋為“access_ok檢查這種情況,不需要檢查兩次”。這種解釋是錯誤的,因為雖然access_ok()確實有效地檢查了相同的情況,但BUG_ON()避免了后續memset()的執行,此后memset()就可以執行了。

在 grsecurity 中,2.6.29 版本的 Linux 在 2009 年 8 月時在 Linux 支持的幾乎所有架構中安全地實施了此檢查,沒有 BUG_ON()。重要的是,此檢查是在 access_ok() 之前執行的,并且在 copy_from_user() 的情況下避免了稍后將討論的易受攻擊的 memset()。

在頂層,這項檢查是由 Kees Cook 在 2019 年 12 月針對 Linux 5.5通過“uaccess: disallow > INT_MAX copy sizes”引入的。由于只有 2 行更改,因此一個月后它被反向移植到 Linux 5.4。然而,由于 copy_*_user API 在前幾年經歷了相當大的變動,這個簡單的改變并沒有被進一步的反向移植,因此在上游的4.4、4.9、4.14或4.19 XLTS內核中也沒有出現,而這些內核現在仍然支持XLTS。

copy_from_user memset 的歷史

在 x86 上,至少可以追溯到 2002 年之前,只有在 access_ok() 成功時才對失敗的 copy_from_user 進行歸零。例如當copy_from_user的大小不是編譯時常量時調用 __generic_copy_from_user 的實現。后來,情況發生了變化,從 Linux 2.4.3.4 的這個提交開始,從隨后的2.4.35版本的這個改變開始,該版本在access_ok()失敗時添加了歸零設置。

Andrew Morton在2003年6月發布了一個x86補丁,提到了在access_ok()失敗的情況下重新放置memset()。

最有趣的是,早在2002年的Linux 2.4.4.4中,ARM就有以下變化:

目前尚不清楚該評論是指它緩解了前面描述的安全漏洞還是引入了一個漏洞,該漏洞可能由攻擊者控制長度的緩沖區歸零,然而,這一改變確實帶來了一個潛在漏洞。考慮到由于計算中的一些溢出而導致 n = -1 的情況:access_ok() 在 32 位 ARM 上將失敗,因為 n 表示為添加到任何用戶空間的無符號值地址將涵蓋包括內核空間在內的范圍。 else 情況將被觸發,導致長度為 0xffffffff 的 memzero(),肯定會導致系統無法恢復的 DoS。

目前該問題仍然存在于頂層中。

由于2019年添加的禁止INT_MAX副本大小的頂層檢查是在check_copy_size()中實現的,因此它失敗了,避免了對_copy_from_user()的調用,這將執行錯誤的memset(),與十年前的grsecurity更改相同。然而,由于未知的原因,在提交消息或它所引用的郵件列表討論中,根本沒有提到修復這個漏洞。

如上所述,由于頂層的更改未向后移植到 4.4、4.9、4.14 或 4.19版本種,因此可以將負長度傳遞給 copy_from_user() 的內核版本中存在的錯誤可能會導致大量內存損壞并保證系統 DoS。如果有人接受某些人提出的緩解建議并啟用 panic_on_warn,2019年進行的頂層更改也會通過恐慌導致 DoS。


責任編輯:武曉燕 來源: 嘶吼網
相關推薦

2014-05-13 15:00:59

2009-12-09 14:25:31

2009-12-21 16:01:07

2009-11-24 13:53:03

SuSE Linux

2013-11-07 13:59:56

Linux內核

2013-11-25 14:07:11

Linux內核內核特性

2013-11-05 09:58:39

Linux內核

2013-11-12 11:01:46

Linux內核

2013-11-06 13:03:10

Linux內核

2021-02-20 06:08:07

LinuxWindows內核

2009-12-22 13:44:33

Linux操作系統

2012-02-06 09:49:40

2009-12-09 09:45:35

袁萌Linux

2011-01-11 13:45:06

2017-04-12 14:30:45

Linux內核DebugFS

2013-05-13 09:52:52

Windows內核Linux內核

2010-03-02 09:17:32

Linux local

2012-04-01 14:44:49

Linux歷史

2022-01-24 17:08:33

Linux容器Docker

2020-05-12 16:58:05

LinuxUnix技術
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 午夜三级网站 | 亚洲欧美久久 | 精品一区二区三区在线视频 | 麻豆亚洲 | 精品欧美一区免费观看α√ | 亚洲精品中文字幕在线 | 欧美日韩在线观看视频网站 | 蜜桃视频成人 | 欧美九九| 中文无码日韩欧 | 中文字幕专区 | 国产精品视频久久 | 欧美成人一区二区三区 | 中文字幕免费视频 | 免费黄色录像片 | 天天干,夜夜操 | www国产成人免费观看视频,深夜成人网 | 欧美日韩在线观看一区二区三区 | 性色在线 | 91aiai| 国产小视频在线 | 国产一区二区在线91 | 国内精品久久久久久久 | 亚洲午夜视频 | 欧美日韩国产在线观看 | 午夜精品一区二区三区在线观看 | 91精品久久久久久久久中文字幕 | 国产91在线精品 | 国产精品日韩欧美一区二区三区 | 99国产精品久久久久老师 | 亚洲一页 | 国产精品日韩欧美一区二区三区 | 日韩一区二区在线播放 | 成人高潮片免费视频欧美 | 一区二区不卡高清 | 免费视频一区二区三区在线观看 | www.嫩草 | 精品综合视频 | 国产99久久 | 日韩在线中文字幕 | 精品欧美一区二区在线观看视频 |