透過 exec 傳遞能力

透過 exec 傳遞能力

我試圖了解 Linux 功能如何傳遞給已exec()被另一個進程處理的進程。根據我的閱讀,為了在 exec 之後保留某個功能,它必須位於可繼承集中。但我不確定該集合是如何填充的。

我的目標是能夠以普通使用者身分執行通常需要 root 權限的程式。它需要的功能是cap_dac_override可以讀取私有檔案。我不想賦予它任何其他功能。

這是我的包裝:

#include <unistd.h>

int main(int argc, char *argv[]) {
    return execl("/usr/bin/net", "net", "ads", "dns", "register", "-P", NULL);
}

當我對生成的可執行檔設定 setuid 權限時,這會起作用:

~ $ sudo chown root: ./registerdns
~ $ sudo chmod u+s ./registerdns
~ $ ./registerdns 
Successfully registered hostname with DNS

不過,我想使用功能而不是 setuid。我嘗試cap_dac_override在包裝器上設定功能:

~ $ sudo setcap cap_dac_override=eip ./registerdns
~ $ ./registerdns 
Failed to open /var/lib/samba/private/secrets.tdb
ERROR: Unable to open secrets database

cap_dac_override我還嘗試在可執行檔本身的功能上設定可繼承標誌net

~ $ sudo setcap cap_dac_override=eip ./registerdns
~ $ sudo setcap cap_dac_override=i /usr/bin/net
~ $ ./registerdns 
Failed to open /var/lib/samba/private/secrets.tdb
ERROR: Unable to open secrets database

我需要使用包裝器來確保該功能僅在使用確切的參數集時才可用;該net程式還執行其他一些操作,如果向使用者授予過於廣泛的權限,這些操作可能會很危險。

我顯然誤解了繼承的運作方式。我似乎無法弄清楚如何設置包裝器以將其功能傳遞給替換過程,以便它可以使用它們。我已經閱讀了手冊頁以及無數其他有關如何使用它的文檔應該工作,我以為我正在做它所描述的事情。

答案1

事實證明,在包裝器上設定 +i 確實可以不是將能力添加到CAP_INHERITABLE包裝進程的集合中,因此它不會被傳遞exec。因此,我必須在調用之前手動CAP_DAC_OVERRIDE添加:CAP_INHERITABLEexecl

#include <sys/capability.h>
#include <stdio.h>
#include <unistd.h>

int main(int argc, char **argv[]) {
    cap_t caps = cap_get_proc();
    printf("Capabilities: %s\n", cap_to_text(caps, NULL));
    cap_value_t newcaps[1] = { CAP_DAC_OVERRIDE, };
    cap_set_flag(caps, CAP_INHERITABLE, 1, newcaps, CAP_SET);
    cap_set_proc(caps);
    printf("Capabilities: %s\n", cap_to_text(caps, NULL));
    cap_free(caps);
    return execl("/usr/bin/net", "net", "ads", "dns", "register", "-P", NULL);
}

此外,我還必須添加cap_dac_override允許的檔案功能設定/usr/bin/net並設定有效位元:

~ $ sudo setcap cap_dac_override=p ./registerdns
~ $ sudo setcap cap_dac_override=ei /usr/bin/net
~ $ ./registerdns
Capabilities = cap_dac_override+p
Capabilities = cap_dac_override+ip
Successfully registered hostname with DNS

我想我現在完全明白發生了什麼事:

  1. 包裝器需要CAP_DAC_OVERRIDE在其允許集中,以便可以將其添加到其可繼承集中。
  2. 包裝器的進程可繼承集與其檔案可繼承集不同,因此在檔案上設定 +i 是沒有用的;包裝器必須明確添加CAP_DAC_OVERRIDECAP_INHERITABLEusing cap_set_flag/ cap_set_proc
  3. net檔案需要包含CAP_DAC_OVERRIDE在其可繼承集中,以便它實際上可以將功能從包裝器繼承到其CAP_PERMITTED集中。它還需要設定有效位,以便自動提升為CAP_EFFECTIVE

答案2

我認為你需要兩者:

setcap cap_dac_override+pe ./registerdns
setcap cap_dac_override+i /usr/bin/net

pe上的標誌表示registerdns運行該程式獲得了該功能。ion 標誌表示net允許從呼叫程式繼承功能。

相關內容