Ada pertanyaan serupa yang berhubungan dengan skenario 'pembungkus', di mana Anda ingin mengganti misalnya cd
dengan perintah yang memanggil builtin cd
.
Namun, mengingat shellshock et al dan mengetahui bahwa bash mengimpor fungsi dari lingkungan, saya telah melakukan beberapa tes dan saya tidak dapat menemukan cara untuk memanggil buildin dengan aman cd
dari skrip saya.
Pertimbangkan ini
cd() { echo "muahaha"; }
export -f cd
Setiap skrip yang dipanggil dalam lingkungan ini menggunakan cd
akan rusak (pertimbangkan efek dari sesuatu seperti cd dir && rm -rf .
).
Ada perintah untuk memeriksa jenis perintah (mudah dipanggil type
) dan perintah untuk mengeksekusi versi builtin daripada fungsi ( builtin
dan command
). Tapi, lihat dan lihat, ini bisa diganti menggunakan fungsi juga
builtin() { "$@"; }
command() { "$@"; }
type() { echo "$1 is a shell builtin"; }
Akan menghasilkan yang berikut:
$ type cd
cd is a shell builtin
$ cd x
muahaha
$ builtin cd x
muahaha
$ command cd x
muahaha
Apakah ada cara untuk memaksa bash secara aman untuk menggunakan perintah builtin, atau setidaknya mendeteksi bahwa suatu perintah bukanlah builtin, tanpa membersihkan seluruh lingkungan?
Saya menyadari jika seseorang mengendalikan lingkungan Anda, Anda mungkin masih bisa mengacaukannya, tetapi setidaknya untuk alias Anda punya opsi untuk tidak memanggil alias dengan menyisipkan \
sebelumnya.
env
perintah sebelumnya, seperti ini:env -i <SCRIPT.sh>
env
tidak didefinisikan ulang sebagai suatu fungsi juga. Ini menakutkan. Saya pertama kali berpikir bahwa karakter khusus akan membantu - memanggil dengan path lengkap yang mencakup/
, menggunakan.
sumber, dan sebagainya. Tapi itu juga bisa digunakan untuk nama fungsi! Anda dapat mendefinisikan kembali fungsi yang Anda inginkan, tetapi sulit untuk kembali memanggil perintah asli.#/bin/sh
jika ini bukan shell interaktif bawaan.Jawaban:
Olivier D hampir benar, tetapi Anda harus mengatur
POSIXLY_CORRECT=1
sebelum menjalankanunset
. POSIX memiliki gagasan tentang Built-in Khusus , dan bash mendukung ini .unset
adalah salah satu builtin tersebut. MencariSPECIAL_BUILTIN
dibuiltins/*.c
dalam sumber bash untuk daftar, itu termasukset
,unset
,export
,eval
dansource
.Nakal yang
unset
sekarang telah dihapus dari lingkungan, jika Anda unsetcommand
,type
,builtin
maka Anda harus bisa melanjutkan, tetapiunset POSIXLY_CORRECT
jika Anda mengandalkan pada perilaku non-POSIX atau fitur pesta canggih.Ini tidak membahas alias, jadi Anda harus menggunakannya
\unset
untuk memastikan itu bekerja di shell interaktif (atau selalu, dalam kasusexpand_aliases
berlaku).Untuk paranoid, ini harus memperbaiki semuanya, saya pikir:
(
while
,do
,done
Dan[[
dicadangkan kata-kata dan tidak perlu tindakan pencegahan.) Catatan kami menggunakanunset -f
untuk memastikan fungsi unset, meskipun variabel dan fungsi berbagi ruang nama yang sama itu mungkin bagi keduanya untuk eksis secara bersamaan (terima kasih kepada Etan Reisner) dalam hal unset-ing dua kali juga akan melakukan trik. Anda dapat menandai fungsi readonly, bash tidak mencegah Anda membatalkan fungsi readonly hingga dan termasuk bash-4.2, bash-4.3 memang mencegah Anda tetapi masih menghormati builtin khusus ketikaPOSIXLY_CORRECT
diatur.Readonly
POSIXLY_CORRECT
bukan masalah nyata, ini bukan boolean atau flag kehadirannya memungkinkan mode POSIX, jadi jika itu ada sebagai readonly Anda dapat mengandalkan fitur POSIX, bahkan jika nilainya kosong atau 0. Anda hanya perlu hapus fungsi bermasalah dengan cara yang berbeda dari yang di atas, mungkin dengan beberapa cut-and-paste:(dan abaikan kesalahan apa pun) atau terlibat dalam beberapa scriptobatics lainnya .
Catatan lain:
function
adalah kata yang dilindungi undang-undang, ini bisa alias tetapi tidak diganti dengan fungsi. (Aliasingfunction
agak sulit karena\function
tidak dapat diterima sebagai cara untuk melewatinya)[[
,]]
adalah kata-kata yang dicadangkan, mereka dapat alias (yang akan diabaikan) tetapi tidak diganti dengan fungsi (meskipun fungsi dapat dinamai demikian)((
bukan nama yang valid untuk suatu fungsi, atau aliassumber
unset
et al dari ditimpa.-f
argumen untukunset
bukan? Kalau tidak, jika kedua variabel dan fungsi bernama sama dengan builtin didefinisikan makaunset
akan memilih variabel untuk tidak disetel terlebih dahulu. Ini juga gagal jika salah satu fungsi yangreadonly
tidak jelas diatur bukan? (Meskipun itu dapat dideteksi dan dapat membuat kesalahan fatal.) Juga ini merindukan[
builtin sepertinya.\unset -f unset
masuk akal, mengingat itu akan dilakukan dalam loop baca. Jikaunset
merupakan fungsi yang\unset
biasanya Anda selesaikan alih-alih builtin, tetapi Anda dapat menggunakannya\unset
dengan aman selama mode POSIX berlaku. Secara eksplisit menyebut\unset -f
tentang[
,.
dan:
mungkin ide yang baik juga, karena tidak termasuk regex Anda mereka. Saya juga akan menambahkan-f
ke\unset
dalam loop, dan akan\unset POSIXLY_CORRECT
setelah loop, daripada sebelumnya.\unalias -a
(Setelah\unset -f unalias
) juga memungkinkan seseorang untuk dengan aman melepaskan pelarian pada perintah berikutnya.[[ ${POSIXLY_CORRECT?non-POSIX mode shell is untrusted}x ]]
ini akan menyebabkan skrip non-interaktif keluar dengan kesalahan yang ditunjukkan jika variabel tidak disetel, atau melanjutkan jika disetel (kosong, atau nilai apa pun).\unset
" ... Harus dicatat bahwa mengutip karakter apa pun akan berfungsi untuk menghindari ekspansi alias, bukan hanya yang pertama.un"se"t
akan bekerja dengan baik, abeit kurang mudah dibaca. "Kata pertama dari setiap perintah sederhana, jika tidak dikutip, diperiksa untuk melihat apakah ada alias." - Bash RefYa itu. Jika Anda menjalankan skrip di lingkungan yang tidak dikenal, segala hal bisa salah, mulai dengan
LD_PRELOAD
menyebabkan proses shell mengeksekusi kode arbitrer sebelum bahkan membaca skrip Anda. Mencoba melindungi dari lingkungan yang bermusuhan dari dalam skrip itu sia-sia.Sudo telah membersihkan lingkungan dengan menghapus apa pun yang tampak seperti definisi fungsi bash selama lebih dari satu dekade. Sejak Shellshock , lingkungan lain yang menjalankan skrip shell di lingkungan yang tidak sepenuhnya tepercaya telah mengikuti.
Anda tidak dapat menjalankan skrip dengan aman di lingkungan yang telah ditetapkan oleh entitas yang tidak dipercaya. Jadi mengkhawatirkan definisi fungsi tidak produktif. Sanitasi lingkungan Anda, dan dengan melakukannya, variabel yang akan ditafsirkan oleh bash sebagai definisi fungsi.
sumber
/bin/cat
chroot bisa memanggil apa saja.) Membersihkan lingkungan memang membuat Anda warasPATH
(tentu saja dengan asumsi Anda melakukannya dengan benar). Saya masih tidak mengerti maksud Anda.Anda dapat menggunakan
unset -f
untuk menghapus fungsi builtin, perintah dan ketik.sumber
unset() { true; }
urus itu.