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 openvpnCapEff არის ის სიმრავლე, რომელიც გამოძახებისთვის მნიშვნელოვანია: შესაძლებლობა, რომელიც CapBnd-შია და CapEff-ში არა, ზედა ზღვრით ნებადართულია და ახლა არ არის დაკავებული. CapAmb მნიშვნელოვანია, როცა ბინარული ჩვეულებრივი setuid გაგებით პრივილეგირებული არაა, რადგან გარემოს შესაძლებლობები ის გზაა, რომლითაც სერვისი ინარჩუნებს პრივილეგიას exec-ის გასწვრივ ფაილის შესაძლებლობების გარეშე. CapInh შეიცავს ბიტებს, რომლებიც exec-ის გასწვრივ მემკვიდრეობით გადაეცემა, მაგრამ მხოლოდ მაშინ, როცა შესრულებული ფაილის მემკვიდრეობითი სიმრავლე იძლევა ამის საშუალებას, ამიტომ იქ არსებული ერთი ბიტი თავისთავად არაფერს იძლევა.
შემდეგ დაადასტურე, რომელი პროფილია ნამდვილად მიმაგრებული. პროცესი შეიძლება შეზღუდული იყოს იმ პროფილის სახელით, რომელსაც არ ელოდე, განსაკუთრებით მაშინ, როცა დისტრიბუტივი თავის ერთეულის ფაილსა და პროფილს ერთად ავრცელებს, და /proc/PID/attr/current-ის წაკითხვა ამას ერთ ხაზში წყვეტს. შენი რედაქტირებული ფაილის შედარება ბირთვის მიერ მოხსენებულ პროფილთან არის სხვაობა მიზეზის გასწორებასა და იმ ფაილის რედაქტირებას შორის, რომელსაც არავინ ტვირთავს.
დაამატე შესაძლებლობის წესი მხოლოდ მაშინ, როცა აუდიტის კვალი ამას ამბობს
ბირთვისა და აუდიტის ჩანაწერები ასახელებენ უარმყოფელ ფენას. მოძებნე უარყოფა, რომელსაც აქვს ოპერაცია capable და სახელი sys_chroot, მისი წარმომქმნელი პროფილით. თუ ეს ჩანაწერი არსებობს, პროცესს შესაძლებლობა უკვე ჰქონდა და AppArmor-მა უარყო, და მიზანმიმართული ცვლილება რეალურ პროფილში შესაძლებლობის წესია:
capability sys_chroot,შეინახე ის ფრაგმენტად იმ პროფილში, რომელიც ნამდვილად მიმაგრებულია, და გადაამოწმე საკვანძო სიტყვა apparmor.d-ის პროფილების ცნობართან და არა უკავშირო გაკვეთილიდან წესის კოპირებით. საერთო include-ში ჩადება მას ყველა შეზღუდულ პროგრამას აძლევს, რომელიც ამ ფაილს იძახებს, და პროფილის complain რეჟიმში გადაყვანა შემდეგ უარყოფას მალავს, ამის გადაწყვეტის ნაცვლად. პროფილის წესი პოლიტიკის უარყოფას აშორებს; ის პრივილეგიას არ ქმნის, ამიტომ პროცესი, რომელსაც ეფექტურ სიმრავლეში CAP_SYS_CHROOT არასოდეს ჰქონია, წესის არსებობისას მაინც ჩავარდება.
თუ აუდიტის ჩანაწერი AppArmor-ის უარყოფას საერთოდ არ აჩვენებს, შეწყვიტე პროფილის რედაქტირება. კრედენციალების პრობლემას უყურებ, და დარჩენილი სამუშაო ერთეულის ფაილში ან მშობელ პროცესშია, და არა პოლიტიკის ენაში.
სერვისის მენეჯერი თავის ზედა ზღვარს ინარჩუნებს
systemd თითოეული სერვისისთვის ადგენს შესაძლებლობების შემზღუდავ სიმრავლეს, და ნაგულისხმევად ეს სიმრავლე ვიწროა. იქ გამორიცხული ყველაფერი პროცესისთვის მიუწვდომელია, რაც არ უნდა თქვას პროფილმა, ამიტომ გამაგრებულ ერთეულებს შეუძლიათ ჩავარდნენ ოპერაციაში, რომელიც მუშაობდა, როცა დემონი ხელით იყო გაშვებული. შესაბამისი დირექტივები ერთეულში ადვილად იკითხება და ადვილად გამორჩება, როცა აპლიკაცია წარუმატებლობას იუწყება. გავრცელების პაკეტის მიერ მოწოდებული drop-in-ები ჩვეულებრივი წყაროა იმ ზედა ზღვრისა, რომლის კონფიგურაცია არავის ახსოვს.
ზედა ზღვრის აწევა და შესაძლებლობის მიცემა ორი ცვლილებაა, არა ერთი. შემზღუდავ სიმრავლეში ჩანაწერი ამბობს, რომ პროცესს შესაძლებლობის შენარჩუნება შეუძლია; ის მას ეფექტურ სიმრავლეს არ უმატებს, და NoNewPrivs-ს შეუძლია შემდგომი აწევის წარმატება შეაჩეროს მაშინაც, როცა ყველაფერი სხვა ერგება. დაამატე მხოლოდ ის, რაც ოპერაციას სჭირდება, შეინარჩუნე დანარჩენი გამაგრება და წინ აღუდექი იმ მოკლე გზას, რომ ერთი გამოძახების გასატარებლად ყველა შესაძლებლობა მისცე.
რიგითობას აქაც აქვს მნიშვნელობა. ჯერ შეცვალე ერთეულის ზედა ზღვარი, დაადასტურე, რომ CapEff ახლა შეიცავს ბიტს, და მხოლოდ ამის შემდეგ გადაწყვიტე, უარყოფს თუ არა AppArmor ჯერ კიდევ. ორივე ცვლილების ერთდროულად გაკეთება ისევ გამოცნობაში გტოვებს, თუ ჩავარდნა გრძელდება.
უარყოფის გაქრობის შემდეგ, შეამოწმე თავად ციხე
წარმატებული chroot ძირს გადაადგილებს, ამიტომ ყველა ბილიკი, რომელსაც დემონი შემდეგ ეხება, ახალ ხეში იხსნება. დაკარგული კონფიგურაცია, არმყოფი მოწყობილობის კვანძი ან ასლგადაუღებელი სერთიფიკატის დირექტორია ახლა ფაილის შეცდომად გამოჩნდება, და ეს შეცდომა განლაგების პრობლემაა და არა შესაძლებლობის. წაიკითხე შემდეგი მოვლენა კიდევ ერთი ფართო ნებართვის დამატების ნაცვლად. გადაადგილება ცვლის იმასაც, რას ნიშნავს ფარდობითი ბილიკი, ამიტომ გამაგრების სახელმძღვანელოები დემონის კონფიგურაციაში აბსოლუტურ ბილიკებს ითხოვენ.
ასევე გვახსოვდეს, რას არ აკეთებს chroot. ეს ბილიკის საზღვარია და არა sandbox: პროცესს, რომელიც პრივილეგიას ინარჩუნებს, შეუძლია გაქცევა, ამიტომ შესაძლებლობა ჩვეულებრივ გამოძახების შემდეგ იყრება და ამიტომ შეზღუდვა დემონის გარშემო უნდა დარჩეს. AppArmor-ის პროფილის, შესაძლებლობების შემზღუდავი სიმრავლისა და ფაილური სისტემის შეზღუდვების ერთად შენარჩუნება ამ სავარჯიშოს მიზანია, და არა ნარჩენი, რომელიც სერვისის ამოქმედებისას უნდა მოიშორო.
გადაწყვეტილების წესი მოკლეა. თუ აუდიტის ჩანაწერი AppArmor-ს ასახელებს, დაამატე ერთი შესაძლებლობის წესი მიმაგრებულ პროფილს. თუ ეფექტური სიმრავლე ცარიელია, გაასწორე ერთეულის ზედა ზღვარი და პრივილეგიის ჩამოშვების რიგი. თუ პროფილი ის არ არის, რომელიც შეცვალე, შეწყვიტე რედაქტირება და იპოვე ნამდვილი.