Хукі, якія працуюць без памылак і ўсё ж паведамляюць пра адсутны файл, звычайна глядзяць не ў тым месцы, а не правальваюць сваю задачу. Адносныя шляхі ў скрыпце вылічваюцца адносна працоўнага каталога працэсу, а служба запускаецца з працоўным каталогам, які вы не выбіралі. Файл побач са скрыптам і файл, які адкрывае працэс, гэта адно і тое ж толькі тады, калі нешта іх замацоўвае. Гэтая розніца тлумачыць значную долю збояў хукоў, якія памылкова чытаюць як праблемы з правамі.

Праверце шлях раней за правы, бо памылка правоў на няправільным файле ўсё яшчэ няправільны файл.

Адносны шлях вылічваецца адносна працэсу, а не файла

Калі скрыпт выклікае open("policy.json"), ядро вылічвае імя адносна бягучага працоўнага каталога працэсу. Нішто ў размяшчэнні самога скрыпта ў гэтым пошуку не ўдзельнічае. OpenVPN запускае хукі з каталога, які выбірае сам, і параметр cd можа яго змяніць, таму скрыпт, правераны ўручную са сваёй папкі, паводзіць сябе інакш, калі яго запускае дэман. Ручны тэст праходзіць, запуск службы не ўдаецца, а радок журнала называе толькі адсутнае імя.

Python паказвае размяшчэнне скрыпта як __file__, і менавіта гэта робіць замацаванне магчымым. Path(__file__).resolve().parent / "policy.json" будуе шлях ад файла, а не ад працэсу. Гэты адзін радок прыбірае залежнасць ад працоўнага каталога, нічога не змяняючы ў прывілеях.

Замацуйце шлях свядома, потым праверце, што робіць resolve

resolve() ідзе па сімвалічных спасылках, таму ўсталяванне, якое звязвае хук на месцы, замацоўваецца на мэце спасылкі, а не на каталогу са спасылкай. Звычайна гэта тое, што патрэбна для версіянаванага разгортвання, і гэта няправільна для схемы, якая чакае даныя побач са спасылкай. Вызначце, што мае на ўвазе разгортванне, і напішыце код адпаведна, а не выяўляйце розніцу ў прадукцыі. Path(__file__).parent без resolve() захоўвае ўласны каталог спасылкі.

Калі даныя належаць экзэмпляру, а не праграме, вазьміце абсалютны шлях з канфігурацыі. Жорсткае кадаванне месца прывязвае хук да адной схемы хоста.

Прайдзіце чатыры межы па парадку

Пачніце з працоўнага каталога: параўнайце WorkingDirectory, параметр cd у OpenVPN і любую абгортку, якая змяняе каталог перад exec. Потым пацвердзіце вылічанае размяшчэнне, бо файл з падобным імем у іншым разгортванні можа адказаць на пошук і схаваць памылку. Далей ідзе бачанне файлавай сістэмы: chroot або прастора мантавання службы могуць проста зрабіць абсалютны шлях хоста адсутным. Апошняе — ідэнтычнасць доступу, гэта асобнае пытанне ад бачнасці.

ProtectHome і PrivateTmp хаваюць розныя месцы, і ніводнае не паказваецца ў лісцінгу каталога, знятым з хоста. Шлях, які існуе для root у абалонцы, можа быць нябачным унутры прасторы імёнаў юніта, і менавіта таму праверка той жа каманды па-за службай так мала даказвае.

Выпраўце пошук, не пашыраючы службу

Замацаванне шляху вырашае толькі першую мяжу. Яно не адкрывае каталог, які хавае служба, і не дае непрывілеяванаму ўліковаму запісу доступ да файла, даступнага толькі root. Павышэнне script-security змяняе, якія скрыпты будзе запускаць OpenVPN; на месца вылічэння адноснага імені гэта не ўплывае. Змена працоўнага каталога для ўсёй службы шырэйшая за праблему, бо кожны іншы адносны шлях да сертыфіката, журнала або дапаможніка рухаецца разам з ім.

Аддайце перавагу вузкаму выпраўленню: дэтэрмінаваны шлях у скрыпце, яўнае значэнне канфігурацыі для даных экзэмпляра і ўласніцтва файлаў, якое адпавядае ўліковаму запісу, ад якога хук фактычна працуе.

Запішыце доказы, якія называюць мяжу

Карысная справаздача пра збой утрымлівае тры рэчы: дакладны шлях, які паспрабаваў хук, асяроддзе, якое яго спарадзіла, і якая мяжа адмовіла. Выведзіце вылічаны шлях і выключэнне, не выліваючы змест файла. Гэтая тройка адрознівае няправільнае замацаванне ад схаванага мантавання і ад адмовы ў правах, а гэта тры розныя выпраўленні.

Сцвярджэнне, што root можа прачытаць файл з тэрмінала, адказвае на адно з гэтых пытанняў і ні на адно з іншых. Замест гэтага правярайце з уласнага кантэксту службы.

Падобныя артыкулы