เป็นไปได้หรือไม่ที่ผู้ใช้ที่ไม่ใช่รูทใช้กระบวนการ chroot บน Ubuntu?
เป็นไปได้หรือไม่ที่ผู้ใช้ที่ไม่ใช่รูทใช้กระบวนการ chroot บน Ubuntu?
คำตอบ:
บน Linux การเรียกระบบchroot (2)สามารถทำได้โดยกระบวนการที่ได้รับการยกเว้นเท่านั้น ความสามารถที่กระบวนการต้องการคือ CAP_SYS_CHROOT
เหตุผลที่คุณไม่สามารถ chroot เนื่องจากผู้ใช้นั้นค่อนข้างเรียบง่าย สมมติว่าคุณมีโปรแกรม setuid เช่น sudo ที่ตรวจสอบ / etc / sudoers หากคุณได้รับอนุญาตให้ทำอะไรบางอย่าง ตอนนี้ใส่ไว้ใน chroot chroot กับ / etc / sudoers ของคุณเอง ทันใดนั้นคุณมีการยกระดับสิทธิ์ทันที
เป็นไปได้ที่จะออกแบบโปรแกรมเพื่อ chroot ตัวเองและรันมันเป็นกระบวนการ setuid แต่โดยทั่วไปถือว่าเป็นการออกแบบที่ไม่ดี ความปลอดภัยเพิ่มเติมของ chroot ไม่ได้กระตุ้นให้เกิดปัญหาด้านความปลอดภัยกับ setuid
chrootภายหลัง
                    @ imz - ความเห็นของ IvanZakharyaschev เกี่ยวกับคำตอบของ pehrs ว่าอาจเป็นไปได้ด้วยการเปิดตัว namespaces แต่สิ่งนี้ยังไม่ได้รับการทดสอบและโพสต์เป็นคำตอบ ใช่มันทำให้ผู้ใช้ที่ไม่ใช่รูทสามารถใช้ 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 ผู้ใช้รากใน namespace ที่ถูกแมปไปที่ไม่ใช่รากนอก ID ผู้ใช้ของ namespace นั้นและในทางกลับกันซึ่งเป็นเหตุผลที่ไฟล์ระบบที่แสดงให้เห็นว่าเป็นเจ้าของโดยผู้ใช้ปัจจุบันเป็นเจ้าของโดยผู้ใช้ ID 0. ปกติls -al rootโดยไม่ต้องunshareไม่ แสดงให้พวกเขาเป็นเจ้าของโดยผู้ใช้ปัจจุบัน
หมายเหตุ: มันเป็นที่รู้จักกันดีว่ากระบวนการที่มีความสามารถในการใช้งานมีความสามารถในการทำลายออกของchroot chrootเนื่องจากunshare -rจะให้chrootสิทธิ์แก่ผู้ใช้ทั่วไปจึงเป็นความเสี่ยงด้านความปลอดภัยหากได้รับอนุญาตภายในchrootสภาพแวดล้อม อันที่จริงมันไม่ได้รับอนุญาตและล้มเหลวด้วย:
ยกเลิกการแชร์: ยกเลิกการแชร์ไม่สำเร็จ: ไม่อนุญาตให้ดำเนินการ
ซึ่งตรงกับเอกสารunshare (2) :
EPERM (ตั้งแต่ Linux 3.9)
CLONE_NEWUSERถูกระบุในแฟล็กและผู้เรียกอยู่ในสภาพแวดล้อม chroot (เช่นไดเร็กทอรีรูทของผู้โทรไม่ตรงกับรูทไดเร็กทอรีของเมาต์เนมสเปซที่มันอยู่)
วันนี้คุณต้องการดู LXC (Linux Containers) แทน chroot / BSD jail มันอยู่ที่ไหนสักแห่งระหว่าง chroot และเครื่องเสมือนที่ให้การควบคุมความปลอดภัยจำนวนมากและการกำหนดค่าทั่วไป ฉันเชื่อว่าสิ่งที่คุณต้องใช้เพื่อดำเนินการในฐานะผู้ใช้คือการเป็นสมาชิกของกลุ่มที่เป็นเจ้าของไฟล์ / อุปกรณ์ที่จำเป็น แต่อาจมีความสามารถ / ระบบการอนุญาตที่เกี่ยวข้อง ไม่ว่าจะด้วยวิธีใดก็ควรเป็นไปได้มากเนื่องจาก LXC นั้นค่อนข้างเร็วหลังจาก SELinux เป็นต้นถูกเพิ่มเข้าไปในเคอร์เนล Linux
นอกจากนี้โปรดทราบว่าคุณสามารถเขียนสคริปต์เป็น root แต่ให้สิทธิ์ผู้ใช้ที่ปลอดภัยในการเรียกใช้สคริปต์เหล่านั้น (โดยไม่ต้องใช้รหัสผ่านหากคุณต้องการ แต่ให้แน่ใจว่าสคริปต์นั้นปลอดภัย) โดยใช้ sudo
การรวมกันของ fakeroot / fakechroot ให้เสมือนจริงของ chroot สำหรับความต้องการง่ายๆเช่นการสร้างคลังเก็บ tar ที่ไฟล์ดูเหมือนว่าจะเป็นเจ้าของโดยราก Fakechroot manpage เป็นhttp://linux.die.net/man/1/fakechroot
คุณไม่ได้รับอนุญาตใหม่ แต่ถ้าคุณเป็นเจ้าของไดเรกทอรี (เช่นปลอม distro) ก่อนที่จะเรียกใช้
fakechroot fakeroot chroot ~/fake-distro some-command
ตอนนี้ให้มองหาคำสั่งบางอย่างเช่นคุณหยั่งรากและเป็นเจ้าของทุกสิ่งภายในโรงกลั่นน้ำมันปลอม
~/fake-distroใช้ busybox ซึ่ง symlinks ls, mvและระบบสาธารณูปโภคอื่น ๆ /bin/busyboxทั่วไปที่จะ ถ้าผมชัดเจนโทร/bin/busybox mv ..., สิ่งที่ทำงาน แต่ถ้าผมเรียกฉันได้รับ/bin/mv ... sh: /bin/mv: not foundการตั้งค่าexport FAKECHROOT_EXCLUDE_PATH=/ก่อนใช้งานการปลอมแปลงรากเทียมจะแก้ไขอาการที่เกิดขึ้น แต่หลังจากนั้นจะหยุดลงบน symlink อื่น ๆ (เช่น/usr/bin/vim -> /usr/bin/vim.vim)
                    ดูเหมือนว่าด้วย user-namespaces ในความเป็นจริงเป็นไปได้ที่จะ chroot โดยไม่ต้องรูท นี่คือตัวอย่างโปรแกรมที่แสดงให้เห็นว่ามันเป็นไปได้ ฉันเพิ่งเริ่มศึกษาว่าลินุกซ์เนมสเปซทำงานอย่างไรและดังนั้นฉันจึงไม่แน่ใจว่ารหัสนี้เป็นวิธีปฏิบัติที่ดีที่สุดหรือไม่
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 น้อยที่สุดที่สร้างขึ้นด้วย multistrap (ดำเนินการในฐานะที่ไม่ใช่ราก) ไฟล์ระบบบางไฟล์เช่น/etc/passwdและ/etc/groupsถูกคัดลอกจากโฮสต์ rootfs ลงใน guest rootfs
Failed to unshare user namespaceสำหรับฉันที่ linux 4.12.10 (Arch Linux)
                    unshareโทรที่ไม่สำเร็จ คุณสามารถลองใช้งานไพ ธ อนรุ่นนี้ซึ่งอาจมีข้อผิดพลาดในการส่งข้อความที่ดีกว่า: github.com/cheshirekow/uchroot
                    ไม่ถ้าฉันจำได้อย่างถูกต้องมีบางสิ่งในระดับเคอร์เนลที่ chroot ทำเพื่อป้องกัน ฉันจำไม่ได้ว่ามันคืออะไร ฉันตรวจสอบมันกลับมาเมื่อทำ messing ด้วยเครื่องมือ Catalyst Build ของ Gentoo (และ chroot บน gentoo นั้นเหมือนกับ chroot บน Ubuntu) แม้ว่ามันจะเป็นไปได้ที่จะทำให้มันเกิดขึ้นโดยไม่ต้องใช้รหัสผ่าน ... แต่สิ่งต่าง ๆ เหล่านี้อยู่ในขอบเขตของความเสี่ยงด้านความปลอดภัยที่อาจเกิดขึ้นและทำให้แน่ใจว่าคุณรู้ว่าคุณกำลังทำอะไรอยู่