RAND_bytes ล้มเหลวใน OpenVPN: ข้อผิดพลาดไลบรารีหรือโหนดที่หายไป
ความล้มเหลวของ RAND_bytes อาจหมายถึงแหล่งเอนโทรปีที่ถูกปฏิเสธหรือโหนดที่ถูกซ่อนโดย jail อ่านคิวข้อผิดพลาดและมุมมองของโปรเซสก่อนสร้างอุปกรณ์
RAND_bytes() failed เป็นข้อความเกี่ยวกับ primitive ภายในเครื่องเดียว ไม่ใช่เกี่ยวกับบัญชี คีย์ที่แชร์ไว้ล่วงหน้า หรือพอร์ตระยะไกล ความล้มเหลวสองแบบที่ต่างกันมากสร้างบรรทัดเดียวกันและทิ้งหลักฐานต่างกัน อย่างหนึ่งคือ backend การเข้ารหัสที่ปฏิเสธการปล่อยไบต์ อีกอย่างคือโปรเซสที่ไม่สามารถเข้าถึงแหล่งเอนโทรปีที่โค้ดถูกสร้างมาเพื่อใช้ การแยกสองอย่างนี้อาศัยการอ่านคิวข้อผิดพลาดหนึ่งครั้งและมองมุมมองระบบไฟล์ของโปรเซสที่ถูกกักขังหนึ่งครั้ง และการตรวจสอบนี้ควรเกิดก่อนสร้างสิ่งใดภายใต้ /dev
ค่าที่ส่งคืนแยกความแตกต่างอะไร
สัญญาที่บันทึกไว้แยกผลลัพธ์สามอย่าง ไม่ใช่สองอย่าง: 1 สำหรับความสำเร็จ, -1 เมื่อวิธี RAND ที่โหลดไม่รองรับคำขอ, และ 0 สำหรับความล้มเหลวอื่น ๆ โดยคำอธิบายอยู่ในคิวข้อผิดพลาด เอกสารอ้างอิง RAND_bytes เพิ่มจุดที่มองข้ามได้ง่าย: ตัวสร้างค่าเริ่มต้นรับเมล็ดจากระบบปฏิบัติการบนแพลตฟอร์มที่รองรับ และเมื่อการใส่เมล็ดล้มเหลว มันจะอยู่ในสถานะผิดพลาดแทนที่จะคืนไบต์ที่คาดเดาได้
มีเพียงตัวเลขเดียวที่อธิบายสภาพแวดล้อม -1 เป็นคำถามเรื่องการสร้าง ผู้ให้บริการ หรือฟีเจอร์ เพราะโค้ดขอสิ่งที่ implementation ที่ใช้งานอยู่ไม่เสนอ ส่วน 0 พร้อมข้อร้องเรียนเรื่องการใส่เมล็ดเป็นคำถามสภาพแวดล้อม เพราะตัวสร้างไม่สามารถได้เอนโทรปีเลย ตัวเลขเพียงลำพังไม่เคยบอกว่าอันไหน และชื่อฟังก์ชันก็ไม่บอก
เมื่อโหนดอุปกรณ์ที่ซ่อนอยู่เป็นสาเหตุจริง
บริการที่ถูกจำกัดมองเห็นต้นไม้ต่างจากเชลล์ที่คุณพิมพ์อยู่ chroot jail อิมเมจคอนเทนเนอร์ และไฟล์ unit ที่เสริมความแข็งแรงมักนำเสนอ /dev ที่มีโหนดน้อยกว่าของโฮสต์ หาก implementation ที่ล้มเหลวเปิด /dev/urandom ตามชื่อพาธ ความแตกต่างนั้นก็พอจะทำให้การเริ่มต้นล้มเหลว ขณะที่โฮสต์เองดูสมบูรณ์ดี อุปกรณ์ที่มีอยู่นอก jail ไม่ได้พิสูจน์อะไรเกี่ยวกับสิ่งที่โปรเซสที่ถูกกักขังได้รับอนุญาตให้เปิด
อย่างไรก็ตาม ไม่ใช่ทุกอินเทอร์เฟซสุ่มที่ต้องการพาธ ระบบเรียก getrandom ของลินุกซ์ไม่รับชื่อไฟล์และไม่รับ file descriptor และหน้าคู่มือระบุว่าคุณสมบัตินี้มีประโยชน์ตรงจุดที่ chroot ซ่อนพาธอุปกรณ์
ดังนั้นคำอธิบายเรื่องโหนดที่หายไปจึงเป็นสมมติฐานเกี่ยวกับสาขาหนึ่งของโค้ด ไม่ใช่กฎเกี่ยวกับตัวเลขสุ่มโดยทั่วไป มันคงอยู่เมื่อหลักฐานระบุพาธ และเป็นการเดาเมื่อหลักฐานระบุสิ่งอื่น
อ่านคิวข้อผิดพลาดก่อน แล้วจึงดูมุมมองของโปรเซส
วิธีที่เร็วที่สุดในการชี้ขาดคำถามคืออ่านสิ่งที่ไลบรารีบันทึกไว้แล้ว จากนั้นดูมุมมองภายใน jail โดยตรง เริ่มจาก บิลด์ OpenSSL ที่บริการโหลดจริง เพราะสแตกของผู้ให้บริการต่างกันระหว่างรุ่นหลักและระหว่างดิสทริบิวชัน จากนั้นถาม systemd ว่าโปรเซสใดทำงานอยู่และมีข้อจำกัดใดบังคับใช้ หลังจากข้อเท็จจริงทั้งสองอยู่บนโต๊ะแล้วจึงคุ้มค่าที่จะไล่รายการโหนดที่โปรเซสนั้นมองเห็น
openssl version -a
systemctl show openvpn-server@lab -p MainPID -p PrivateDevices -p DevicePolicy
pid=$(systemctl show -p MainPID --value openvpn-server@lab)
sudo ls -l /proc/"$pid"/root/dev/urandom /proc/"$pid"/root/dev/random
ทำการอ่านเหล่านั้นกับโปรเซสเดียวกัน ไม่ใช่กับเชลล์ที่บังเอิญเปิดอยู่ การเปรียบเทียบ /dev ของโฮสต์กับมุมมองของโปรเซสที่ไม่เกี่ยวข้องคือวิธีที่การพึ่งพาผิดถูกซ่อมสองครั้ง
เพิ่มการพึ่งพาเมื่อคุณตั้งชื่อมันได้เท่านั้น
เมื่อหลักฐานระบุพาธจริง ๆ การซ่อมก็เล็กน้อย: ทำให้พาธเดียวนั้นพร้อมใช้ภายใน jail และปล่อยอย่างอื่นไว้ bind mount ของโหนดเดียวมักเพียงพอ และ mknod พร้อมหมายเลข major และ minor มาตรฐานของโหนดให้ผลเหมือนกันในการติดตั้งที่การ mount ไม่ใช่ตัวเลือก การขยาย sandbox การให้สิทธิ์เข้าถึงอุปกรณ์อักขระทุกตัว หรือการปิด PrivateDevices แลกการแก้ไขแบบเจาะจงกับการถดถอยด้านความปลอดภัยถาวร
เดมอนเอนโทรปีไม่ใช่สิ่งทดแทนการซ่อมนั้น แพ็กเกจอย่าง haveged เปลี่ยนวิธีป้อนพูลของเคอร์เนล พวกมันไม่สามารถสร้างพาธที่โปรเซสที่ถูกกักขังได้รับอนุญาตให้เปิดได้ การติดตั้งหนึ่งตัวอาจทำให้กราฟสุขภาพดูดีขึ้นขณะที่การเรียกเปิดยังล้มเหลว แยกปัญหาสองอย่างนี้ออกจากกัน มิฉะนั้นความล้มเหลวครั้งถัดไปจะถูกโยงไปยังชั้นผิดอีกครั้ง
ตรวจสอบตัวสร้างและอุโมงค์แยกจากกัน
การรีสตาร์ตเป็นการทดสอบเดียวที่ใช้การกำหนดค่าเดิม ไฟล์ unit เดิม และการกักกันเดิมที่ทำให้เกิดความล้มเหลว รันมัน แล้วอ่านรายการบันทึกที่ใหม่ที่สุดแทนตัวอย่างจากการบูตก่อนหน้า
sudo systemctl restart openvpn-server@lab
sudo journalctl -u openvpn-server@lab --since -5min --no-pager | grep -iE 'rand|entropy|Initialization Sequence'
มองหาสองสิ่งที่แยกจากกันในผลลัพธ์นั้น: ข้อความเกี่ยวกับแหล่งสุ่มที่หายไป และอุโมงค์ที่ไปถึงหมุดหมายการเริ่มต้นตามปกติ ตัวสร้างที่ทำงานได้อีกครั้งขจัดความล้มเหลวภายในเครื่องหนึ่งอย่างและไม่พูดอะไรเกี่ยวกับตัวตนของเซิร์ฟเวอร์ ข้อมูลรับรอง หรือการกำหนดเส้นทาง ทดสอบด้วยการกำหนดค่าผู้ใช้เดิมที่ล้มเหลวก่อนหน้านี้ เพื่อให้ผลลัพธ์เปรียบเทียบได้และไม่ใช่แค่ดีขึ้น