Người dùng không phải root có thể chạy tiến trình chroot trên Ubuntu không?
Người dùng không phải root có thể chạy tiến trình chroot trên Ubuntu không?
Câu trả lời:
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.
chroot
sau đó thực hiện .
@ 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 dash
và một liên kết tĩnh busybox
và một bash
vỏ đ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 unshare
có 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 -r
sẽ cấp chroot
quyề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 chroot
mô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ú).
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.
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ả.
~/fake-distro
sử dụng busybox, mà liên kết tượng trưng ls
, mv
và 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
).
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
và /etc/groups
được sao chép từ rootfs máy chủ vào rootfs khách.
Failed to unshare user namespace
với tôi trên linux 4.12.10 (Arch Linux).
unshare
cuộ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
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ì.