簡體   English   中英

如何從root暫時刪除權限?

[英]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,然后就沒辦法了)。

看下一個例子:

文件pru49015.c:

#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的用戶(被叫有效用戶IDsuid用戶)的次數。你要。

這里

通常,當執行進程時,有效,實際和已保存的用戶和組ID都將分別設置為進程父級的實際用戶和組ID。 但是,當在可執行文件上設置setuid位時,有效和已保存的用戶ID將設置為擁有該文件的用戶標識。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM