今日golang發布乙個安全版本(go 1.15.7 和go 1.14.14),解決了涉及在不受信任目錄中進行path查詢的問題cve-2021-3115,相關的問題會導致執行go get命令時遠端執行。關於該問題golang官方部落格進行了介紹,我們來學習下。
如果go get不能執行任意**,那麼其呼叫的所有程式,例如編譯器和版本控制系統,也都在安全範圍內。例如,過去曾經遇到過這樣的問題,即在版本控制系統中巧妙地使用晦澀的編譯器功能或遠端執行漏洞,導致go中的遠端執行。
所有作業系統都有乙個可執行路徑path的概念(在類unix系統上是用$path定義,windows上為%path%)。它是一些可執行檔案儲存目錄的列表。在shell提示符下輸入命令時,shell依次在列出的每個目錄中查詢具有該名稱的可執行檔案,然後執行找到的第乙個命令,如果編譯列表找不到該名稱,就會報錯 "找不到命令"。
-bash: ***: command not found
bourne shell手冊說明中:
shell引數$path定義包含命令的目錄的搜尋路徑。每個備用目錄名稱都用冒號(:)分隔。預設路徑為:/bin:/usr/bin。如果命令名稱中包含/,則不使用搜尋路徑。否則,將在path中的各個目錄中搜尋可執行檔案。
預設值:當前目錄(.)在/bin和之前列出/usr/bin。ms-dos和windows中是硬編碼了這個行為:在windows下會首先自動搜尋當前目錄(.),然後再搜尋%path%列出的目錄。
path設定的系統目錄之前先搜尋當前目錄,這樣如果cd進入目錄並執行ls,則可能會從當前目錄中執行惡意副本,而不是系統程式。而且,如果可以欺騙系統管理員以ls身份登入時,其他使用者主目錄root中執行,那麼也可以執行所需的任何**。由於這個問題和其他類似的問題,基本上所有現代*nix發行版都將預設path設定中排除當前目錄(即.)。但是,在windows中,預設是首先搜尋當前目錄(.)。例如,當輸入go version命令時,預設配置的*nix上,shell都從path中的系統目錄執行go可執行檔案。但是,在windows上鍵入輸入該命令時,cmd.exe會首先檢查當前目錄(.),如果存在.go.exe(或.go.bat等等),cmd.exe就會先執行這個可執行檔案(.go.exe),而不是path中路徑設定的系統go編譯器。
對於golang,path搜尋由exec.lookpath自動處理exec.command。為了很好地適應主機系統,goland的exec.lookpath在*nix上和windows各自通過呼叫底層的系統的規則來實現。下面的命令:
out, err := exec.command("go", "version").combinedoutput()
行為與在作業系統shell中直接執行go version命令是一樣的。
在windows上,如果當前目錄存在.go.exe,就會優先執行。
為了呼叫c編譯器,go命令需要通過系統path來查詢。但是如果在程式包源目錄中執行c編譯器時,它將從go呼叫命令的原始目錄中查詢:
cmd := exec.command("gcc", "file.c")
cmd.dir = "badpkg"
cmd.run()
因此,即使windows系統上存在badpkggcc.exe,也找不到它。exec.command進行path搜尋時候不包括badpkg目錄。
go命令使用類似的**來呼叫cgo,但是不會有路徑查詢,因為cgo總是來自於goroot:
cmd := exec.command(goroot+"/pkg/tool/"+goos_goarch+"/cgo", "file.go")
cmd.dir = "badpkg"
cmd.run()
這第一段**看起來更加安全,沒有執行存在的問題的cgo.exe可能。
但是,實際上cgo本身還需要在它建立的某些臨時檔案上呼叫宿主的c編譯器,這樣,它還要執行以下**:
cmd := exec.command("gcc", "tmpfile.c")
cmd.run()
由於cgo執行時,當前目錄就是badpkg,而不是go執行命令的目錄,因此如果badpkggcc.exe存在,就會被呼叫執行,而不會再去path中查詢系統的gcc。
*nix系統由於從根本上就不包括當前目錄,所以不會受到影響。並且由於golang模組解包時不會對其寫入的檔案設定執行位,所以預設是無法執行的。
但是,如果系統設定時候,手動path中增加"."路徑,並且使用gopath模式的使用者也會受到影響。
乙個可能的解決方法:由於cgo在不受信任的源目錄中而不是在go呼叫命令的目錄中c編譯器,這會導致問題。那麼解決我們通過更改go命令,將cgo完整路徑傳遞給主機c編譯器,讓cgo無需在不受信任的目錄中進行path查詢。
由於問題出在path查詢時候的查詢當前路徑(.),無論在windows上自動發生還是由於在*nix系統上顯式的設定當前路徑(.)的path。使用者可能希望在當前目錄中查詢以找到在控制台或shell程式視窗中鍵入的命令,但是一般不會希望查詢鍵入的命令的子命令。那麼解決方法就是更改cgo 的path查詢過程中不包括當前目錄(.)。
golang的新版本中對這兩方面都予以了修復。go命令會把完整的主機c編譯器路徑傳遞給cgo。最重要的是,go和cgo轉到命令現在使用的乙個變種os/exec,如果將以前使用的當前目錄(.)的可執行檔案,會報錯誤。這些go程式包go/build命令和其他工具go/import使用相同的策略。出於謹慎考慮,還對諸如goimports和gopls命令以及golang.org/x/tools/go/analysis和golang.org/x/tools/go/packages庫進行了類似的修復,這些庫將命令作為子程序呼叫。
更新到新的go版本後,可以gopls使用以下方法更新到最新版本:
go111module=on
go get golang.org/x/tools/[email protected]
使用以下方法更新到最新版的goimports工具或其他工具:
go111module=on
go get golang.org/x/tools/cmd/[email protected]
在golang.org/x/tools/go/packages通過在以下過程中新增對依賴關係的顯式公升級來更新依賴於的程式:
go111module=on
go get golang.org/cmd/thecmd golang.org/x/[email protected]
對於使用的程式,go/build 就可以使用更新的go版本重新編譯它們。
同樣,僅當是windows使用者或*nix使用者且path中手動設定了.並且在不信任的源目錄中執行這些程式(可能包含惡意程式)時,才需要更新這些程式。
如果**中使用了exec.lookpath或exec.command,則需要關注在不受信任內容的目錄中執行程式。可以使用os/execas替換:
import "os/exec"
與import exec "golang.org/x/sys/execabs"
並重新編譯。
c 中 p a和p a的區別
大學初學指標的時候,時常懵逼,有時候覺得自己已經掌握了,但是一看複雜的程式和原始碼裡的指標用法,就又蒙了,以至於談指標色變。至於二級指標,陣列指標 指標陣列 函式指標什麼的更是被嚇懵。現在來逐個擊破他們,為我們的程式設計道路掃清阻礙。首先需要明白一點的是,指標是個變數,它和int型別 float型別...
關於gopath go111module的坑
使用 go env 檢視go的環境變數 go path 顯示go的路徑,一般go的模組會安裝到該路徑下 go111module 是否使用模組支援的變數,如果設為off 代表無模組支援,import的包會從gopath下尋找。如果設為on,代表模組支援,會忽略gopath,在go.mod中尋找依賴。所...
p a 與 int p a 的區別
int a int p a 將整形變數a的位址放入指標p中。int a 1 int p a 將陣列a的首位址放入指標p中。int p之後是位址變數。int p int a 1 include int main int p int a 1 a表示整個陣列的位址 printf d d a 1 p 1 輸...