Scroll to navigation

EXECVE(2) Linux Programmeurs Handleiding EXECVE(2)

NAAM

execve - voer programma uit

SAMENVATTING

#include <unistd.h>
int execve(const char *padnaam, char *const argv[],
           char *const envp[]);

BESCHRIJVING

execve() voert het programma uit waar padnaam naar wijst. Dit zorgt er voor dat het programma dan momenteel wordt uitgevoerd door het aanroepende proces wordt vervangen door een nieuw programma, met een niet-geïnitialiseerde stack, heap en (geïnitialiseerde en niet-geïnitialiseerde) data segmenten.

padnaam moet ofwel een binair uitvoerbaar bestand zijn, ofwel een script dat begint met een regel van de vorm:


#!interpreter[optioneel-arg]

Zie de "Interpreter scripts" hieronder, voor details over het laatste geval.

argv is een lijst van wijzers naar tekenreeksen die worden doorgegeven naar een nieuw programma als zijn commando-regel argumenten. Per conventie zou de eerste van deze tekenreeksen (m.a.w. argv[0]) de bestandsnaam moeten zijn van het bestand dat uitgevoerd wordt. De argv lijst moet worden afgesloten met een NULL wijzer. (Daarom, zal in het nieuwe programma, argv[argc] NULL zijn.)

envp is een lijst van wijzers naar tekenreeksen, bij conventie van de vorm key=value, die worden doorgegeven als omgeving van een nieuw programma. De envp lijst moet worden afgesloten met een NULL wijzer.

De argumenten vector en omgeving kunnen worden benaderd door de main-functie van het nieuwe programma, mits deze is gedefinieerd als:


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

Let evenwel op dat het gebruik van het derde argument van de main-functie niet gespecificeerd is in POSIX.1; volgens POSIX.1, zou de omgeving moeten worden benaderd via de externe variabele environ(7).

Bij succes keert execve() niet terug, en de text, geïnitialiseerde data, niet-geinitialiseerde data (bss) en stack van het aanroepende proces worden overschreven volgens de inhoud van het nieuw geladen programma.

Als het huidige programma momenteel wordt ge-ptrace´ed, dan wordt er een SIGTRAP signaal naar verstuurd na een succesvolle execve() aanroep .

Als het set-user-ID bit is gezet op het programma bestand aangewezen door padnaam, dan wordt het effectieve gebruiker ID van het aanroepende proces veranderd naar dat van de eigenaar van het programma bestand. Vergelijkbaar, is het set-group-ID bit is gezet op het programma bestand, dan wordt het effectieve group ID van het aanroepende proces gezet op de groep van het programma bestand.

De hiervoor genoemde transformaties van de effectieve ID worden niet uitgevoerd (m.a.w. de set-user-ID en set-group-ID bits worden genegeerd) als een van de volgende waar is:

  • het no_new_privs attribuut wordt gezet voor de aanroepende thread (zie prctl(2));
  • het onderliggende bestandssysteem is gekoppeld nosuid (de MS_NOSUID vlag voor mount(2)); of
  • het aanroepende proces wordt ge-ptrace´d.

De capaciteiten van het programma bestand (zie capabilities(7) worden ook genegeerd als enig van de bovenstaande waar is.

Het effectieve gebruiker ID van het proces wordt gekopieerd naar het bewaarde set-user-ID; vergelijkbaar, het effectieve groep ID wordt gekopieerd naar het bewaarde set-group-ID. Het kopiëren vindt plaats na effectieve ID veranderingen die optreden vanwege de set-user-ID en set-group-ID modus bits.

De echte UID en echte GID van het proces, zowel als zijn supplementaire groep ID´s blijven onveranderd door de aanroep van execve().

Als het uitvoerbaar bestand een a.out dynamisch gelinked binair uitvoerbaar bestand is dat ook shared-library stompjes bevat, dan wordt de Linux dynamische linker ld.so(8) aangeroepen na de aanvang van uitvoering, om zo de benodigde gedeelde objecten in het geheugen te laden en het uitvoerbaar bestand hiermee te linken.

If the executable is a dynamically linked ELF executable, the interpreter named in the PT_INTERP segment is used to load the needed shared objects. This interpreter is typically /lib/ld-linux.so.2 for binaries linked with glibc (see ld-linux.so(8)).

Effect op proces attributen

Alle proces attributen blijven behouden tijdens een execve(), behalve de volgende:

  • De disposities van elk signaal dat wordt gevangen wordt gereset naar het standaard (signal(7)).
  • Alle afwisselende signaal stacks blijven niet behouden (sigaltstack(2)).
  • Geheugen indelingen blijven niet behouden (mmap(2)).
  • Aangekoppelde System V gedeelde geheugen segmenten worden los gekoppeld (shmat(2)).
  • POSIX gedeelde geheugen regionen worden vrijgegeven (shm_open(3)).
  • Open POSIX berichtrij beschrijvingen worden gesloten (mq_overview(7)).
  • Alle open POSIX genaamde semaforen worden gesloten (sem_overview(7)).
  • POSIX timers blijven niet behouden (timer_create(2)).
  • Alle open map streams worden gesloten (opendir(3)).
  • Geheugen sloten blijven niet behouden mlock(2), mlockall(2)).
  • Beëindiging afhandelaren blijven niet behouden (atexit(3), on_exit(3)).
  • De drijvende-komma omgeving wordt gereset naar de standaard (zie fenv(3)).

De proces attributen in de voorafgaande lijst zijn alle gespecificeerd in POSIX.1. De volgende Linux-specifieke proces attributen blijven niet behouden tijdens een 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).
  • De prctl(2) PR_SET_KEEPCAPS vlag wordt gewist.
  • (Vanaf Linux 2.4.36 / 2.6.23) Als een set-user-ID of set-user-ID programma wordt uitgevoerd, dan wordt het dood signaal van de ouder, gezet door de prctl(2) PR_SET_PDEATHSIG vlag, gewist.
  • De proces naam, zoals gezet door prctl(2) PR_SET_NAME (en getoond door ps -o comm), wordt gereset naar de naam van het nieuwe uitvoerbare bestand.
  • De SECBIT_KEEP_CAPS securebits vlag wordt gewist. Zie capabilities(7).
  • Het beëindiging signaal wordt gereset naar SIGCHLD (zie clone(2)).
  • The file descriptor table is unshared, undoing the effect of the CLONE_FILES flag of clone(2).

Let op de volgende punten:

  • Alle thread anders dan de aanroepende thread worden vernietigd tijdens een execve(). Mutexes, conditie variabelen, en andere pthreads objecten blijven niet behouden.
  • Het equivalent van setlocale(LC_ALL, "C") wordt uitgevoerd bij de start van een programma.
  • POSIX.1 specifies that the dispositions of any signals that are ignored or set to the default are left unchanged. POSIX.1 specifies one exception: if SIGCHLD is being ignored, then an implementation may leave the disposition unchanged or reset it to the default; Linux does the former.
  • Alle uitstaande asynchrone Invoer/Uitvoer operaties worden beëindigd (aio_read(3), aio_write(3)).
  • Voor de behandeling van capaciteiten tijdens execve(), zie capabilities(7).
  • Standaard blijven bestandsindicatoren open langs een execve(). Bestandsindicatoren die zijn gemarkeerd als close-on-exec worden gesloten; die de beschrijving van FD_CLOEXEC in fcntl(2). (Als een bestandsindicator wordt gesloten, dan zal dit de vrijgave van alle locks op het onderliggende bestand door dit proces veroorzaken. Zie fcntl(2) voor details.) POSIX.1 zegt dat als de bestandsindicatoren 0, 1 en 2 ook zouden worden gesloten na een succesvolle execve(), en het proces zou privileges verkrijgen omdat het set-user-ID of set-group-ID bit werd gezet om het uitgevoerde bestand, dan mag het systeem een niet gespecificeerd bestand voor elk van deze bestandsindicatoren openen. Als een algemeen principe kan een niet-overdraagbaar programma, al dan niet geprivilegieerd, aannemen dat deze drie bestandsindicatoren gesloten blijven langs een execve().

Interpreter scripts

Een interpreter script is een tekst bestand met de uitvoer permissie aan gezet en wiens eerste regel van de vorm is:


#!interpreter[optioneel-arg]

De interpreter moet een geldige padnaam voor een uitvoerbaar bestand zijn.

Als het padnaam argument van execve() een interpreter script specificeert dan zal de interpreter worden aangeroepen met de volgende argumenten:


interpreter  [optional-arg] padnaam arg...

waar padnaam de padnaam van het bestand dat als eerste argument werd gespecificeerd van execve(), en arg... is een serie woorden aangewezen door het argv argument van execve() beginnende bij argv[1]. Merk op dat er geen manier is om argv[0] te verkrijgen die doorgegeven werd naar de execve() aanroep.

Voor overdraagbaar gebruik, zou optional-arg afwezig moeten zijn of moeten worden gespecificeerd als een enkel woord (m.a.w. het zou geen witruimtes moeten bevatten); zie OPMERKINGEN hieronder.

Vanaf Linux 2.6.28 staat de kernel toe dat de interpreter van een script, zelf een script is. Dit recht is recursief, tot aan een limiet van vier recursies, zodat de interpreter een script mag zijn dat wordt geïnterpreteerd door een script, en zo voorts.

Limieten op de grootte van argumenten en omgeving

Most UNIX implementations impose some limit on the total size of the command-line argument (argv) and environment (envp) strings that may be passed to a new program. POSIX.1 allows an implementation to advertise this limit using the ARG_MAX constant (either defined in <limits.h> or available at run time using the call sysconf(_SC_ARG_MAX)).

On Linux prior to kernel 2.6.23, the memory used to store the environment and argument strings was limited to 32 pages (defined by the kernel constant MAX_ARG_PAGES). On architectures with a 4-kB page size, this yields a maximum size of 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 MiB). 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.22 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.

EIND WAARDE

Bij succes keert execve() niet terug, bij falen wordt -1 teruggegeven, en wordt errno overeenkomstig gezet.

FOUTEN

Het totaal aantal bytes in de omgeving (envp) en de argumenten lijst (argv) is te groot.
Search permission is denied on a component of the path prefix of pathname or the name of a script interpreter. (See also path_resolution(7).)
Het bestand of de script interpreter is geen normaal bestand.
Uitvoer toestemming werd geweigerd voor het bestand of een script of ELF interpreter.
Het bestandsysteem is gemount met noexec.
Having changed its real UID using one of the set*uid() calls, the caller was—and is now still—above its RLIMIT_NPROC resource limit (see setrlimit(2)). For a more detailed explanation of this error, see NOTES.
padnaam of een van de wijzers in de vectoren argv of envp wijst buiten door de, voor u, toegankelijke adres ruimte.
Een ELF uitvoerbaar bestand heeft meer dan 1 PT_INTERP segment (probeerde meer dan 1 interpreter te benoemen).
Een Invoer/Uitvoer fout trad op.
Een ELF interpreter was een map.
Een ELF interpreter had een onbekende vorm.
Teveel symbolische koppelingen werden tegengekomen bij het "oplossen" van padnaam of de naam van een script of ELF interpreter.
The maximum recursion limit was reached during recursive script interpretation (see "Interpreter scripts", above). Before Linux 3.8, the error produced for this case was ENOEXEC.
De per-proces limiet van het aantal open bestandsbeschrijvingen werd bereikt.
padnaam is te lang.
De grens aan het aantal open bestanden van het systeem is bereikt.
Het bestand padnaam of een script of een ELF interpreter bestaat niet.
Een uitvoerbaar bestand is niet in een bekende vorm: het is voor de verkeerde architectuur, of heeft een of andere vormfout waardoor het niet kan worden uitgevoerd.
Onvoldoende kernelgeheugen voorhanden.
Een deel van het pad-voorvoegsel van padnaam of van een script of ELF interpreter is geen map.
Het bestandssysteem was gekoppeld met nosuid, de gebruiker is niet de supergebruiker, en het bestand heeft het set-user-ID of set-group-ID bit aan staan.
Het proces wordt gevolgd, de gebruiker is niet de supergebruiker en het bestand heeft een set-user-ID of set-group-ID bit aan staan.
A "capability-dumb" applications would not obtain the full set of permitted capabilities granted by the executable file. See capabilities(7).
Uitvoerbaar bestand is open voor schrijven bij een of meer processen.

VOLDOET AAN

POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD. POSIX does not document the #! behavior, but it exists (with some variations) on other UNIX systems.

OPMERKINGEN

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.

Set-user-ID and set-group-ID processes can not be ptrace(2)d.

The result of mounting a filesystem nosuid varies across Linux kernel versions: some will refuse execution of set-user-ID and set-group-ID executables when this would give the user powers they did not have already (and return EPERM), some will just ignore the set-user-ID and set-group-ID bits and exec() successfully.

On Linux, argv and envp can be specified as NULL. In both cases, this has the same effect as specifying the argument as a pointer to a list containing a single null pointer. Do not take advantage of this nonstandard and nonportable misfeature! On many other UNIX systems, specifying argv as NULL will result in an error (EFAULT). Some other UNIX systems treat the envp==NULL case the same as Linux.

POSIX.1 says that values returned by sysconf(3) should be invariant over the lifetime of a process. However, since Linux 2.6.23, if the RLIMIT_STACK resource limit changes, then the value reported by _SC_ARG_MAX will also change, to reflect the fact that the limit on space for holding command-line arguments and environment variables has changed.

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.

Interpreter scripts

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.

The semantics of the optional-arg argument of an interpreter script vary across implementations. On Linux, the entire string following the interpreter name is passed as a single argument to the interpreter, and this string can include white space. However, behavior differs on some other systems. Some systems use the first white space to terminate optional-arg. On some systems, an interpreter script can have multiple arguments, and white spaces in optional-arg are used to delimit the arguments.

Linux (like most other modern UNIX systems) ignores the set-user-ID and set-group-ID bits on scripts.

execve() and EAGAIN

A more detailed explanation of the EAGAIN error that can occur (since Linux 3.1) when calling execve() is as follows.

The EAGAIN error can occur when a preceding call to setuid(2), setreuid(2), or setresuid(2) caused the real user ID of the process to change, and that change caused the process to exceed its RLIMIT_NPROC resource limit (i.e., the number of processes belonging to the new real UID exceeds the resource limit). From Linux 2.6.0 to 3.0, this caused the set*uid() call to fail. (Prior to 2.6, the resource limit was not imposed on processes that changed their user IDs.)

Since Linux 3.1, the scenario just described no longer causes the set*uid() call to fail, because it too often led to security holes where buggy applications didn't check the return status and assumed that—if the caller had root privileges—the call would always succeed. Instead, the set*uid() calls now successfully change the real UID, but the kernel sets an internal flag, named PF_NPROC_EXCEEDED, to note that the RLIMIT_NPROC resource limit has been exceeded. If the PF_NPROC_EXCEEDED flag is set and the resource limit is still exceeded at the time of a subsequent execve() call, that call fails with the error EAGAIN. This kernel logic ensures that the RLIMIT_NPROC resource limit is still enforced for the common privileged daemon workflow—namely, fork(2) + set*uid() + execve().

If the resource limit was not still exceeded at the time of the execve() call (because other processes belonging to this real UID terminated between the set*uid() call and the execve() call), then the execve() call succeeds and the kernel clears the PF_NPROC_EXCEEDED process flag. The flag is also cleared if a subsequent call to fork(2) by this process succeeds.

Historisch

With UNIX V6, the argument list of an exec() call was ended by 0, while the argument list of main was ended by -1. Thus, this argument list was not directly usable in a further exec() call. Since UNIX V7, both are NULL.

VOORBEELDEN

The following program is designed to be execed by the second program below. It just echoes its command-line arguments, one per line.


/* 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); }

Dit programma kan worden gebruikt om het op de commando regel genoemde programma uit te voeren:


/* execve.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{

char *newargv[] = { NULL, "hello", "world", NULL };
char *newenviron[] = { NULL };
if (argc != 2) {
fprintf(stderr, "Usage: %s <file-to-exec>\n", argv[0]);
exit(EXIT_FAILURE);
}
newargv[0] = argv[1];
execve(argv[1], newargv, newenviron);
perror("execve"); /* execve() returns only on error */
exit(EXIT_FAILURE); }

We kunnen het tweede programma om het eerste, als volgt, uit te voeren


$ cc myecho.c -o myecho
$ cc execve.c -o execve
$ ./execve ./myecho
argv[0]: ./myecho
argv[1]: hello
argv[2]: world

We kunnen deze programma´s ook gebruiken om het gebruik van ee script interpreter te demonstreren. Om dit te doen creëren wij een script wiens "interpreter' on myecho programma is:


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

We can then use our program to exec the script:


$ ./execve ./script
argv[0]: ./myecho
argv[1]: script-arg
argv[2]: ./script
argv[3]: hello
argv[4]: world

ZIE OOK

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

COLOFON

Deze pagina is onderdeel van release 5.13 van het Linux man-pages-project. Een beschrijving van het project, informatie over het melden van bugs en de nieuwste versie van deze pagina zijn op https://www.kernel.org/doc/man-pages/ te vinden.

VERTALING

De Nederlandse vertaling van deze handleiding is geschreven door Jos Boersema <joshb@xs4all.nl>, Mario Blättermann <mario.blaettermann@gmail.com> en Luc Castermans <luc.castermans@gmail.com>

Deze vertaling is vrije documentatie; lees de GNU General Public License Version 3 of later over de Copyright-voorwaarden. Er is geen AANSPRAKELIJKHEID.

Indien U fouten in de vertaling van deze handleiding zou vinden, stuur een e-mail naar debian-l10n-dutch@lists.debian.org.

27 augustus 2021 Linux