chroot ล้มเหลวบน OpenVPN: กฎ AppArmor หรือความสามารถ?
การเพิ่มพาธในโปรไฟล์ AppArmor ไม่เคยให้ CAP_SYS_CHROOT และ chroot ที่ถูกปฏิเสธอาจมาจากสามชั้นที่แยกจากกัน ตัดสินใจว่าจะเปลี่ยนชั้นไหน
เดมอนบันทึกความล้มเหลวของ chroot และโปรไฟล์ดูใจกว้างอยู่แล้ว การแก้ที่ชวนทำจึงเป็นการขยายกฎพาธแล้วรีสตาร์ต ซึ่งมักไม่เปลี่ยนอะไร เพราะ chroot ถูกกำหนดโดยสิทธิพิเศษที่โปรไฟล์ไม่เคยส่งต่อได้ การตัดสินใจว่าจะแตะชั้นไหนต้องใช้การตรวจสามอย่าง และมันถูก: โปรเซสได้รับอนุญาตให้ถืออะไร นโยบายอนุญาตอะไร และตัวเรียกใช้ลบอะไรออกไปก่อนที่ทั้งสองอย่างจะมีความหมาย
สองประตูที่แยกจากกัน และมีเพียงประตูเดียวที่เป็นของ AppArmor
chroot ต้องมี CAP_SYS_CHROOT ในเนมสเปซของผู้ใช้ที่โปรเซสกำลังทำงานอยู่ นั่นคือสิทธิพิเศษปกติของ Linux ซึ่งเคอร์เนลตรวจสอบก่อนที่การเรียกจะทำอะไรกับพาธ แยกจากกันนั้น โปรไฟล์ AppArmor ที่บังคับใช้สามารถปฏิเสธความสามารถได้แม้โปรเซสจะถืออยู่ เพราะนโยบายภาคบังคับถูกพิจารณาเพิ่มจากข้อมูลรับรอง ไม่ใช่แทนที่ข้อมูลเหล่านั้น ความต่างนี้สำคัญในทางปฏิบัติ: ทั้งสองชั้นอยู่ในไฟล์ต่างกันและมักดูแลโดยคนละคน
ประตูทั้งสองล้มเหลวด้วย errno เดียวกัน ทั้งคู่ให้ EPERM และทั้งคู่ปรากฏเป็นข้อร้องเรียนเรื่องสิทธิ์แบบกว้าง ๆ ในบันทึกของเดมอน นั่นคือเหตุผลที่การเดาเนื้อหาโปรไฟล์ทำให้เสียเวลามาก กฎพาธที่คุณกำลังจะเพิ่มควบคุมการเข้าถึงไฟล์หลังจาก chroot สำเร็จเท่านั้น มันไม่มีผลต่อว่าการกระทำนั้นได้รับอนุญาตหรือไม่
ประตูที่สามอยู่เหนือทั้งสอง ชุด ถ้าตัวจัดการบริการหรือตัวห่อเริ่มโปรเซสโดยไม่มีความสามารถนั้นในชุดขอบเขตของมัน การเปลี่ยน AppArmor ใด ๆ ก็เอากลับมาไม่ได้ และการเพิ่มความสามารถในโปรไฟล์เป็นเพียงการบันทึกเจตนาที่เคอร์เนลจะไม่ปฏิบัติตาม
อ่านสถานะสิทธิพิเศษก่อนแก้ไขนโยบาย
เริ่มจากโปรเซสที่กำลังทำงาน ไม่ใช่จากคอนฟิกที่คุณคิดว่าใช้งานอยู่ ไฟล์สถานะแสดงมาสก์ความสามารถห้าตัวและแฟล็ก no-new-privileges และมันตอบคำถามต่างกัน:
grep -E '^(CapInh|CapPrm|CapEff|CapBnd|CapAmb|NoNewPrivs):' /proc/$(pidof openvpn)/status
sudo aa-status | grep -i openvpn
CapEff คือชุดที่สำคัญต่อการเรียก: ความสามารถที่มีใน CapBnd แต่ไม่มีใน CapEff ได้รับอนุญาตจากเพดานและไม่ได้ถูกถืออยู่ในขณะนั้น CapAmb สำคัญเมื่อไบนารีไม่ได้มีสิทธิพิเศษในความหมาย setuid ปกติ เพราะความสามารถแบบแอมเบียนต์คือวิธีที่บริการรักษาสิทธิพิเศษข้าม exec โดยไม่ต้องมีความสามารถระดับไฟล์ CapInh เก็บบิตที่อาจสืบทอดข้าม exec ได้ แต่เฉพาะเมื่อชุดสืบทอดของไฟล์ที่ถูกเรียกอนุญาต บิตที่นั่นจึงไม่ได้ให้อะไรด้วยตัวเอง
จากนั้นยืนยันว่าโปรไฟล์ใดถูกผูกอยู่จริง โปรเซสอาจถูกจำกัดด้วยชื่อโปรไฟล์ที่คุณไม่ได้คาดไว้ โดยเฉพาะเมื่อดิสทริบิวชันจัดส่ง unit และโปรไฟล์ของตัวเองมาด้วยกัน และการอ่าน /proc/PID/attr/current ก็ชี้ชัดในบรรทัดเดียว การเปรียบเทียบไฟล์ที่คุณแก้กับโปรไฟล์ที่เคอร์เนลรายงานคือ ความต่างระหว่างการแก้ที่ต้นเหตุกับการแก้ไฟล์ที่ไม่มีใครโหลด
เพิ่มกฎความสามารถเมื่อร่องรอยการตรวจสอบบอกเช่นนั้นเท่านั้น
บันทึกของเคอร์เนลและการตรวจสอบระบุชื่อชั้นที่ปฏิเสธ มองหาการปฏิเสธที่พา operation capable และชื่อ sys_chroot มาด้วย พร้อมโปรไฟล์ที่สร้างมันขึ้นมา ถ้าบันทึกนั้นมีอยู่ โปรเซสก็ถือความสามารถอยู่แล้วและ AppArmor ปฏิเสธมัน การเปลี่ยนแปลงที่ตรงจุดคือกฎความสามารถภายในโปรไฟล์จริง:
capability sys_chroot,
เก็บมันเป็นชิ้นส่วนในโปรไฟล์ที่ผูกอยู่จริง และตรวจคำสำคัญกับ เอกสารอ้างอิงโปรไฟล์ apparmor.d แทนการคัดลอกกฎจากบทแนะนำที่ไม่เกี่ยวข้อง การใส่มันใน include ที่ใช้ร่วมกันจะให้สิทธิ์นั้นกับทุกโปรแกรมที่ถูกจำกัดซึ่งโหลดไฟล์นั้น และการสลับโปรไฟล์ไปโหมด complain จะซ่อนการปฏิเสธครั้งถัดไปแทนที่จะแก้ครั้งนี้ กฎในโปรไฟล์ลบการปฏิเสธเชิงนโยบาย มันไม่ได้สร้างสิทธิพิเศษ โปรเซสที่ไม่เคยมี CAP_SYS_CHROOT ในชุดที่มีผลจึงยังล้มเหลวแม้มีกฎอยู่
ถ้าบันทึกการตรวจสอบไม่แสดงการปฏิเสธของ AppArmor เลย ให้หยุดแก้โปรไฟล์ คุณกำลังเผชิญปัญหาข้อมูลรับรอง และงานที่เหลืออยู่ใน unit หรือในโปรเซสแม่ ไม่ใช่ในภาษานโยบาย
ตัวจัดการบริการมีเพดานของตัวเอง
systemd กำหนดชุดขอบเขตความสามารถให้แต่ละบริการ และโดยค่าเริ่มต้นชุดนั้นแคบ สิ่งใดที่ถูกกีดกันไว้จะใช้ไม่ได้กับโปรเซสไม่ว่าโปรไฟล์จะว่าอย่างไร นั่นคือเหตุผลที่ unit ที่เสริมความแข็งแรงอาจล้มเหลวในการกระทำที่เคยทำงานเมื่อเริ่มเดมอนด้วยมือ คำสั่งที่เกี่ยวข้องอ่านง่ายใน unit และมองข้ามได้ง่ายเมื่อแอปพลิเคชันเองรายงานความผิดพลาด drop-in ที่แพ็กเกจดิสทริบิวชันจัดส่งมาเป็นแหล่งปกติของเพดานที่ไม่มีใครจำได้ว่าตั้งไว้
การยกเพดานกับการให้ความสามารถเป็นการเปลี่ยนแปลงสองอย่าง ไม่ใช่หนึ่งอย่าง รายการในชุดขอบเขตบอกว่าโปรเซสอาจถือความสามารถได้ มันไม่ได้เพิ่มเข้าไปในชุดที่มีผล และ NoNewPrivs อาจขัดขวางไม่ให้การยกระดับในภายหลังสำเร็จ แม้ทุกอย่างอื่นจะสอดคล้องกัน เพิ่มเฉพาะสิ่งที่การกระทำต้องการ รักษาการเสริมความแข็งแรงที่เหลือไว้ และอย่าหลงทางลัดของการให้ความสามารถทั้งหมดเพื่อให้การเรียกครั้งเดียวผ่าน
ลำดับก็สำคัญที่นี่ เปลี่ยนเพดานของ unit ก่อน ตรวจว่า CapEff มีบิตนั้นแล้ว และจากนั้นจึงตัดสินว่า AppArmor ยังปฏิเสธอยู่หรือไม่ การทำทั้งสองอย่างพร้อมกันจะทำให้คุณต้องเดาอีกครั้งหากความล้มเหลวยังคงอยู่
เมื่อการปฏิเสธหายไป ให้ตรวจตัวคุกเอง
chroot ที่สำเร็จจะย้ายรูท ดังนั้นทุกพาธที่เดมอนแตะหลังจากนั้นจะถูกแก้ภายในทรีใหม่ คอนฟิกที่หายไป โหนดอุปกรณ์ที่ไม่มี หรือไดเรกทอรีใบรับรองที่ไม่ได้คัดลอกเข้ามาจะปรากฏเป็นข้อผิดพลาดไฟล์ และข้อผิดพลาดนั้นเป็นปัญหาการจัดวาง ไม่ใช่ปัญหาความสามารถ อ่านเหตุการณ์ถัดไปแทนการเพิ่มสิทธิ์กว้างอีกอัน การย้ายยังเปลี่ยนความหมายของพาธสัมพัทธ์ ซึ่งเป็นเหตุผลที่คู่มือเสริมความแข็งแรงยืนยันให้ใช้พาธสัมบูรณ์ในคอนฟิกของเดมอน
ยังช่วยให้จำสิ่งที่ chroot ไม่ได้ทำด้วย มันเป็นขอบเขตของพาธ ไม่ใช่แซนด์บ็อกซ์: โปรเซสที่รักษาสิทธิพิเศษไว้สามารถหลบหนีออกไปได้ นั่นคือเหตุผลที่มักปลดความสามารถหลังการเรียก และเหตุผลที่การจำกัดควรอยู่รอบเดมอนต่อไป การเก็บโปรไฟล์ AppArmor ชุดขอบเขตความสามารถ และข้อจำกัดของระบบไฟล์ไว้ด้วยกันคือจุดประสงค์ของแบบฝึกหัดนี้ ไม่ใช่เศษที่ต้องถอดออกเมื่อบริการเริ่มทำงาน
กฎการตัดสินใจสั้น ถ้าบันทึกการตรวจสอบระบุชื่อ AppArmor ให้เพิ่มกฎความสามารถหนึ่งข้อในโปรไฟล์ที่ผูกอยู่ ถ้าชุดที่มีผลว่างเปล่า ให้แก้เพดานของ unit และลำดับการปลดสิทธิพิเศษ ถ้าโปรไฟล์ไม่ใช่ไฟล์ที่คุณแก้ ให้หยุดแก้แล้วหาไฟล์จริง