Ubuntu-非rootユーザーはchroot jailでプロセスを実行できますか?


18

非rootユーザーがUbuntuでchrootプロセスを実行することは可能ですか?


この古いFreeBSDスレッドは同じ質問を扱っています:lists.freebsd.org/pipermail/freebsd-security/2003-April/…短い答え:いいえ、非ルートchroot jail内でルートとしてプロセスを実行することはできません。
デビッドハリソン

chroot jailはbsdに固有です。Linuxのchrootは刑務所ではありません。最後に、ユーザーとしてchrootできないことを確認しました。
xenoterracide

1
@xenoterracide JailはBSD固有ですが、chrootはLinuxコミュニティで「chroot jail」として一般的に知られています。かなり混乱しています。
ペール

2
何をしようとしているのですか?fakechrootやschrootなどのツールは、要件に応じて実行可能な代替手段を提供します。
ゾレダチェ

また、ルートにならずにプロセスを「投獄する方法」で、より関連する議論がありました このタスクを解決するためのより実用的または暫定的なアプローチを記載しています。
imz-イヴァンザカリヤシェフ

回答:


12

Linuxでは、chroot(2)システムコールは特権のあるプロセスによってのみ実行できます。プロセスに必要な機能はCAP_SYS_CHROOTです。

ユーザーとしてchrootできない理由は非常に簡単です。何かを行うことが許可されている場合、/ etc / sudoersをチェックするsudoなどのsetuidプログラムがあるとします。次に、独自の/ etc / sudoersを使用してchroot chrootに配置します。突然、特権のエスカレーションが即座に発生します。

プログラムを自分自身をchrootしてsetuidプロセスとして実行するように設計することは可能ですが、これは一般に悪い設計と考えられています。chrootの追加のセキュリティは、setuidのセキュリティ問題を動機付けません。


3
Linux の名前空間の新しい可能性により、おそらく、「組み込み」ルートユーザーが存在する新しい「ユーザー」名前空間を作成(共有解除)し、実行することができますchroot
imz-イワンザカリヤシェフ

1
@ imz--IvanZakharyaschevあなたは絶対に正しいです。簡単にテストできる答えとしてそれを書く自由を私が取ったことを気にしないでください。
hvd 14

@hvd素晴らしい!これは、具体的なコマンドで新しいなじみのないLinux機能を使用する方法を示すため、非常に役立つはずです。
imz-イヴァンザカリヤシェフ14

6

@ imz--IvanZakharyaschevは、名前空間の導入によって可能になるかもしれないとpehrsの答えにコメントしていますが、これはテストされておらず、答えとして投稿されていません。はい、そうすることで、非rootユーザーがchrootを使用できるようになります。

静的にリンクされたdash、静的にリンクされたbusybox、およびbash非ルートとして実行されている実行中のシェルがある場合:

$ mkdir root
$ cp /path/to/dash root
$ cp /path/to/busybox root
$ unshare -r bash -c 'chroot root /dash -c "/busybox ls -al /"'
total 2700
drwxr-xr-x    2 0        0             4096 Dec  2 19:16 .
drwxr-xr-x    2 0        0             4096 Dec  2 19:16 ..
drwxr-xr-x    1 0        0          1905240 Dec  2 19:15 busybox
drwxr-xr-x    1 0        0           847704 Dec  2 19:15 dash

その名前空間内のルート・ユーザIDは、ユーザID 0 A正規が所有するようにシステムが示すファイルは、現在のユーザーが所有する理由であり、その名前空間の非ルートユーザIDの外側にマッピングされ、その逆もさls -al rootせずにunshare、い現在のユーザーが所有しているものとして表示します。


注:を使用できるプロセスchrootは、から抜け出すことができることはよく知られていますchroot。以来unshare -r与えるだろうchroot普通のユーザーに権限をそれが内部で許可された場合、それはセキュリティ上のリスクになるchroot環境。実際、それは許可されておらず、次のように失敗します。

共有解除:共有に失敗しました:操作は許可されていません

unshare(2)のドキュメントと一致します:

EPERM(Linux 3.9以降)

CLONE_NEWUSERフラグで指定され、呼び出し元がchroot環境にあります(つまり、呼び出し元のルートディレクトリが、それが存在するマウント名前空間のルートディレクトリと一致しません)。


マウント名前空間でpivot_rootを実行すると、chrootと同様の効果がありますが、ユーザー名前空間との競合は回避されます。
ティモシーボールドウィン

1
同じまたは子PIDとユーザー名前空間の同じUIDを持つ外部プロセスである場合は、/ procに降りることでchrootまたはマウント名前空間をエスケープできます。
ティモシーボールドウィン

2

最近では、chroot / BSD jailの代わりにLXC(Linux Containers)を見たいと思っています。chrootと仮想マシンの間のどこかにあり、多くのセキュリティ制御と一般的な構成可能性を提供します。ユーザーとして実行するために必要なのは、必要なファイル/デバイスを所有するグループのメンバーになることだけであると考えていますが、機能/システムのアクセス許可も含まれている可能性があります。いずれにしても、SELinuxなどがLinuxカーネルに追加されてからずっと経ったLXCはごく最近のものであるため、非常に実行可能です。

また、rootとしてスクリプトを作成するだけで、sudoを使用してそれらのスクリプトを実行するための安全なアクセス許可をユーザーに与えることができることに注意してください(必要な場合はパスワードなしで、スクリプトが安全であることを確認してください)。


1

fakeroot / fakechrootの組み合わせは、ファイルがルートによって所有されているように見えるtarアーカイブを作成するなどの単純なニーズに対して、chrootのシミュレーションを提供します。Fakechrootのマンページはhttp://linux.die.net/man/1/fakechrootです。

ただし、新しい権限は取得しませんが、呼び出す前にディレクトリ(fake-distroなど)を所有している場合

fakechroot fakeroot chroot ~/fake-distro some-command

rootであり、fake-distro内のすべてを所有しているようなコマンドを探します。


これはいいアイデアですが、シンボリックリンクを予測不能に処理するようです。私の~/fake-distro用途のbusyboxの、シンボリックリンクlsmvおよび他の一般的なユーティリティへ/bin/busybox。を明示的に呼び出すと/bin/busybox mv ...、動作しますが、呼び出すと、が/bin/mv ...取得されsh: /bin/mv: not foundます。export FAKECHROOT_EXCLUDE_PATH=/fakechrootを実行する前に設定すると、その症状は修正されますが、他のシンボリックリンク(例:)で壊れ/usr/bin/vim -> /usr/bin/vim.vimます。
ポンカドゥードル

多分FAKECHROOT_EXCLUDE_PATH = /:/ usrが役立つでしょうか?
シルヴァインウルグ

1

ユーザー名前空間では、実際にはルートなしでchrootできるようです。これが可能であることを示すサンプルプログラムです。Linuxの名前空間がどのように機能するかを調査し始めたばかりなので、このコードがベストプラクティスであるかどうかは完全にはわかりません。

として保存しuser_chroot.ccます。でコンパイルしg++ -o user_chroot user_chroot.ccます。使用法は./user_chroot /path/to/new_rootfsです。

// references:
// [1]: http://man7.org/linux/man-pages/man7/user_namespaces.7.html
// [2]: http://man7.org/linux/man-pages/man2/unshare.2.html

#include <sched.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <cerrno>
#include <cstdio>
#include <cstring>

int main(int argc, char** argv) {
    if(argc < 2) {
        printf("Usage: %s <rootfs>\n", argv[0]);
    }

    int uid = getuid();
    int gid = getgid();
    printf("Before unshare, uid=%d, gid=%d\n", uid, gid);

    // First, unshare the user namespace and assume admin capability in the
    // new namespace
    int err = unshare(CLONE_NEWUSER);
    if(err) {
        printf("Failed to unshare user namespace\n");
        return 1;
    }

    // write a uid/gid map
    char file_path_buf[100];
    int pid = getpid();
    printf("My pid: %d\n", pid);

    sprintf(file_path_buf, "/proc/%d/uid_map", pid);
    int fd = open(file_path_buf, O_WRONLY);
    if(fd == -1) {
        printf("Failed to open %s for write [%d] %s\n", file_path_buf, errno, 
               strerror(errno));
    } else {
        printf("Writing : %s (fd=%d)\n", file_path_buf, fd);
        err = dprintf(fd, "%d %d 1\n", uid, uid);
        if(err == -1) {
            printf("Failed to write contents [%d]: %s\n", errno, 
                   strerror(errno));
        }
        close(fd);
    }

    sprintf(file_path_buf, "/proc/%d/setgroups", pid);
    fd = open(file_path_buf, O_WRONLY);
    if(fd == -1) {
        printf("Failed to open %s for write [%d] %s\n", file_path_buf, errno, 
               strerror(errno));
    } else {
        dprintf(fd, "deny\n");
        close(fd);
    }

    sprintf(file_path_buf, "/proc/%d/gid_map", pid);
    fd = open(file_path_buf, O_WRONLY);
    if(fd == -1) {
        printf("Failed to open %s for write [%d] %s\n", file_path_buf, errno, 
               strerror(errno));
    } else {
        printf("Writing : %s (fd=%d)\n", file_path_buf, fd);
        err = dprintf(fd, "%d %d 1\n", gid, gid);
        if(err == -1) {
            printf("Failed to write contents [%d]: %s\n", errno, 
                   strerror(errno));
        }
        close(fd);
    }

    // Now chroot into the desired directory
    err = chroot(argv[1]);
    if(err) {
        printf("Failed to chroot\n");
        return 1;
    }

    // Now drop admin in our namespace
    err = setresuid(uid, uid, uid);
    if(err) {
        printf("Failed to set uid\n");
    }

    err = setresgid(gid, gid, gid);
    if(err) {
        printf("Failed to set gid\n");
    }

    // and start a shell
    char argv0[] = "bash";
    char* new_argv[] = {
        argv0,
        NULL
    };

    err = execvp("/bin/bash", new_argv);
    if(err) {
        perror("Failed to start shell");
        return -1;
    }
}

これをマルチストラップで生成された最小限のrootfs(非ルートとして実行)でテストしました。いくつかのシステムファイルが好き/etc/passwd/etc/groupsゲストにrootfsにホストにrootfsからコピーされました。


Failed to unshare user namespaceLinux 4.12.10(Arch Linux)で失敗します。
ポンカドゥードル

@wallacolooはおそらくprintf()をperror()に変更し、実際のエラーが何であるかを確認します。呼び出しが失敗した場合に発生する可能性のあるエラーコードについては、man7.org / linux / man-pages / man2 / unshare.2.htmlを参照してくださいunshare。:また、この優れたエラーメッセージを持っているかもしれませんPythonのバージョン試すことができますgithub.com/cheshirekow/uchroot
cheshirekow

1
実際に、それはそれのカーネル構築にアーチ無効のような特権を持たないユーザーの名前空間の音@wallacoloo:lists.archlinux.org/pipermail/arch-general/2017-February/...は
cheshirekow

0

いいえ。正しく思い出せば、chrootがそれを妨げるカーネルレベルのことがあります。そのことを思い出せません。GentooのCatalyst Buildツールをいじったときに調査しました(そしてgentooのchrootはubuntuのchrootと同じです)。パスワードなしでそれを実現することは可能ですが...しかし、そのようなことは潜在的なセキュリティ脆弱性の領域に任せられ、あなたが何をしているのかを確実に確認します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.