Linux Namespaces in operation記錄 - part 6

:本文絕大部分內容來自Linux Namespaces實踐part 6,原文系列文章詳細描述了Linux Namespace相關內容,英語過關的建議閱讀原文,本文內容主要用來記錄學習內容,如有不當之處還請評論區指正。

User Namespace 與 capabilities

  • User Namespace
    • 每個進程都關聯一個User Namespace
    • fork或無CLONE_NEWUSER標誌的clone函數創建的子進程,其User Namespace與父進程相同
    • 擁有CAP_SYS_ADMIN的進程通過setns函數可以更改其User Namespace,並獲得該User Namespace中的所有權限
    • clone(CLONE_NEWUSER)使子進程運行在在新User Namespace中,並建立相關的父子關係
    • init外,其它User Namespace皆有一個父User Namespace
    • unshare(CLONE_NEWUSER)也創建新User Namespace,與clone不同,unshare將當前進程放在新創建的User Namespace,新創建的Namespace爲當前進程之前Namespace的子代
    • User Namespace的父子關係決定了一個子Namespace所擁有的的權限
  • capabilities
    • 每個進程關聯三個capabilities集合: permitted, effective, inheritable,詳見capabilities
    • 特定User Namespace中,進程只能在該Namespace管理的資源上進行操作
    • 一個進程是否有某項權限取決於其在該Namespace的地位以及Namespace的父子關係,規則如下
      1. 如果一個進程位於Namespace中,則該進程擁有其effective capability set中的權限。進程可以通過多種方式獲得capabilities,一種方式(emmm沒懂): *The most common reasons are that it executed a program that conferred capabilities (a set-user-ID program or a program that has associated file capabilities)*或者該進程是clone(CLONE_NEWUSER)的執行函數
      2. 如果進程在一個User Namespace中擁有某項權限,那麼它的所有子Namespace也有該權限。
      3. 進程創建User Namespace時,內核會記錄該進程的有效用戶ID(effective user ID)作爲創建的Namespace的"所有者(owner)"。如果一個進程的有效用戶ID與一個Namespace的相同,並且是位於其父Namespace中,則該進程在這個Namespace中擁有所有權限。

一個栗子

本例使用了userns_setns_test.c以及userns_child_exec.c,大致過程如下:

  1. 使用userns_child_exec.c程序創建User Namespace並在其中運行ksh程序
  2. 查看步驟1創建的ksh的PID,得到路徑/proc/PID/ns/user/
  3. 將步驟2得到的路徑作爲參數傳遞給userns_setns_test.c,該程序會在新User Namespace中創建子進程,並通過setns,嘗試將父、子進程加入到kshUser Namespace

步驟及輸出:

  1. 在終端中執行下列命令查看輸出
    $ id -u
    1000
    $ readlink /proc/$$/ns/user       # Obtain ID for initial   namespace
    user:[4026531837]
    $ ./userns_child_exec -U -M '0 1000 1' -G '0 1000 1' ksh
    ksh$ echo $$                      # Obtain PID of shell
    528
    ksh$ readlink /proc/$$/ns/user    # This shell is in a new   namespace
    
  2. 切換到另一個終端執行如下命令查看輸出
    $ readlink /proc/$$/ns/user       # Verify that we are in parent namespace
    user:[4026531837]
    $ ./userns_setns_test /proc/528/ns/user
    parent: readlink("/proc/self/ns/user") ==> user:[4026531837]
    parent: setns() succeeded
    
    child:  readlink("/proc/self/ns/user") ==> user:[4026532319]
    child:  setns() failed: Operation not permitted
    

下圖展示了創建的User Namespace的父子關係:
userns_hierarchy
可以看到,userns_setns_testuserns_child_exec位於相同User Namespace中,因此在4026531838中擁有所有權限,而其子進程位於4026532319中,沒有ksh所在Namespace的權限,因此執行setns失敗。

User Namespace與其它Namespace的結合

  • User Namespace外,單獨創建其它Namespace需要CAP_SYS_ADMIN
  • 對於使用CLONE_NEWUSER標誌的clone()unshare()函數,在標誌中包含其它標誌如CLONE_NEWPID時不需要CAP_SYS_ADMIN,內核會保證CLONE_NEWUSER先執行,之後再執行其它標誌創建對應的Namespace。例如clone(child_func, stackp, CLONE_NEWUSER | CLONE_NEWUTS, arg);不需要root權限

再看capabilities

  • 儘管新User Namespace中的第一個進程擁有所有capabilities,但該進程在整個系統中並不會具有超級用戶權限
  • 當通過clone()unshare()創建一個新PIDmountnetwork等Namespace時,內核會記錄這些Namespace對應的User Namespace,並據此檢查這些Namespace對系統資源的權限
    • 例如,假設通過CLONE(CLONE_NEWUSER)創建一個新的User Namespace,那麼
    • 一方面,子進程(擁有該Namespace所有capabilities,特權用戶)能夠創建其它的的Namespace或將用戶ID或組ID更改爲其它映射到的ID
    • 另一方面,子進程無法掛載文件系統,因爲該進程位於父進程的mount Namespace中,而在該mount namespace對應的User Namespace中,子進程沒有相應的capabilities,即非特權用戶
    • 進一步來說,子進程無法執行一些需要額外的、其所在·Namespace·不包含的·capabilities·的操作,例如提升硬件資源限制、設置系統時間、設置進程屬性或加載內核模塊等

總結

通過隔離·capabilities·的影響(effect),·User Namespace·允許非特權用戶執行一些需要root身份的操作,這也給用戶空間應用程序創造了機會,例如,非特權用戶可以運行Linux containers而不需要root權限等。本文對·User Namespace·以及相關的·capabilities·作了短期的總結,接下來會介紹·network namespace·與·mount namespace·。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章