Linux

通過 exec 傳遞能力

  • May 15, 2014

我試圖了解 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程序還做了一些其他的事情,這些事情可能會給使用者過於廣泛的權限帶來危險。

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

事實證明,在包裝器上設置 +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

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

  1. 包裝器需要CAP_DAC_OVERRIDE在其允許的集合中,以便可以將其添加到其可繼承集合中。
  2. wrapper的程序可繼承集與其文件可繼承集不同,所以在文件上設置+i是沒有用的;包裝器必須顯式添加CAP_DAC_OVERRIDECAP_INHERITABLEusing cap_set_flag/ cap_set_proc
  3. net文件需要CAP_DAC_OVERRIDE在其可繼承集中,以便它實際上可以將包裝器的功能繼承到其CAP_PERMITTED集中。它還需要設置有效位,以便自動提升為CAP_EFFECTIVE.

引用自:https://unix.stackexchange.com/questions/128394