Linux kernel · Security

seccomp 學習筆記

近年來由於 IoT 風潮帶來萬物皆連網, 但隨之而來的就是 萬物皆可攻擊” 的安全議題

下圖 [1] 為 1999 ~ 2017 年 CVE (Common Vulnerabilities and Exposures) 統計 (CVE 收集各種資訊安全弱點及漏洞並供大眾查閱) 可以看到這幾年 CVE 數量明顯增加.

2017-08-17_150730.png

程式有安全漏洞在所難免, 即便開發者具備良好的程式技巧跟心態, 還是有機會出現安全漏洞, 導致系統被有心人士攻擊入侵. 所以事後的防護就很重要, seccomp 就是為此而產生


seccomp 設計宗旨:

指定 process 只能呼叫特定的 system call 

以 Linux kernel 為例, 其提供的 system call 就有上百種 . 但大部份 system call 都不會被 process 所使用. 透過設定 seccomp 除了不影響原本執行結果, 也能降低一旦 process 遭受攻擊對整體系統造成的影響.


seccomp 在 Linux 上的實作:

首先需開啟 kernel 選項, 確保下列設定已選取

  • CONFIG_SECCOMP=y
  • CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
  • CONFIG_SECCOMP_FILTER=y

1

 

seccomp 實作共分成兩種模式

1. Strict mode
√ kernel space: 

若 process 設成 strict mode, 只能呼叫下列四種 system calls. 其他 system calls 會收到 SIGKILL signal

  • read
  • write
  • _exit (不含 exit_group)
  • sigreturn

相關實作在 kernel/seccomp.c 中. 如下圖所示

2017-08-17_172155.png

若 seccomp 模式為 strict, 則只會設定之前提到的四種 system calls 進白名單.

未命名.png

最後會呼叫位於 kernel/auditsc.c 中的 audit_seccomp 來進行 system-call auditing

user space: 

可使用 prctl 或者 seccomp (kernel 版本需大於 3.17) 函式, 兩者等價, 皆可設定成 strict 模式

2017-08-17_174425
2017-08-17_174417

 

2. Filter mode [5]
√ kernel space: 

在此模式下, 允許使用 BPF [8] 來設定黑名單或者白名單. 若白名單中允許 fork 以及 clone system call, 則此 process 的 child process 一律繼承 parent process 原有的 system call filters.

設定此模式 caller 需具備 CAP_SYS_ADMIN 的屬性或者 thread 必須設定 no_new_privs [9]. 若 thread 尚未設定, 可透過 prctl(PR_SET_NO_NEW_PRIVS, 1);  來啟動設定. 否則 SECCOMP_SET_MODE_FILTER 會回傳錯誤. 透過這些設定可確保無特權的 process 無法新增惡意 filters 並且執行 execve system call.

no_new_privs 是 kernel 3.5 之後才加入的功能, 一旦啟動設定, 則所有透過 fork, clone, 以及 execve 執行產生的 process 皆繼承 parent process 權限. 避免因為 execve 允許執行的程式權限大於 parent 而造成一些安全漏洞.

相關實作在 kernel/seccomp.c 中. 如下圖所示

2017-08-22_175444.png

user space: 

可使用 prctl 或者 seccomp (kernel 版本需大於 3.17) 函式, 兩者等價, 皆可設定成 filters 模式

  • seccomp(SECCOMP_SET_MODE_FILTER, 0, args);
  • prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, args);

seccomp filter 回傳 32-bit 大小的值, 前 16-bit 為 SECCOMP_RET_ACTION, 後 16-bit 為 SECCOMP_RET_DATA 

1. SECCOMP_RET_ACTION – kernel 執行特定行為

seccomp filter 則定義數種行為如下:

  • SECCOMP_RET_KILL – 不執行 system call, 立即中止 process (SIGSYS)
  • SECCOMP_RET_TRAP – 不執行 system call,  process 送出 (SIGSYS) system call, 並且將 system call 相關資訊儲存至 siginfo_t [11]
  • SECCOMP_RET_ERRNO – 不執行 system call, SECCOMP_RET_DATA 回傳 errno
  • SECCOMP_RET_TRACE – 會驅動 ptrace base 的 tracer (如gdb), 讓 tracer 可以來接手處理. 若沒有相關 tracer 則回傳 -ENOSYS
  • SECCOMP_RET_ALLOW – system call 正常執行

若同時符合多個條件, SECCOMP_RET_ACTION 則只會回傳優先權較高的值.

2. SECCOMP_RET_DATA – 回傳值

 

Filter mode 下的寫法複雜許多, 需要瞭解並撰寫 BPF instructions. 可參考 kernel source: samples/seccomp/  [10] 底下, 有許多 seccomp filter 相關範例.


查詢 Process 是否已設定 seccomp:

可透過 /proc/<pid>/status 來查詢該 process 的 seccomp 模式

  • 0: 尚未啟動
  • 1: 啟用 “STRICT” 模式
  • 2: 啟用 “FILTER” 模式

如下圖所示, 此 process 尚未啟動 seccomp


使用時機:

√ 建置沙盒

建置沙盒 (sandbox) 的隔離環境, 限定隔離環境中的應用程式只能執行特定 system calls, 避免應用程式遭攻擊時影響整個系統.

√ 建立測試環境

可用來建立測試應用程式環境, 限定隔離環境中的應用程式只能執行特定 system calls, 避免應用程式錯誤發生而影響整個系統

 


注意事項:

使用 filter mode 時, 須注意實際機器的 CPU  architecture .  因為不同 CPU 架構的 system call number 可能相異, 一不注意會造成問題.

 


心得:

“Software Bugs Will Always Exist”

使用 seccomp 來限制特定 process 的權限, 即便程式出了問題, 也能將整體系統的傷害降到最低. 不過 BPF 的寫法較為複雜, 這邊要小心處理, 避免 filter 無法作動.

 


References:

[1]: http://www.cvedetails.com/browse-by-date.php

[2]: http://elixir.free-electrons.com/linux/latest/source/arch/arm/tools/syscall.tbl

[3]: http://kernsec.org/files/lss2015/seccomp.pdf

[4]: http://man7.org/conf/lpc2015/limiting_kernel_attack_surface_with_seccomp-LPC_2015-Kerrisk.pdf

[5]: https://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt

[6]: https://lwn.net/Articles/656307/

[7]: http://man7.org/linux/man-pages/man2/seccomp.2.html

[8]: https://www.kernel.org/doc/Documentation/networking/filter.txt

[9]: https://www.kernel.org/doc/Documentation/prctl/no_new_privs.txt

[10]: http://elixir.free-electrons.com/linux/latest/source/samples/seccomp/

[11]: http://man7.org/linux/man-pages/man2/sigaction.2.html

發表迴響