È possibile per un utente non root eseguire un processo chroot su Ubuntu?
È possibile per un utente non root eseguire un processo chroot su Ubuntu?
Risposte:
Su Linux la chiamata di sistema chroot (2) può essere effettuata solo con un processo privilegiato. La capacità di cui il processo ha bisogno è CAP_SYS_CHROOT.
Il motivo per cui non è possibile eseguire il chroot come utente è piuttosto semplice. Supponiamo di avere un programma setuid come sudo che controlla / etc / sudoers se ti è permesso fare qualcosa. Ora mettilo in un chroot chroot con il tuo / etc / sudoers. All'improvviso hai un'escalation di privilegi istantanea.
È possibile progettare un programma per chroot stesso ed eseguirlo come un processo setuid, ma questo è generalmente considerato una cattiva progettazione. La sicurezza aggiuntiva del chroot non motiva i problemi di sicurezza con il setuid.
chroot
poi eseguire .
@ imz - IvanZakharyaschev commenta la risposta di Pehrs che potrebbe essere possibile con l'introduzione di spazi dei nomi, ma questo non è stato testato e pubblicato come risposta. Sì, ciò rende effettivamente possibile per un utente non root usare chroot.
Dato uno staticamente collegato dash
, uno staticamente collegato busybox
e una bash
shell in esecuzione in esecuzione come non 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
L'ID utente root in quel namespace è mappata non root ID utente all'esterno di detto spazio, e viceversa, motivo per cui i file di sistema mostra proprietà dell'utente corrente come proprietà di ID utente 0. Un regolare ls -al root
, senza unshare
, fa mostrarli come di proprietà dell'utente corrente.
Nota: è noto che i processi in grado di utilizzare chroot
sono in grado di uscire da a chroot
. Poiché unshare -r
concederebbe le chroot
autorizzazioni a un utente normale, sarebbe un rischio per la sicurezza se ciò fosse consentito all'interno di un chroot
ambiente. In effetti, non è consentito e non riesce con:
unshare: unshare non riuscita: operazione non consentita
che corrisponde alla documentazione unshare (2) :
EPERM (dal Linux 3.9)
CLONE_NEWUSER è stato specificato nei flag e il chiamante si trova in un ambiente chroot (ovvero, la directory principale del chiamante non corrisponde alla directory principale dello spazio dei nomi di mount in cui risiede).
In questi giorni, vuoi guardare LXC (Linux Containers) invece di chroot / BSD jail. È a metà strada tra un chroot e una macchina virtuale, offrendoti molto controllo di sicurezza e configurabilità generale. Credo che tutto ciò di cui hai bisogno per eseguirlo come utente sia essere un membro del gruppo che possiede i file / dispositivi necessari, ma potrebbero esserci anche capacità / autorizzazioni di sistema. Ad ogni modo, dovrebbe essere molto fattibile, dato che LXC è abbastanza recente, molto tempo dopo che SELinux ecc. È stato aggiunto al kernel Linux.
Inoltre, tieni presente che puoi semplicemente scrivere script come root ma dare agli utenti l'autorizzazione sicura per eseguirli (senza una password se vuoi, ma assicurati che lo script sia sicuro) usando sudo.
La combinazione di fakeroot / fakechroot fornisce un simulacro di chroot per esigenze semplici come la produzione di archivi tar in cui i file sembrano essere di proprietà di root. La manpage di Fakechroot è http://linux.die.net/man/1/fakechroot .
Tuttavia, non si ottiene alcuna nuova autorizzazione, ma se si possiede una directory (ad esempio fake-distro) prima di invocare
fakechroot fakeroot chroot ~/fake-distro some-command
ora cerca qualche comando come se fossi root e possiedi tutto in fake-distro.
~/fake-distro
usi busybox, che link simbolici ls
, mv
e altre utilità comuni /bin/busybox
. Se chiamo esplicitamente /bin/busybox mv ...
, le cose funzionano, ma se chiamo /bin/mv ...
ottengo sh: /bin/mv: not found
. L'impostazione export FAKECHROOT_EXCLUDE_PATH=/
prima di eseguire fakechroot corregge quel sintomo, ma poi si interrompe su altri collegamenti simbolici (ad es /usr/bin/vim -> /usr/bin/vim.vim
.).
Sembra che con gli spazi dei nomi utente sia possibile chroot senza root. Ecco un programma di esempio che dimostra che è possibile. Ho solo iniziato a esplorare come funzionano gli spazi dei nomi di Linux e quindi non sono del tutto sicuro se questo codice sia la migliore pratica o meno.
Salva come user_chroot.cc
. Compila con g++ -o user_chroot user_chroot.cc
. L'uso è ./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;
}
}
Ho provato questo su un minimo rootfs generato con multistrap (eseguito come non root). Alcuni file di sistema gradiscono /etc/passwd
e /etc/groups
sono stati copiati dai rootfs host ai rootfs guest.
Failed to unshare user namespace
per me su Linux 4.12.10 (Arch Linux).
unshare
chiamata non riuscita . Puoi anche provare questa versione di Python che potrebbe avere una migliore messaggistica di errore: github.com/cheshirekow/uchroot
No. Se ricordo bene c'è qualcosa a livello di kernel che Chroot fa per impedirlo. Non ricordo cos'era quella cosa. L'ho studiato di nuovo quando si scherzava con lo strumento Catalyst Build di Gentoo (e un chroot su gentoo è lo stesso di un chroot su Ubuntu). Anche se sarebbe possibile farlo accadere senza un passwd ... ma tali cose sono lasciate al regno delle potenziali vulnerabilità della sicurezza e assicurandosi di sapere cosa stai facendo.