File hasil memfd_create() dapat bermula sebagai state bersama yang writable lalu berubah menjadi semakin terbatas. File seal membuat transisi itu monotonik: seal yang berhasil dipasang menjadi properti inode, berlaku pada setiap descriptor yang merujuk inode tersebut, dan tidak dapat dihapus.
Sifat ini berguna ketika satu proses menyiapkan byte lalu mengirim descriptor ke proses lain. Penerima dapat memeriksa pembatasan yang ditegakkan kernel, bukan hanya bergantung pada janji protokol bahwa produsen sudah berhenti mengubah objek.
Sealing harus diaktifkan saat pembuatan
memfd_create() membuat file anonim dan mengembalikan file descriptor O_RDWR. Dukungan sealing diaktifkan secara eksplisit dengan MFD_ALLOW_SEALING.
int fd = memfd_create("payload", MFD_CLOEXEC | MFD_ALLOW_SEALING);
if (fd == -1)
handle_error();Dengan MFD_ALLOW_SEALING, set seal awal kosong. Tanpa flag itu, file dimulai dengan F_SEAL_SEAL, sehingga penambahan seal berikutnya tidak diizinkan.
Nama yang diberikan ke memfd_create() bersifat diagnostik, bukan pathname filesystem. Objeknya tetap berperilaku seperti file: ukurannya dapat ditetapkan, datanya dapat dibaca, ditulis, dipetakan, diwariskan melalui fork(), atau dikirim sebagai file descriptor.
Setiap seal membatasi dimensi mutasi yang berbeda
F_ADD_SEALS menambahkan bit mask pembatasan melalui fcntl(). Seal utama tidak melarang operasi yang sama.
F_SEAL_SHRINK mencegah pengurangan ukuran file. F_SEAL_GROW mencegah penambahan ukuran. F_SEAL_WRITE mencegah modifikasi konten melalui operasi seperti write() dan juga mencegah pembuatan shared writable mapping baru. Perubahan ukuran tetap merupakan dimensi terpisah, sehingga payload immutable dengan ukuran tetap biasanya menggabungkan seal write, grow, dan shrink.
int seals = F_SEAL_WRITE | F_SEAL_GROW | F_SEAL_SHRINK;
if (fcntl(fd, F_ADD_SEALS, seals) == -1)
handle_error();Setelah seal berhasil dipasang, operasi yang dilarang oleh seal tersebut gagal dengan EPERM. Descriptor yang sudah ada tidak dapat melewati pembatasan karena seal melekat pada inode, bukan pada satu descriptor.
Writable mapping menentukan titik transisi
F_SEAL_WRITE tidak dapat ditambahkan selama masih ada writable shared mapping untuk file tersebut. Dalam kondisi itu, F_ADD_SEALS gagal dengan EBUSY.
Produsen yang mengisi memfd melalui MAP_SHARED | PROT_WRITE memiliki batas transisi yang konkret: selesaikan mutasi, lepaskan writable shared mapping, lalu pasang F_SEAL_WRITE.
F_SEAL_FUTURE_WRITE memiliki batas berbeda. Seal ini memblokir pemanggilan write() berikutnya dan writable mapping baru, tetapi shared writable mapping yang dibuat sebelum seal tetap dapat memodifikasi file. Perbedaan ini cocok untuk desain handoff ketika mapping milik produsen tetap aktif sementara peer yang baru menerima descriptor tidak dapat memperoleh akses tulis setara.
F_SEAL_SEAL menutup kebijakan seal
Set seal juga dapat dikunci. Setelah F_SEAL_SEAL terpasang, pemanggilan F_ADD_SEALS berikutnya gagal dengan EPERM.
if (fcntl(fd, F_ADD_SEALS,
F_SEAL_WRITE | F_SEAL_GROW |
F_SEAL_SHRINK | F_SEAL_SEAL) == -1)
handle_error();Mekanisme ini membentuk dua lapisan monotonik. Seal individual mengurangi mutasi file yang diizinkan, sedangkan F_SEAL_SEAL mencegah perubahan lanjutan pada set pembatasan tersebut. Flag ini tidak menghapus pembatasan yang sudah ada atau membuat objek lebih permisif.
Penerima dapat membaca mask saat ini dengan F_GET_SEALS dan menolak descriptor bila pembatasannya lebih lemah daripada kebutuhan protokol.
int seals = fcntl(fd, F_GET_SEALS);
if (seals == -1)
handle_error();
int required = F_SEAL_WRITE | F_SEAL_GROW | F_SEAL_SHRINK;
if ((seals & required) != required)
reject_payload();Transfer descriptor mempertahankan objek sealed yang sama
Pengiriman memfd melalui UNIX domain socket dengan SCM_RIGHTS memberi proses penerima descriptor untuk file dasar yang sama. Karena itu, set seal ikut melintasi batas proses sebagai state inode.
Perilaku ini berbeda dari menyalin byte ke buffer lokal baru. Penyalinan membuat storage terpisah dengan integritas yang bergantung pada titik penyalinan. memfd yang sudah diberi seal mempertahankan satu objek bersama sambil membatasi mutasi lanjutan yang akan diterima kernel.
Seal juga tidak menyediakan autentisitas, kerahasiaan, atau otorisasi untuk transfer descriptor. Seal membatasi operasi pada file setelah pembatasan terkait terpasang. Protokol tetap memerlukan aturan sendiri untuk memilih peer, memvalidasi konten, dan menentukan mask seal yang memadai.
Jaminannya lebih sempit daripada immutability umum
File sealing adalah mekanisme khusus Linux dengan semantik pada tingkat operasi. F_SEAL_WRITE saja tidak membekukan ukuran file. F_SEAL_GROW saja tidak mencegah penulisan di dalam extent yang sudah ada. F_SEAL_FUTURE_WRITE memang mempertahankan mutasi melalui writable shared mapping yang dibuat sebelumnya.
Invariant yang berguna berasal dari kombinasi seal yang tepat dan titik saat seal dipasang. Setelah pembatasan itu ada, kernel menegakkan transisi satu arah dari memfd yang lebih mudah dimutasi menuju objek bersama yang lebih terbatas.