為什麼在Docker裡使用gdb偵錯程式會報錯
背景
前幾天一個小夥伴發郵件問我,他在docker內部使用gdb除錯時刻遇到了gdb如下報錯資訊ptrace:Operation not permitted
當時我的答覆是在docker create或者docker run時刻開啟萬精油–privileged引數。小夥伴的問題就此解決了。
但是事實並非如此簡單
Docker上涉及到gdb除錯許可權的特性
capabilities
Docker借用了linux對程式設定capabilities,而其子程式繼承父程式capabilites特性來完成對容器capacities的控制。Docker
create和docker run引數中有下面兩個引數可以對容器預設的capabilites進行修改:--cap-add //新增某個capabilites屬性 --cap-del //剔除某個預設的capabilites屬性
cap-add和cap-del可以設定的引數可以通過下面連結查詢到:
https://docs.docker.com/engine/reference/commandline/run/
- Docker 將gdb除錯需要SYS_PTRACE屬性被禁止掉了,所以gdb在除錯的時候會顯示ptrace被禁止。所以想在docker內部除錯gdb解決辦法就是create和run的時候帶上–cap-add sys_ptrace*
例如:
docker run -it --cap-add sys_ptrace centos:latest /bin/bash
root@7f5a2130e975>cd /home/
root@7fa2130e975> vi test.c
#include <stdio.h>
int main(){
int i = 0;
printf(“Testing begin
”);
While(1){
printf(“Loop cnt:%d
”,i++);
sleep(10);
}
}
root@7fa2130975>gcc -c -g -o test.o test.c
root@7fa2130975>gcc -o test -g test.o
root@7fa2130975>./test&
[1] 18
root@7fa2130975>gdb attach 18
//ok可以除錯了
但是這並不是問題的全部,對於上述測試程式,如果執行下面命令gdb又有告警出來
root@7fa2130975>gdb ./test
(gdb) r
Warning:Error disabling address space randomization:Operation not permitted
雖然依然可以除錯,但是我們還是需要搞清楚上述告警的意思。地址隨機化是linux一項安全特性,它允許核心程式啟動每次載入庫的時候都在隨機化的分佈在程式虛擬記憶體地址空間上(早期固定的庫要載入到固定地方,如果固定地方被佔用才載入到別地方。會造成多次載入程式,其庫地址都不變。如此有安全隱患)。在gdb除錯中gdb預設需要關閉linux的地址隨機化功能,可以通過gdb
命令set disable-randomization off關閉。如果在地址隨機化下除錯同一段程式,多次run時候可以看到它的執行地址和函式地址不一致,這沒有什麼太大的問題。問題可以結束了
關於gdb 設定地址隨機化開關詳情見下面連結:
http://visualgdb.com/gdbreference/commands/set_disable-randomization
當然上述告警其實也可以不通過gdb設定來完成,可以通過下面介紹的Docker引數可以達成。
seccomp
Docker預設情況下為每個容器都設定了一個預設的seccom profile。一般情況下無需修改。但是docker依然支援
docker create或者docker run時候通過–security-opt seccomp=xxx引數來設定docker容器的seccomp策略。
xxx可以是一個json格式檔案,裡面定義了docker容器每個具體的seccomp規則。也可以是字元unconfined表示關閉預設的docker seccomp 規則。
可以通過下面命令徹底關閉docker預設seccomp引入的任何限制docker run -it --security-opt seccomp=unconfined centos:lastes
在執行上述gdb 除錯命令run一個程式,告警資訊終於徹底消失了。
Docker設定的seccomp 預設profile規則可以通過如下連結查詢到:
https://docs.docker.com/engine/security/seccomp/
本文就不再做詳細展開了。
Docker背後的實現技術
Docker實現seccomp控制
從Linux
2.6.23開始支援這種特性對程式能夠使用的系統呼叫進行控制,如此可以進行一些安全性策略。sandbox就是依賴於此技術。docker梳理了Linux的系統呼叫,從300+個系統呼叫中遮蔽掉了44個系統呼叫,但是又最大程度的不影響正常的應用使用系統。
- 在Docker
engine上有一個叫seccomp模組提供了為docker提供預設seccomp規則(GetDefaultProfile()函式),而我們在命令列配置的seccomp屬性會覆蓋預設的seccomp規則(在setSeccomp()函式裡)。最終規則在engine內部建立runc
spec時刻函式createSpec生產。將seccomp傳遞到oci runtime spec的spec.linux.seccomp欄位裡。 - 而runc通過seccomp庫的InitSeccomp()函式,在Init一個容器時刻和exec觸發的將一個程式setns到容器內部時刻呼叫此函式 將seccomp屬性設定到容器的init程式或者exec程式裡。
- Linux程式屬性裡有seccomp屬性,此屬性也會父子繼承,通過/proc/$pid/status裡可以看到程式的seccomp屬性。
Docker實現capabilities
從Linux
2.1開始支援的特性,將超級使用者的許可權劃分為多個組,每個程式都有一個capabilities屬性,子程式從自己的父程式中基礎capacities。這個特性和sudo不一樣,因為sudo控制粒度太粗;而capabilities控制粒度很精細。linux有一系列的呼叫可以設定、檢視,清除和比較程式的capabilities。可以通過:man cap_set_flag
來檢視這一系列的系統呼叫。而具體程式的capacities可以通過/proc/$pid/status中:
Capxxx欄位看到,本文就不再展開。感興趣的朋友可以參考
https://www.cnblogs.com/iamfy/archive/2012/09/20/2694977.html
- 在oci runtime
spec裡規定了spec.Process.Capabilities屬性。runc中finializeNamespace()根據此屬性對程式的capabilities進行設定。此函式會在init容器和exec加一個程式到容器時刻呼叫。
相關文章
- 在Docker內部使用gdb偵錯程式報錯-Operation not permittedDockerMIT
- 如何在Docker內部使用gdb偵錯程式Docker
- 使用GDB命令列偵錯程式除錯C/C++程式命令列除錯C++
- GDB偵錯程式(學習筆記)筆記
- 5 個鮮為人知 GNU 偵錯程式(GDB)技巧
- Linux gdb偵錯程式用法全面解析Linux
- Linux下彙編偵錯程式GDB的使用薦Linux
- linux下的c/c++偵錯程式gdbLinuxC++
- pytest.main () 為什麼會報錯?AI
- 在MacOS上使用gdb(cgdb)除錯Golang程式Mac除錯Golang
- 幽默:編寫Python程式碼你們使用什麼偵錯程式?Python
- 使用 GDB 除錯多程式程式除錯
- PsySH作為偵錯程式
- GDB程式碼除錯與使用除錯
- 微信偵錯程式
- Linux中使用GDB除錯程式Linux除錯
- GDB 除錯程式碼除錯
- gdb除錯多程式除錯
- 用GDB除錯程式除錯
- GDB多程式除錯除錯
- 在海思晶片上使用GDB遠端除錯晶片除錯
- 什麼是Docker?為什麼使用docker?Docker
- hashmap遍歷時用map.remove方法為什麼會報錯?HashMapREM
- 偵錯程式工作原理(三):除錯資訊除錯
- 偵錯程式工作原理(3):除錯資訊除錯
- 用GDB除錯程式(六)除錯
- GDB除錯使用記錄除錯
- 使用 gdb 工具除錯 Go除錯Go
- Xcode偵錯程式LLDBXCodeLLDB
- go語言偵錯程式Go
- Linux GDB 程式除錯工具使用詳解Linux除錯
- Rails開發中使用byebug偵錯程式AI
- 請你解釋一個為什麼10.toFixed(10)會報錯?
- Emacs 除錯祕籍之 GUD 偵錯程式Mac除錯
- 反除錯 -- 利用ptrace阻止偵錯程式附加除錯
- JS 裡為什麼會有 thisJS
- gdb除錯除錯
- vi/vim使用進階: 在VIM中使用GDB除錯 – 使用vimgdb除錯