Jak mam powiedzieć, że biegam w chroot?


46

Mam instalację uniksową, która powinna być użyteczna zarówno jako chroot, jak i jako samodzielny system. Jeśli działa jako chroot, nie chcę uruchamiać żadnej usługi (cron, inetd itd.), Ponieważ mogą one powodować konflikt z systemem hosta lub być redundantne.

Jak napisać skrypt powłoki, który zachowuje się inaczej w zależności od tego, czy jest uruchomiony w chroot? Moją natychmiastową potrzebą jest nowoczesny system Linux z /proczamontowanym w chroot, a skrypt działa jako root, ale mile widziane są również bardziej przenośne odpowiedzi. (Zobacz Jak mam powiedzieć, że działam w chroot, jeśli / proc nie jest zamontowany? W przypadku Linuksa bez /proc.)

Mówiąc bardziej ogólnie, interesujące byłyby sugestie, które działają w przypadku innych metod powstrzymywania. Praktyczne pytanie brzmi: czy ten system powinien obsługiwać jakieś usługi? (Odpowiedź brzmi „nie” w chroot i „tak” w pełnoprawnych maszynach wirtualnych; nie wiem o przypadkach pośrednich, takich jak więzienia lub kontenery).

Odpowiedzi:


45

To, co zrobiłem tutaj, to sprawdzenie, czy podstawa initprocesu (PID 1) jest taka sama jak podstawa bieżącego procesu. Chociaż /proc/1/rootzawsze jest to link do /(chyba że initsam jest chrootowany, ale nie jest to przypadek, na którym mi zależy), podążanie za nim prowadzi do głównego katalogu głównego. Ta technika jest używana w kilku skryptach konserwacyjnych w Debianie, na przykład, aby pominąć uruchamianie udev po instalacji w chroot.

if [ "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" ]; then
  echo "We are chrooted!"
else
  echo "Business as usual"
fi

(Nawiasem mówiąc, jest to kolejny przykład, dlaczego chrootjest bezużyteczny dla bezpieczeństwa, jeśli proces chrootowany ma dostęp do roota. Procesy inne niż root nie mogą czytać /proc/1/root, ale mogą śledzić, /proc/1234/rootjeśli istnieje uruchomiony proces z PID 1234 działającym tak samo użytkownik.)

Jeśli nie masz uprawnień roota, możesz przejrzeć /proc/1/mountinfoi /proc/$$/mountinfo(krótko udokumentowane w filesystems/proc.txtdokumentacji jądra Linuksa ). Ten plik jest czytelny dla całego świata i zawiera wiele informacji o każdym punkcie montowania w widoku systemu plików procesu. Ścieżki w tym pliku są ograniczone przez chroot wpływający na proces czytnika, jeśli taki istnieje. Jeśli odczyt procesu /proc/1/mountinfojest chrootowany do systemu plików innego niż globalny katalog główny (przy założeniu, że katalog główny pid 1 jest globalnym katalogiem głównym), wówczas w polu nie /pojawia się wpis /proc/1/mountinfo. Jeśli odczyt procesu /proc/1/mountinfojest chrootowany do katalogu w globalnym systemie plików root, wtedy wpis dla /pojawia się w /proc/1/mountinfo, ale z innym identyfikatorem montowania. Nawiasem mówiąc, pole główne ($4) wskazuje, gdzie chroot znajduje się w głównym systemie plików.

[ "$(awk '$5=="/" {print $1}' </proc/1/mountinfo)" != "$(awk '$5=="/" {print $1}' </proc/$$/mountinfo)" ]

To jest czysto rozwiązanie Linux. Może być generalizowalny do innych wariantów Uniksa z wystarczająco podobnymi /proc(Solaris ma podobne /proc/1/root, myślę, ale nie mountinfo).


1
To nie zadziała w OpenBSD, ponieważ ma losowe PID ; proces rootowania w zasadzie nigdy nie jest PID 1. Teraz wiesz, dlaczego!
Adam Katz

@AdamKatz „... z kilkoma oczywistymi wyjątkami, np. Init (8).” Więc co to jest?
muru

@muru: aw, pieprzy. Zestrzeliłeś mnie. Nie jestem pewien, dlaczego init(8)absolutnie musiałbym mieć slot nr 1, chyba że istnieje jakaś zakodowana natura, która tego wymaga (w którym nadal nie jestem pewien, dlaczego ). Oczywiście BSD mają znacznie bardziej zaawansowane więzienia niż tylko chroot, więc nie jestem nawet pewien, jak problematyczne jest to.
Adam Katz

4
@AdamKatz Odwrotnie: pid 1 ma szczególną rolę (musi czerpać zombie i jest odporny na SIGKILL). Program init jest realizacją tej roli. Powód, dla którego moja odpowiedź nie działa w OpenBSD, nie ma z tym nic wspólnego: to dlatego, że OpenBSD nie ma nic takiego jak Solaris / Linux /proc. W każdym razie moja odpowiedź nie dotyczyła niczego poza Linuksem.
Gilles „SO- przestań być zły”

@Gilles Doszedłem do wniosku, że OpenBSD pokonałoby to w taki czy inny sposób. Mimo to jestem zaskoczony, że wszystkie te specjalne role nie mogą być zastosowane do arbitralnego PID (bez konsekwencji), co miałem na myśli w moim kursywy „dlaczego” wcześniej.
Adam Katz

22

Jak wspomniano w Przenośny sposób znajdowania numeru i- węzła i Wykrywanie więzienia chroot od wewnątrz , możesz sprawdzić, czy numer i-węzła /to 2:

$ ls -di /
2 /

Liczba i-węzłów różna od 2 wskazuje, że pozorny katalog główny nie jest rzeczywistym katalogiem głównym systemu plików. Nie wykryje to chrootów, które zdarzają się zrootowane w punkcie montowania lub w systemach operacyjnych z losowymi liczbami i-węzłów root .


Na jakich systemach plików działa ta heurystyka?
Gilles 'SO - przestań być zły'

Testowane na ext3 i hfs.
l0b0

Wygłupiałem się i myślę, że znalazłem bardziej niezawodną metodę, która nie wymaga uprawnień roota (tylko Linux). Nadal jestem otwarty na kontrprzykłady lub bardziej przenośne metody.
Gilles 'SO - przestań być zły'

6
Dotyczy to ext [234], ale nie wszystkich systemów plików. Testuje również tylko, czy katalog główny jest katalogiem głównym systemu plików, którego nie można zamontować jako prawdziwy katalog główny. Innymi słowy, jeśli zamontujesz inną partycję w / jail chroot /jail, a wtedy będzie wyglądać jak prawdziwy root do tego testu.
psusi

1
@AdamKatz Najwyraźniej nie. Testowany w stabilnej wersji Openbsd 6.0, liczba i-węzłów nadal wynosi 2 dla faktycznej ścieżki katalogu głównego, podczas gdy jest to liczba losowa dla chroota.
Dmitri DB

5

Chociaż wyraźnie nie jest tak przenośny, jak wiele innych opcji tutaj wymienionych, jeśli korzystasz z systemu opartego na Debianie, spróbuj ischroot.

Zobacz: https://manpages.debian.org/jessie/debianutils/ischroot.1.en.html

Aby uzyskać status bezpośrednio w konsoli, używając ischroot:

ischroot;echo $?

Kody wyjścia:

0 if currently running in a chroot
1 if currently not running in a chroot
2 if the detection is not possible (On GNU/Linux this happens if the script is not run as root).
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.