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, но само когато наследяемият набор на изпълнявания файл го позволява, затова бит там сам по себе си не дава нищо.
След това потвърдете кой профил е действително прикачен. Един процес може да е ограничен от име на профил, което не сте очаквали, особено когато дистрибуция доставя своя unit файл и профил заедно, и четенето на /proc/PID/attr/current решава това с един ред. Сравняването на вашия редактиран файл с профила, който ядрото отчита, е разликата между поправяне на причината и редактиране на файл, който никой не зарежда.
Добавяйте правилото за способност само когато одитната следа го казва
Записите на ядрото и одита назовават слоя, който отказва. Търсете отказ, който носи операцията capable и името sys_chroot, заедно с профила, който го е породил. Ако такъв запис съществува, процесът вече е държал способността и AppArmor я е отказал, а насочената промяна е правило за способност вътре в истинския профил:
capability sys_chroot,Дръжте го като фрагмент в профила, който е наистина прикачен, и сверявайте ключовата дума с справката за профили apparmor.d, вместо да копирате правило от несвързан урок. Ако го сложите в споделен включен файл, то го дава на всяка ограничена програма, която дърпа този файл, а превключването на профилите в режим на оплакване скрива следващия отказ, вместо да реши този. Правилото в профила премахва отказ на политиката; то не създава привилегия, затова процес, който никога не е имал CAP_SYS_CHROOT в ефективния си набор, пак ще се провали с това правило.
Ако одитният запис изобщо не показва отказ на AppArmor, спрете да редактирате профила. Имате проблем с идентификационните данни и останалата работа е в unit файла или в родителския процес, а не в езика на политиката.
Мениджърът на услуги държи собствен таван
systemd задава набор от граници на способностите за всяка услуга и по подразбиране този набор е тесен. Всичко изключено там е недостъпно за процеса, каквото и да казва профилът, затова укрепените unit файлове могат да се провалят на операция, която е работела, когато демонът е бил стартиран на ръка. Съответните директиви се четат лесно в unit файла и лесно се пропускат, когато приложението отчете грешката. Drop-in файловете, доставени от пакет на дистрибуция, са обичайният източник на таван, който никой не помни, че е настройвал.
Вдигането на тавана и даването на способността са две промени, не една. Записът в набора от граници казва, че процесът може да държи способността; той не я добавя към ефективния набор, а NoNewPrivs може да попречи на по-късно повишаване да успее, дори когато всичко останало съвпада. Добавяйте само нужното за операцията, запазете останалото укрепване и устоявайте на изкушението да дадете всички способности, за да мине едно извикване.
Редът тук също има значение. Променете първо тавана на unit файла, проверете че CapEff вече съдържа бита, и само след това решете дали AppArmor още отказва. Ако направите двете промени наведнъж, при траен неуспех отново ще гадаете.
След като отказът отпадне, проверете самия затвор
Успешният chroot премества корена, затова всеки път, който демонът докосне след това, се разрешава вътре в новото дърво. Липсваща конфигурация, отсъстващ възел на устройство или директория за сертификати, която не е копирана, сега ще се появи като файлова грешка и тази грешка е проблем на подредбата, а не на способността. Четете следващото събитие, вместо да добавяте още едно широко разрешение. Преместването променя и какво означава относителен път, затова ръководствата за укрепване настояват на абсолютни пътища в конфигурацията на демона.
Полезно е да помните и какво chroot не прави. Това е граница на пътища, не пясъчник: процес, който запази привилегията, може да избяга от нея, затова способността обикновено се сваля след извикването и затова ограничаването трябва да остане около демона. Запазването на профила на AppArmor, набора от граници на способностите и файловите ограничения заедно е смисълът на упражнението, а не остатък, който да се махне, щом услугата стартира.
Правилото за решение е кратко. Ако одитният запис назовава AppArmor, добавете едно правило за способност към прикачения профил. Ако ефективният набор е празен, поправете тавана на unit файла и реда на сваляне на привилегиите. Ако профилът не е този, който редактирахте, спрете да редактирате и намерете истинския.