[英]How to drop privilege temporarily from root?
我正在開發一個以root用戶身份運行的守護進程,但需要與用戶調用API,我檢查了API代碼,它使用getuid()
來獲取用戶。
如果root用戶通過setuid()
刪除權限,則無法將其還原為root。 如果調用seteuid(),API仍將以用戶uid=0
執行某些操作。
我認為在訪問子進程中的API和setuid之前的fork應該可行,但即使COW,如果多次調用API也會花費很多。 除了使用進程池之外,是否可以解決問題?
是! 創建單個進程以使用適當的UID調用API,並通過管道,UNIX域套接字或( 共享內存 ) 1與程序的其余部分進行通信。
我的意思是,只分叉一次並讓特權用戶運行另一個進程。 然后根據需要在需要時創建兩者之間的通信。 此外,您可能需要考慮使用dbus,因為它還與systemd和現代Linux完美集成,您希望您的守護進程能夠很好地與兩者進行交互。
注意 :我絕不是這方面的專家,但這是一個簡單的想法,對我來說似乎很清楚。 您無需為每次調用API創建進程。 這是XY問題的一個很好的例子,你想要解決的真正問題與避免fork()
多次無關,因為這樣做的想法是錯誤的解決方案。 您只需要fork()
一次,刪除權限並在沒有權限的情況下保持在那里,如果/需要,與父進程通信。
1 適用於您的任何IPC機制。
您可以將以前的有效uid 存儲在進程的已保存UID中:
uid_t real = getuid();
uid_t privileged = geteuid();
setresuid(real, real, privileged);
do_API_call(); // API's getuid() call now returns real
setresuid(real, privileged, -1); // allowed, since saved==privileged
還有一個相應的setresgid
來使用已保存的GID。
請注意,此答案特定於Linux(根據問題標簽)。 HP-UX和某些BSD系統上存在類似的調用,但我沒有檢查語義是否相同。
實際上,在進一步閱讀時, setreuid()
應該足夠了(並且符合POSIX)。 setuid()
說:
如果調用者的有效UID是root(更准確地說:如果調用者具有
CAP_SETUID
功能),則還會設置實際UID和已保存的set-user-ID。
和
如果用戶是root用戶或程序是set-user-ID-root,則必須特別小心。
setuid()
函數檢查調用者的有效用戶ID,如果是超級用戶,則所有與進程相關的用戶ID都設置為uid
。 發生這種情況后,程序無法重新獲得root權限。
但是setreuid()
沒有這樣的聲明。
只需調用seteuid(2)
來做適當的非特權事情。 seteuid(2)
允許在真實 (或保存)的用戶ID(在你的情況下啟動suid程序或root
)和suid用戶id(suid程序所屬的用戶id)之間切換,所以應該沒有問題以后重新獲得特權用戶ID(因為保存的用戶ID是root
,你一次又一次切換到它沒有任何問題)。
如果你用setuid(2)
更改uid,你將改變所有 (有效,保存和真實的uid),這只允許root用戶(或程序setuid root,然后就沒辦法了)。
看下一個例子:
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
int main(int argc, char **argv)
{
int opt, suid = getuid(), /* this is the saved uid */
uid = 0;
while ((opt = getopt(argc, argv, "i:")) != EOF) {
switch (opt) {
case 'i': uid = atoi(optarg); break;
}
}
/* execute this program with root privileges, like setuid root, for example */
printf("real uid=%d; effective uid=%d\n", getuid(), geteuid());
seteuid(uid); /* change to the non-privileged id configured */
printf("real uid=%d; effective uid=%d\n", getuid(), geteuid());
seteuid(suid); /* return back to saved uid */
printf("real uid=%d; effective uid=%d\n", getuid(), geteuid());
}
你會得到這樣的輸出:
$ pru49015 -i 37
real uid=502; effective uid=0
real uid=502; effective uid=37
real uid=502; effective uid=502
當用作setuid-root程序時
如果您以root身份使用它,您將獲得以下輸出:
$ sudo pru$$ -i 37
real uid=0; effective uid=0
real uid=0; effective uid=37
real uid=0; effective uid=0
機制是允許你在setuid程序之間切換用戶(讓我們稱之為已保存的用戶ID )和程序運行setuid的用戶(被叫有效用戶ID或suid用戶)的次數。你要。
從這里 :
通常,當執行進程時,有效,實際和已保存的用戶和組ID都將分別設置為進程父級的實際用戶和組ID。 但是,當在可執行文件上設置setuid位時,有效和已保存的用戶ID將設置為擁有該文件的用戶標識。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.