Sebuah layanan berprivilege dapat menerima pathname relatif dari komponen dengan tingkat kepercayaan lebih rendah, sementara akses seharusnya terbatas pada file di bawah direktori tertentu. Pemeriksaan string terhadap .., penolakan garis miring di awal, atau inspeksi symbolic link sebelum open() berikutnya tidak mengikat pemeriksaan tersebut ke lookup kernel yang memperoleh file. Entri direktori dapat berubah di antara dua operasi, symbolic link dapat mengalihkan traversal, dan topologi mount dapat mengubah namespace yang dicapai oleh sebuah path.

Linux openat2() menempatkan batas tersebut langsung pada resolusi pathname. struct open_how memiliki field resolve dengan flag RESOLVE_* yang membatasi penelusuran kernel untuk satu operasi open. File descriptor hanya dikembalikan jika lookup memenuhi batas tersebut. Dengan demikian, keputusan keamanan berpindah dari prediksi userspace tentang sebuah path menjadi kondisi yang diterapkan selama akuisisi.

Descriptor direktori menjadi jangkar lookup

Seperti openat(), openat2() dapat meresolusikan path relatif dari direktori yang dirujuk oleh dirfd. File descriptor direktori merupakan jangkar yang lebih stabil dibanding prefix tekstual karena penggantian nama direktori tidak mengarahkan descriptor tersebut ke objek direktori lain.

Jangkar itu sendiri tidak membatasi traversal. Resolusi relatif biasa dapat memproses komponen .. dan symbolic link yang menuju ke luar direktori awal. Kebijakan resolve menentukan transisi namespace yang diizinkan kernel selama penelusuran dari jangkar.

RESOLVE_BENEATH menolak resolusi yang keluar dari turunan dirfd. Pathname absolut ditolak, demikian pula target symbolic link absolut yang akan keluar dari hierarki berjangkar. Properti yang diberikan adalah pembatasan di bawah direktori, bukan larangan umum terhadap symbolic link.

RESOLVE_IN_ROOT memakai model berbeda. Untuk operasi open tersebut, dirfd bertindak sebagai root resolusi pathname. Input path absolut ditafsirkan relatif terhadap direktori itu, symbolic link absolut juga berakar di sana, dan .. pada root sementara tidak dapat bergerak ke atasnya. Efek ini menyerupai batas root per operasi, bukan perubahan state chroot() untuk seluruh proses.

Pembatasan dan penolakan symbolic link menangani persoalan berbeda. Symbolic link relatif dapat tetap sepenuhnya berada di bawah jangkar dan tetap sah dengan RESOLVE_BENEATH. Layanan yang mensyaratkan setiap komponen bukan symbolic link dapat menambahkan RESOLVE_NO_SYMLINKS.

RESOLVE_NO_SYMLINKS berlaku pada seluruh komponen pathname, berbeda dari O_NOFOLLOW yang mengatur komponen terakhir. Flag ini juga mengimplikasikan pembatasan magic link. Perbedaan tersebut penting bagi kode yang sebelumnya menggabungkan descriptor direktori dengan O_NOFOLLOW lalu menganggap komponen perantara mendapat perlakuan setara.

Magic link Linux, seperti entri tertentu yang diekspos melalui procfs, memiliki semantik di luar teks symbolic link biasa. RESOLVE_NO_MAGICLINKS memblokir resolusinya tanpa melarang symbolic link biasa. Dokumentasi menyatakan bahwa RESOLVE_BENEATH dan RESOLVE_IN_ROOT saat ini turut memblokir magic link, tetapi aplikasi yang memerlukan properti itu tetap perlu meminta RESOLVE_NO_MAGICLINKS secara eksplisit karena efek samping tersebut bukan jaminan API permanen.

Kebijakan yang sempit dapat mengizinkan symbolic link biasa sambil menolak magic link, atau melarang keduanya. Kombinasi yang tepat mengikuti kontrak namespace layanan, bukan aturan universal bahwa semua symbolic link tidak aman.

Perpindahan mount membentuk batas namespace lain

Sebuah pathname dapat tetap berada di bawah direktori secara tekstual tetapi menyeberang ke filesystem lain yang di-mount. Bind mount membuat kondisi ini relevan karena sebuah subtree dapat mengekspos objek dari lokasi berbeda tanpa komponen .. atau symbolic link.

RESOLVE_NO_XDEV menolak traversal mount point, termasuk bind mount. Jika digabungkan dengan flag pembatasan, resolusi dapat diwajibkan tetap berada dalam hierarki berjangkar sekaligus pada mount yang sama. Properti ini lebih ketat daripada pembatasan direktori saja.

Aturan yang lebih ketat juga dapat menolak layout yang sah. Sistem sering memakai bind mount dan mount terpisah di dalam tree aplikasi. Karena itu, layanan sebaiknya memakai RESOLVE_NO_XDEV hanya jika perpindahan mount berada di luar kebijakan pemilihan objek yang dimaksud. Flag tersebut menyatakan batas konkret, bukan sakelar penguatan generik tanpa biaya kompatibilitas.

Kegagalan resolusi merupakan bagian dari kontrak keamanan

openat2() dapat mengembalikan EXDEV ketika RESOLVE_BENEATH atau RESOLVE_IN_ROOT mendeteksi upaya keluar dari batas. Operasi juga dapat menghasilkan EAGAIN ketika kernel tidak dapat memastikan secara aman bahwa traversal .. tetap terbatas akibat race pada namespace. Dalam kondisi tersebut, seluruh operasi openat2() dapat dicoba kembali.

Perilaku ini penting bagi pemanggil berprivilege. Memperlakukan EAGAIN sebagai izin untuk beralih ke openat() yang lebih lemah justru menghapus properti yang membuat operasi gagal secara aman. Penanganan kompatibilitas harus mempertahankan kebijakan resolusi yang dimaksud, bukan diam-diam mengganti primitive akuisisi.

RESOLVE_CACHED menggunakan EAGAIN untuk kondisi berbeda: flag ini meminta lookup yang selesai dari informasi cache tanpa revalidasi atau I/O. Kegagalan dengan flag tersebut menandakan fast path cache tidak mencukupi. Pemanggil dapat mencoba kembali tanpa RESOLVE_CACHED sambil tetap mempertahankan pembatasan direktori dan link yang relevan bagi keamanan.

Nilai yang tidak dikenal atau saling bertentangan dalam open_how ditolak, bukan diabaikan diam-diam. Struktur ini dapat diperluas, dan pemanggil diharapkan mengisi nol seluruh struktur agar field masa depan dimulai dengan perilaku nol yang didefinisikan.

Open yang berhasil mengikat objek, bukan pathname

Nilai keamanan openat2() berakhir pada akuisisi file descriptor yang memenuhi batas lookup yang diminta pada operasi tersebut. Setelah dikembalikan, descriptor merujuk ke objek file yang telah dibuka meskipun entri direktori kemudian diganti nama atau diganti dengan objek lain.

Stabilitas itu tidak membekukan isi objek, permission, atau state lain yang dapat berubah. Jika layanan memerlukan integritas konten, metadata yang tidak dapat berubah, atau otorisasi yang tetap berlaku setelah open, properti tersebut memerlukan kontrol terpisah. Pembatasan resolusi path hanya menentukan objek yang dapat diperoleh melalui penelusuran namespace yang dibatasi.

Perbedaan ini juga membatasi klaim untuk operasi path berikutnya. Memvalidasi satu path dengan openat2() lalu membuka kembali teks yang sama melalui API lain tidak memindahkan jaminan awal. Operasi sensitif sebaiknya dilanjutkan dari descriptor yang telah diperoleh, atau menerapkan lookup terbatas yang setara pada setiap operasi pathname terpisah.

Pembatasan per-open menjaga kebijakan namespace tetap lokal

openat2() tidak membuat mount namespace dan tidak mengisolasi seluruh proses. Flag resolusinya mengatur satu lookup pathname. Cakupan ini berguna bagi layanan yang menangani path internal tepercaya sekaligus nama dari luar tanpa mengubah state filesystem global milik proses.

Mekanisme ini paling tepat ketika descriptor direktori mewakili batas otoritas yang dipilih secara sengaja dan kumpulan RESOLVE_* sesuai dengan transisi namespace yang diizinkan. RESOLVE_BENEATH menyediakan pembatasan turunan, RESOLVE_IN_ROOT menyediakan resolusi dengan root sementara, flag link mengendalikan kelas pengalihan, dan RESOLVE_NO_XDEV mengendalikan perpindahan mount.

Properti tersebut tetap lebih sempit daripada sandbox. Mekanisme ini tidak membatasi descriptor yang sudah terbuka, akses jaringan, syscall lain, atau lookup path berikutnya yang tidak memakai kebijakan tersebut. Efek keamanannya spesifik: kernel menolak mengembalikan descriptor ketika pathname yang diminta tidak dapat diresolusikan dalam batas yang dideklarasikan untuk operasi open itu.