focal (2) execve.2.gz

Provided by: manpages-pl-dev_0.7-2_all bug

NAZWA

       execve - uruchomienie programu

SKŁADNIA

       #include <unistd.h>

       int execve(const char *filename, char *const argv[],
        char *const envp[]);

OPIS

       execve()  wykonuje  program  wskazywany  przez  filename.  filename  musi  być  albo wykonywalnym plikiem
       binarnym, albo skryptem zaczynającym się od linii w postaci:

           #! interpreter [opcjonalny-parametr]

       Szczegóły tego ostatniego przypadku można znaleźć poniżej w rozdziale "Skrypty interpretowane".

       argv jest tablicą łańcuchów przekazywanych jako argumenty nowego programu. Zgodnie z konwencją pierwszy z
       nich  powinien  zawierać  nazwę  pliku  skojarzonego z wykonywanym programem. envp jest tablicą łańcuchów
       postaci klucz=wartość, która jest przekazywana jako środowisko do nowego programu. Zarówno  argv,  jak  i
       envp  muszą  być  zakończone  wskaźnikiem pustym (NULL). Tablica argumentów oraz środowisko są dostępne w
       funkcji main wywoływanego programu, jeżeli jest ona zdefiniowana jako:

           int main(int argc, char *argv[], char *envp[])

       W razie powodzenia execve() nie powraca, a sekcje tekstu, danych, bss  i  stos  wywołującego  procesu  są
       nadpisywane odpowiednimi sekcjami ładowanego programu.

       Jeśli obecny program jest śledzony za pomocą ptrace, wysyła się mu SIGTRAP po pomyślnym execve().

       Jeżeli  plik  programu wskazywany przez filename ma ustawiony bit set-user-ID i plik ten jest umieszczony
       na systemie plików zamontowanym bez opcji nosuid (znacznika MS_NOSUID  wywołania  mount(2))  oraz  proces
       wywołujący  nie  jest  śledzony  (ptrace(2)), to efektywny identyfikator użytkownika procesu wywołującego
       jest ustawiany na właściciela pliku programu. Podobnie, jeżeli dla  pliku  programu  ustawiony  jest  bit
       set-group-ID,  to  efektywnemu  identyfikatorowi grupy procesu wywołującego jest przypisywana grupa pliku
       programu.

       Efektywny identyfikator użytkownika jest kopiowany do saved-set-user-ID; podobnie efektywny identyfikator
       grupy jest kopiowany do saved-set-group-ID. Kopiowanie odbywa się po zmianie któregokolwiek z efektywnych
       identyfikatorów związanej z bitami trybu set-user-ID i set-group-ID.

       Jeśli program wykonywalny jest skonsolidowany dynamicznie w formacie a.out z bibliotekami dzielonymi,  to
       na początku uruchamiania wywoływany jest konsolidator dynamiczny ld.so(8), który ładuje wszystkie obiekty
       do pamięci i konsoliduje z nimi program wykonywalny.

       Jeżeli program  jest  skonsolidowany  dynamicznie  jako  ELF,  to  do  załadowania  potrzebnych  obiektów
       współdzielonych  używany  jest  interpreter  określony  w  segmencie  PT_INTERP.  Tym  interpreterem jest
       zazwyczaj /lib/ld-linux.so.2, w wypadku programów skonsolidowanych z glibc2 (zob. ld-linux.so(8)).

       Wszystkie atrybuty procesu są zachowywane podczas execve(), z wyjątkiem poniższych:

       *  Ustawienia obsługi sygnałów, które są przechwytywane, są zmieniane na wartości domyślne (signal(7)).

       *  Alternatywny stos sygnałów nie jest zachowywany (sigaltstack(2)).

       *  Mapowania pamięci nie są zachowywane (mmap(2))

       *  Dołączone segmenty pamięci dzielonej Systemu V są odłączane (shmat(2)).

       *  Regiony pamięci dzielonej POSIX są odmapowane (shm_open(3)).

       *  Otwarte kolejki komunikatów POSIX są zamykane (mq_overview(7)).

       *  Otwarte semafory nazwane POSIX są zamykane (mq_overview(7)).

       *  Timery POSIX nie są zachowywane (timer_create(2)).

       *  Otwarte strumienie katalogów są zamykane (opendir(3)).

       *  Blokady pamięci nie są zachowywane (mlock(2), mlockall(2)).

       *  Zarejestrowanie  funkcje  wykonywanych  po  zakończeniu  procesu  nie   są   zachowywane   (atexit(3),
          on_exit(3)).

       *  Środowisko zmiennoprzecinkowe jest ustawiane na domyślne (patrz fenv(3)).

       Atrybuty  procesu  w  liście  przedstawionej  powyżej są określone w POSIX.1. Następujące specyficzne dla
       Linuksa atrybuty procesu również nie są zachowywane podczas execve():

       *  Znacznik PR_SET_DUMPABLE prctl(2) jest  ustawiany,  chyba  że  wykonywany  program  ma  ustawiony  bit
          set-user-ID lub set-group-ID, w którym przypadku znacznik ten jest czyszczony.

       *  Znacznik PR_SET_KEEPCAPS prctl(2) jest czyszczony.

       *  (Od  Linuksa  2.4.36 / 2.6.23) Jeśli wykonywany program ma ustawiony bit set-user-ID lub set-group-ID,
          to jest czyszczony znacznik PR_SET_PDEATHSIG  sygnału śmierci rodzica ustawiony przez  prctl(2).

       *  Nazwa procesu ustawiona przez PR_SET_NAME z prctl(2) (i wyświetlana przez ps -o comm)  jest  ustawiana
          na nazwę nowego pliku wykonywalnego.

       *  Znacznik SECBIT_KEEP_CAPS w securebits jest czyszczony. Patrz capabilities(7).

       *  Sygnał zakończenia jest ustawiany na SIGCHLD (patrz clone(2)).

       *  Tablica deskryptora plików nie jest dzielona, co anuluje działanie flagi CLONE_FILES clone(2).

       Dalsze uwagi:

       *  Wszystkie  wątki oprócz wątku wywołującego są niszczone podczas execve(). Muteksy, zmienne warunkowe i
          inne obiekty pthreads nie są zachowywane.

       *  Odpowiednik setlocale(LC_ALL, "C") jest wykonywany po uruchomieniu programu.

       *  POSIX.1 określa, że ustawienie procedur obsługi sygnału na ignorowanie lub na  wartość  domyślną  jest
          pozostawiane bez zmian. POSIX.1 przewiduje jeden wyjątek od tej reguły: jeśli SIGCHLD jest ignorowany,
          to implementacja może albo nie zmienić tego ustawienia, albo przestawić je na wartość domyślną;  Linux
          robi to pierwsze.

       *  Wszystkie asynchroniczne operacje wejścia/wyjście są anulowane (aio_read(3), aio_write(3)).

       *  Sposób obsługi atrybutów (zdolności) procesu podczas execve() opisano w capabilities(7).

       *  Domyślnie  deskryptory  plików  pozostają  otwarte  po  execve().  Deskryptory  plików  oznaczone jako
          "close-on-exec" są zamykane, patrz opis  FD_CLOEXEC  w  fcntl(2).  (Jeśli  deskryptor  pliku  zostanie
          zamknięty,  to  zwolnione  zostaną  wszystkie  blokady  rekordów  dotyczące  pliku  związanego  z  tym
          deskryptorem. Szczegóły można znaleźć w fcntl(2)). POSIX.1 mówi, że jeżeli deskryptory plików 0, 1 i 2
          zostałyby  zamknięte  po  pomyślnym  wykonaniu  execve(),  a  proces  uzyskałby  przywileje  z  powodu
          ustawionego na wykonywanym pliku bitu trybu set-user-ID lub  set-group-ID,  to  system  może  otworzyć
          bliżej  nieokreślony plik dla każdego z tych deskryptorów plików. Jako zasadę należy przyjąć, że żaden
          przenośny program, uprzywilejowany czy nie, nie może zakładać, że  te  trzy  deskryptory  plików  będą
          zamknięte po execve().

   Skrypty interpretowane
       Skrypt  interpretowany jest plikiem tekstowym mającym ustawione prawo do wykonywania. Pierwsza linia tego
       pliku jest w postaci:

           #! interpreter [opcjonalny-parametr]

       interpreter mus być poprawną nazwą ścieżki do pliku  wykonywalnego.  Jeśli  argument  filename  wywołania
       execve() określa interpreter, to zostanie uruchomiony interpreter z następującymi argumentami:

           interpreter [opcjonalny-arg] filename arg...

       gdzie arg... jest serią słów, na które wskazuje argument argv wywołania execve(), poczynając od argv[1].

       Dla  zachowania  przenośności  na  inne systemu optional-arg albo w ogóle nie powinien być podawany, albo
       powinien być podany jako pojedyncze słowo (nie powinien zawierać spacji); patrz UWAGI poniżej.

       Od Linuksa 2.6.28 jądro pozwala, aby interpreterem  skryptu  również  był  skrypt.  To  uprawnienie  jest
       rekurencyjne, aż po czterykroć, tak więc interpreter może być skryptem interpretowanym przez skrypt itd.

   Ograniczenia rozmiaru argumentów i środowiska
       Większość  implementacji Uniksa narzuca ograniczenia na całkowity rozmiar argumentów linii poleceń (argv)
       i środowiska  (envp)  przekazywanych  do  nowego  programu.  POSIX.1  pozwala  implementacji  ogłosić  te
       ograniczenia  za  pomocą  stałej  ARG_MAX  (albo  zdefiniowanej  w  <limits.h>,  albo  dostępnej  podczas
       wykonywania programu za pomocą wywołania sysconf(_SC_ARG_MAX)).

       W jadrach Linuksa wcześniejszych niż 2.6.23, pamięć używana do przechowywania łańcuchów znaków środowiska
       i   argumentów   była  ograniczana  do  32  stron  (zdefiniowane  przez  stałą  jądra  MAX_ARG_PAGES).  W
       architekturach mających strony o rozmiarze 4 kB oznaczało to maksymalny rozmiar równy 128 kB.

       W jądrze 2.6.23 i późniejszych większość  architektur  wspiera  ograniczenie  rozmiaru  wywodzące  się  z
       miękkiego  limitu  zasobu   RLIMIT_STACK  (patrz getrlimit(2)), obowiązującego podczas wywołania execve()
       (Wyjątek stanowią architektury  nie  mające  jednostki  zarządzania  pamięcią:  przechowują  ograniczenie
       obowiązujące  przed  wersją  jądra   2.6.23). Zmiana ta pozwala programom na posiadanie znacznie większej
       listy argumentów lub środowiska. Na  tych  architekturach  całkowity  rozmiar  jest  ograniczony  do  1/4
       dopuszczalnego  rozmiaru  stosu.  (Limit   1/4  zapewnia, że zostanie jakaś przestrzeń na stos dla nowego
       programu). Od Linuksa 2.6.25 jądro przyjmuje wartość minimalną 32 stron dla  tego  limitu  rozmiaru,  tak
       żeby  zagwarantować,  że w przypadku gdy RLIMIT_STACK ma niewielką wartość, aplikacje dostaną co najmniej
       taką przestrzeń na argumenty i środowisko,  jaką  miały  w  Linuksie  2.6.23  i  wcześniejszych.  (Takiej
       gwarancji nie ma w Linuksach 2.6.23 i 2.6.24). Dodatkowo ograniczeniem na pojedynczy łańcuch znaków są 32
       strony (stała jądra MAX_ARG_STRLEN), a maksymalna liczba takich łańcuchów wynosi 0x7FFFFFFF.

WARTOŚĆ ZWRACANA

       Po pomyślnym zakończeniu execve() nie wraca, w wypadku błędu zwracane jest  -1  i  odpowiednio  ustawiane
       errno.

BŁĘDY

       E2BIG  Całkowita liczba bajtów środowiska (envp) i listy argumentów (argv) jest za duża.

       EACCES Brak praw do przeszukiwania dla składnika ścieżki filename lub ścieżki interpretera skryptu (patrz
              także path_resolution(7)).

       EACCES Plik lub interpreter skryptu nie jest zwykłym plikiem.

       EACCES Brak praw wykonywania dla pliku, skryptu lub intepretera ELF.

       EACCES System plików jest zamontowany jako noexec.

       EAGAIN (od Linuksa 3.1)
              Po zmianie swojego rzeczywistego UID za pomocą jednego z wywołań set*uid(), wywołujący był—i wciąż
              jest—powyżej  swojego  limitu  zasobó  RLIMIT_NPROC  (zob.  setrlimit(2)). Więcej informacji o tym
              błędzie znajduje się w rozdziale UWAGI.

       EFAULT filename lub jeden ze wskaźników w wektorach argv lub envp wskazuje poza dostępną dla  użytkownika
              przestrzeń adresową.

       EINVAL Plik  wykonywalny  w  formacie ELF ma więcej niż jeden segment PT_INTERP (tzn. ma więcej niż jeden
              interpreter).

       EIO    Wystąpił błąd wejścia-wyjścia.

       EISDIR Intepreter ELF jest katalogiem.

       ELIBBAD
              Nie został rozpoznany format interpretera ELF.

       ELOOP  Podczas rozwiązywania filename, nazwy skryptu lub interpretera ELF napotkano zbyt  wiele  dowiązań
              symbolicznych.

       ELOOP  Osiągnięto  maksymalny  limit  rekurencji  podczas  intepretacji rekurencyjnego skryptu (zob. pow.
              "Skrypty interpretowane"). Przed Linuksem 3.8 w takim wypadku występował błąd ENOEXEC.

       EMFILE Zostało osiągnięte ograniczenie na liczbę otwartych deskryptorów plików dla procesu.

       ENAMETOOLONG
              filename jest zbyt długie.

       ENFILE Zostało osiągnięte systemowe ograniczenie na całkowitą liczbę otwartych plików.

       ENOENT Plik filename, skrypt,  lub  intepreter  ELF  nie  istnieje  albo  nie  można  znaleźć  biblioteki
              współdzielonej potrzebnej do uruchomienia pliku lub interpretera.

       ENOEXEC
              Nie  rozpoznano  formatu  pliku  binarnego, plik ten jest skompilowany dla innej architektury albo
              wystąpił jakiś inny błąd formatu pliku, który powoduje, że program nie może być uruchomiony.

       ENOMEM Brak dostępnej pamięci jądra.

       ENOTDIR
              Składnik ścieżki filename, ścieżki skryptu lub ścieżki interpretera ELF nie jest katalogiem.

       EPERM  System plików jest zamontowany jako  nosuid,  użytkownik  nie  jest  administratorem,  a  plik  ma
              ustawiony bit set-user-ID lub set-group-ID.

       EPERM  Proces  jest  śledzony  (trace),  użytkownik  nie jest superużytkownikiem, a plik ma ustawiony bit
              set-user-ID lub set-group-ID.

       EPERM  Aplikację ślepe na przywileje nie pozyskają pełnego zestawu  dozwolonych  przywilejów  przyznanego
              przez plik wykonywalny. Zob. capabilities(7).

       ETXTBSY
              Podany plik wykonywalny był otwarty do zapisu przez jeden lub więcej procesów.

ZGODNE Z

       POSIX.1-2001,  POSIX.1-2008, SVr4, 4.3BSD.  POSIX nie opisuje zachowania #!, lecz istnieje ono (z pewnymi
       odmianami) na innych systemach Uniksowych.

UWAGI

       Procesy z ustawionymi  znacznikami  set-user-ID  oraz  set-group-ID  nie  mogą  być  śledzone  za  pomocą
       ptrace(2).

       Efekt  zamontowania  systemu  plików nosuid jest różny dla różnych wersji jądra Linuksa: niektóre odmówią
       uruchomienia programów set-user-ID i  set-group-ID,  gdy  spowodowałoby  to  udostępnienie  użytkownikowi
       możliwości,  którymi  w  danym  momencie  nie  dysponuje  (i zwrócą EPERM), inne po prostu zignorują bity
       set-user-ID i set-group-ID i pomyślnie wykonają exec().

       Pod Linuksem argv i envp może być podany jako NULL. W obu przypadkach, ma to ten sam  skutek  co  podanie
       danego argumentu jako wskaźnika do listy zawierającej pojedynczy wskaźnik null. Prosimy nie wykorzystywać
       tej niestandardowej i nieprzenośnej pseudofunkcji! Na większości innych systemów Uniksowych podanie  jako
       argv  wartości  NULL  spowoduje  wystąpienie  błędu  (EFAULT).  Część innych systemów Uniksowych traktuje
       przypadek envp==NULL tak samo jak Linux.

       POSIX.1 określa, że wartości zwracane przez sysconf(3) nie powinny się zmieniać  przez  cały  czas  życia
       procesu.  Jednakże  od  wersji  2.6.23 Linuksa zmiana limitu zasobów RLIMIT_STACK powoduje również zmianę
       wartości zwracanej przez _SC_ARG_MAX, żeby odzwierciedlić fakt, że zmieniły się ograniczenia  przestrzeni
       służącej do przechowywania argumentów linii poleceń i zmiennych środowiska.

       W  większości  sytuacji  gdy execve() zawiedzie, kontrola powraca do oryginalnego obrazu wykonywalnego, a
       wywołujący execve() może następnie obsłużyć błąd.  Jednak  są  (rzadkie)  przypadki  (zwykle  przy  braku
       zasobów),  gdy błąd może wystąpić w momencie bez powrotu: oryginalny obraz wykonywalne został podzielony,
       a nie można całkowicie zbudować nowego obrazu. W takich sytuacjach jądro zabija proces sygnałem SIGKILL.

   Skrypty interpretowane
       Maksymalna długość pierwszego wiersza skryptu interpretera wynosi 127 znaków.

       Semantyka argumentu optional-arg skryptu interpretera różni się pomiędzy  implementacjami.  Pod  Linuksem
       cały  łańcuch  znaków  występujący  po  nazwie  interpretera  jest przekazywany jako pojedynczy argument.
       Jednakże inne systemy zachowują się inaczej. Niektóre systemy traktują  pierwszy znaku białej spacji jako
       znak  kończący  optional-arg.  Na innych systemach skrypt interpretera może przyjmować wiele argumentów i
       białe znaki optional-arg służą do ich rozdzielania.

       Linux ignoruje bity set-user-ID i set-group-ID dla skryptów.

   execve() i EAGAIN
       Poniżej znajduje się bardziej szczegółowy opis błędu EAGAIN, który może wystąpić (od  Linuksa  3.1)  przy
       wywoływaniu execve().

       Błąd   EAGAIN  może  wystąpić,  gdy  wywołanie  poprzedzające  setuid(2),  setreuid(2)  lub  setresuid(2)
       spowodowało, że rzeczywisty ID użytkownika procesu zmienił się i ta zmiana  doprowadziła  do  wyczerpania
       jego  limitu zasobów RLIMIT_NPROC (tzn. liczba procesów należących do nowego rzeczywistego UID przekroczy
       limit zasobów). W wersjach Linuksa od 2.6.0 do 3.0 powodowało to niepowodzenie wywołania set*uid(). Przed
       wersja  2.6  limit  zasobów  nie  był nakładany  w  przypadku  procesów  zmieniających swój identyfikator
       użytkownika.

       Od Linuksa 3.1, opisana sytuacja nie powoduje już niepowodzenia wywołania set*uid(), ponieważ zbyt często
       prowadziło  to  do  dziur  bezpieczeństwa,  gdy  nieprawidłowo  napisane  programy nie sprawdzały statusu
       zakończenia i przyjmowały, że—jeśli wywołujący  ma  uprawnienia  roota—wywołanie  zawsze  powiedzie  się.
       Obecnie  wywołania  set*uid()  poprawnie  zmieniają  rzeczywisty UID, lecz jądro ustawia wewnętrzną flagę
       PF_NPROC_EXCEEDED, wskazując że przekroczono limit zasobów RLIMIT_NPROC.  Jeśli  flaga  PF_NPROC_EXCEEDED
       jest  ustawiona,  a  limit  zasobów  jest  wciąż  przekroczony w trakcie kolejnego wywołania execve(), to
       wywołanie to zakończy się z błędem EAGAIN.  Ta logika jądra zapewnia, że limit zasobów RLIMIT_NPROC  jest
       wciąż  wymuszony  dla  zwykłej  pracy  demonów uprzywilejowanych —przykładem jest fork(2)  + set*uid()  +
       execve().

       Jeśli jednak limit zasobów nie był już przekroczony w trakcie wywołania execve() (ponieważ zakończyły się
       inne  procesy należące do tego rzeczywistego UID pomiędzy wywołaniami set*uid() i execve()), to wywołanie
       execve() powiedzie się, a jądro usunie  flagę  procesu  PF_NPROC_EXCEEDED.  Flaga  jest  usuwana  również
       wówczas, gdy kolejne wywołanie do fork(2) przez ten proces powiedzie się.

   Historia
       W Uniksie V6 lista argumentów wywołania exec() była kończona 0, podczas gdy lista argumentów funkcji main
       była kończona -1. Dlatego lista argumentów  przekazana  do  main  nie  mogła  być  bezpośrednio  użyta  w
       wywołaniu exec(). Od Uniksa V7 obie te wartości są NULL.

PRZYKŁAD

       Następujący program jest zaprojektowany do wykonania przez drugi program przedstawiony poniżej. Wyświetla
       swoje argumenty uruchomienia po jednym w wierszu.

           /* myecho.c */

           #include <stdio.h>
           #include <stdlib.h>

           int
           main(int argc, char *argv[])
           {
               int j;

               for (j = 0; j < argc; j++)
                   printf("argv[%d]: %s\n", j, argv[j]);

               exit(EXIT_SUCCESS);
           }

       Tego programu można użyć do uruchomienia programu podanego w argumencie linii poleceń:

           /* execve.c */

           #include <stdio.h>
           #include <stdlib.h>
           #include <unistd.h>

           int
           main(int argc, char *argv[])
           {
               char *newargv[] = { NULL, "witaj", "świecie", NULL };
               char *newenviron[] = { NULL };

               if (argc != 2) {
                   fprintf(stderr, "Użycie: %s <plik-do-uruchomienia>\n", argv[0]);
                   exit(EXIT_FAILURE);
               }

               newargv[0] = argv[1];

               execve(argv[1], newargv, newenviron);
               perror("execve");   /* execve() wraca tylko w przypadku błędu */
               exit(EXIT_FAILURE);
           }

       Możemy użyć drugiego programu do uruchomienia pierwszego:

           $ cc myecho.c -o myecho
           $ cc execve.c -o execve
           $ ./execve ./myecho
           argv[0]: ./myecho
           argv[1]: witaj
           argv[2]: świecie

       Możemy także użyć tych programów do pokazania używania interpretera  skryptu.  Aby  to  zrobić,  tworzymy
       skrypt, którego "interpreterem"  jest nasz program myecho:

           $ cat > script
           #!./myecho script-arg
           ^D
           $ chmod +x script

       Następnie używamy naszego programu do wykonania skryptu:

           $ ./execve ./script
           argv[0]: ./myecho
           argv[1]: script-arg
           argv[2]: ./script
           argv[3]: witaj
           argv[4]: świecie

ZOBACZ TAKŻE

       chmod(2),  execveat(2),  fork(2),  ptrace(2), execl(3), fexecve(3), getopt(3), system(3), credentials(7),
       environ(7), path_resolution(7), ld.so(8)

O STRONIE

       Angielska wersja tej strony pochodzi z wydania 4.07 projektu Linux man-pages. Opis  projektu,  informacje
       dotyczące   zgłaszania   błędów,   oraz   najnowszą   wersję   oryginału   można   znaleźć   pod  adresem
       https://www.kernel.org/doc/man-pages/.

TŁUMACZENIE

       Autorami  polskiego  tłumaczenia  niniejszej   strony   podręcznika   man   są:   Przemek   Borys   (PTM)
       <pborys@dione.ids.pl>,    Andrzej    Krzysztofowicz    (PTM)    <ankry@mif.pg.gda.pl>,   Robert   Luberda
       <robert@debian.org> i Michał Kułach <michal.kulach@gmail.com>.

       Polskie tłumaczenie jest częścią  projektu  manpages-pl;  uwagi,  pomoc,  zgłaszanie  błędów  na  stronie
       http://sourceforge.net/projects/manpages-pl/. Jest zgodne z wersją  4.07 oryginału.