Na co pozwala syscall w Linux execve – praktyczne przykłady

Wyobraź sobie, że chcesz uruchomić inny program z poziomu swojego procesu — na przykład uruchomić skrypt, program lub powłokę. W systemie Linux, aby to zrobić na najniższym poziomie, korzystamy z wywołania systemowego execve.

W tym artykule dowiesz się, czym jest syscall execve, jak działa i zobaczysz praktyczne przykłady jego użycia — zarówno z poziomu języka C, jak i asemblera.

Co to jest execve?

execve (ang. execute program) to wywołanie systemowe w Linuxie służące do uruchomienia nowego programu, zastępując obecny obraz procesu nowym programem.

  • Nie tworzy nowego procesu — zamienia kod, dane i stos bieżącego procesu.
  • Przyjmuje ścieżkę do programu, argumenty oraz zmienne środowiskowe.
  • Po wywołaniu execve obecny program przestaje istnieć — zastępuje go nowy.

Jak działa execve?

Wywołanie execve ma następującą sygnaturę:

int execve(const char *pathname, char *const argv[], char *const envp[]);
  • pathname — ścieżka do wykonywalnego pliku.
  • argv — tablica wskaźników do argumentów przekazywanych do programu.
  • envp — tablica wskaźników do zmiennych środowiskowych.

Jeśli wywołanie powiedzie się, nie wraca do programu wywołującego — proces jest zastąpiony nowym programem. Jeśli zwróci błąd, execve zwróci -1.

execve w asemblerze x86-64

Wywołania systemowe w Linux x86-64 wykonuje się instrukcją syscall. Numer execve to 59 (decimal).

Argumenty przekazujemy do rejestrów:

RejestrArgument
raxnumer syscall (59)
rdipathname
rsiargv
rdxenvp

Przykład minimalnego kodu w NASM, który uruchamia /bin/ls:

section .data
    path db '/bin/ls', 0
    argv dq path, 0
    envp dq 0

section .text
    global _start

_start:
    mov rax, 59        ; execve syscall number
    mov rdi, path      ; ścieżka programu
    mov rsi, argv      ; argumenty
    mov rdx, envp      ; środowisko
    syscall

    ; jeśli execve zawiedzie - zakończ program
    mov rax, 60        ; exit syscall
    xor rdi, rdi
    syscall

Kompilacja powyższego kodu na Linux

$ nasm -f elf64 -o run_ls_asm.o run_ls_asm.asm
$ ld -o run_ls_asm run_ls_asm.o

$ ./run_ls_asm
run_ls_asm run_ls_asm.asm run_ls_asm.o

Praktyczne zastosowania execve

1. Implementacja własnego exec w shellu

execve to fundament działania wielu powłok (shelli). Po wpisaniu polecenia:

ls -l /home

shell wykorzystuje fork() do utworzenia procesu potomnego, a w nim execve do uruchomienia /bin/ls z argumentami.

2. Uruchamianie skryptów lub programów z własnej aplikacji

Czasem aplikacja musi uruchomić zewnętrzny program, np. narzędzie do konwersji plików. execve pozwala na zastąpienie procesu tym programem, albo (częściej) wykorzystuje się fork() + execve(), by nie zamknąć aplikacji macierzystej.

3. Zastąpienie bieżącego procesu nowym programem

Jeśli w procesie chcesz całkowicie zmienić jego kod i dane (np. po zalogowaniu się użytkownika), wywołujesz execve, co zastępuje proces nowym obrazem.

execve vs system()

Funkcja system() w C uruchamia powłokę /bin/sh i wykonuje komendę. Jest wygodna, ale mniej elastyczna i bezpieczna niż bezpośrednie użycie execve.

Uwaga na błędy

  • Jeśli ścieżka jest błędna lub program nie ma uprawnień — execve zwróci błąd.
  • Pamiętaj o przekazaniu poprawnych tablic argumentów i środowiska.
  • execve nigdy nie wraca jeśli jest sukcesem!

Podsumowanie

  • execve to najniższy poziom uruchamiania programów w Linuxie.
  • Zastępuje obecny proces nowym obrazem programu.
  • Jest fundamentem działania powłok i procesów potomnych.
  • Można go używać bezpośrednio z asemblera, lub przez standardowe funkcje w C.
TUX - maskotka systemu Linux

About the author

Autor "BIELI" to zapalony entuzjasta otwartego oprogramowania, który dzieli się swoją pasją na blogu poznajlinuxa.pl. Jego wpisy są skarbnicą wiedzy na temat Linuxa, programowania oraz najnowszych trendów w świecie technologii. Autor "BIELI" wierzy w siłę społeczności Open Source i zawsze stara się inspirować swoich czytelników do eksplorowania i eksperymentowania z kodem.