open() biasanya menggabungkan dua efek: resolusi pathname memilih objek sistem file, lalu file descriptor yang dihasilkan membawa mode akses untuk I/O data. Linux O_PATH memisahkan kedua efek tersebut. open(path, O_PATH) yang berhasil menghasilkan descriptor yang merujuk objek terpilih, sementara read() dan write() biasa melalui descriptor itu tidak diizinkan.

Pemisahan ini berguna ketika proses memerlukan referensi kernel yang tahan terhadap perubahan nama untuk operasi metadata atau operasi relatif terhadap pathname, tanpa membuka objek untuk transfer data. Analisis race juga berubah: operasi berikutnya dapat dimulai dari descriptor, bukan melakukan resolusi ulang terhadap pathname awal.

Descriptor O_PATH adalah referensi dengan himpunan operasi terbatas

Descriptor O_PATH tetap merupakan file descriptor dan mengikuti aturan lifetime descriptor biasa. Descriptor dapat diduplikasi, diwariskan sesuai descriptor flags, dikirim melalui Unix-domain socket memakai SCM_RIGHTS, diperiksa dengan fstat(), dan ditutup.

Himpunan operasinya sengaja lebih sempit daripada descriptor yang dibuka dengan O_RDONLY, O_WRONLY, atau O_RDWR. Pemanggilan transfer data seperti read() dan write() gagal karena O_PATH tidak menetapkan mode akses file biasa. Jadi descriptor ini bukan descriptor read-only dengan sintaks berbeda; ia mewakili antarmuka kernel yang berbeda.

Perbedaan tersebut juga tampak pada status flags. F_GETFL melaporkan O_PATH untuk descriptor semacam ini. Aplikasi yang menerima descriptor arbitrer dapat memakai fakta tersebut ketika kontraknya memerlukan open file description yang mampu melakukan I/O data, bukan sekadar referensi pathname.

Pathname dapat berubah setelah referensi diperoleh

Pathname adalah rute melalui directory entry, bukan identitas objek permanen. Setelah open dengan O_PATH berhasil, proses lain dapat melakukan rename atau unlink pada directory entry yang dipakai saat lookup. Descriptor tetap merujuk objek yang dipilih oleh open yang berhasil selama referensi kernel tersebut masih valid.

open() berikutnya terhadap pathname awal melakukan lookup baru dan karena itu dapat memilih objek berbeda. Kedua operasi memiliki semantik berbeda:

int ref = open("queue/current", O_PATH | O_CLOEXEC);
if (ref == -1)
    return -1;

/* queue/current dapat di-rename atau diganti di sini */

struct stat st;
if (fstat(ref, &st) == -1)
    return -1;

fstat(ref, ...) bekerja pada objek yang dirujuk. Pemanggilan itu tidak melakukan resolusi ulang terhadap queue/current. Hal ini mengeluarkan penggantian pathname dari interval antara pemilihan dan pemeriksaan metadata, tetapi tidak membekukan metadata atau isi objek yang dapat berubah.

Referensi direktori menjadi anchor lookup

Ketika descriptor O_PATH merujuk direktori, antarmuka keluarga *at() dapat memakainya sebagai dirfd. Lookup relatif kemudian dimulai dari direktori yang dirujuk, bukan dari working directory proses.

Properti ini membuat identitas direktori eksplisit pada kode yang jika tidak demikian harus menggabungkan string path atau bergantung pada state proses yang dapat berubah. Sebagai contoh, openat(dirfd, "state", flags) meresolusikan state relatif terhadap direktori yang direpresentasikan oleh dirfd.

Descriptor tersebut tidak menerapkan containment dengan sendirinya. Komponen seperti .., symbolic link, dan traversal mount tetap mengikuti semantik operasi yang dipanggil. Kode yang memerlukan resolusi terbatas membutuhkan antarmuka yang menyatakan batas tersebut, misalnya openat2() dengan RESOLVE_* flags yang sesuai. Descriptor direktori O_PATH menyediakan anchor; descriptor itu bukan batas sandbox.

AT_EMPTY_PATH dapat menarget descriptor itu sendiri

Sejumlah antarmuka Linux *at() mendukung AT_EMPTY_PATH. Dengan pathname kosong dan descriptor yang memenuhi syarat, operasi menarget objek yang dirujuk descriptor tersebut alih-alih melakukan lookup pathname nonkosong baru.

Hal ini membentuk model komposisi yang berguna: satu operasi memperoleh referensi, lalu operasi berikutnya bertindak pada referensi itu melalui API yang parameter pathname-nya jika tidak demikian akan memerlukan lookup lain. Dukungan bersifat spesifik per antarmuka, sehingga pemanggil perlu memeriksa flags dan persyaratan kernel yang terdokumentasi untuk setiap syscall, bukan menganggap semua fungsi *at() menerima path kosong.

Mekanisme yang sama dapat berlaku pada descriptor O_PATH yang merujuk objek non-direktori. Nilai descriptor ini karena itu lebih luas daripada lookup relatif terhadap direktori saja.

O_PATH tidak otomatis membuat symbolic link itu sendiri menjadi objek yang dirujuk. Pada lookup normal, symbolic link diikuti sesuai aturan resolusi pathname.

Kombinasi O_PATH dengan O_NOFOLLOW mengubah kasus komponen terakhir: bila komponen terakhir adalah symbolic link, descriptor yang dihasilkan dapat merujuk link itu sendiri. Antarmuka Linux yang menerima path kosong kemudian dapat menjalankan operasi yang didukung pada link tersebut tanpa meresolusikan targetnya lagi.

Ini tetap merupakan batas identitas, bukan bypass izin umum. Izin pencarian direktori tetap berperan dalam resolusi pathname, dan operasi berikutnya menerapkan pemeriksaan otorisasinya sendiri.

Kepemilikan referensi tidak menghapus pemeriksaan otorisasi

Descriptor O_PATH membuktikan bahwa proses memegang referensi kernel ke sebuah objek; descriptor itu tidak memberi semua operasi yang dapat menyebut objek tersebut. Pemeriksaan izin bergantung pada syscall berikutnya dan aturan yang didokumentasikan untuk syscall itu.

Pemisahan ini penting ketika descriptor melintasi batas proses. Mengirim descriptor O_PATH dengan SCM_RIGHTS memindahkan referensi yang dapat dipakai penerima untuk operasi yang kompatibel dengan descriptor tersebut. Tindakan itu tidak mengubah penerima menjadi pembuka awal dan tidak membuat semua mutasi metadata atau namespace menjadi diizinkan.

Desain yang memperlakukan descriptor sebagai capability karena itu perlu mendefinisikan himpunan operasi persis yang diekspos proses penerima serta pemeriksaan kernel yang melekat pada operasi tersebut. Properti yang relevan adalah transfer referensi stabil, bukan otoritas file tanpa batas.

Identitas objek dan state objek tetap terpisah

Memegang descriptor O_PATH menstabilkan referensi objek terpilih terhadap perubahan pathname berikutnya, tetapi tidak membuat snapshot state objek. Ukuran file, timestamp, ownership, mode bits, extended attributes, dan isi direktori tetap dapat berubah ketika aktor lain memiliki otoritas untuk mengubahnya.

Batas ini mencegah klaim yang terlalu luas: mengganti lookup pathname berulang dengan operasi relatif terhadap descriptor menutup satu kelas race nama-ke-objek, tetapi tidak membuat rangkaian syscall terpisah menjadi atomik. Jika kebenaran bergantung pada metadata yang tetap sama antara pemeriksaan dan tindakan, desain masih memerlukan mekanisme yang menegakkan kondisi tersebut.

O_PATH paling tepat diperlakukan sebagai primitive referensi. Linux dapat mempertahankan dan memindahkan hasil pemilihan pathname secara independen dari otoritas I/O data biasa. Pemisahan tersebut memberi operasi berikutnya anchor objek yang stabil sambil mempertahankan mutasi, otorisasi, dan semantik spesifik operasi sebagai persoalan yang terpisah.