最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

教你使用eBPF LSM熱修復(fù)Linux內(nèi)核漏洞

2022-11-07 21:10 作者:補(bǔ)給站Linux內(nèi)核  | 我要投稿

本文就是一個(gè)簡(jiǎn)單的eBPF LSM實(shí)現(xiàn)思路,核心內(nèi)容是確定精準(zhǔn)HOOK點(diǎn)的思路。怎么找HOOK點(diǎn)?HOOK點(diǎn)掛載后,對(duì)性能影響是什么?如何做權(quán)衡?接下來(lái),我們一起了解一下。

前言

Linux Security Modules^[2]^ (LSM)是一個(gè)鉤子的基于框架,用于在Linux內(nèi)核中實(shí)現(xiàn)安全策略和強(qiáng)制訪問(wèn)控制。直到現(xiàn)在,能夠?qū)崿F(xiàn)實(shí)施安全策略目標(biāo)的方式只有兩種選擇,配置現(xiàn)有的LSM模塊(如AppArmor、SELinux),或編寫(xiě)自定義內(nèi)核模塊。

Linux Kernel 5.7[^3^ ]引入了第三種方式:LSM擴(kuò)展伯克利包過(guò)濾器^[4]^ (eBPF)(簡(jiǎn)稱BPF LSM)。LSM BPF允許開(kāi)發(fā)人員編寫(xiě)自定義策略,而無(wú)需配置或加載內(nèi)核模塊。LSM BPF程序在加載時(shí)被驗(yàn)證,然后在調(diào)用路徑中,到達(dá)LSM鉤子時(shí)被執(zhí)行。

實(shí)踐出真知

命名空間命名空間

現(xiàn)代操作系統(tǒng)提供了允許對(duì)內(nèi)核資源進(jìn)行的工具。例如FreeBSD有,Solaris有。Linux不一樣,提供了一組看似獨(dú)立的工具,每個(gè)進(jìn)程都允許隔離特定的資源。他就是,經(jīng)過(guò)多年來(lái)不停迭代,孕育了、、應(yīng)用。大部分是沒(méi)有爭(zhēng)議的,如UTS命名空間,它允許主機(jī)系統(tǒng)隱藏主機(jī)名和時(shí)間。其他的則比較復(fù)雜但簡(jiǎn)單明了————眾所周知,NET和NS(mount)命名空間很難讓人理解。最后,還有一個(gè)非常特殊、非常有趣的。partitioning``jails``zones``Namespaces``Docker``lxc``firejail``Namespaces``USER Namespaces

USER Namespaces很特別,因?yàn)樗试S所有者作為操作。其工作原理超出了本文的范圍,但是,可以說(shuō)它是讓等工具不作為真正的root操作,或者說(shuō)是容器。root``Docker``rootless

由于其特性,允許未授權(quán)用戶訪問(wèn)總是會(huì)帶來(lái)很大的安全風(fēng)險(xiǎn)。其中最大的風(fēng)險(xiǎn)是。USER Namespaces``提權(quán)

提權(quán)原理

提權(quán)是操作系統(tǒng)的常見(jiàn)攻擊面。user獲得權(quán)限的一種方法是通過(guò)unsharesyscall[5]將其命名空間映射到空間,并指定標(biāo)志。這會(huì)告訴創(chuàng)建一個(gè)具有完全權(quán)限的新用戶命名空間,并將新用戶和Group ID映射到以前的命名空間。即使用unshare(1)[6]程序?qū)oot映射到原始命名空間:root``CLONE_NEWUSER``unshare

多數(shù)情況下,使用是沒(méi)有風(fēng)險(xiǎn)的,都是以較低的權(quán)限運(yùn)行。但是,已經(jīng)被用于提權(quán)了,比如CVE-2022-0492[7],那么本文就重點(diǎn)以這個(gè)場(chǎng)景為例。unshare

Syscalls clone和也很值得研究,都有的功能。但在這篇文章中,我們將重點(diǎn)關(guān)注。clone3``CLONE_NEWUSER``unshare

Debian用add sysctl to disallow unprivileged CLONE_NEWUSER by default^[8]^ 補(bǔ)丁解決了這個(gè)問(wèn)題,但它沒(méi)有被合并到源碼mainline主線中。另一個(gè)類似的補(bǔ)丁sysctl: allow CLONE_NEWUSER to be disabled嘗試合并到mainline,但被拒絕了。理由是在某些特定應(yīng)用中無(wú)法切換到該特性^[9]^ 。在控制對(duì)用戶命名空間的訪問(wèn)[^10]^ 一文中,作者寫(xiě)道:

...目前的補(bǔ)丁似乎沒(méi)有一條通往mainline主線的捷徑。

如你所示,補(bǔ)丁最終沒(méi)有包含到vanilla內(nèi)核^[11]^ 中。


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個(gè)人覺(jué)得比較好的學(xué)習(xí)書(shū)籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書(shū)、實(shí)戰(zhàn)項(xiàng)目及代碼)? ?

我們的解決方案LSM BPF

基于上面一些經(jīng)驗(yàn),可以看到限制的代碼似乎行不通,我們決定使用來(lái)規(guī)避這些問(wèn)題。并且不需要修改內(nèi)核,還可以自定義檢測(cè)防御的規(guī)則。USER Namespaces``LSM BPF

尋找合適的候選鉤子

首先,讓我們跟蹤我們的目標(biāo)系統(tǒng)調(diào)用。我們可以在include/linux/syscalls.h^[12]^ 文件中找到原型。

很清晰得看到,在kernel/fork.c^[13]^ 文件中,注釋部分中留下了下一個(gè)位置的線索。在ksys_unshare()^[14]^ 那里調(diào)用。深入研究該函數(shù),發(fā)現(xiàn)了一個(gè)對(duì)unshare_userns()^[15]^ 的調(diào)用。這讓我看到了希望。

現(xiàn)在,我們已經(jīng)確定了syscall實(shí)現(xiàn),但是接下來(lái)的問(wèn)題是用哪些鉤子?怎么選擇合適的鉤子?

從man-pages[16]中了解到unshare用于改變,那么,我們重點(diǎn)關(guān)注include/linux/lsm_hooks.h[17]中的關(guān)于的鉤子。在函數(shù)unshare_userns()[18]中,可以找到對(duì)prepare_creds()[19]的調(diào)用。對(duì)于cred_prepare[20]的HOOK來(lái)說(shuō)看上去不錯(cuò)。為了驗(yàn)證對(duì)prepare_creds()[21]的理解是否正確,接下來(lái)繼續(xù)分析security_prepare_creds()[22]的調(diào)用,可以確認(rèn),其最終會(huì)調(diào)用這個(gè)HOOK:task``task

暫不過(guò)多討論這個(gè)問(wèn)題,現(xiàn)在能確認(rèn)的是這個(gè)HOOK比較合適,因?yàn)檎迷谥械闹氨徽{(diào)用,而unshare_userns()[23]是我們?cè)噲D阻止的操作。prepare_creds()``unshare_userns()``create_user_ns()

LSM BPF解決方案

我們將使用eBPF編譯一次到處運(yùn)行(CO-RE)^[24]^ 的方法對(duì)代碼進(jìn)行編譯。在不同版本內(nèi)核的IDC中,會(huì)特別適用。(不過(guò),國(guó)內(nèi)外大部分五至十年的互聯(lián)網(wǎng)公司,都有著大量低于5.0的內(nèi)核版本)。本文的演示,將只對(duì)x86_64 CPU架構(gòu)系統(tǒng)驗(yàn)證。ARM64的LSM BPF仍在開(kāi)發(fā)中。你可以訂閱BPF郵件列表^[25]^ 來(lái)了解最新進(jìn)展。

此解決方案在上進(jìn)行了測(cè)試,配置如下:Kernel Version >=5.15

如果CONFIG_LSM列表中不包含,則需要你自己重新編譯,并開(kāi)啟選項(xiàng).bpf``lsm=bpf

內(nèi)核空間代碼

開(kāi)始看內(nèi)核空間代碼::deny_unshare.bpf.c

共產(chǎn)

接下來(lái),我們以下列方式為CO-RE重新定位建立必要的結(jié)構(gòu)::deny_unshare.bpf.c

用戶空間

加載程序并將其附加到目標(biāo)的鉤子上是用戶空間的功能。有幾種方法可以做到這一點(diǎn):

  1. Cilium ebpf^[26]^ 項(xiàng)目

  2. 防銹裝訂^[27]^

  3. ebpf.io[28]項(xiàng)目展示的其他類庫(kù)landscape

這里,我們將使用原生libbpf^[29]^ 。

生成文件

最后,進(jìn)行編譯,這里使用Makefile

結(jié)果

打開(kāi)一個(gè)新終端,運(yùn)行命令

在另一個(gè)終端里,可以看到成功的被阻止了。

這個(gè)策略有個(gè)附加的特性,可以允許傳遞授權(quán)。

在無(wú)特權(quán)場(chǎng)景中,系統(tǒng)調(diào)用會(huì)提前中止。有特權(quán)情況下的性能影響是什么?

性能對(duì)比

我們將使用一行unshare命令來(lái)映射用戶命名空間,并在中執(zhí)行一個(gè)命令來(lái)進(jìn)行測(cè)量:

使用系統(tǒng)調(diào)用unshare enter/exit的CPU周期分辨率,我們將以root用戶身份測(cè)量以下內(nèi)容:

  1. 命令在沒(méi)有策略的情況下運(yùn)行

  2. 與策略一起運(yùn)行的命令

我們將使用ftrace^[30]^ 記錄測(cè)量結(jié)果:

此時(shí),我們將專門(mén)為unshare啟用對(duì)系統(tǒng)調(diào)用的跟蹤。現(xiàn)在,我們?cè)O(shè)置調(diào)用的來(lái)計(jì)算CPU周期:enter/exit``enter/exit``time-resolution

接下來(lái),我們開(kāi)始評(píng)測(cè)

在新終端里運(yùn)行策略,執(zhí)行下一個(gè)syscall

現(xiàn)在,我們收集到兩種CALLS結(jié)果進(jìn)行對(duì)比

分別是:

  • unshare-92014 使用了 63294 個(gè)周期。

  • 取消共享-92019 使用了 70138 個(gè)周期。

可以看到二者之間有6,844(~10%)個(gè)周期的差異,還行。

兩次測(cè)量之間有6,844(~10%)個(gè)周期損失。不錯(cuò)嘛!

這些數(shù)字是針對(duì)單個(gè)系統(tǒng)調(diào)用的,代碼調(diào)用的頻率越高,這些數(shù)字就越多。Unshare通常在任務(wù)創(chuàng)建時(shí)調(diào)用,在程序的正常執(zhí)行期間不會(huì)重復(fù)調(diào)用。對(duì)于你的場(chǎng)景,需要仔細(xì)考慮評(píng)估。

結(jié)尾

我們了解了是什么,如何使用unshare將映射到,以及如何通過(guò)在eBPF中實(shí)現(xiàn)程序來(lái)解決真實(shí)場(chǎng)景的問(wèn)題。跟蹤準(zhǔn)確的鉤子不是一件容易的事,需要有豐富的經(jīng)驗(yàn),以及豐富的內(nèi)核代碼經(jīng)驗(yàn)。這些一個(gè)策略代碼是用C語(yǔ)言編寫(xiě)的,所以我們可以根據(jù)因地制宜,不同的問(wèn)題做不同的策略,代碼經(jīng)過(guò)輕微調(diào)整,就可以快速擴(kuò)展,增加其他鉤子點(diǎn)等。最后,我們對(duì)比了這個(gè)LSM程序的性能影響,性能與安全的權(quán)衡,是你需要考慮的問(wèn)題。LSM BPF``user``root

Cannot allocate memory(無(wú)法分配內(nèi)存)不是拒絕權(quán)限的最準(zhǔn)確的描述。我們提出了一個(gè)補(bǔ)丁[31],用于將錯(cuò)誤代碼從掛鉤傳到調(diào)用堆棧。cred_prepare

最后,我們的結(jié)論就是鉤子非常適合實(shí)時(shí)修復(fù)Linux內(nèi)核漏洞.


嵌入式Linux內(nèi)核?發(fā)布于?16?秒前?閱讀?1只看樓主

本文就是一個(gè)簡(jiǎn)單的eBPF LSM實(shí)現(xiàn)思路,核心內(nèi)容是確定精準(zhǔn)HOOK點(diǎn)的思路。怎么找HOOK點(diǎn)?HOOK點(diǎn)掛載后,對(duì)性能影響是什么?如何做權(quán)衡?接下來(lái),我們一起了解一下。

前言

Linux Security Modules^[2]^ (LSM)是一個(gè)鉤子的基于框架,用于在Linux內(nèi)核中實(shí)現(xiàn)安全策略和強(qiáng)制訪問(wèn)控制。直到現(xiàn)在,能夠?qū)崿F(xiàn)實(shí)施安全策略目標(biāo)的方式只有兩種選擇,配置現(xiàn)有的LSM模塊(如AppArmor、SELinux),或編寫(xiě)自定義內(nèi)核模塊。

Linux Kernel 5.7[^3^ ]引入了第三種方式:LSM擴(kuò)展伯克利包過(guò)濾器^[4]^ (eBPF)(簡(jiǎn)稱BPF LSM)。LSM BPF允許開(kāi)發(fā)人員編寫(xiě)自定義策略,而無(wú)需配置或加載內(nèi)核模塊。LSM BPF程序在加載時(shí)被驗(yàn)證,然后在調(diào)用路徑中,到達(dá)LSM鉤子時(shí)被執(zhí)行。

實(shí)踐出真知

命名空間命名空間

現(xiàn)代操作系統(tǒng)提供了允許對(duì)內(nèi)核資源進(jìn)行的工具。例如FreeBSD有,Solaris有。Linux不一樣,提供了一組看似獨(dú)立的工具,每個(gè)進(jìn)程都允許隔離特定的資源。他就是,經(jīng)過(guò)多年來(lái)不停迭代,孕育了、、應(yīng)用。大部分是沒(méi)有爭(zhēng)議的,如UTS命名空間,它允許主機(jī)系統(tǒng)隱藏主機(jī)名和時(shí)間。其他的則比較復(fù)雜但簡(jiǎn)單明了————眾所周知,NET和NS(mount)命名空間很難讓人理解。最后,還有一個(gè)非常特殊、非常有趣的。partitioning``jails``zones``Namespaces``Docker``lxc``firejail``Namespaces``USER Namespaces

USER Namespaces很特別,因?yàn)樗试S所有者作為操作。其工作原理超出了本文的范圍,但是,可以說(shuō)它是讓等工具不作為真正的root操作,或者說(shuō)是容器。root``Docker``rootless

由于其特性,允許未授權(quán)用戶訪問(wèn)總是會(huì)帶來(lái)很大的安全風(fēng)險(xiǎn)。其中最大的風(fēng)險(xiǎn)是。USER Namespaces``提權(quán)

提權(quán)原理

提權(quán)是操作系統(tǒng)的常見(jiàn)攻擊面。user獲得權(quán)限的一種方法是通過(guò)unsharesyscall[5]將其命名空間映射到空間,并指定標(biāo)志。這會(huì)告訴創(chuàng)建一個(gè)具有完全權(quán)限的新用戶命名空間,并將新用戶和Group ID映射到以前的命名空間。即使用unshare(1)[6]程序?qū)oot映射到原始命名空間:root``CLONE_NEWUSER``unshare

$?id uid=1000(fred)?gid=1000(fred)?groups=1000(fred)?… $?unshare?-rU #?id uid=0(root)?gid=0(root)?groups=0(root),65534(nogroup) #?cat?/proc/self/uid_map ?????????0???????1000??????????1

多數(shù)情況下,使用是沒(méi)有風(fēng)險(xiǎn)的,都是以較低的權(quán)限運(yùn)行。但是,已經(jīng)被用于提權(quán)了,比如CVE-2022-0492[7],那么本文就重點(diǎn)以這個(gè)場(chǎng)景為例。unshare

Syscalls clone和也很值得研究,都有的功能。但在這篇文章中,我們將重點(diǎn)關(guān)注。clone3``CLONE_NEWUSER``unshare

Debian用add sysctl to disallow unprivileged CLONE_NEWUSER by default^[8]^ 補(bǔ)丁解決了這個(gè)問(wèn)題,但它沒(méi)有被合并到源碼mainline主線中。另一個(gè)類似的補(bǔ)丁sysctl: allow CLONE_NEWUSER to be disabled嘗試合并到mainline,但被拒絕了。理由是在某些特定應(yīng)用中無(wú)法切換到該特性^[9]^ 。在控制對(duì)用戶命名空間的訪問(wèn)[^10]^ 一文中,作者寫(xiě)道:

...目前的補(bǔ)丁似乎沒(méi)有一條通往mainline主線的捷徑。

如你所示,補(bǔ)丁最終沒(méi)有包含到vanilla內(nèi)核^[11]^ 中。

我們的解決方案LSM BPF

基于上面一些經(jīng)驗(yàn),可以看到限制的代碼似乎行不通,我們決定使用來(lái)規(guī)避這些問(wèn)題。并且不需要修改內(nèi)核,還可以自定義檢測(cè)防御的規(guī)則。USER Namespaces``LSM BPF

尋找合適的候選鉤子

首先,讓我們跟蹤我們的目標(biāo)系統(tǒng)調(diào)用。我們可以在include/linux/syscalls.h^[12]^ 文件中找到原型。

/*?kernel/fork.c?*/

很清晰得看到,在kernel/fork.c^[13]^ 文件中,注釋部分中留下了下一個(gè)位置的線索。在ksys_unshare()^[14]^ 那里調(diào)用。深入研究該函數(shù),發(fā)現(xiàn)了一個(gè)對(duì)unshare_userns()^[15]^ 的調(diào)用。這讓我看到了希望。

現(xiàn)在,我們已經(jīng)確定了syscall實(shí)現(xiàn),但是接下來(lái)的問(wèn)題是用哪些鉤子?怎么選擇合適的鉤子?

從man-pages[16]中了解到unshare用于改變,那么,我們重點(diǎn)關(guān)注include/linux/lsm_hooks.h[17]中的關(guān)于的鉤子。在函數(shù)unshare_userns()[18]中,可以找到對(duì)prepare_creds()[19]的調(diào)用。對(duì)于cred_prepare[20]的HOOK來(lái)說(shuō)看上去不錯(cuò)。為了驗(yàn)證對(duì)prepare_creds()[21]的理解是否正確,接下來(lái)繼續(xù)分析security_prepare_creds()[22]的調(diào)用,可以確認(rèn),其最終會(huì)調(diào)用這個(gè)HOOK:task``task

… rc?=?call_int_hook(cred_prepare,?0,?new,?old,?gfp); …

暫不過(guò)多討論這個(gè)問(wèn)題,現(xiàn)在能確認(rèn)的是這個(gè)HOOK比較合適,因?yàn)檎迷谥械闹氨徽{(diào)用,而unshare_userns()[23]是我們?cè)噲D阻止的操作。prepare_creds()``unshare_userns()``create_user_ns()

LSM BPF解決方案

我們將使用eBPF編譯一次到處運(yùn)行(CO-RE)^[24]^ 的方法對(duì)代碼進(jìn)行編譯。在不同版本內(nèi)核的IDC中,會(huì)特別適用。(不過(guò),國(guó)內(nèi)外大部分五至十年的互聯(lián)網(wǎng)公司,都有著大量低于5.0的內(nèi)核版本)。本文的演示,將只對(duì)x86_64 CPU架構(gòu)系統(tǒng)驗(yàn)證。ARM64的LSM BPF仍在開(kāi)發(fā)中。你可以訂閱BPF郵件列表^[25]^ 來(lái)了解最新進(jìn)展。

此解決方案在上進(jìn)行了測(cè)試,配置如下:Kernel Version >=5.15

BPF_EVENTS BPF_JIT BPF_JIT_ALWAYS_ON BPF_LSM BPF_SYSCALL BPF_UNPRIV_DEFAULT_OFF DEBUG_INFO_BTF DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT DYNAMIC_FTRACE FUNCTION_TRACER HAVE_DYNAMIC_FTRACE

如果CONFIG_LSM列表中不包含,則需要你自己重新編譯,并開(kāi)啟選項(xiàng).bpf``lsm=bpf

內(nèi)核空間代碼

開(kāi)始看內(nèi)核空間代碼::deny_unshare.bpf.c

#include?<linux/bpf.h> #include?<linux/capability.h> #include?<linux/errno.h> #include?<linux/sched.h> #include?<linux/types.h> #include?<bpf/bpf_tracing.h> #include?<bpf/bpf_helpers.h> #include?<bpf/bpf_core_read.h> #define?X86_64_UNSHARE_SYSCALL?272 #define?UNSHARE_SYSCALL?X86_64_UNSHARE_SYSCALL

共產(chǎn)

接下來(lái),我們以下列方式為CO-RE重新定位建立必要的結(jié)構(gòu)::deny_unshare.bpf.c

… typedef?unsigned?int?gfp_t; struct?pt_regs?{ ?long?unsigned?int?di; ?long?unsigned?int?orig_ax; }?__attribute__((preserve_access_index)); typedef?struct?kernel_cap_struct?{ ?__u32?cap[_LINUX_CAPABILITY_U32S_3]; }?__attribute__((preserve_access_index))?kernel_cap_t; struct?cred?{ ?kernel_cap_t?cap_effective; }?__attribute__((preserve_access_index)); struct?task_struct?{ ????unsigned?int?flags; ????const?struct?cred?*cred; }?__attribute__((preserve_access_index)); char?LICENSE[]?SEC("license")?=?"GPL"; …

用戶空間

加載程序并將其附加到目標(biāo)的鉤子上是用戶空間的功能。有幾種方法可以做到這一點(diǎn):

  1. Cilium ebpf^[26]^ 項(xiàng)目

  2. 防銹裝訂^[27]^

  3. ebpf.io[28]項(xiàng)目展示的其他類庫(kù)landscape

這里,我們將使用原生libbpf^[29]^ 。

#include?<bpf/libbpf.h> #include?<unistd.h> #include?"deny_unshare.skel.h" static?int?libbpf_print_fn(enum?libbpf_print_level?level,?const?char?*format,?va_list?args) { ????return?vfprintf(stderr,?format,?args); } int?main(int?argc,?char?*argv[]) { ????struct?deny_unshare_bpf?*skel; ????int?err; ????libbpf_set_strict_mode(LIBBPF_STRICT_ALL); ????libbpf_set_print(libbpf_print_fn); ????//?Loads?and?verifies?the?BPF?program ????skel?=?deny_unshare_bpf__open_and_load(); ????if?(!skel)?{ ????????fprintf(stderr,?"failed?to?load?and?verify?BPF?skeleton\n"); ????????goto?cleanup; ????} ????//?Attaches?the?loaded?BPF?program?to?the?LSM?hook ????err?=?deny_unshare_bpf__attach(skel); ????if?(err)?{ ????????fprintf(stderr,?"failed?to?attach?BPF?skeleton\n"); ????????goto?cleanup; ????} ????printf("LSM?loaded!?ctrl+c?to?exit.\n"); ????//?The?BPF?link?is?not?pinned,?therefore?exiting?will?remove?program ????for?(;;)?{ ????????fprintf(stderr,?"."); ????????sleep(1); ????} cleanup: ????deny_unshare_bpf__destroy(skel); ????return?err; }

生成文件

最后,進(jìn)行編譯,這里使用Makefile

CLANG??=?clang-13 LLVM_STRIP??=?llvm-strip-13 ARCH?:=?x86 INCLUDES?:=?-I/usr/include?-I/usr/include/x86_64-linux-gnu LIBS_DIR?:=?-L/usr/lib/lib64?-L/usr/lib/x86_64-linux-gnu LIBS?:=?-lbpf?-lelf .PHONY:?all?clean?run all:?deny_unshare.skel.h?deny_unshare.bpf.o?deny_unshare run:?all ?sudo?./deny_unshare clean: ?rm?-f?*.o ?rm?-f?deny_unshare.skel.h # #?BPF?is?kernel?code.?We?need?to?pass?-D__KERNEL__?to?refer?to?fields?present #?in?the?kernel?version?of?pt_regs?struct.?uAPI?version?of?pt_regs?(from?ptrace) #?has?different?field?naming. #?See:?https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fd56e0058412fb542db0e9556f425747cf3f8366 # deny_unshare.bpf.o:?deny_unshare.bpf.c ?$(CLANG)?-g?-O2?-Wall?-target?bpf?-D__KERNEL__?-D__TARGET_ARCH_$(ARCH)?$(INCLUDES)?-c?$<?-o?$@ ?$(LLVM_STRIP)?-g?$@?#?Removes?debug?information deny_unshare.skel.h:?deny_unshare.bpf.o ?sudo?bpftool?gen?skeleton?$<?>?$@ deny_unshare:?deny_unshare.c?deny_unshare.skel.h ?$(CC)?-g?-Wall?-c?$<?-o?$@.o ?$(CC)?-g?-o?$@?$(LIBS_DIR)?$@.o?$(LIBS) .DELETE_ON_ERROR:

結(jié)果

打開(kāi)一個(gè)新終端,運(yùn)行命令

$?make?run … LSM?loaded!?ctrl+c?to?exit.

在另一個(gè)終端里,可以看到成功的被阻止了。

$?unshare?-rU unshare:?unshare?failed:?Cannot?allocate?memory $?id uid=1000(fred)?gid=1000(fred)?groups=1000(fred)?…

這個(gè)策略有個(gè)附加的特性,可以允許傳遞授權(quán)。

$?sudo?unshare?-rU #?id uid=0(root)?gid=0(root)?groups=0(root)

在無(wú)特權(quán)場(chǎng)景中,系統(tǒng)調(diào)用會(huì)提前中止。有特權(quán)情況下的性能影響是什么?

性能對(duì)比

我們將使用一行unshare命令來(lái)映射用戶命名空間,并在中執(zhí)行一個(gè)命令來(lái)進(jìn)行測(cè)量:

$?unshare?-frU?--kill-child?--?bash?-c?"exit?0"

使用系統(tǒng)調(diào)用unshare enter/exit的CPU周期分辨率,我們將以root用戶身份測(cè)量以下內(nèi)容:

  1. 命令在沒(méi)有策略的情況下運(yùn)行

  2. 與策略一起運(yùn)行的命令

我們將使用ftrace^[30]^ 記錄測(cè)量結(jié)果:

$?sudo?su #?cd?/sys/kernel/debug/tracing #?echo?1?>?events/syscalls/sys_enter_unshare/enable?;?echo?1?>?events/syscalls/sys_exit_unshare/enable

此時(shí),我們將專門(mén)為unshare啟用對(duì)系統(tǒng)調(diào)用的跟蹤?,F(xiàn)在,我們?cè)O(shè)置調(diào)用的來(lái)計(jì)算CPU周期:enter/exit``enter/exit``time-resolution

#?echo?'x86-tsc'?>?trace_clock?

接下來(lái),我們開(kāi)始評(píng)測(cè)

#?unshare?-frU?--kill-child?--?bash?-c?"exit?0"?& [1]?92014

在新終端里運(yùn)行策略,執(zhí)行下一個(gè)syscall

#?unshare?-frU?--kill-child?--?bash?-c?"exit?0"?& [2]?92019

現(xiàn)在,我們收集到兩種CALLS結(jié)果進(jìn)行對(duì)比

# cat trace # tracer: nop # # entries-in-buffer/entries-written: 4/4 ? #P:8 # # ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?_-----=> irqs-off # ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? / _----=> need-resched # ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| / _---=> hardirq/softirq # ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|| / _--=> preempt-depth # ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?||| / _-=> migrate-disable # ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|||| / ? ? delay # ? ? ? ? ? TASK-PID ? ? CPU# ?||||| ?TIMESTAMP ?FUNCTION # ? ? ? ? ? ? ?| | ? ? ? ? | ? ||||| ? ? | ? ? ? ? | ? ? ? ? unshare-92014 ? [002] ..... 762950852559027: sys_unshare(unshare_flags: 10000000) ? ? ? ? unshare-92014 ? [002] ..... 762950852622321: sys_unshare -> 0x0 ? ? ? ? unshare-92019 ? [007] ..... 762975980681895: sys_unshare(unshare_flags: 10000000) ? ? ? ? unshare-92019 ? [007] ..... 762975980752033: sys_unshare -> 0x0

分別是:

  • unshare-92014 使用了 63294 個(gè)周期。

  • 取消共享-92019 使用了 70138 個(gè)周期。

可以看到二者之間有6,844(~10%)個(gè)周期的差異,還行。

兩次測(cè)量之間有6,844(~10%)個(gè)周期損失。不錯(cuò)嘛!

這些數(shù)字是針對(duì)單個(gè)系統(tǒng)調(diào)用的,代碼調(diào)用的頻率越高,這些數(shù)字就越多。Unshare通常在任務(wù)創(chuàng)建時(shí)調(diào)用,在程序的正常執(zhí)行期間不會(huì)重復(fù)調(diào)用。對(duì)于你的場(chǎng)景,需要仔細(xì)考慮評(píng)估。

結(jié)尾

我們了解了是什么,如何使用unshare將映射到,以及如何通過(guò)在eBPF中實(shí)現(xiàn)程序來(lái)解決真實(shí)場(chǎng)景的問(wèn)題。跟蹤準(zhǔn)確的鉤子不是一件容易的事,需要有豐富的經(jīng)驗(yàn),以及豐富的內(nèi)核代碼經(jīng)驗(yàn)。這些一個(gè)策略代碼是用C語(yǔ)言編寫(xiě)的,所以我們可以根據(jù)因地制宜,不同的問(wèn)題做不同的策略,代碼經(jīng)過(guò)輕微調(diào)整,就可以快速擴(kuò)展,增加其他鉤子點(diǎn)等。最后,我們對(duì)比了這個(gè)LSM程序的性能影響,性能與安全的權(quán)衡,是你需要考慮的問(wèn)題。LSM BPF``user``root

Cannot allocate memory(無(wú)法分配內(nèi)存)不是拒絕權(quán)限的最準(zhǔn)確的描述。我們提出了一個(gè)補(bǔ)丁[31],用于將錯(cuò)誤代碼從掛鉤傳到調(diào)用堆棧。cred_prepare

最后,我們的結(jié)論就是鉤子非常適合實(shí)時(shí)修復(fù)Linux內(nèi)核漏洞.

原文作者:Linux內(nèi)核之旅



教你使用eBPF LSM熱修復(fù)Linux內(nèi)核漏洞的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
津市市| 普定县| 阿鲁科尔沁旗| 灵山县| 郓城县| 龙陵县| 新乡市| 宜丰县| 乐业县| 唐海县| 裕民县| 满洲里市| 姜堰市| 马鞍山市| 牙克石市| 大丰市| 桑日县| 钟祥市| 始兴县| 萝北县| 芦溪县| 阿巴嘎旗| 潼南县| 定西市| 龙门县| 抚顺市| 栾川县| 庆阳市| 滦南县| 云霄县| 琼结县| 会昌县| 宜兴市| 灯塔市| 三门峡市| 亳州市| 勐海县| 桦南县| 漳州市| 万宁市| 威信县|