Ubuntu - người dùng không phải root có thể chạy tiến trình trong chroot jail?


18

Người dùng không phải root có thể chạy tiến trình chroot trên Ubuntu không?


Chủ đề FreeBSD cũ này bao gồm cùng một câu hỏi : lists.freebsd.org/pipermail/freebsd-security/2003-April/ trộm Câu trả lời ngắn gọn: Không, bạn không thể chạy một quy trình với quyền root trong nhà tù chroot không root.
David Harrison

nhà tù chroot là cụ thể cho bsd. một chroot trong linux không phải là một nhà tù. Lần cuối tôi kiểm tra không thể chroot là người dùng.
xenoterracide

1
@xenoterracide Jails là đặc trưng của BSD, nhưng chroot thường được gọi là "nhà tù chroot" trong cộng đồng Linux. Nó khá bối rối.
pehrs

2
Bạn đang cố gắng làm gì và tại sao? Có những công cụ như fakechroot và schroot cung cấp một sự thay thế hoàn toàn khả thi tùy thuộc vào yêu cầu của bạn.
Zoredache

Ngoài ra còn có nhiều cuộc thảo luận liên quan tại Làm thế nào để vứt bỏ tù một quy trình mà không cần root? với các cách tiếp cận làm việc hoặc dự kiến ​​hơn để giải quyết nhiệm vụ này được liệt kê.
imz - Ivan Zakharyaschev

Câu trả lời:


12

Trên Linux, cuộc gọi hệ thống chroot (2) chỉ có thể được thực hiện bởi một quy trình được đặc quyền. Khả năng mà quá trình cần là CAP_SYS_CHROOT.

Lý do bạn không thể chroot là người dùng khá đơn giản. Giả sử bạn có một chương trình setuid như sudo sẽ kiểm tra / etc / sudoers nếu bạn được phép làm điều gì đó. Bây giờ đặt nó trong một chroot chroot với / etc / sudoers của riêng bạn. Đột nhiên bạn có một sự leo thang đặc quyền ngay lập tức.

Có thể thiết kế một chương trình để tự chroot và chạy nó như một quy trình setuid, nhưng đây thường được coi là thiết kế xấu. Bảo mật bổ sung của chroot không thúc đẩy các vấn đề bảo mật với setuid.


3
Với các khả năng mới của không gian tên trong linux, có lẽ có thể tạo (không chia sẻ) một không gian tên "người dùng" mới, nơi sẽ có một người dùng root "nhúng" và chrootsau đó thực hiện .
imz - Ivan Zakharyaschev

1
@ imz - IvanZakharyaschev Bạn hoàn toàn chính xác, và tôi hy vọng bạn không phiền vì tôi đã tự do viết nó lên như một câu trả lời dễ kiểm chứng.
hvd

@hvd Tuyệt vời! Nó phải rất hữu ích, vì nó trình bày cách sử dụng các tính năng mới lạ của Linux với các lệnh cụ thể.
imz - Ivan Zakharyaschev

6

@ imz - IvanZakharyaschev nhận xét về câu trả lời của pehrs rằng có thể có thể với việc giới thiệu không gian tên, nhưng điều này đã không được thử nghiệm và đăng dưới dạng câu trả lời. Vâng, điều đó thực sự làm cho người dùng không phải root có thể sử dụng chroot.

Đưa ra một liên kết tĩnh dashvà một liên kết tĩnh busyboxvà một bashvỏ đang chạy đang chạy dưới dạng không root:

$ 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 người dùng gốc trong không gian tên đó được ánh xạ tới ID người dùng không phải gốc bên ngoài không gian tên đó và ngược lại, đó là lý do tại sao hệ thống hiển thị các tệp do người dùng hiện tại sở hữu bởi ID người dùng 0. Thông thường ls -al root, không unsharecó hiển thị chúng là sở hữu của người dùng hiện tại.


Lưu ý: điều nổi tiếng là các quy trình có khả năng sử dụng chroot, có khả năng thoát ra khỏi a chroot. Vì unshare -rsẽ cấp chrootquyền cho người dùng thông thường, sẽ có rủi ro bảo mật nếu điều đó được cho phép trong chrootmôi trường. Thật vậy, nó không được phép và thất bại với:

unshare: unshare fail: Thao tác không được phép

phù hợp với tài liệu unshare (2) :

EPERM (kể từ Linux 3.9)

CLONE_NEWUSER đã được chỉ định trong các cờ và người gọi đang ở trong môi trường chroot (nghĩa là thư mục gốc của người gọi không khớp với thư mục gốc của không gian tên mount mà nó cư trú).


Chạy p Pivot_root trong không gian tên mount có tác dụng tương tự như chroot nhưng tránh xung đột với không gian tên người dùng.
Timothy Baldwin

1
Người ta có thể thoát khỏi một không gian tên chroot hoặc mount bằng cách hạ xuống / Proc nếu chúng là một quá trình bên ngoài với cùng một UID trong cùng một không gian tên PID và người dùng.
Timothy Baldwin

2

Ngày nay, bạn muốn xem xét LXC (Linux Container) thay vì chroot / BSD jail. Nó nằm đâu đó giữa chroot và máy ảo, mang lại cho bạn nhiều quyền kiểm soát bảo mật và cấu hình chung. Tôi tin rằng tất cả những gì bạn cần để chạy nó với tư cách là người dùng là thành viên của nhóm sở hữu các tệp / thiết bị cần thiết, nhưng cũng có thể có các khả năng / quyền hệ thống liên quan. Dù bằng cách nào, nó sẽ rất khả thi, vì LXC khá gần đây, rất lâu sau khi SELinux, v.v. được thêm vào nhân Linux.

Ngoài ra, hãy nhớ rằng bạn chỉ có thể viết tập lệnh dưới dạng root nhưng cung cấp cho người dùng quyền an toàn để chạy các tập lệnh đó (không có mật khẩu nếu bạn muốn, nhưng đảm bảo tập lệnh được bảo mật) bằng sudo.


1

Sự kết hợp của fakeroot / fakechroot tạo ra một mô hình chroot cho các nhu cầu đơn giản như sản xuất tài liệu lưu trữ tar nơi các tập tin dường như được sở hữu bởi root. Trang chủ của Fakechroot là http://linux.die.net/man/1/fakechroot .

Mặc dù vậy, bạn không nhận được bất kỳ quyền mới nào, nhưng nếu bạn sở hữu một thư mục (ví dụ: bản phân phối giả) trước khi gọi

fakechroot fakeroot chroot ~/fake-distro some-command

bây giờ nó tìm kiếm một số lệnh như bạn đã root và sở hữu mọi thứ trong bản phân phối giả.


Đây là một ý tưởng tốt, nhưng nó dường như xử lý các liên kết tượng trưng không thể đoán trước. Tôi ~/fake-distrosử dụng busybox, mà liên kết tượng trưng ls, mvvà các tiện ích phổ biến khác để /bin/busybox. Nếu tôi gọi một cách rõ ràng /bin/busybox mv ..., mọi thứ sẽ hoạt động, nhưng nếu tôi gọi thì /bin/mv ...tôi nhận được sh: /bin/mv: not found. Cài đặt export FAKECHROOT_EXCLUDE_PATH=/trước khi chạy fakechroot sẽ khắc phục triệu chứng đó, nhưng sau đó nó sẽ phá vỡ các liên kết tượng trưng khác (ví dụ /usr/bin/vim -> /usr/bin/vim.vim).
Ponkadoodle

có lẽ FAKECHROOT_EXCLUDE_PATH = /: / usr sẽ giúp ích?
sylvainulg

1

Có vẻ như với không gian tên người dùng, trên thực tế có thể chroot mà không cần root. Đây là một chương trình ví dụ chứng minh rằng nó có thể. Tôi mới chỉ bắt đầu khám phá cách các không gian tên linux hoạt động và vì vậy tôi không hoàn toàn chắc chắn liệu mã này có thực hành tốt nhất hay không.

Lưu như user_chroot.cc. Biên dịch với g++ -o user_chroot user_chroot.cc. Cách sử dụng là ./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;
    }
}

Tôi đã thử nghiệm điều này trên một rootfs tối thiểu được tạo bằng multistrap (được thực thi dưới dạng không root). Một số tệp hệ thống thích /etc/passwd/etc/groupsđược sao chép từ rootfs máy chủ vào rootfs khách.


Thất bại Failed to unshare user namespacevới tôi trên linux 4.12.10 (Arch Linux).
Ponkadoodle

@wallacoloo có lẽ sửa đổi printf () thành perror () và xem lỗi thực tế là gì. tham khảo man7.org/linux/man-pages/man2/unshare.2.html để biết mã lỗi nào có thể xảy ra do một unsharecuộc gọi không thành công . Bạn cũng có thể dùng thử phiên bản python này có thể có thông báo lỗi tốt hơn: github.com/cheshirekow/uchroot
cheshirekow

1
Trên thực tế @wallacoloo có vẻ như vòm sẽ vô hiệu hóa các không gian tên người dùng không được quản lý trong bản dựng kernel của nó: list.archlinux.org/pipermail/arch-general/2017-F / 2 /
cheshirekow

0

Không. Nếu tôi nhớ lại một cách chính xác, có một số thứ cấp kernel mà chroot thực hiện để ngăn chặn nó. Tôi không nhớ đó là cái gì Tôi đã điều tra lại khi sử dụng công cụ Catalyst Build của Gentoo (và một chroot trên gentoo cũng giống như một chroot trên ubfox). Mặc dù có thể làm cho nó xảy ra mà không có mật khẩu ... nhưng những thứ như vậy được để lại cho các lỗ hổng bảo mật tiềm ẩn và đảm bảo bạn biết bạn đang làm gì.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.