Dlaczego źródło Basha nie potrzebuje bitu wykonania?


57

Dzięki Bash'owi sourcemożliwe jest wykonanie skryptu bez zestawu bitów wykonania. Jest to udokumentowane i oczekiwane zachowanie, ale czy nie jest to sprzeczne z użyciem bitu wykonania?

Wiem, że sourceto nie tworzy podpowłoki.


2
Fakt, że chmodmożesz ustawić uprawnienia (w tym `x) za pomocą liczby ósemkowej, daje pewną wskazówkę, z jakiej epoki pochodzi. Nie zdziwiłbym się, gdyby zaczął się jako szybki i brudny wskaźnik „jest to plik binarny, który można wykonać”, jeszcze przed wynalezieniem she-bang, ale nie mam na to żadnych dowodów
naprawiono

9
Z drugiej strony, kiedy pojawia się SUID, różne poziomy ochrony dla różnych kategorii użytkowników stają się coraz ważniejsze. Śmiało i przeczytaj mój program SUID, jeśli chcesz. Ale jeśli wykonasz to po prostu czytając, moce SUID nie nadejdą wraz z nim
naprawiono

@infixed Program ładujący systemu Linux nawet nie spojrzy na shebang, dopóki nie zostanie ustawiony bit wykonania. (Aby trochę trącić mój własny róg: patrz tutaj .)
Kyle Strand

Możesz także mieć + xr, ale to trochę dziwne, ponieważ zwykle można odczytać plik binarny poprzez wstrzyknięcie kodu do uruchomionego procesu
Niklas B.

@KyleStrand przez „jeśli wykonasz to, po prostu czytając, moce SUID nie idą w parze z tym” Wyobrażałem sobie coś podobnegocp /sbin/suidexecutable /tmp/mycopy; /tmp/mycopy
naprawiony

Odpowiedzi:


36

Bash jest tłumaczem; przyjmuje dane wejściowe i robi wszystko, co chce. Nie musi zwracać uwagi na wykonywalny bit. W rzeczywistości Bash jest przenośny i może działać na systemach operacyjnych i systemach plików, które nie mają pojęcia o bicie wykonywalnym.

Bitem wykonywalnym zależy na jądrze systemu operacyjnego. Kiedy jądro Linux wykonuje exec, na przykład, sprawdza, czy system plików nie jest zamontowany z noexecopcją, sprawdza bit wykonywalny pliku programu i egzekwuje wszelkie wymagania nałożone przez moduły bezpieczeństwa (takie jak SELinux lub AppArmor).

Zauważ, że wykonywalny bit jest raczej dyskrecjonalnym rodzajem kontroli. Na przykład w systemie Linux x86-64 można pominąć weryfikację bitu wykonywalnego przez jądro, jawnie wywołując /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2jako interpreter :

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

Jest to nieco analogiczne do pozyskiwania kodu źródłowego Bash w Bash, z wyjątkiem tego, że ld.sojest to interpreter, a kod, który wykonuje, jest kodem maszynowym w formacie ELF.


3
Używanie modułu ładującego jako „interpretera” „kodu bajtowego”, który po prostu okazuje się być prawdziwym plikiem wykonywalnym ..... niesamowitym. Dziękuję za to.
Kyle Strand

@KyleStrand może istnieć kilka poziomów pośredniczących (różnica między przechowywanym programem a załadowanym procesem oraz sposobem mapowania pamięci, różnymi nadzorcami, maszynami wirtualnymi itp.), Ale w zasadzie kod maszynowy może być wykonywany bezpośrednio przez CPU (bez mikrokodu, itp.) i dlatego kod maszynowy nie jest interpretowany: sprzęt rozumie go takim, jakim jest - jest językiem ojczystym - tłumacze nie są potrzebni.
jfs

2
@JFSebastian Tak, wiemy, że jest to kod natywny, stąd „interpreter” jest w cudzysłowie. Zadaniem ld.sojest dynamiczne łączenie.
200_success

@JFSebastian What 200_success powiedział. Ponadto, to miałem na myśli przez „prawdziwy wykonywalny plik binarny”, a także wstawiłem „bytecode” w cudzysłowie (ponieważ „bajtecode” AFAIK zwykle nie jest używany w odniesieniu do rzeczywistego skompilowanego natywnie wykonywalnego kodu binarnego). Również ładna nazwa użytkownika.
Kyle Strand

@JFSebastian Wierzę, że współczesne procesory podobne do x86 są tak naprawdę wewnętrznie RISC, a zestaw instrukcji CISC w starym stylu zasadniczo steruje wykonywaniem mikrokodu odpowiednich instrukcji RISC, przy czym jedna instrukcja CISC może powodować wykonanie wielu instrukcji RISC. W pewnym sensie nazywanie tego, co CPU robi z kodem maszynowym RISC, „interpretacja” jest, jeśli nie całkowicie poprawna z technicznego punktu widzenia, to przynajmniej poprawnym modelem mentalnym. AES-NI jest prawdopodobnie jednym z najbardziej ekstremalnych przykładów: jedna instrukcja CISC na rundę AES!
CVn

57

sourcelub równoważna, ale standardowa kropka. nie wykonuje skryptu, ale odczytuje polecenia z pliku skryptu, a następnie wykonuje je wiersz po wierszu w bieżącym środowisku powłoki.

Nie ma nic przeciwko używaniu bit wykonania, ponieważ powłoka tylko trzeba czytać uprawnienia do odczytu zawartości pliku.

Bit wykonania jest wymagany tylko po uruchomieniu skryptu. Tutaj powłoka uruchomi fork()nowy proces, a następnie użyje execve()funkcji do utworzenia nowego obrazu procesu ze skryptu, który musi być zwykłym plikiem wykonywalnym.


5
@alexis: Nie jestem pewien, czy naprawdę podążam. Jeśli to zrobisz bash < script, uzyskasz zasadniczo taki sam wynik jak source script. Jaką ochronę zapewnia wykonanie kontroli bitów?
Widoczny kompilator

27
@alexis, sprawdzanie uprawnień interpretowanych skryptów nie jest zadaniem tłumacza. Nic tego nie robi - ani Python, ani Ruby, ani wirtualna maszyna Java, ani inne losowe powłoki. Bit wykonawczy kontroluje, czy execvrodzina syscalli OS * może być używana z plikiem wykonywalnym, a nie czy interpreter go uruchomi. Po co mylić ludzi (i przerywać zdolność do oceny kodu przesyłanego strumieniowo ze źródeł innych niż pliki) przez łamanie konwencji?
Charles Duffy

14
@alexis, ... ponadto istnieje cenne znaczenie posiadania biblioteki powłoki, która nie jest wykonywalna: Mówi: „Jestem biblioteką, a nie poleceniem - podaj mnie, nie wykonuj mnie”. W przeciwnym razie będziesz musiał napisać kod, aby wykryć i naprawić niewłaściwe użycie kodu przeznaczonego wyłącznie do pozyskiwania, ale nie posiadając uprawnienia + x możesz zagwarantować, że użytkownicy nie będą mogli (nie) nadużywać biblioteki w taki sposób.
Charles Duffy

6
@alexis ”była to decyzja autorów„ Tylko w tym sensie, że każdy możliwy fragment kodu, który nie został uwzględniony, był decyzją. Powłoka otwiera plik do odczytu, aby odczytać z niego polecenia. Nie spodziewałbym się, że sprawdzi uprawnienia do odczytu, po prostu próbuje otworzyć plik i kończy się niepowodzeniem, jeśli nie może. Podobnie nie sprawdza uprawnień do zapisu ani wykonywania, ponieważ te kontrole nie są istotne dla odczytu pliku.
Randy Orrison

2
@alexis Jest to stosowane w praktyce, na przykład w przypadku virtualenv Pythona, skrypt do aktywacji ma być pozyskiwany, a nie wykonywany, a zatem bin/activatenie ma bitu wykonywalnego. Skrypty mogą być całkowicie bibliotekami lub innymi tego typu rzeczami. Wydaje mi się, że posiadanie .sh może być również sygnałem, ale posiadanie minimalnej broni palnej jest dobre: ​​fajnie, że nie można uruchomić ./bin/activateprzypadkiem zamiast. bin/activate
daboross

20

Bity wykonywalne (w przeciwieństwie do pozostałych) w plikach nonsetuid i nonsetguid nie stanowią większego mechanizmu bezpieczeństwa. Wszystko, co możesz przeczytać, możesz uruchomić pośrednio, a Linux pozwoli ci pośrednio przeczytać wszystko, co możesz uruchomić, ale nie bezpośrednio przeczytać (to powinno wystarczyć, aby wykopać dziurę w koncepcji nie ustawionego (g) uid x-bit będącego pomiar bezpieczeństwa).

Jest to bardziej wygoda: pozwól systemowi uruchomić go dla mnie bezpośrednio, jeśli bit jest ustawiony, w przeciwnym razie muszę to zrobić pośrednio ( bash the_script;lub trochę włamania, aby uzyskać obraz pamięci wykonywalnego pliku bez uprawnień do odczytu ).

Możesz ustawić tę opcję dla wygody, jeśli zamierzasz korzystać zarówno ze źródła, jak i ze swojego źródła.

Najwyraźniej jednak wielu implementatorów bibliotek współużytkowanych podziela twoje zdanie, w związku z czym wiele systemów wymaga, aby biblioteki współdzielone, które są zasadniczo natywnym odpowiednikiem powłokowych powłok, były oznaczone jako pliki wykonywalne, aby były użyteczne. Zobacz: Dlaczego biblioteki współdzielone są wykonywalne? .


3
@ Motte001 Mogą wykonać te załączniki, jeśli naprawdę chcą. To wygoda.
PSkocik

2
Bit wykonywalny nie służy bezpieczeństwu: jeśli jestem właścicielem pliku, mam do chmodniego swobodę i sprawia, że ​​jest wykonywalny. Służy do sortowania danych z programów, więc pytanie PO jest rozsądne.
Alexis

1
@ Motte001 To bardziej funkcja bezpieczeństwa przeglądarki plików graficznych / aplikacji pocztowej - może łatwo zdecydować, że dwukrotne kliknięcie dowolnego pliku, którego nazwa kończy się na „.sh”, zostanie wykonane w terminalu (w stylu Windows) lub odwrotnie kliknięcie dowolnego pliku w katalogu „pobranych załączników” wywoła wbudowaną aplikację podglądu w piaskownicy. Ten xkawałek to tylko dodatkowe miejsce, w którym potrafi czytać / pisać wskazówki, co robić.
IMSoP

3
Jednym z powodów, dla których potrzebujemy bitu wykonywalnego, jest uruchamianie programów setuid, szczególnie tych należących do roota. Chociaż możesz je wykonać samodzielnie, potrzebujesz systemu operacyjnego, aby je uruchomić, aby miały niezbędne uprawnienia. W niektórych innych przypadkach jest to po prostu wygoda.
Waleed Khan

2
„Linux pozwoli ci czytać wszystko, co możesz uruchomić przez / proc” - Cóż, moje podstawowe jądro Debiana nie: /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

To dobre pytanie! Unix używa bitu wykonywalnego do rozróżnienia programów i danych. System operacyjny nie wymaga bitu wykonania, ponieważ skrypt źródłowy nie jest przekazywany do systemu operacyjnego w celu wykonania jako nowy proces. Ale powłoka traktuje skrypt $PATHźródłowy jako program i szuka pliku, który chcesz pobrać. Tak więc sama powłoka mogła wymagać pozwolenia na wykonanie plików źródłowych; ale tak nie było.

Pytanie musiało pojawić się dawno temu. Projekt powłoki Bourne'a był wynikiem „długiej sekwencji modyfikacji, dialogu, dyskusji” wśród mieszkańców Bell Labs, a wiele decyzji projektowych było dyskutowanych przez SR Bourne'a i innych na przestrzeni lat. Niestety, moje szybkie spojrzenie nie znalazło żadnej dyskusji na temat funkcji źródłowej (w mojej obronie trudno go znaleźć w Google). Znalazłem to, że „.” polecenie nie pojawia się we wczesnym wprowadzeniu do powłoki przez samego Bourne'a, ale jest obecne w bardziej dojrzałej wersji 7 .

Brak autorytetu, oto moja własna interpretacja:

  1. .Poleceń, aka source, jest włączenie efektów tekstowych (jak #includew preprocesora C) do kodu źródłowego skryptu wykonującego lub sesji interaktywnej. Jako taki, dołączony plik prawdopodobnie nie jest „wykonywany”.

  2. Filozofią Uniksa zawsze było dawanie programistom wystarczającej ilości liny do powieszenia się. Po prostu przeszkadza zbyt duże trzymanie się za ręce i arbitralne ograniczenia. Dopiero niedawno niektóre dystrybucje rm -r /odmawiają robienia tego, o co prosisz. (Polecenie to mówi rmsię usunąć wszystko na komputerze. Nie próbuj go jako root! Albo jeszcze lepiej, a nie w ogóle). Tak więc, może Bourne przy al. właśnie zdecydowałem, że przy próbie źródła pliku zakłada się, że wiesz, co robisz. Pozwala to również uniknąć niepotrzebnej pracy, a cykle miały wówczas duże znaczenie.


Ale zdecydowanie nie należy robić tego, co powiedział @cat.
TOOGAM,

Dziwię się, że nie został on oznaczony i usunięty @TOOGAM, ale wstawiłem / s!
kot

Tam nie wiem, co napisał @cat, ale jeszcze bardziej zabezpieczyłem odpowiedź przed dziećmi. (Ale daj spokój, było już wystarczająco jasne z kontekstu.)
Alexis

4

Jeśli chodzi o system operacyjny, plik zawierający skrypt powłoki to tylko dane. Jeśli przekażesz nazwę takiego pliku danych do sourcepolecenia lub przekażesz go w wierszu polecenia do wywołania powłoki bash, wszystko, co widzi system operacyjny, to ciąg znaków, który pokrywa się z nazwą pliku zawierającego dane.

Jak w takim przypadku bit wykonawczy byłby w ogóle istotny?


3

To rozróżnienie jest ważne, ponieważ możesz mieć plik poleceń powłoki, który nie jest użyteczny jako plik wykonywalny, ale jest przydatny tylko po uzyskaniu. W przypadku tego pliku można wyłączyć bit wykonywania, a wtedy dostęp do niego nigdy nie będzie możliwy, chyba że zostanie to jawnie wykonane w poleceniu źródłowym. Powodem tego jest efekt uboczny powłoki, z której jest uruchamiany. Na konkretny przykład mam skrypt o nazwie fix_path, który przegląda i modyfikuje ścieżkę.


1

Na wszelki wypadek, gdy ktoś jest zainteresowany dalszymi badaniami i / lub wyjaśnieniami: W powłoce prawie zgodnej z POSIX zaimplementowanej jakiś czas temu wewnętrzne funkcje funkcji „exec_program ()” i „wbudowane_źródło ()” są bardzo przykładowe. W tych funkcjach widać dokładnie, jaka jest między nimi różnica:

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

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

w zasadzie pozyskiwanie może być postrzegane jako powłoka tymczasowo przekierowująca swój wewnętrzny deskryptor pliku, z którego analizuje skrypt powłoki (terminal w trybie interaktywnym). więc jest bardzo podobny do innych przekierowań takich jak <input_file.txti, >>append_to_something.lista one tylko muszą otwierać i zamykać pliki.

więc wykonanie jest obsługiwane przez execve()wywołanie systemowe, dla którego bit wykonania jest obowiązkowy.

Pamiętam, że widziałem niektóre systemy, które pozwalają na uruchamianie plików binarnych ELF / a.out, ale poprzez wykonanie „/lib/ld-dynamic-linker.so” i programu binarnego (bez bitu exec) jako pierwszego argumentu. Myślę, że tak było na niektórych komputerach DEC Alpha lub VAX (czy to mógł być SCO Unix?)


-2

Inny punkt widzenia:

Skrypt źródłowy zasadniczo składa się z wbudowanych powłok i wywołań programów. Wbudowane powłoki (wraz z sourcenimi) są częściami powłoki i powłoka musi być wykonywalna w pierwszej kolejności. Każdy wywoływany program (czyli ELF, inny skrypt z shebang, cokolwiek) musi mieć ustawiony bit wykonania, w przeciwnym razie nie będzie działał.

Dlatego nie jest to sprzeczne z użyciem bitu wykonania, ponieważ nic bez bitu wykonania nie będzie działać. Sprawdzanie poprawności nie występuje dla całego skryptu źródłowego; jest wykonywany dla każdej części osobno, ale tak jest.


Wbudowane powłoki nie są pobierane ze skryptu powłoki. Zazwyczaj są one częścią pliku wykonywalnego powłoki. W ksh93, zsh i kilku innych powłokach mogą być rozszerzeniami powłoki.
fpmurphy

@ fpmurphy1 Czy to nie jest moje zdanie „wbudowane powłoki (...) są częściami powłoki”?
Kamil Maciorowski
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.