Bagaimana saya tahu saya menjalankan chroot?

47

Saya memiliki instalasi unix yang seharusnya dapat digunakan baik sebagai chroot maupun sebagai sistem mandiri. Jika dijalankan sebagai chroot, saya tidak ingin menjalankan layanan apa pun (cron, inetd, dan sebagainya), karena mereka akan bertentangan dengan sistem host atau menjadi mubazir.

Bagaimana cara saya menulis skrip shell yang berperilaku berbeda tergantung pada apakah skrip itu berjalan dalam chroot? Kebutuhan mendesak saya adalah sistem Linux modern, dengan /procmount di chroot, dan skrip berjalan sebagai root, tetapi jawaban yang lebih portabel juga diterima. (Lihat Bagaimana saya tahu saya menjalankan chroot jika / proc tidak di-mount? Untuk Linux tanpa /proc.)

Secara umum, saran yang bekerja untuk metode penahanan lainnya akan menarik. Pertanyaan praktisnya adalah, apakah sistem ini seharusnya menjalankan layanan? (Jawabannya adalah tidak di chroot, dan ya di mesin virtual lengkap; Saya tidak tahu tentang kasus menengah seperti penjara atau wadah.)

Gilles 'SANGAT berhenti menjadi jahat'
sumber

Jawaban:

46

Apa yang saya lakukan di sini adalah untuk menguji apakah root dari initproses (PID 1) sama dengan root dari proses saat ini. Meskipun /proc/1/rootselalu merupakan tautan ke /(kecuali initdirinya chroot, tapi itu bukan masalah yang saya pedulikan), setelah itu mengarah ke direktori root "master". Teknik ini digunakan dalam beberapa skrip pemeliharaan di Debian, misalnya untuk melewatkan memulai udev setelah instalasi di chroot.

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

(Omong-omong, ini adalah contoh lain mengapa chroottidak berguna untuk keamanan jika proses chroot memiliki akses root. Proses non-root tidak dapat membaca /proc/1/root, tetapi mereka dapat mengikuti /proc/1234/rootjika ada proses yang berjalan dengan PID 1234 berjalan sebagai sama pengguna.)

Jika Anda tidak memiliki izin root, Anda dapat melihat /proc/1/mountinfodan /proc/$$/mountinfo(secara singkat didokumentasikan dalam filesystems/proc.txtdokumentasi kernel Linux ). File ini dapat dibaca dunia dan berisi banyak informasi tentang setiap titik pemasangan dalam pandangan proses sistem file. Jalur dalam file tersebut dibatasi oleh chroot yang memengaruhi proses pembaca, jika ada. Jika proses membaca /proc/1/mountinfochroot ke sistem file yang berbeda dari root global (dengan asumsi root pid 1 adalah root global), maka tidak ada entri untuk /muncul di /proc/1/mountinfo. Jika pembacaan proses /proc/1/mountinfodilakukan chroot ke direktori pada sistem file root global, maka entri untuk /muncul /proc/1/mountinfo, tetapi dengan id mount berbeda. Kebetulan, bidang root ($4) menunjukkan di mana chroot berada di sistem file induknya.

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

Ini adalah solusi Linux murni. Ini dapat digeneralisasikan untuk varian Unix lain dengan cukup mirip /proc(Solaris memiliki yang serupa /proc/1/root, saya pikir, tetapi tidak mountinfo).

Gilles 'SANGAT berhenti menjadi jahat'
sumber
1
Ini tidak akan berfungsi di OpenBSD karena memiliki PID acak ; proses root pada dasarnya tidak pernah PID 1. Sekarang Anda tahu mengapa!
Adam Katz
@AdamKatz "... dengan beberapa pengecualian yang jelas, misalnya, init (8)." Jadi yang mana?
muru
@uru: aw, brengsek. Anda telah menembak saya. Saya tidak yakin mengapa init(8)benar-benar harus memiliki slot # 1 kecuali ada beberapa jenis hard-coded yang membutuhkannya (di mana saya masih tidak yakin mengapa ). Tentu saja, BSD memiliki penjara yang jauh lebih maju dari sekadar chroot, jadi saya bahkan tidak yakin betapa problematisnya ini.
Adam Katz
4
@ AdamKatz Sebaliknya: pid 1 memiliki peran khusus (ia harus menuai zombie, dan itu kebal terhadap SIGKILL). Program init adalah implementasi dari peran itu. Alasan jawaban saya tidak berfungsi di OpenBSD tidak ada hubungannya dengan ini: itu karena OpenBSD tidak memiliki apa pun seperti Solaris / Linux /proc. Jawaban saya tidak dimaksudkan untuk mengatasi apa pun selain Linux.
Gilles 'SANGAT berhenti menjadi jahat'
@Gilles Saya pikir OpenBSD akan mengalahkan ini dengan cara apa pun. Namun, saya terkejut bahwa semua item peran khusus tidak mampu diterapkan pada PID sewenang-wenang (tanpa konsekuensi), yang saya maksudkan dalam huruf miring saya "mengapa" sebelumnya.
Adam Katz
22

Seperti disebutkan dalam cara Portable untuk menemukan nomor inode dan Mendeteksi jail chroot dari dalam , Anda dapat memeriksa apakah nomor inode /adalah 2:

$ ls -di /
2 /

Nomor inode yang berbeda dari 2 menunjukkan bahwa root yang terlihat bukan root sebenarnya dari sistem file. Ini tidak akan mendeteksi chroot yang kebetulan di-root pada mount point, atau pada sistem operasi dengan nomor inode root acak .

l0b0
sumber
Pada filesystem apa sajakah heuristik ini bekerja?
Gilles 'SO- stop being evil'
Diuji pada ext3 dan hfs.
l0b0
Jadi saya bermain-main, dan saya pikir saya telah menemukan metode yang lebih dapat diandalkan yang tidak memerlukan izin root (hanya Linux). Saya masih terbuka untuk contoh-contoh atau lebih banyak metode portabel.
Gilles 'SO- stop being evil'
6
Ini berlaku untuk ext [234], tetapi tidak untuk semua sistem file. Itu juga hanya menguji bahwa root Anda adalah root dari sistem file, yang mungkin tidak dipasang sebagai root sebenarnya. Dengan kata lain, jika Anda me-mount partisi lain di / jail dan chroot /jail, maka itu akan terlihat seperti root asli untuk tes ini.
psusi
1
@ AdamKatz Tampaknya tidak. Diuji dalam openbsd 6.0-stable, nomor inode masih 2 untuk path root yang sebenarnya sementara itu nomor acak untuk chroot.
Dmitri DB
5

Meskipun jelas tidak portabel seperti banyak opsi lain yang tercantum di sini, jika Anda menggunakan sistem berbasis Debian, cobalah ischroot.

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

Untuk mendapatkan status di konsol secara langsung, gunakan ischroot:

ischroot;echo $?

Kode keluar:

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).
thom_nic
sumber