Hook'u root olarak elle çalıştırdığınızda çalışır ve şunu döndürür Operation not permitted hizmet onu başlattığı anda. Dosya bu çalıştırmalar arasında değişmedi; ortam değişti. systemd sürece daha küçük bir dünya verir: daha az yetenek, farklı bir /dev, salt okunur dosya sistemi yolları ve bir görev tavanı. Hatayı, bir betiğin bozulması olarak değil, belirli bir işlemi reddeden bir sınır olarak okuyun.

Reddedilen İşlemden Başlayın

Unit'in başarısız olduğunu söyleyen bir günlük satırı size neredeyse hiçbir şey söylemez. Yararlı satır, reddedilen çağrıyı adlandırır: açılamayan bir aygıt düğümü, yazılamayan bir dizin, oluşturulamayan bir namespace. Tek bir yönergeye dokunmadan önce o çağrıyı bulun, çünkü her biri farklı bir kısıtlamaya karşılık gelir. Ardından paketin gönderdiği dosya yerine, drop-in'ler dahil, gerçekten çalışan unit'i okuyun.

Aşağıdaki sorgu fragment yolunu, drop-in dizinlerini ve bir aygıt veya dosya sistemi reddi için önemli olan özellikleri yazdırır. Hangi sınırın ilgili olduğuna karar vermeden önce hepsini okuyun:

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'

O blokta hiçbir şey yazmaz. Reddedilen çağrı günlükte yoksa, yönergeleri tahmin etmek yerine bir çalıştırma için istemcinin ayrıntı düzeyini yükseltin. Çalışan bir süreç, unit'in başladığını kanıtlar, hook'un ihtiyaç duyduğu ayrıcalıklarla çalıştığını değil.

Bir Namespace, TUN Aygıtının Hiç Kullanmadığı Mount Haklarına İhtiyaç Duyar

Tek bir hook içinde benzer görünen iki işlemin farklı izin profilleri vardır. Şunu açmak /dev/net/tun ve arayüzü oluşturmak, ağ yönetimi artı o düğüme erişim gerektirir. Adlandırılmış bir ağ namespace'i oluşturmak da mount ile ilgili iş gerektirir, çünkü namespace aracı yeni bir /sys görünümü mount eder ve bir durum dizinini yerine bağlar. Üst kaynak istemci unit'i mount yönetimini kasıtlı olarak kendi sınırlama kümesinin dışında bırakır, bu yüzden namespace adımı reddedilirken tünelin kendisi çalışmış olurdu.

Bu yüzden aygıt düğümünü vermek betiği kurtarmaz. Bir aygıt izni tek bir soruyu yanıtlar, bu sürecin bu düğümü açıp açamayacağını, namespace sorusu ise başkadır. Herhangi bir şeyi genişletmeden önce başarısız çağrıyı yeteneğiyle eşleştirin.

Kabuğunuzdaki bir test, kısıtlanmamış bir root'un sahip olduğu her yeteneği devralır ve unit, sınırlama kümesinin sakladığını devralır. İki çalıştırma farklı deneylerdir ikili aynı olsa bile.

Aygıtlar, Korunan Yollar ve Görev Tavanları

Reddedilen işlem bilindiğinde, üç yönerge grubu başarısızlıkların çoğunu açıklar. Aygıt erişimini PrivateDevices yönetir; bu /dev aygıtını en az sözde aygıt kümesiyle değiştirir, ve DevicePolicy ile birlikte DeviceAllow cgroup'un neye izin verdiğine karar verir. /dev/net/tun bu en az kümenin parçası değildir, bu yüzden PrivateDevices=yes içeren bir unit, aygıt politikası ne derse desin onu açamaz.

Dosya sistemi koruması ikinci bir soruyu yanıtlar. ProtectHome=yes /home, /root ve /run/user dizinlerini erişilemez kılar; ProtectSystem=full ise /usr, /boot ve /etc dizinlerini salt okunur yapar. Bir hook kendi yapılandırma dosyasının yanına yazdığı için kabuğunuzda çalışır ve unit altında başarısız olur, eksik bir yetenekle aynı izin biçiminde. Yazılabilir girdiyi politikanın izin verdiği bir yola taşıyın veya dar bir ReadWritePaths= girdi ekleyin.

Kaynak sınırları üçüncü gruptur ve en az belirgin olanıdır. TasksMax= unitin oluşturabileceği görev sayısını sınırlar ve bir dosya tanımlayıcı tavanı soketler ve tutamaçlar için aynı şekilde davranır. Tavanı aşacak kadar büyüyen bir dağıtım, izin hatası yerine kaynak hatasıyla başarısız olur, bu yüzden tam mesaj hâlâ önemlidir.

Namespace Adımını Hook'un Dışına Taşıyın

İstemcinin sahip olmaması gereken bir ayrıcalık gerektiren hazırlık kendi unit'ine aittir. İstemciden önce çalışan, sonucunu koruyan ve bağlantının önüne sıralanan bir oneshot, namespace adımına ihtiyacı olanı verir ve bu hakları tünel sürecine devretmez. İstemci daha sonra betiği up hook'undan çağırmak yerine o unit'e başvurur.

Aşağıdaki şablon bir başlangıç biçimidir, okunmadan uygulanacak bir şey değildir. Hazırlığı ayrıcalığın yaşadığı yerde tutar ve tünel unit'ini dokunulmadan bırakır:

# /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

Sıralamayı paketlenmiş unit'i düzenlemek yerine bir drop-in ile ekleyin, böylece bir yükseltme değişikliğinizi sessizce düşüremez. Dizin örnek adına bağlıdır, bu yüzden ikinci profil kendi dosyasına ihtiyaç duyar:

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

Değişiklikten Sonra Aynı Çağrıyı Yineleyin

Bir onarım ancak aynı çağrı farklı bir sonuç ürettiğinde doğrulanır. İki unit'i de yeniden başlatın, başarısız olan işlemi çalıştırın ve sonucunu değişiklikten önce kaydettiğiniz günlük satırıyla karşılaştırın. Hook bir daha hiç çalışmazken başlayan bir unit onarım değildir.

Aşağıdaki dizi karşılaştırmayı dürüst tutar, çünkü unit'in rengini değil reddedilen çağrıyı denetler. Çıktısını değişiklikten önce yakaladığınız günlük satırının yanına kaydedin:

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

Son satırı okumak yerine reddetmeleri sayın, çünkü bir hook başarısız olabilir, yeniden deneyebilir ve başarılı olabilir ve sınırın hareket edip etmediğini yalnızca sayı gösterir. Drop-in'de gevşettiğiniz yönergeyi ve nedeni adlandıran bir yorum bırakın, çünkü bir sonraki yükseltme yapılandırmanızı paketlenmiş varsayılanla karşılaştırır. Her koruma devre dışı bırakıldıktan sonra başlayan bir unit düzeltilmemiştir.

İlgili makaleler