Sebuah proses dapat memperoleh duplikat file descriptor yang sudah terbuka di proses lain tanpa meminta proses tersebut mengirimkannya melalui UNIX domain socket. Linux pidfd_getfd() melakukan transfer itu melalui PID file descriptor, dengan izin yang dibatasi oleh pemeriksaan akses ptrace.

Descriptor yang diterima merupakan entry baru di caller, tetapi objek kernel di baliknya bukan objek independen. Descriptor tersebut merujuk ke open file description yang sama dengan descriptor target. Perbedaan ini menentukan sharing offset, file status flags, dan operasi terhadap objek dasarnya.

Descriptor hasil duplikasi berbagi state open file

File descriptor adalah entry pada tabel descriptor suatu proses. Untuk banyak tipe file, entry tersebut menunjuk ke open file description yang dikelola kernel. pidfd_getfd() membuat entry baru pada tabel descriptor caller yang menunjuk ke open file description yang sama dengan targetfd.

proses target                       caller
+-----------+                  +-----------+
| fd 7      |                  | fd baru 11|
+-----+-----+                  +-----+-----+
      |                              |
      +--------------+---------------+
                     |
                     v
             open file description
             offset / status flags
                     |
                     v
                file object

Semantiknya lebih dekat ke dup() yang melintasi batas proses daripada membuka ulang pathname. Jika objek memiliki file offset bersama, read atau write melalui salah satu descriptor dapat menggeser offset tersebut. File status flags yang melekat pada open file description juga dibagi.

Descriptor flags berada pada lapisan berbeda. Descriptor hasil pidfd_getfd() memiliki FD_CLOEXEC, sehingga execve() tidak mempertahankannya kecuali caller secara eksplisit mengubah flag descriptor tersebut.

pidfd memilih proses tanpa lookup PID mentah

Argumen pertama adalah PID file descriptor, yang umumnya diperoleh melalui pidfd_open(). Argumen kedua adalah nomor descriptor di proses target.

int remote = 7;
int local = syscall(SYS_pidfd_getfd, pidfd, remote, 0);

if (local == -1) {
    perror("pidfd_getfd");
}

Argumen flags saat ini dicadangkan dan harus bernilai nol. Linux menambahkan system call ini pada versi 5.6. Antarmuka Linux man-pages mendokumentasikan pemanggilan langsung melalui syscall() karena glibc tidak menyediakan wrapper khusus.

pidfd menyediakan handle kernel yang stabil untuk lifetime proses. Operasi ini tidak perlu dibangun di atas PID yang kelak dapat dipakai ulang untuk proses lain. Namun, pidfd tidak membekukan tabel descriptor target. targetfd tetap harus terbuka ketika kernel menjalankan pidfd_getfd().

Jika descriptor target sudah tidak terbuka, operasi gagal dengan EBADF. Jika proses yang direpresentasikan pidfd sudah berakhir dan telah di-wait, error yang didokumentasikan adalah ESRCH.

Duplikasi tidak memerlukan kerja sama proses target

SCM_RIGHTS juga dapat memindahkan akses ke open file description antarproses, tetapi alur kontrolnya kooperatif. Sender dan receiver memerlukan UNIX domain socket, dan proses yang memegang descriptor harus mengirimkannya.

pidfd_getfd() mengubah model koordinasi tersebut. Target tidak menjalankan operasi send dan tidak memerlukan koneksi socket ke caller. Caller menunjuk descriptor target yang sudah ada lalu meminta kernel membuat duplikat.

Properti ini cocok untuk supervisor proses, debugger, infrastruktur container, dan tool inspeksi yang sudah memiliki relasi akses sah dengan proses lain. Konsekuensinya, operasi ini tidak sama dengan descriptor passing biasa antara dua peer yang sama-sama berpartisipasi.

Aturan akses ptrace menjadi batas izin

Kernel membatasi pidfd_getfd() dengan pemeriksaan akses PTRACE_MODE_ATTACH_REALCREDS. Kegagalan pemeriksaan tersebut menghasilkan EPERM.

Pemeriksaan ini lebih luas daripada sekadar membandingkan UID. Akses ptrace mempertimbangkan credentials, state dumpable target, capabilities pada user namespace terkait, dan policy Linux Security Module. Sistem yang memakai Yama LSM juga dapat menerapkan pembatasan tambahan melalui ptrace_scope.

Karena itu, memiliki pidfd saja tidak memberi wewenang untuk menyalin descriptor apa pun dari proses yang dirujuk. pidfd mengidentifikasi proses; pemeriksaan akses ptrace menentukan apakah operasi lintas proses tersebut diizinkan.

Pemisahan ini relevan pada desain privilege. Memberikan pidfd ke komponen lain dapat menyediakan process handle tanpa otomatis memberikan semua operasi yang menerima pidfd.

Duplikat bekerja pada objek dasar yang sama

Karena kedua descriptor merujuk ke open file description yang sama, caller dapat memakai duplikat dengan operasi yang didukung objek dasarnya. Untuk socket, misalnya, duplikat merujuk ke objek socket yang sama, bukan membuat endpoint koneksi baru.

Hal ini berbeda secara material dari merekonstruksi state berdasarkan metadata /proc/<pid>/fd. Hasil pidfd_getfd() adalah descriptor nyata yang dapat dipakai dalam system call berbasis descriptor.

Identitas bersama tersebut juga membawa kebutuhan koordinasi. Operasi melalui descriptor hasil duplikasi dapat memengaruhi state yang dilihat proses target. Shared file offset merupakan contoh paling jelas: read oleh caller dapat mengubah offset yang terlihat oleh read berikutnya di target. Operasi socket juga dapat bekerja pada objek socket yang sama.

Supervisor yang hanya bermaksud melakukan inspeksi tetap perlu memperhitungkan semantik setiap operasi. System call ini memberi akses ke objek; ia tidak membuat clone observasional yang read-only.

Lifetime descriptor terpisah setelah duplikasi

Setelah pidfd_getfd() berhasil, menutup descriptor milik proses target tidak membatalkan duplikat milik caller. Setiap descriptor memegang referensinya sendiri terhadap objek kernel bersama. Objek tetap hidup selama masih ada referensi.

Kebalikannya juga berlaku: menutup duplikat milik caller tidak menutup descriptor milik target. Keduanya berada pada tabel descriptor terpisah walaupun mengarah ke open file description yang sama.

Pemisahan lifetime ini merupakan bagian inti kontrak API. pidfd_getfd() menangkap akses ke objek yang sedang terbuka pada satu titik waktu. Setelah duplikasi berhasil, caller memiliki descriptor normal dengan lifetime yang dikelola secara lokal.

Batas API adalah transfer objek, bukan introspeksi proses penuh

pidfd_getfd() tidak mengekspos seluruh tabel descriptor dan bukan channel kontrol generik untuk proses lain. Caller harus sudah mengetahui nomor descriptor target, memiliki pidfd, dan lolos pemeriksaan akses. Setiap pemanggilan yang berhasil hanya menduplikasi satu descriptor terpilih.

Kontrak yang sempit ini mempertahankan semantik file descriptor biasa. Target dan caller memperoleh entry pada tabel descriptor masing-masing, sementara open file description tetap dibagi. Linux dengan demikian menyediakan akses lintas proses ke objek kernel aktif tanpa mengubah objek itu menjadi pathname, representasi serial, atau pesan socket kooperatif.