我試圖了解 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_INHERITABLE
execl
#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
我想我現在完全明白發生了什麼事:
- 包裝器需要
CAP_DAC_OVERRIDE
在其允許集中,以便可以將其添加到其可繼承集中。 - 包裝器的進程可繼承集與其檔案可繼承集不同,因此在檔案上設定 +i 是沒有用的;包裝器必須明確添加
CAP_DAC_OVERRIDE
到CAP_INHERITABLE
usingcap_set_flag
/cap_set_proc
。 - 該
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
運行該程式獲得了該功能。i
on 標誌表示net
允許從呼叫程式繼承功能。