Чи можливо для некористувального користувача запустити процес chroot на Ubuntu?
Чи можливо для некористувального користувача запустити процес chroot на Ubuntu?
Відповіді:
У Linux системний виклик chroot (2) може здійснюватися лише привілейованим процесом. Можливість, яку потребує процес, становить CAP_SYS_CHROOT.
Причина, по якій ви не можете хронізуватися як користувач, досить проста. Припустимо, у вас встановлена програма, така як sudo, яка перевіряє / etc / sudoers, якщо вам дозволяють щось робити. Тепер покладіть його в chroot chroot із власними / etc / sudoers. Раптом у вас моментальна ескалація привілеїв.
Можна створити програму, щоб хронізувати себе та запустити її як встановлений процес, але це, як правило, вважається поганим дизайном. Додаткова безпека chroot не мотивує проблеми безпеки із налаштуванням.
chroot
його.
@ imz - ІванЗахарящев коментує відповідь 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
Ідентифікатор кореневого користувача в цьому просторі імен відображається на ідентифікатор некорінного користувача поза цим простором імен, і навпаки, тому система показує файли, що належать поточному користувачеві, як власник ідентифікатора користувача 0. Регулярний ls -al root
, без unshare
, робить показувати їх як власність поточного користувача.
Примітка: загальновідомо, що процеси, які здатні використовувати chroot
, здатні вибиватися з a chroot
. Оскільки unshare -r
надасть chroot
дозволи звичайному користувачеві, це було б ризиком для безпеки, якби це було дозволено всередині chroot
середовища. Дійсно, це не дозволено, і не вдається:
unshare: unshare failed: Операція не дозволена
яка відповідає документації, що не використовується (2) :
EPERM (з Linux 3.9)
CLONE_NEWUSER був вказаний у прапорах, а абонент знаходиться у середовищі chroot (тобто коренева директорія абонента не відповідає кореневій директорії простору імен версії, в якій він знаходиться).
У ці дні ви хочете подивитися на LXC (Linux Containers) замість chroot / BSD. Це десь між chroot і віртуальною машиною, що дає вам багато контролю над безпекою і загальної налаштованості. Я вважаю, що все, що вам потрібно, щоб запустити його як користувач - це бути членом групи, яка володіє необхідними файлами / пристроями, але також можуть бути залучені можливості / системні дозволи. У будь-якому випадку це має бути дуже придатним, оскільки LXC є нещодавним, довго після того, як до ядра Linux було додано SELinux тощо.
Також майте на увазі, що ви можете просто писати скрипти як root, але надавати користувачам безпечний дозвіл на запуск цих сценаріїв (без пароля, якщо вам подобається, але переконайтеся, що сценарій захищений) за допомогою sudo.
Поєднання fakeroot / fakechroot дає змогу chroot для простих потреб, таких як створення архівів tar, де файли, як видається, належать root. Сторінка Fakechroot - це http://linux.die.net/man/1/fakechroot .
Ви не отримуєте жодного нового дозволу, але якщо у вас є каталог (наприклад, підроблений дистрибутив) перед тим, як викликати його
fakechroot fakeroot chroot ~/fake-distro some-command
тепер шукайте якусь команду, як ви root, і володієте всім у підробці distro.
~/fake-distro
використання BusyBox, які символічні посилання ls
, mv
і інші загальні утиліти для /bin/busybox
. Якщо я чітко телефоную /bin/busybox mv ...
, все працює, але якщо я дзвоню, /bin/mv ...
я отримую sh: /bin/mv: not found
. Встановлення export FAKECHROOT_EXCLUDE_PATH=/
перед запуском фальшивки виправляє цей симптом, але потім він порушується на інших символьних посиланнях (наприклад /usr/bin/vim -> /usr/bin/vim.vim
).
Здається, що з просторами імен користувачів можна насправді хронуватись без кореня. Ось приклад програми, яка демонструє, що це можливо. Я лише почав досліджувати, як працюють простори імен 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;
}
}
Я перевірив це на мінімальних коренях, згенерованих за допомогою мультистрапу (виконується як некореневий). Деякі системні файли, як /etc/passwd
і /etc/groups
були скопійовані з хост-корфів у гостьові корни.
Failed to unshare user namespace
для мене на Linux 4.12.10 (Arch Linux).
unshare
виклику. Ви також можете спробувати цю версію python, яка може мати кращі повідомлення про помилки: github.com/cheshirekow/uchroot
Ні. Якщо я правильно пригадую, є щось, що робить chroot, що перешкоджає цьому. Я не пам'ятаю, що це було. Я досліджував це ще раз, коли возився з інструментом збирання Catalyst Gentoo (а chroot на gentoo - те саме, що chroot на ubuntu). Хоча можна було б це зробити і без пароля ... але такі речі залишаються в царині потенційних вразливих місць безпеки і обов'язково знаєте, що ви робите.