Prompt dan konteks
Dua proses tempatan menyelaras melalui soket domain Unix: proses berkeistimewaan membuka fail atau mencipta soket pendengaran dan menyerahkannya kepada pekerja yang kurang berkeistimewaan. Terangkan cara menghantar deskriptor, perkara yang diterima oleh penerima, dan cara mengendalikan risiko pemotongan (truncation) dan kebenaran.
Ini menguji IPC Linux/Unix, perbezaan antara jadual deskriptor fail dan open file description, serta protokol data sampingan (ancillary data) sendmsg/recvmsg. Linux unix(7) mentakrifkan SCM_RIGHTS untuk menghantar atau menerima set deskriptor fail terbuka antara proses.
Perkara yang diuji oleh penemu duga
- Membezakan integer fd setempat proses daripada open file description milik kernel.
- Mengetahui bahawa
SCM_RIGHTSmenggunakan data sampingan dan bukannya meletakkan integer dalam muatan biasa. - Menentukan saiz
cmsghdr,CMSG_SPACE, danCMSG_LENdengan betul, serta menyemakMSG_CTRUNC. - Merangkumi kebenaran laluan soket, identiti penghantar, had sumber, masa penutupan (close timing), dan pembersihan kegagalan.
Soalan untuk dijelaskan terlebih dahulu
- Adakah proses-proses tersebut berkongsi pengguna, dan di manakah penurunan keistimewaan atau sempadan kepercayaan?
- Adakah deskriptor itu fail biasa, soket bersambung, soket pendengaran, epoll fd, atau peranti fd?
- Adakah saluran itu
SOCK_STREAMatauSOCK_DGRAM, dan adakah protokol memerlukan sempadan mesej serta perakuan (acknowledgements)? - Bolehkah penerima mengesahkan kelayakan penghantar, jenis sumber, sifat baca sahaja, dan bilangan fd yang dijangkakan?
Jawapan 30 saat
Saya akan mencipta pasangan soket domain Unix, membawa deskriptor dalam mesej kawalan SOL_SOCKET/SCM_RIGHTS daripada sendmsg, dan meletakkan versi protokol serta ID permintaan dalam muatan sebenar. Penerima akan memanggil recvmsg dengan penimbal CMSG_SPACE yang mencukupi besar, menyemak tahap, jenis, panjang, dan MSG_CTRUNC, kemudian menggunakan fd yang diterima sebagai integer baharu dalam prosesnya sendiri. Perkara yang merentasi sempadan ialah rujukan kepada open file description, jadi penerima biasanya mendapat nombor fd yang berbeza. Protokol akan mengesahkan kelayakan rakan setara (peer), mengehadkan kiraan, menetapkan close-on-exec, dan menutup deskriptor yang tidak diterima atau tidak digunakan pada setiap laluan ralat.
Perbincangan terperinci langkah demi langkah
Membezakan nombor fd daripada open file description
Fd ialah indeks integer dalam jadual fd sesuatu proses. Open file description ialah objek kernel yang memegang keadaan terbuka seperti ofset fail dan bendera status. SCM_RIGHTS menyalin rujukan kepada objek kernel tersebut; penerima biasanya mendapat integer fd yang berbeza, secara semantik serupa dengan menduplikasi fd ke dalam jadual fd proses lain.
Menggunakan data sampingan dan bukannya bait biasa
sendmsg dan recvmsg membawa rantaian rekod cmsghdr melalui msghdr.msg_control. Tetapkan cmsg_level kepada SOL_SOCKET, cmsg_type kepada SCM_RIGHTS, dan letakkan tatasusunan fd integer dalam kawasan data. Muatan biasa boleh membawa versi, tujuan, dan ID perakuan, tetapi tidak boleh menggantikan mesej kawalan.
Menentukan saiz penimbal kawalan dengan betul
Untuk kiraan sebenar, penghantar menggunakan CMSG_LEN(n * sizeof(int)) untuk cmsg_len; penerima memperuntukkan ruang sejajar sekurang-kurangnya CMSG_SPACE(n * sizeof(int)). Huraikan dengan CMSG_FIRSTHDR dan CMSG_NXTHDR, menolak panjang yang pendek dan jenis yang tidak dijangka.
Mengendalikan pemotongan dan sempadan penstriman (stream boundaries)
Jika penimbal kawalan terima terlalu kecil, data sampingan boleh dipotong atau dibuang dan MSG_CTRUNC ditetapkan; penerima tidak boleh menggunakan senarai deskriptor separa. Linux memerlukan sekurang-kurangnya satu bait sebenar dengan data sampingan pada SOCK_STREAM, dan data sampingan membentuk halangan terima (receive barrier), jadi ikatkan mesej kawalan kepada ID permintaan dan bukannya bergantung pada kedudukan strim bait.
Mewujudkan sempadan identiti dan kebenaran
Kebenaran direktori dan soket ialah sempadan pertama untuk soket sistem fail. Pelayan juga harus menggunakan SO_PEERCRED atau SCM_CREDENTIALS dan mengesahkan penyewa, tujuan, dan jenis sumber pada lapisan aplikasi. Menerima fd tidak memberikan autoriti tambahan dengan sendirinya; penghantar hanya boleh memindahkan rujukan yang dibenarkan.
Menguruskan jangka hayat dan had sumber
Penghantar boleh menutup fd miliknya sendiri selepas menghantar, tetapi kernel mengekalkan rujukan dalam penerbangan (in-flight) sehingga penerima menerimanya. Linux mengehadkan operasi dengan RLIMIT_NOFILE dan SCM_MAX_FD; halaman manual semasa merekodkan SCM_MAX_FD biasanya 253, manakala versi lebih lama menggunakan 255. Hadkan deskriptor bagi setiap mesej dan setiap pekerja, serta jadikan penolakan boleh diperhatikan (observable).
struct msghdr msg = {0};
struct iovec iov = {.iov_base = "F", .iov_len = 1};
union { char buf[CMSG_SPACE(sizeof(int))]; struct cmsghdr align; } control;
msg.msg_iov = &iov; msg.msg_iovlen = 1;
msg.msg_control = control.buf; msg.msg_controllen = sizeof(control.buf);
struct cmsghdr *c = CMSG_FIRSTHDR(&msg);
c->cmsg_level = SOL_SOCKET; c->cmsg_type = SCM_RIGHTS;
c->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(c), &fd, sizeof(fd));
sendmsg(sock, &msg, MSG_NOSIGNAL);Contoh jawapan yang mantap
Saya akan menjadikan ini protokol IPC tempatan dengan perakuan. Penghantar menggunakan sendmsg pada soket domain Unix dengan mesej kawalan SOL_SOCKET/SCM_RIGHTS; muatan sebenar membawa versi protokol, tujuan, dan ID permintaan. Penerima memperuntukkan ruang kawalan dengan CMSG_SPACE, menyemak jenis, panjang, dan MSG_CTRUNC, mengesahkan kelayakan rakan setara, bilangan deskriptor, dan jenis sumber, dan hanya selepas itu menyerahkannya kepada pekerja. Perkara semantik yang penting ialah pemindahan tersebut merujuk kepada open file description, jadi integer penerima biasanya berbeza dan ofset fail atau status terbuka mungkin dikongsi. Saya akan menetapkan close-on-exec, mengehadkan deskriptor dalam penerbangan, mengendalikan RLIMIT_NOFILE dan SCM_MAX_FD, serta menutup dan mengaudit setiap laluan kegagalan.
Kesilapan lazim
- Menulis integer fd ke dalam JSON atau muatan bait dan menganggap proses lain boleh menggunakannya secara terus.
- Mengabaikan penjajaran
CMSG_SPACEdan hanya memperuntukkansizeof(int)untuk data kawalan. - Melangkau pemeriksaan
MSG_CTRUNCdan menggunakan senarai deskriptor yang telah dipotong. - Hanya menyemak laluan soket Unix tanpa mengesahkan kelayakan rakan setara dan tujuan.
- Terlupa bahawa penerima mendapat nombor fd baharu atau gagal menyatakan semantik ofset dan status yang dikongsi.
- Mengabaikan close-on-exec, had fd, kegagalan penghantaran, dan penutupan deskriptor yang tidak digunakan.
Soalan susulan dan jawapan
Adakah penerima mendapat deskriptor fail yang sama?
Biasanya bukan integer yang sama. Kernel menyalin rujukan kepada open file description yang sama ke dalam jadual fd penerima, jadi ofset fail dan beberapa keadaan terbuka mungkin dikongsi. Jika ofset bebas diperlukan, buka semula atau salin data dan bukannya menganggap nombor fd adalah sama.
Mengapa perlu menghantar satu bait sebenar?
Soket strim Unix Linux memerlukan sekurang-kurangnya satu bait sebenar dalam sendmsg yang sama apabila data sampingan dihantar; ia juga membolehkan protokol mengaitkan mesej kawalan dengan permintaan. Datagram Linux boleh meninggalkannya, tetapi kod mudah alih (portable) tetap perlu menyertakan satu bait sebenar.
Bagaimana jika penimbal kawalan terlalu kecil?
Data sampingan boleh dipotong atau dibuang dan MSG_CTRUNC ditetapkan. Tutup deskriptor yang tidak sah atau berlebihan, kembalikan ralat protokol, dan rekodkan peristiwa tersebut; jangan sekali-kali menganggap senarai separa sebagai kebenaran lengkap.
Bagaimanakah anda menghalang proses berkeistimewaan daripada menyerahkan sumber yang salah?
Gunakan kebenaran soket dan kelayakan rakan setara untuk menyekat sambungan, kemudian ikatkan ID permintaan, penyewa, tujuan, dan jenis sumber pada lapisan aplikasi. Penghantar hanya memilih daripada senarai dibenarkan (allowlist); penerima menyemak sifat baca sahaja, keadaan laluan atau soket, dan mengaudit setiap kebenaran dan penutupan.