memfd_secret(2)

NUME
memfd_secret - creează un fișier anonim bazat pe RAM pentru a accesa regiuni de memorie secrete

BIBLIOTECA
Biblioteca C standard (libc, -lc)

SINOPSIS

#include <sys/syscall.h>      /* Definirea constantelor SYS_* */
#include <unistd.h>

int syscall(SYS_memfd_secret, unsigned int flags);

Notă: glibc nu oferă nicio funcție învăluitoare pentru memfd_secret(), fiind necesară utilizarea syscall(2).

DESCRIERE
memfd_secret() creează un fișier anonim bazat pe RAM și returnează un descriptor de fișier care face referire la acesta. Fișierul oferă o modalitate de a crea și de a accesa regiuni de memorie cu o protecție mai puternică decât fișierele obișnuite bazate pe RAM și hărțile de memorie anonime. Odată ce toate referințele deschise la fișier sunt închise, acesta este eliberat automat. Dimensiunea inițială a fișierului este stabilită la 0. În urma apelului, dimensiunea fișierului ar trebui să fie stabilită utilizând ftruncate(2).

Zonele de memorie care susțin fișierul creat cu memfd_secret(2) sunt vizibile numai pentru procesele care au acces la descriptorul de fișier. Regiunea de memorie este eliminată din tabelele de pagini ale nucleului și numai tabelele de pagini ale proceselor care dețin descriptorul de fișier cartografiază memoria fizică corespunzătoare; (astfel, paginile din regiune nu pot fi accesate de către nucleul însuși, astfel încât, de exemplu, indicatorii către regiune nu pot fi trecuți în apelurile de sistem).

Următoarele valori pot fi combinate în mod binar OR în flags pentru a controla comportamentul lui memfd_secret():

FD_CLOEXEC
    Activează fanionul „close-on-exec” pe noul descriptor de fișier, ceea ce face ca regiunea să fie eliminată din proces la execve(2). A se vedea descrierea fanionului O_CLOEXEC în open(2).

Ca valoare de retur, memfd_secret() returnează un nou descriptor de fișier care se referă la un fișier anonim. Acest descriptor de fișier este deschis atât pentru citire, cât și pentru scriere (O_RDWR), iar O_LARGEFILE este definit pentru descriptorul de fișier.

În ceea ce privește fork(2) și execve(2), se aplică semantica obișnuită pentru descriptorul de fișier creat de memfd_secret(). O copie a descriptorului de fișier este moștenită de procesul-copil creat de fork(2) și se referă la același fișier. Descriptorul de fișier este păstrat de execve(2), cu excepția cazului în care nu a fost activat fanionul „close-on-exec”.

Regiunea de memorie este blocată în memorie în același mod ca și în cazul mlock(2), astfel încât nu va fi niciodată scrisă în spațiul de interschimb, iar hibernarea este inhibată atâta timp cât există descrieri memfd_secret(). Cu toate acestea, implementarea lui memfd_secret() nu va încerca să populeze întregul interval în timpul apelului mmap(2) care atașează regiunea în spațiul de adrese al procesului; în schimb, paginile sunt alocate efectiv doar pe măsură ce sunt introduse prin eroare. Cantitatea de memorie permisă pentru hărțile de memorie ale descriptorului de fișier se supune acelorași reguli ca și mlock(2) și nu poate depăși RLIMIT_MEMLOCK.

VALOAREA RETURNATĂ
În caz de succes, memfd_secret() returnează un nou descriptor de fișier. În caz de eroare, se returnează -1, iar errno este configurată pentru a indica eroarea.

ERORI-IEȘIRE

EINVAL
    flags include biți necunoscuți.

EMFILE
    Limita per proces a numărului de descriptori de fișiere deschise a fost atinsă.

EMFILE
    Limita la nivel de sistem a numărului total de fișiere deschise a fost atinsă.

ENOMEM
    Nu a existat suficientă memorie pentru a crea un nou fișier anonim.

ENOSYS
    memfd_secret() nu este implementat pe această arhitectură sau nu a fost activat în linia de comandă a nucleului cu secretmem_enable=1.

STANDARDE
Linux.

ISTORIC
Linux 5.14.

Înainte de Linux 6.5, memfd_secret() era dezactivat în mod implicit și disponibil numai dacă administratorul de sistem îl activa folosind parametrul de nucleu „secretmem.enable=y”.

NOTE
Apelul de sistem memfd_secret() este conceput pentru a permite unui proces din spațiul utilizatorului să creeze un interval de memorie inaccesibil pentru oricine altcineva, inclusiv pentru nucleu. Nu există o garanție de 100% că nucleul nu va putea accesa intervale de memorie susținute de memfd_secret() în orice circumstanțe, dar, cu toate acestea, este mult mai greu de a extrage date din aceste regiuni.

memfd_secret() asigură următoarele protecții:

•   Protecție îmbunătățită (împreună cu toate celelalte sisteme de prevenire a atacurilor din nucleu) împotriva atacurilor ROP. Absența oricărei primitive în interiorul nucleului pentru accesarea memoriei susținute de memfd_secret() înseamnă că atacul ROP cu un singur gadget (dispozitiv) nu poate funcționa pentru a realiza extragerea de date. Atacatorul ar trebui să găsească suficiente gadget-uri ROP pentru a reconstrui intrările lipsă din tabelul de pagini, ceea ce sporește în mod semnificativ dificultatea atacului, în special atunci când există alte protecții, cum ar fi limitarea dimensiunii stivei în nucleu și organizarea aleatorie a spațiului de adrese.

•   Împiedicați expunerile de memorie în spațiul utilizatorului între procese. Odată ce o regiune pentru o cartografiere de memorie memfd_secret() este alocată, utilizatorul nu o poate trece accidental în nucleu pentru a fi transmisă undeva. Paginile de memorie din această regiune nu pot fi accesate prin intermediul hărții directe și sunt interzise în get_user_pages.

•   Protejați-vă împotriva defectelor de nucleu exploatate. Pentru a accesa zonele de memorie susținute de memfd_secret(), un atac la nivelul nucleului ar trebui fie să parcurgă tabelele de pagini și să creeze altele noi, fie să genereze un nou proces privilegiat în spațiul utilizatorului pentru a efectua extragerea de secrete utilizând ptrace(2).

Pentru a preveni eventualele scurgeri de date din regiunile de memorie susținute de memfd_secret() dintr-o imagine de hibernare, hibernarea este împiedicată atunci când există utilizatori memfd_secret() activi.

CONSULTAȚI ȘI
fcntl(2), ftruncate(2), mlock(2), memfd_create(2), mmap(2), setrlimit(2)

TRADUCERE
Traducerea în limba română a acestui manual a fost făcută de Remus-Gabriel Chelu <remusgabriel.chelu@disroot.org>

Această traducere este documentație gratuită; citiți Licența publică generală GNU Versiunea 3 (https://www.gnu.org/licenses/gpl-3.0.html) sau o versiune ulterioară cu privire la condiții privind drepturile de autor. NU se asumă NICIO RESPONSABILITATE.

Dacă găsiți erori în traducerea acestui manual, vă rugăm să trimiteți un e-mail la translation-team-ro@lists.sourceforge.net.