Mengapa sumber Bash tidak membutuhkan bit eksekusi?

57

Dengan Bash, sourcedimungkinkan untuk mengeksekusi skrip tanpa set bit eksekusi. Ini perilaku yang didokumentasikan dan diharapkan, tetapi bukankah ini menentang penggunaan bit eksekusi?

Saya tahu, itu sourcetidak membuat subkulit.

Motte001
sumber
2
Fakta yang chmoddapat memungkinkan Anda menetapkan izin (termasuk `x) dengan angka oktal memberikan petunjuk tentang dari mana era itu berasal. Saya tidak akan terkejut jika itu dimulai sebagai indikator cepat dan kotor "ini adalah file biner yang dapat Anda jalankan", dari hari-hari sebelum dia-bang diciptakan, tetapi saya tidak punya bukti untuk itu
dipasang
9
Kemudian lagi, ketika SUID berperan, berbagai tingkat perlindungan untuk berbagai kategori pengguna menjadi lebih penting. Silakan dan baca program SUID saya jika Anda mau. Tetapi jika Anda menjalankannya hanya dengan membacanya, kekuatan SUID tidak ikut serta
infixed
@infixed Program-loader Linux bahkan tidak akan melihat shebang kecuali bit eksekusi ditetapkan. (Untuk sedikit membunyikan klakson sendiri: lihat di sini .)
Kyle Strand
Anda juga dapat memiliki + xr, tetapi itu agak aneh karena biasanya mungkin untuk membaca biner dengan menyuntikkan kode ke dalam proses yang sedang berjalan
Niklas B.
@KyleStrand oleh "jika Anda mengeksekusinya hanya dengan membacanya, kekuatan SUID tidak menyertainya" Saya membayangkan sesuatu di sepanjang bariscp /sbin/suidexecutable /tmp/mycopy; /tmp/mycopy
infixed

Jawaban:

36

Bash adalah seorang juru bahasa; ia menerima input dan melakukan apa pun yang diinginkannya. Tidak perlu memperhatikan bit yang dapat dieksekusi. Bahkan, Bash bersifat portable, dan dapat berjalan pada sistem operasi dan sistem file yang tidak memiliki konsep bit yang dapat dieksekusi.

Apa yang peduli dengan bit yang dapat dieksekusi adalah kernel sistem operasi. Ketika kernel Linux melakukan exec, misalnya, ia memeriksa apakah sistem file tidak di-mount dengan noexecopsi, ia memeriksa bit yang dapat dieksekusi dari file program, dan memberlakukan persyaratan yang diberlakukan oleh modul keamanan (seperti SELinux atau AppArmor).

Perhatikan bahwa bit yang dapat dieksekusi adalah jenis kontrol yang agak diskresioner. Pada sistem Linux x86-64, misalnya, Anda dapat mem-bypass verifikasi kernel dari bit yang dapat dieksekusi dengan secara eksplisit memanggil /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2sebagai interpreter :

cp /bin/ls /tmp/
chmod -x /tmp/ls
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /tmp/ls

Ini agak analog dengan sumber kode sumber Bash di Bash, kecuali itu ld.soadalah interpreter, dan kode yang dijalankannya adalah kode mesin dalam format ELF.

200_sukses
sumber
3
Menggunakan loader sebagai "interpreter" dari "bytecode" yang kebetulan merupakan biner yang benar-benar dapat dieksekusi ..... mengagumkan. Terima kasih untuk itu.
Kyle Strand
@KyleStrand mungkin ada beberapa tingkat tipuan (perbedaan antara program yang disimpan dan proses yang dimuat dan bagaimana memori dipetakan, berbagai pengawas, VM, dll) tetapi pada prinsipnya kode mesin dapat dijalankan oleh CPU secara langsung (tanpa mikrokode, dll) dan oleh karena itu kode mesin tidak diartikan: perangkat keras memahaminya sebagaimana adanya — itu adalah bahasa asli — tidak diperlukan penerjemah.
jfs
2
@ JSFSebastian Ya, kami tahu bahwa itu adalah kode asli, karenanya "juru bahasa" ada dalam tanda kutip. Tugasnya ld.soadalah melakukan tautan dinamis.
200_sukses
@ JFSebastian Apa yang dikatakan 200_success. Juga, itulah yang saya maksudkan dengan "biner nyata yang dapat dieksekusi," dan saya juga memasukkan "bytecode" dalam tanda kutip (karena AFAIK "bytecode" biasanya tidak digunakan untuk merujuk ke kode biner yang sebenarnya dapat dieksekusi secara alami yang dapat dieksekusi). Juga, nama pengguna yang bagus.
Kyle Strand
@ JFSebastian Saya percaya bahwa CPU modern seperti x86 sebenarnya adalah RISC secara internal, dengan instruksi CISC gaya lama pada dasarnya menggerakkan eksekusi mikrokode dari instruksi RISC yang sesuai, di mana satu instruksi CISC dapat menyebabkan banyak instruksi RISC dieksekusi. Jadi dalam arti tertentu, menyebut apa yang dilakukan CPU dengan kode mesin RISC "menafsirkan" adalah, jika tidak sepenuhnya benar dari sudut pandang teknis, maka setidaknya model mental yang valid. AES-NI mungkin salah satu contoh yang lebih ekstrem: satu instruksi CISC per putaran AES!
CVn
57

sourceatau setara tetapi standar dot. tidak menjalankan script, tapi membaca perintah dari file script, kemudian mengeksekusi mereka, baris demi baris, di lingkungan shell saat ini.

Ada apa-apa terhadap penggunaan bit eksekusi, karena shell hanya perlu membaca izin untuk membaca isi dari file.

Bit eksekusi hanya diperlukan saat Anda menjalankan skrip. Di sini shell akan fork()memproses baru kemudian menggunakan execve()fungsi untuk membuat gambar proses baru dari skrip, yang diperlukan untuk menjadi file biasa yang dapat dieksekusi.

cuonglm
sumber
5
@alexis: Saya tidak yakin saya benar-benar mengikuti. Jika ya bash < script, pada dasarnya Anda mendapatkan hasil yang sama dengan source script. Perlindungan apa yang disediakan oleh pemeriksaan bit eksekusi?
Compiler mencolok
27
@alexis, ini bukan tugas penerjemah untuk memeriksa izin skrip yang ditafsirkan. Tidak ada yang melakukan ini - bukan Python, bukan Ruby, bukan mesin virtual Java, bukan kerang acak lainnya. Bit eksekusi mengontrol apakah keluarga OS execv* dari syscall dapat digunakan dengan executable, bukan apakah seorang juru bahasa akan menjalankannya. Mengapa membingungkan orang (dan merusak kemampuan untuk mengevaluasi kode yang dialirkan dari sumber non-file) dengan melanggar konvensi?
Charles Duffy
14
@alexis, ... selain itu, ada makna yang berharga memiliki perpustakaan shell yang tidak dapat dieksekusi: Ia mengatakan "Saya perpustakaan, bukan perintah - sumber saya, jangan jalankan saya". Kalau tidak, Anda harus menulis kode untuk mendeteksi dan memulihkan penyalahgunaan kode yang dimaksudkan hanya bersumber, tetapi dengan tidak memiliki izin + x Anda dapat memastikan bahwa pengguna tidak dapat (tidak) menyalahgunakan perpustakaan sedemikian rupa.
Charles Duffy
6
@alexis "itu adalah keputusan oleh penulis" Hanya dalam arti bahwa setiap kemungkinan kode yang tidak termasuk adalah keputusan. Shell membuka file untuk membaca, untuk membaca perintah dari itu. Saya tidak akan mengharapkannya untuk memeriksa izin baca, itu hanya mencoba untuk membuka file dan gagal jika tidak bisa. Demikian juga itu tidak memeriksa untuk menulis atau mengeksekusi izin, karena cek itu tidak relevan untuk membaca file.
Randy Orrison
2
@alexis Ini digunakan dalam prakteknya, misalnya, dengan virtualenv python, skrip untuk mengaktifkannya harus bersumber, dan tidak dieksekusi, dan dengan demikian bin/activatetidak memiliki bit yang dapat dieksekusi. Naskah dapat sepenuhnya menjadi perpustakaan atau hal lain seperti itu. Saya kira memiliki .sh mungkin merupakan sinyal juga, tetapi memiliki minimum senjata kaki itu baik: itu bagus bahwa tidak mungkin dijalankan ./bin/activatesecara tidak sengaja. bin/activate
daboross
20

Bit yang dapat dieksekusi (tidak seperti yang lain) pada file nonsetuid dan nonsetguid tidak banyak mekanisme keamanan. Apa pun yang dapat Anda baca, Anda dapat menjalankan secara tidak langsung, dan Linux akan membiarkan Anda secara tidak langsung membaca apa pun yang dapat Anda jalankan tetapi tidak secara langsung membaca (yang seharusnya cukup untuk melubangi konsep non-set (g) dan x-bit menjadi langkah keamanan).

Ini lebih merupakan hal yang mudah: Biarkan sistem menjalankannya untuk saya secara langsung jika bitnya diatur, kalau tidak saya perlu melakukannya secara tidak langsung ( bash the_script;atau beberapa peretasan untuk mendapatkan gambar memori dari eksekusi tanpa izin yang dapat dijalankan ).

Anda dapat mengaturnya untuk kenyamanan jika Anda berniat baik dalam-sumber dan mengeksekusi insourcable Anda.

Namun, tampaknya, banyak pelaksana perpustakaan bersama yang berbagi pemikiran Anda dan akibatnya, banyak sistem mengharuskan perpustakaan bersama, yang pada dasarnya adalah padanan asli dari sumber shell, ditandai dapat dieksekusi agar dapat digunakan. Lihat Mengapa perpustakaan bersama dapat dieksekusi? .

PSkocik
sumber
3
@ Motte001 Mereka dapat menjalankan lampiran itu jika mereka benar-benar mau. Itu kenyamanan.
PSkocik
2
Bit yang dapat dieksekusi bukan untuk keamanan: Jika saya memiliki file, saya bebas untuk chmoditu dan membuatnya dapat dieksekusi. Ini untuk menyortir data dari program, jadi pertanyaan OP adalah pertanyaan yang masuk akal.
alexis
1
@ Motte001 Itu lebih merupakan fitur keamanan aplikasi file / browser GUI - dapat dengan mudah memutuskan bahwa mengklik dua kali file apa pun yang namanya berakhir ".sh" dijalankan di terminal (gaya Windows), atau sebaliknya double- mengklik file apa pun di direktori "lampiran yang diunduh" akan meminta aplikasi pratinjau built-in sandbox. The xbit hanya sebuah tempat ekstra itu dapat membaca / menulis petunjuk apa yang harus dilakukan.
IMSoP
3
Salah satu alasan kita membutuhkan bit yang dapat dieksekusi adalah untuk menjalankan program setuid, terutama yang dimiliki oleh root. Meskipun Anda dapat menjalankannya sendiri, Anda membutuhkan OS untuk menjalankannya sehingga mereka memiliki izin yang diperlukan. Dalam beberapa kasus lain itu hanya kenyamanan.
Waleed Khan
2
"Linux akan membiarkan Anda membaca apa pun yang dapat Anda jalankan melalui / proc" - Yah, stok saya kernel Debian tidak: /tmp$ cp /bin/cat ./cat ; chmod a-rw ./cat ; ./cat & cp /proc/$!/exe /tmp/cat2->cp: cannot stat ‘/proc/16260/exe’: Permission denied
ilkkachu
9

Itu pertanyaan yang bagus! Unix menggunakan bit yang dapat dieksekusi untuk membedakan antara program dan data. OS tidak memerlukan bit eksekusi, karena skrip bersumber tidak diteruskan ke OS untuk dieksekusi sebagai proses baru. Tetapi shell memperlakukan skrip bersumber sebagai sebuah program, dan akan mencari $PATHfile yang ingin Anda sumber. Jadi, shell itu sendiri dapat meminta izin untuk mengeksekusi file bersumber; tapi ternyata tidak.

Pertanyaannya pasti sudah lama muncul. Desain cangkang Bourne adalah hasil dari "rangkaian modifikasi, dialog, diskusi" yang panjang di antara para penghuni Bell Labs, dan banyak keputusan desain didiskusikan oleh SR Bourne dan yang lainnya selama bertahun-tahun. Sayangnya, pandangan cepat saya tidak menemukan diskusi tentang fitur sumber (dalam pertahanan saya, sulit untuk google untuk itu). Apa yang saya temukan adalah "." perintah tidak muncul dalam pengantar awal ke shell oleh Bourne sendiri, tetapi hadir dalam versi 7 versi yang lebih matang .

Tanpa otoritas, inilah interpretasi saya sendiri:

  1. The .perintah, alias source, ini berlaku tekstual inklusi (seperti #includedi C preprocessor) ke kode sumber dari script mengeksekusi atau sesi interaktif. Karena itu, file yang disertakan tidak boleh "dieksekusi".

  2. Filosofi Unix selalu memberi para programmer cukup tali untuk menggantung diri. Terlalu banyak larangan berpegangan tangan dan sewenang-wenang hanya menghalangi. Baru-baru ini beberapa distribusi rm -r /menolak untuk melakukan apa yang Anda minta. (Perintah ini memberi tahu rmuntuk menghapus semua yang ada di komputer Anda. Jangan mencobanya sebagai root! Atau lebih baik lagi, tidak sama sekali.) Jadi, mungkin Bourne di al. baru saja memutuskan bahwa ketika Anda mencoba untuk sumber file, Anda dianggap tahu apa yang Anda lakukan. Itu juga menghindari pekerjaan yang tidak perlu, dan siklus sangat berarti saat itu.

alexis
sumber
Tapi satu harus pasti tidak melakukan apa @cat kata.
TOOGAM
Saya terkejut itu belum ditandai dan dihapus @ TOOGAM tapi saya memasukkan / s!
kucing
Di sana, saya tidak tahu apa yang telah ditulis oleh @cat tetapi saya lebih membuktikan bahwa jawabannya adalah anak-anak. (Tapi ayolah, sudah cukup jelas dari konteksnya.)
alexis
4

Sejauh menyangkut OS, file yang berisi skrip shell hanyalah data. Jika Anda meneruskan nama file data seperti itu ke sourceperintah atau meneruskannya di baris perintah ke doa bash shell, semua OS melihat adalah string yang kebetulan bertepatan dengan nama file yang berisi data.

Bagaimana bit eksekusi akan relevan dalam kasus itu?

Stephen M. Webb
sumber
3

Perbedaannya penting karena Anda mungkin memiliki file perintah shell yang tidak berguna sebagai executable, tetapi hanya berguna ketika bersumber. Untuk file ini, Anda dapat mematikan bit eksekusi dan kemudian tidak akan pernah diakses kecuali secara eksplisit dalam perintah sumber. Alasan untuk hal seperti itu adalah untuk memiliki efek samping pada cangkang asalnya. Untuk contoh tertentu, saya memiliki skrip bernama fix_path yang melihat dan memodifikasi path.

PETA
sumber
1

Untuk berjaga-jaga kalau-kalau ada yang tertarik dalam studi lebih lanjut dan / atau klarifikasi: Dalam shell yang hampir memenuhi syarat POSIX diimplementasikan beberapa waktu lalu, kerja internal fungsi 'exec_program ()' dan 'builtin_source ()' sangat patut dicontoh. Dalam fungsi-fungsi itu Anda melihat secara persis apa perbedaan di antara mereka:

https://github.com/rsenn/shish/blob/master/src/builtin/builtin_source.c

https://github.com/rsenn/shish/blob/master/src/exec/exec_program.c

pada dasarnya sumber dapat dilihat sebagai shell sementara mengarahkan kembali deskriptor file internal di mana ia mem-parsing script shell dari (terminal dalam mode interaktif). jadi sangat mirip dengan pengalihan lainnya seperti <input_file.txtdan >>append_to_something.listdan ini hanya perlu membuka dan menutup file.

jadi eksekusi ditangani oleh execve()system call yang mana bit eksekusi itu wajib.

Saya ingat melihat beberapa sistem yang memungkinkan eksekusi binari ELF / a.out, tetapi melalui mengeksekusi "/lib/ld-dynamic-linker.so" dan dengan program biner (tanpa bit exec) sebagai argumen pertama. Saya percaya itu pada beberapa mesin DEC Alpha atau VAX (Mungkinkah itu SCO Unix?)

rsenn
sumber
-2

Sudut pandang lain:

Skrip bersumber pada dasarnya terdiri dari shell bawaan dan panggilan program. Shell builtin (dengan sourcedi antaranya) adalah bagian dari shell dan shell harus dapat dieksekusi di tempat pertama. Setiap program yang dipanggil (yang menjadi ELF, skrip lain dengan shebang, apa pun) harus memiliki bit eksekusi, jika tidak maka ia tidak akan berjalan.

Jadi itu tidak menentang penggunaan bit eksekusi, karena tidak ada yang tanpa bit eksekusi yang akan berjalan. Validasi tidak terjadi untuk skrip bersumber secara keseluruhan; itu dilakukan untuk setiap bagian secara terpisah, tetapi itu dilakukan.

Kamil Maciorowski
sumber
Shell buildin tidak bersumber dari skrip shell. Biasanya mereka adalah bagian dari shell yang dapat dieksekusi. Di ksh93, zsh dan beberapa shell lainnya, mereka bisa menjadi ekstensi shell.
fpmurphy
@ fpmurphy1 Bukankah ini kalimat saya "shell builtins (...) adalah bagian dari shell"?
Kamil Maciorowski