Provided by: manpages-pl-dev_4.13-4_all 

NAZWA
execve - uruchomienie programu
SKŁADNIA
#include <unistd.h>
int execve(const char *pathname, char *const argv[],
char *const envp[]);
OPIS
execve() executes the program referred to by pathname. This causes the program that is currently being
run by the calling process to be replaced with a new program, with newly initialized stack, heap, and
(initialized and uninitialized) data segments.
pathname 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 is an array of pointers to strings passed to the new program as its command-line arguments. By
convention, the first of these strings (i.e., argv[0]) should contain the filename associated with the
file being executed. The argv array must be terminated by a NULL pointer. (Thus, in the new program,
argv[argc] will be NULL.)
envp is an array of pointers to strings, conventionally of the form key=value, which are passed as the
environment of the new program. The envp array must be terminated by a NULL pointer.
The argument vector and environment can be accessed by the new program's main function, when it is
defined as:
int main(int argc, char *argv[], char *envp[])
Note, however, that the use of a third argument to the main function is not specified in POSIX.1;
according to POSIX.1, the environment should be accessed via the external variable environ(7).
execve() does not return on success, and the text, initialized data, uninitialized data (bss), and stack
of the calling process are overwritten according to the contents of the newly loaded program.
Jeśli obecny program jest śledzony za pomocą ptrace, wysyła się mu SIGTRAP po pomyślnym execve().
If the set-user-ID bit is set on the program file referred to by pathname, then the effective user ID of
the calling process is changed to that of the owner of the program file. Similarly, if the set-group-ID
bit is set on the program file, then the effective group ID of the calling process is set to the group of
the program file.
The aforementioned transformations of the effective IDs are not performed (i.e., the set-user-ID and
set-group-ID bits are ignored) if any of the following is true:
* the no_new_privs attribute is set for the calling thread (see prctl(2));
* the underlying filesystem is mounted nosuid (the MS_NOSUID flag for mount(2)); or
* the calling process is being ptraced.
The capabilities of the program file (see capabilities(7)) are also ignored if any of the above are
true.
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.
The process's real UID and real GID, as well its supplementary group IDs, are unchanged by a call to
execve().
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)).
Effect on process attributes
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():
* The process's "dumpable" attribute is set to the value 1, unless a set-user-ID program, a set-group-ID
program, or a program with capabilities is being executed, in which case the dumpable flag may instead
be reset to the value in /proc/sys/fs/suid_dumpable, in the circumstances described under
PR_SET_DUMPABLE in prctl(2). Note that changes to the "dumpable" attribute may cause ownership of
files in the process's /proc/[pid] directory to change to root:root, as described in proc(5).
* 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 pathname wywołania execve() określa interpreter, to zostanie uruchomiony interpreter z
następującymi argumentami:
interpreter [opcjonalny-arg] pathname arg...
where pathname is the absolute pathname of the file specified as the first argument of execve(), and
arg... is the series of words pointed to by the argv argument of execve(), starting at argv[1]. Note
that there is no way to get the argv[0] that was passed to the execve() call.
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.
On kernel 2.6.23 and later, most architectures support a size limit derived from the soft RLIMIT_STACK
resource limit (see getrlimit(2)) that is in force at the time of the execve() call. (Architectures
with no memory management unit are excepted: they maintain the limit that was in effect before kernel
2.6.23.) This change allows programs to have a much larger argument and/or environment list. For these
architectures, the total size is limited to 1/4 of the allowed stack size. (Imposing the 1/4-limit
ensures that the new program always has some stack space.) Additionally, the total size is limited to
3/4 of the value of the kernel constant _STK_LIM (8 Mibibytes). Since Linux 2.6.25, the kernel also
places a floor of 32 pages on this size limit, so that, even when RLIMIT_STACK is set very low,
applications are guaranteed to have at least as much argument and environment space as was provided by
Linux 2.6.23 and earlier. (This guarantee was not provided in Linux 2.6.23 and 2.6.24.) Additionally,
the limit per string is 32 pages (the kernel constant MAX_ARG_STRLEN), and the maximum number of strings
is 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 pathname 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 pathname 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 pathname, 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
Ścieżka pathname jest zbyt długa.
ENFILE Zostało osiągnięte systemowe ograniczenie na całkowitą liczbę otwartych plików.
ENOENT The file pathname or a script or ELF interpreter does not exist.
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 pamięci jądra.
ENOTDIR
Składnik ścieżki pathname, ś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
One sometimes sees execve() (and the related functions described in exec(3)) described as "executing a
new process" (or similar). This is a highly misleading description: there is no new process; many
attributes of the calling process remain unchanged (in particular, its PID). All that execve() does is
arrange for an existing process (the calling process) to execute a new program.
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.
In most cases where execve() fails, control returns to the original executable image, and the caller of
execve() can then handle the error. However, in (rare) cases (typically caused by resource exhaustion),
failure may occur past the point of no return: the original executable image has been torn down, but the
new image could not be completely built. In such cases, the kernel kills the process with a SIGSEGV
(SIGKILL until Linux 3.17) signal.
Skrypty interpretowane
The kernel imposes a maximum length on the text that follows the "#!" characters at the start of a
script; characters beyond the limit are ignored. Before Linux 5.1, the limit is 127 characters. Since
Linux 5.1, the limit is 255 characters.
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 (like most other modern UNIX systems) ignores the set-user-ID and set-group-ID bits on scripts.
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ŁADY
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[])
{
for (int 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), get_robust_list(2), ptrace(2), exec(3), fexecve(3), getopt(3), system(3),
capabilities(7), credentials(7), environ(7), path_resolution(7), ld.so(8)
O STRONIE
Angielska wersja tej strony pochodzi z wydania 5.10 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 są: Przemek Borys <pborys@dione.ids.pl>,
Andrzej Krzysztofowicz <ankry@green.mf.pg.gda.pl>, Robert Luberda <robert@debian.org> i Michał Kułach
<michal.kulach@gmail.com>
Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje o warunkach licencji można uzyskać
zapoznając się z GNU General Public License w wersji 3 lub nowszej. Nie przyjmuje się ŻADNEJ
ODPOWIEDZIALNOŚCI.
Błędy w tłumaczeniu strony podręcznika prosimy zgłaszać na adres listy dyskusyjnej manpages-pl-
list@lists.sourceforge.net.
Linux 13 sierpnia 2020 r. EXECVE(2)