Bash'in kaynağının neden yürütme bitine ihtiyacı yok?


57

Bash ile sourcebir yürütme bit kümesi olmadan bir betiği çalıştırmak mümkündür. Bu, belgelenmiş ve beklenen bir davranıştır, ancak bu bir yürütme bitinin kullanımına karşı değil mi?

Biliyorum, bu sourcebir deniz kabuğu yaratmıyor.


2
chmodSekizli bir sayı ile izinleri (`x dahil) ayarlamanıza izin vermesi gerçeği, hangi dönemin geldiği konusunda bazı ipuçları verir. Bu hızlı ve kirli olarak başlayan eğer sürpriz olmaz dişi patlama icat edilmeden önce gün, gösterge "bu yürütebileceği bir ikili dosyadır", ama bu hiçbir kanıt var
sabitlendikten

9
Ardından, SUID devreye girdiğinde, farklı kullanıcı kategorileri için farklı koruma seviyeleri daha önemli hale geliyor. Devam edin ve isterseniz SUID programımı okuyun. Sadece okumadan yoluyla çalıştırmak Ama eğer, SUID güçler onunla birlikte gelmiyorsun
sabitlendikten

@infixed Linux program yükleyicisi , yürütme biti ayarlanmadıkça shebang'a bile bakmaz . (Kendi boynuzumu biraz toot etmek için: buraya bakın .)
Kyle Strand

Ayrıca + xr değerine sahip olabilirsiniz, ancak bu biraz gariptir çünkü genellikle kodun çalıştırma işlemine enjekte edilmesiyle ikili kodu okumak mümkündür
Niklas B.

@KyleStrand "Basitçe okuyarak uygularsanız, SUID güçleri onunla birlikte gelmiyor" satırları boyunca bir şeyler öngörüyordumcp /sbin/suidexecutable /tmp/mycopy; /tmp/mycopy
infixed

Yanıtlar:


36

Bash bir tercümandır; girdiyi kabul eder ve ne isterse yapar. Yürütülebilir biti dikkate alması gerekmez. Aslında, Bash taşınabilirdir ve çalıştırılabilir bir bit kavramına sahip olmayan işletim sistemleri ve dosya sistemlerinde çalışabilir.

Yürütülebilir bit ile ilgilenen, işletim sistemi çekirdeğidir. execÖrneğin, Linux çekirdeği bir dosya gerçekleştirdiğinde, dosya sisteminin bir noexecseçenekle donatılmadığını kontrol eder, program dosyasının çalıştırılabilir bitini denetler ve güvenlik modülleri (SELinux veya AppArmor gibi) tarafından uygulanan gereklilikleri uygular.

Çalıştırılabilir bit'in isteğe bağlı bir denetim türü olduğunu unutmayın. Örneğin, bir Linux x86-64 sisteminde, tercüman olarak açıkça çağırarak/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 çekirdeğin çalıştırılabilir biti doğrulamasını atlayabilirsiniz :

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

Bu, ld.sotercüman olması haricinde, Bash'deki Bash kaynak kodunun kaynaklanmasına biraz benzerdir ve çalıştırdığı kod, ELF biçimindeki makine kodudur.


3
Yükleyiciyi "bytecode" ifadesinin "tercümanı" olarak kullanmak, yalnızca gerçek bir çalıştırılabilir dosya örneği olur .... awesome. Bunun için teşekkür ederim.
Kyle Strand,

@KyleStrand birkaç dolaylı seviyeye sahip olabilir (depolanan program ile yüklü işlem arasındaki fark ve hafızanın nasıl haritalandığı, çeşitli denetleyiciler, VM'ler vb.), Ancak prensip olarak makine kodu doğrudan CPU tarafından çalıştırılabilir (mikro kod yok, vb) ve dolayısıyla makine kodu yorumlanmıyor: donanım, anadil olduğu gibi anlıyor - tercümana gerek yok.
jfs

2
@ JFSebastian Evet, yerel kod olduğunu biliyoruz, bu nedenle "tercüman" tırnak içindedir. İşi ld.sodinamik bağlantı yapmaktır.
200_success

@ JFSebastian Ne 200_success dedi. Ayrıca, "gerçek yürütülebilir ikili" ile kastettiğim budur ve ayrıca "bytecode" ifadelerini tırnak işaretleri içine koyarım (AFAIK "bytecode" genellikle gerçek derlenmiş yerel olarak çalıştırılabilir ikili kodlara atıfta bulunmak için kullanılmaz). Ayrıca, güzel kullanıcı adı.
Kyle Strand,

@JFSebastian Modern x86 benzeri CPU'ların aslında dahili olarak RISC olduğuna inanıyorum, eski stil CISC komut seti, temel olarak tek bir CISC komutunun birçok RISC komutunun yürütülmesine neden olabileceği ilgili RISC komutlarının mikro kod yürütülmesini sağlar. Yani, bir anlamda, RISC makine koduyla CPU’nun ne yaptığını söylemek “yorumlamak”, teknik açıdan tamamen doğru değilse, en azından geçerli bir zihinsel modeldir. AES-NI muhtemelen en aşırı örneklerden biridir: AES turunda bir CISC talimatı!
25:06

57

sourceveya eşdeğeri ancak standart nokta. komut dosyasını çalıştırmaz, ancak komut dosyalarını komut dosyasından okur , sonra bunları geçerli kabuk ortamında satır satır çalıştırır.

Yürütme biti kullanımına karşı hiçbir şey yoktur, çünkü kabuğun sadece dosya içeriğini okumak için okuma iznine ihtiyacı vardır .

Yürütme biti sadece betiği çalıştırdığınızda gereklidir . Burada kabuk fork()yeni bir işlem yapacaktır ve execve()normal, çalıştırılabilir bir dosya olması gereken komut dosyasından yeni bir işlem görüntüsü oluşturmak için işlev kullanacaktır.


5
@alexis: Gerçekten takip ettiğimden emin değilim. Bunu yaparsanız bash < script, esas olarak aynı sonucu alırsınız source script. Yürütme biti kontrolü hangi korumayı sağlar?
Göze çarpan derleyici,

27
@alexis, yorumladığı scriptlerin izinlerini kontrol etmek tercümanın işi değildir. Hiçbir şey yapmaz - Python değil, Ruby, Java sanal makinesi değil, rastgele diğer kabuklar değil. Execute bit, OS execv* sistem çağrı ailesinin bir tercümanın çalıştırıp çalıştırmayacağına dair çalıştırılabilir bir dosyayla kullanılıp kullanılamayacağını kontrol eder. İnsanları, neden kuralları ihlal ederek karıştırıyor (ve dosya dışı kaynaklardan gelen kodu değerlendirme yeteneğini bozuyor)?
Charles Duffy

14
@alexis, ... ayrıca, çalıştırılamayan bir kabuk kütüphanesine sahip olmanın değerli bir anlamı var: "Ben bir kütüphaneyim, bir komut kaynağı değil, beni çalıştırma" diyor. Aksi takdirde, yalnızca kaynak kodlu kötüye kullanımı saptamak ve gidermek için kod yazmanız gerekir; ancak + x iznine sahip olmadıkça, kullanıcıların bir kütüphaneyi bu şekilde kötüye kullanmamasını (kullanmamasını) sağlayabilirsiniz.
Charles Duffy

6
@alexis "bu yazarlar tarafından verilen bir karardı" Sadece dahil edilmeyen her diğer kod parçasının bir karar olduğu anlamında. Kabuk, komutları okumak için okumak için dosyayı açar. Okuma iznini kontrol etmesini beklemem, dosyayı açmaya çalışır ve eğer yapamazsa başarısız olur. Aynı şekilde, bu kontroller dosyayı okumak için uygun olmadığından yazma veya yürütme iznini kontrol etmez.
Randy Orrison

2
@alexis Bu uygulamada, örneğin python's virtualenv ile etkinleştirmek için kullanılan betiğin kaynaklandığı ve çalıştırılmadığı ve bu nedenle bin/activateçalıştırılabilir bir biti olmadığı için pratikte kullanılır . Scriptler tamamen kütüphaneler veya bunun gibi başka şeyler olabilir. Sanırım .sh'in de bir sinyal olabileceğini düşünüyorum, ancak asgari tabanca tabancalarına sahip olmak iyidir: ./bin/activatekaza yerine . bin/activate
koşmanın

20

Ayarlanamayan ve ayarlanmayan dosyalardaki yürütülebilir bit (diğerlerinden farklı olarak) bir güvenlik mekanizması değildir. Okuyabildiğiniz her şeyi dolaylı olarak çalıştırabilirsiniz ve Linux doğrudan çalıştırabileceğiniz ancak doğrudan okuyamayacağınız bir şeyi dolaylı olarak okumanıza izin verecektir (bu, setsiz (g) kullanıcı kimliği olmayan x-bit kavramına bir delik açmak için yeterli olmalıdır. güvenlik önlemi).

Bu çok daha kolay bir şey: Bit ayarlanmışsa sistemin doğrudan benim için çalıştırmasına izin verin, aksi halde dolaylı olarak yapmam gerekir ( bash the_script;veya okunamaz durumda olan bir uygulamanın hafıza görüntüsünü elde etmek için bilgisayar korsanlığı ).

Hem kaynağında hem de kaynağınızda yürütmeyi düşünüyorsanız, kolaylık sağlamak için ayarlayabilirsiniz.

Bununla birlikte, görünüşe göre, birçok paylaşılan kütüphane uygulayıcısı düşüncenizi paylaşır ve sonuç olarak, birçok sistem, esas olarak kabuk kaynak kaynaklarının yerel eşdeğeri olan paylaşılan kitaplıkların kullanılabilir olması için çalıştırılabilir olarak işaretlenmesini gerektirir. Bkz Neden paylaşılır kütüphaneler yürütülebilir? .


3
@ Motte001 Eğer gerçekten isterlerse bu ekleri uygulayabilirler. Bu bir kolaylık.
PSkocik

2
Yürütülebilir bit güvenlik için değil: Bir dosyam varsa, özgürüm chmodve çalıştırılabilir hale getirdim . Programlardan veri sıralamak içindir, bu nedenle OP'nin sorusu makul bir sorundur.
alexis,

1
@ Motte001 Bu GUI dosya tarayıcısının / posta uygulamasının bir güvenlik özelliğidir - adı ".sh" biten bir dosyaya çift tıklandığında bir terminalde (Windows tarzı) veya tam olarak o çift tuşa basıldığına kolayca karar verebilir. "indirilen ekler" dizinindeki herhangi bir dosyayı tıklamak, yerleşik bir sanal alan önizleme uygulamasını çağırır. xBiraz o okuma / ne yapacağını bir ipucu yazabilir sadece fazladan bir yerdir.
IMSoP

3
Yürütülebilir bit'e ihtiyaç duymamızın bir nedeni , özellikle root tarafından sahip olunan program programları çalıştırmaktır. Bunları kesinlikle kendi başınıza yürütebilseniz de, gerekli izinlere sahip olmaları için işletim sistemine ihtiyacınız vardır. Diğer bazı durumlarda bu gerçekten kolaylık sağlıyor.
Waleed Khan,

2
"Linux, / proc üzerinden çalıştırabileceğiniz her şeyi okumanıza izin verecek" - Pekala, benim hisse senedi Debian /tmp$ cp /bin/cat ./cat ; chmod a-rw ./cat ; ./cat & cp /proc/$!/exe /tmp/cat2cp: cannot stat ‘/proc/16260/exe’: Permission denied
kernel'de

9

Bu iyi bir soru! Unix, programları ve verileri birbirinden ayırmak için yürütülebilir biti kullanır. İşletim sistemi yürütme biti gerektirmez, çünkü kaynak kodlu bir komut dosyası işletim sistemine yeni bir işlem olarak geçmediği için işletim sistemi tarafından geçilmez. Ancak kabuk, kaynak kodlu bir betiği bir program olarak ele alır ve kaynaklamak $PATHistediğiniz dosyayı arar . Dolayısıyla, kabuğun kendisi kaynak dosyalar için yürütme izni gerektirebilirdi; ama olmadı.

Soru uzun zaman önce ortaya çıkmış olmalı. Bourne kabuğunun tasarımı, Bell Laboratuarlarının sakinleri arasında "uzun bir değişiklik dizisi, diyalog, tartışma" nın sonucuydu ve birçok tasarım kararı SR Bourne ve diğerleri tarafından yıllar boyunca tartışıldı. Maalesef, hızlı bakışım kaynak özelliği hakkında herhangi bir tartışma bulamadı (savunmamda, bunun için google yapmak zor). Bulduğum şey "." Bourne'un kendisi tarafından kabuğa bu ilk girişte komut görünmüyor , ancak daha olgun olan Versiyon 7 versiyonunda mevcut .

Yok otorite, işte kendi yorumum:

  1. .Komut, diğer adıyla source, (gibi etki metinsel dahil olduğu #includeyürütme komut dosyası veya etkileşimli oturumda kaynak koduna C önişlemcisine olarak). Bu nedenle, dahil edilen dosyanın tartışmasız "çalıştırılmadığı".

  2. Unix felsefesi daima programcılara kendilerini asacak kadar ip vermek olmuştur. Çok fazla el tutma ve keyfi kısıtlama yolunda gitmektedir. Sadece son zamanlarda bazı dağıtımlar rm -r /ne istersen yapmayı reddetti. (Bu komut söyler rmetmek . Bilgisayarınızdaki her şeyi silmek root olarak deneyin! Etmeyin ark, belki Bourne'u. Hiç de daha iyisi Ya) Yani. Sadece bir dosyayı bulmaya çalıştığınızda ne yaptığınızı bildiğiniz varsayılır. Bu da gereksiz işleri önler ve döngüleri o zamanlar çok önemlidir.


Ama bir gerektiğini kesinlikle değil @cat söylediklerini yapmak.
TOOGAM

@TOOGAM tarafından işaretlenmemiş ve silinmemiş olmasına şaşırdım ancak / s!
kedi,

Orada, @cat'ın ne yazdığını bilmiyorum ama cevabı daha da fazla prova ettim. (Ama hadi, zaten içeriğinden yeterince açıktı.)
alexis

4

İşletim sistemi söz konusu olduğunda, kabuk betiğini içeren bir dosya sadece veridir. Bu tür bir veri dosyasının adını sourcekomuta veya komut satırından bash kabuğunun çağrılmasına geçirirseniz, tüm işletim sistemi görür, veri içeren bir dosyanın adıyla çakışan bir dizedir.

Bu durumda yürütme biti nasıl bir anlam ifade eder?


3

Bu ayrım önemlidir, çünkü çalıştırılabilir olarak kullanışlı olmayan, ancak yalnızca kaynak yapıldığında yararlı olan bir kabuk komut dosyanız olabilir. Bu dosya için çalıştırma bitini kapatabilirsiniz ve daha sonra bir kaynak komutunda açıkça belirtilmedikçe asla erişilmez. Böyle bir şeyin nedeni, çalıştırıldığı kabuk üzerinde yan etkilere neden olmaktır. Belirli bir örnek için, fix_path adında ve yolu değiştiren bir komut dosyası var.


1

Birisinin daha fazla araştırma ve / veya açıklama ile ilgilenmesi durumunda: Bir süre önce uygulanan 'exec_program ()' ve 'builtin_source ()' işlevlerinin içsel çalışmaları çok örnek niteliğindedir. Bu işlevlerde, aralarındaki farkın tam olarak ne olduğunu görüyorsunuz:

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

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

Temel olarak kaynak, kabuk komut dosyasını ayrıştırdığı iç dosya tanımlayıcısını geçici olarak yönlendiren kabuk (etkileşimli modda terminal) olarak görülebilir. bu nedenle gibi diğer yönlendirmeler çok benzer <input_file.txtve >>append_to_something.listbunlar sadece açmak ve kapatmak dosyalar gerekir ve.

bu nedenle yürütme, execve()yürütme bitinin zorunlu olduğu sistem çağrısı tarafından gerçekleştirilir.

ELF / a.out ikili dosyalarının yürütülmesine izin veren bazı sistemleri gördüğümü hatırlıyorum, ancak "/lib/ld-dynamic-linker.so" ve ikili programla (exec bit olmadan) ilk argüman olarak çalıştırarak. Bunun bazı DEC Alpha veya VAX makinelerinde olduğuna inanıyorum (SCO Unix olabilir mi?)


-2

Başka bir bakış açısı:

Kaynak komut dosyası temelde kabuk yerleşimleri ve program çağrılarından oluşur. Kabuk sourceyapıları ( bunlarla birlikte) kabuğun parçalarıdır ve kabuğun ilk önce çalıştırılabilir olması gerekir. Her program (ELF olan, shebang ile başka bir betik, her neyse) olarak adlandırılan yürütme biti ayarlanmış olmalıdır, aksi takdirde çalışmayacaktır.

Bu nedenle, yürütme biti kullanımına karşı değildir, çünkü yürütme biti olmayan hiçbir şey çalışmaz. Doğrulama, kaynak kodun tamamı için yapılmaz; Her bölüm için ayrı ayrı yapılır, ancak öyle.


Kabuk yapıları bir kabuk betiğinden kaynaklanmamıştır. Tipik olarak çalıştırılabilir kabuğun bir parçasıdır. Ksh93, zsh ve diğer birkaç kabukta kabuk uzantıları olabilir.
fpmurphy

@ fpmurphy1 Bu benim cümle değil mi "kabuk yerleşikleri (...) kabuğun parçaları"?
Kamil Maciorowski
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.