setuid は標準ユーザーアカウントでは機能しません

setuid は標準ユーザーアカウントでは機能しません

この C プログラムを見てください:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    printf("UID:  %d\n", getuid());
    printf("EUID: %d\n", geteuid());
    system("id");

    printf("res=%d\n", setuid(1001));

    printf("UID:  %d\n", getuid());
    printf("EUID: %d\n", geteuid());
    system("id");
    return 0;
}

私のユーザー アカウントは「test」(ID 1000) です。2 番目のユーザー アカウントは「test2」(ID 1001) です。

私がやったことは次のとおりです:

gcc test.c -o ./a.out
sudo chown test2 ./a.out
sudo chmod u+s ./a.out

ここで、./a.out を起動すると何が起こるかを示します。

UID:  1000
EUID: 1001
uid=1000(test) gid=1000(test) groups=1000(test),...
res=0
UID:  1000
EUID: 1001
uid=1000(test) gid=1000(test) groups=1000(test),...
          

2 番目の部分に uid=1001 が表示されない理由がわかりません...

私はこれを試しました:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    printf("UID:  %d\n", getuid());
    printf("EUID: %d\n", geteuid());
    system("id");

    printf("res=%d\n", setuid(0));  // <- Here is the change

    printf("UID:  %d\n", getuid());
    printf("EUID: %d\n", geteuid());
    system("id");
    return 0;
}
          
gcc test.c -o ./a.out
sudo chown root ./a.out
sudo chmod u+s ./a.out

./a.out を実行すると、次の結果が表示されます。

UID:  1000
EUID: 0
uid=1000(test) gid=1000(test) groups=1000(test),...
res=0
UID:  0
EUID: 0
uid=0(root) gid=1000(test) groups=1000(test),...
           

今は動作します。

では、setuid が test2 ユーザーでは機能せず、root ユーザーでは機能する理由がわかりません...

何か案が ?

ありがとう

答え1

ここで混乱を引き起こしているのは、いくつかのことです。Setuid はどちらの場合も機能しますが、思ったようには機能しません。まず、実際のユーザー ID と有効なユーザー ID の問題があります。setuid(2) マニュアルページ

呼び出しプロセスが特権を持っている場合 (より正確には、プロセスがCAP_SETUIDユーザー名前空間で機能を持っている場合)、実 UID と保存された set-user-ID も設定されます。

これはまた、呼び出しプロセスがない権限を持っている場合CAP_SETUID(一般ユーザーの場合)、UIDはない変更されるのは EUID のみです。

では、呼び出しに移りますsystem()。呼び出しはsystem("anything")、次の呼び出しと同じです。

execl("/bin/sh", "sh", "-c", "anything", (char *) NULL);

そこで、/bin/sh新しいシェルがコマンドを実行するための引数を提供する を生成します。シェルとしてbashを使用していると仮定します。bashは

シェルが実効ユーザー (グループ) ID と実際のユーザー (グループ) ID が等しくない状態で起動され、-p オプションが指定されていない場合、(...) 実効ユーザー ID は実際のユーザー ID に設定されます。

したがって、プロセスに権限がない場合CAP_SETUID、実ユーザーIDは変更されず、実効UIDのみが変更されます。その後、bashが起動されると、UIDはEUIDと等しくないため、実効UIDが削除されます。これを確認するには、次を呼び出します。

system("touch /tmp/blah")

そして追加

FILE *file = fopen("/tmp/blah2", "w+");
fclose(file);

プログラムに追加します。 の所有者は/tmp/blah「test」になりますが (EUID はシェル実行時に削除されるため)、/tmp/blah2「test2」に属します。

関連情報