Hook-г root-оор гараар ажиллуулахад ажиллаж, буцаана Operation not permitted үйлчилгээ эхлүүлсэн тэр мөчид. Файл эдгээр ажиллагааны хооронд өөрчлөгдөөгүй; орчин өөрчлөгдсөн. systemd процессд жижиг ертөнц өгдөг: цөөн чадвар, өөр /dev, зөвхөн унших файлын системийн зам, даалгаврын дээд хязгаар. Алдааг нэг тодорхой үйлдлийг татгалзсан хил хязгаар гэж уншаарай, эвдэрсэн скрипт гэж биш.

Татгалзсан үйлдлээс эхэл

unit бүтэлгүйтсэн гэсэн лог мөр бараг юу ч хэлэхгүй. Хэрэгтэй мөр нь татгалзсан дуудлагыг нэрлэдэг: нээгдээгүй төхөөрөмжийн зангилаа, бичигдээгүй хавтас, үүсгэгдээгүй нэрийн орон зай. Нэг ч зааварт хүрэхээс өмнө тэр дуудлагыг ол, учир нь тус бүр өөр хязгаарлалтад тохирдог. Дараа нь багцаас ирсэн файл биш, үнэхээр ажилласан unit-г унш, drop-in-уудыг оролцуулан.

Доорх асуулга фрагментийн зам, drop-in хавтас, төхөөрөмж эсвэл файлын системээс татгалзахад чухал шинж чанаруудыг хэвлэнэ. Аль хил хязгаар хамаатайг шийдэхээс өмнө бүгдийг уншаарай:

systemctl show "[email protected]" -p FragmentPath -p DropInPaths -p PrivateDevices -p DevicePolicy -p DeviceAllow -p ProtectHome -p ProtectSystem -p TasksMax
journalctl -u "[email protected]" -b --no-pager | grep -iE 'operation not permitted|permission denied|cannot open|failed'

Тэр блокт юу ч бичихгүй. Хэрэв татгалзсан дуудлага журналд байхгүй бол зааврыг таамаглахын оронд нэг ажиллагаанд клиентийн дэлгэрэнгүй байдлыг өсгө. Ажиллаж буй процесс unit эхэлснийг нотолдог, hook шаардлагатай эрхээр ажилласныг биш.

Нэрийн орон зайд TUN төхөөрөмж хэзээ ч ашигладаггүй mount эрх хэрэгтэй

Нэг hook дотор адил харагдах хоёр үйлдэл өөр зөвшөөрлийн профайлтай. /dev/net/tun нээх, интерфейс үүсгэхэд сүлжээний удирдлага болон тэр зангилаанд хандах эрх хэрэгтэй. Нэртэй сүлжээний нэрийн орон зай үүсгэхэд мөн mount ажил хэрэгтэй, учир нь нэрийн орон зайн хэрэгсэл шинэ /sys харагдацыг mount хийж, төлөвийн хавтсыг байранд нь холбодог. дээд урсгалын клиент unit mount удирдлагыг өөрийн хил хязгаарын олонлогоос санаатайгаар гадуур үлдээдэг, тиймээс нэрийн орон зайн алхам татгалзагдана, харин туннель өөрөө ажиллах байсан.

Тиймээс төхөөрөмжийн зангилаа өгөх нь скриптийг аварч чадахгүй. Төхөөрөмжийн зөвшөөрөл нэг асуултад хариулдаг, энэ процесс энэ зангилааг нээж чадах уу, харин нэрийн орон зайн асуулт өөр. Ямар нэг зүйлийг өргөтгөхөөс өмнө бүтэлгүйтсэн дуудлагыг чадвартай нь тааруул.

Таны shell дахь тест хязгааргүй root-ын бүх чадварыг өвлөнө, unit нь хил хязгаарын олонлогоос үлдээснийг өвлөнө. Тэр хоёр ажиллагаа өөр туршилт бинарь ижил байсан ч.

Төхөөрөмж, хамгаалагдсан зам, даалгаврын дээд хязгаар

Татгалзсан үйлдэл мэдэгдэж дууссаны дараа гурван бүлэг заавар ихэнх алдааг тайлбарладаг. Төхөөрөмжид хандах эрхийг зохицуулдаг нь PrivateDevices, энэ нь /dev -г хамгийн бага хуурамч төхөөрөмжийн багцаар солино, мөн DevicePolicy -тэй DeviceAllow, тэд cgroup юуг зөвшөөрөхийг шийддэг. /dev/net/tun тэр хамгийн бага багцын хэсэг биш, тиймээс PrivateDevices=yes бүхий unit төхөөрөмжийн бодлого юу ч гэсэн нээж чадахгүй.

Файлын системийн хамгаалалт хоёр дахь асуултад хариулдаг. ProtectHome=yes болгоно /home, /root болон /run/user -г хүрэх боломжгүй, харин ProtectSystem=full болгоно /usr, /boot болон /etc -г зөвхөн унших болгоно. Тиймээс өөрийн тохиргооны файлын хажууд бичдэг hook таны shell-д ажиллаж, unit дор бүтэлгүйтдэг, дутуу чадвартай ижил зөвшөөрлийн хэлбэрээр. Бичих боломжтой оролтыг бодлого зөвшөөрсөн зам руу зөө, эсвэл нарийн ReadWritePaths= бичлэг нэм.

Нөөцийн хязгаар нь гурав дахь бүлэг бөгөөд хамгийн тод бус нь. TasksMax= unit хэдэн даалгавар үүсгэж болохыг хязгаарладаг, файлын тодорхойлогчийн дээд хязгаар socket болон бариулын хувьд мөн адил ажилладаг. Хязгаараас хэтэрч өссөн байрлуулалт зөвшөөрлийн алдааны оронд нөөцийн алдаагаар бүтэлгүйтдэг, тиймээс нарийн мессеж одоо ч чухал.

Нэрийн орон зайн алхмыг hook-оос гарга

Клиентэд байх ёсгүй эрх шаарддаг бэлтгэл өөрийн unit-д хамаарна. Клиентээс өмнө ажиллаж, үр дүнгээ хадгалж, холболтоос өмнө эрэмбэлэгдсэн oneshot нэрийн орон зайн алхамд хэрэгтэйг өгдөг, тэр эрхийг туннелийн процессд шилжүүлэхгүйгээр. Дараа нь клиент скриптийг өөрийн up hook-оос дуудахын оронд тэр unit-д лавлана.

Доорх загвар бол эхлэлийн хэлбэр, уншилгүй хэрэглэх зүйл биш. Бэлтгэлийг эрх амьдардаг газарт нь байлгаж, туннелийн unit-г хөндөхгүй орхидог:

# /etc/systemd/system/[email protected]
[Unit]
Description=Namespace preparation for %i
Before=openvpn-client@%i.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/netns-up.sh %i
CapabilityBoundingSet=CAP_NET_ADMIN CAP_SYS_ADMIN
[Install]
WantedBy=multi-user.target

Эрэмбийг багцлагдсан unit-г засахын оронд drop-in-оор нэм, ингэснээр шинэчлэл таны өөрчлөлтийг чимээгүй хаяж чадахгүй. Хавтас нь хувилбарын нэрэнд холбогдсон тул хоёр дахь профайлд өөрийн файл хэрэгтэй:

sudo mkdir -p /etc/systemd/system/[email protected]
sudo tee /etc/systemd/system/[email protected]/10-namespace.conf >/dev/null <<'CONF'
[Unit]
[email protected]
[email protected]
CONF
sudo systemctl daemon-reload

Өөрчлөлтийн дараа ижил дуудлагыг давт

Засвар нь ижил дуудлага өөр үр дүн гаргахад л баталгаажина. Хоёр unit-г дахин эхлүүлж, бүтэлгүйтсэн үйлдлийг гүйцэтгэж, үр дүнг өөрчлөлтөөс өмнө хадгалсан журналын мөртэй харьцуул. Hook дахин хэзээ ч ажиллахгүй байхад эхэлдэг unit засвар биш.

Доорх дараалал харьцуулалтыг шударга байлгадаг, учир нь unit-ийн өнгийг биш, татгалзсан дуудлагыг шалгадаг. Гаралтыг өөрчлөлтөөс өмнө барьсан журналын мөрийн хажууд хадгал:

sudo systemctl restart "[email protected]" "[email protected]"
systemctl status "[email protected]" --no-pager
journalctl -u "[email protected]" -b --no-pager | grep -c 'Operation not permitted'
ip -brief addr show tun0

Сүүлийн мөрийг уншихын оронд татгалзалтыг тоол, учир нь hook бүтэлгүйтэж, дахин оролдож, амжилттай болж болно, хил хязгаар хөдөлсөн эсэхийг зөвхөн тоо харуулна. drop-in-д сулруулсан заавар болон шалтгааныг тэмдэглэсэн тайлбар үлдээ, учир нь дараагийн шинэчлэл таны тохиргоог багцын өгөгдмөлтэй харьцуулдаг. Бүх хамгаалалтыг унтраасны дараа л эхэлдэг unit засагдаагүй.

Холбоотой нийтлэлүүд