ping - Operation not permitted

Von Michael Gisbers 1. August 2022

In Schulungen für Linux Administratoren ist eine der Übungen den lokalen Rechner in ein tar - Archiv zu packen, dieses im Netz abzulegen, den Rechner zu bereinigen und über das Archiv wiederherzustellen.

Dabei werden viele Tools wie fdisk/gdisk, mkfs, mount, tar und grub-install benötigt um den Datenträger vorzubereiten, die Partitionen zu formatieren und die Dateisysteme wieder richtig einzuhängen um dort das Archiv zu entpacken. Nach der Installation des GRUB läuft dann in der Regel das System wieder und kann getestet werden.

Leider kommt es immer mal wieder dazu, daß der Versuch als Benutzer einen ping in dem neu aufgebauten System einen Fehler meldet.

user@linux $ ping gisbers.de
ping: socket: Operation not permitted

Woher kommt der Fehler? Das System ist korrekt hochgefahren und auch die Netzwerkumgebung läuft einwandfrei, aber es kommt - egal ob über eine IP - Adresse oder einen DNS-Namen aufgerufen - immer die gleiche Fehlermeldung.

Bei einem genauen Blick auf die Fehlermeldung wird klar, daß ping versucht eine Verbindung aufzubauen, die er nicht aufbauen darf. Dazu muss man hinter die Aufgabe des Befehls schauen: Er soll einem per IP - Netzwerk erreichbaren Gerät eine Nachricht des Typs 8 (Echo Request) über das Internet Control Message Protocol (ICMP) und auf die Antwort des anderen Gerätes warten. Dieses schickt - solange ihm das nicht verboten ist oder eine Firewall blockt - eine Antwort mit einer Nachricht Typ 0 ICMP (Echo Reply) zurück.

Um die Nachrichten versenden und Antworten zu empfangen muss ping in der Lage sein einen passenden Socket für das Senden und einen für den Empfang der Antwort zu öffnen.

Und genau hier wird die Fehlermeldung generiert. Dem Befehl ping fehlt das Recht diese Sockets zu öffnen. Wird der Befehl als Benutzer root aufgerufen funktioniert er wie gewohnt.

Was dem Benutzer fehlt ist das Recht Sockets für ICMP zu erstellen. Für die Protokolle TCP und UDP - bei Ports größer 1023 - darf er das und damit auch eigene Programme starten, die sie benutzen.

Sehr lange Zeit haben die Distributionen den Befehl ping über ein SetUID zu einem Befehl gemacht, der als Benutzer root läuft. Dazu muss der Besitzer des Befehls der Benutzer root und das s (SetUID) - Flag für den Benutzer gesetzt sein. Zu sehen an dem kleinen s in den Zugriffsrechten.

user@linux $ ls -l /bin/ping
-rwsr-xr-x 1 root root 76568 22 Dez. 2021 /bin/ping

Mit den durch diese Einstellung vergebenen Rechten läuft der Befehl ping beim Aufruf mit den effektiven Rechten des Benutzer root. Bedeutet, daß es möglich ist durch Fehler innerhalb des Befehls z. B. andere Programme zu starten, die dann auch direkt mit uneingeschränkten root Rechten laufen.

Das schöne an diesen Rechten ist, daß sie in einen tar Archiv transportierbar sind und nach dem entpacken als Benutzer root wieder vorhanden sind.

Allerdings wäre es sehr viel sinnvoller dem Befehl nur die benötigten Rechte zum Erstellen der Sockets zu geben und nicht die vollen root Rechte.

Die root - Rechte sind capabilities (Fähigkeiten), die dem Benutzer root in einem Linux basierten System zugewiesen sind. Im Gegensatz zu normalen Benutzern erhält root alle capabilities, der Benutzer keine.

Schaut man durch die Liste der capabilities, dann findet man eine mit dem Namen CAP_NET_RAW.

CAP_NET_RAW
       * Use RAW and PACKET sockets;
       * bind to any address for transparent proxying.

Die Beschreibung verspricht, daß ein Zugriff auf RAW und Packet Sockets erlaubt ist. Zusätzlich erlaubt es auf beliebige Adressen zu binden.

Der neue Trick der Distributionen ist also dem Befehl ping die capability CAP_NET_RAW zu geben und darüber nur ein eingeschränktes Recht zu erhalten. Vorteil dieser Vorgehensweise: Bei einem Fehler im Befehl können von ihm aufgerufene Programme davon nicht profitieren.

user@linux $ ls -l /bin/ping
-rwsr-xr-x 1 root root 76568 22 Dez. 2021 /bin/ping

user@linux $ getcap /bin/ping
/bin/ping cap_net_raw+p

Wie im Listing zu sehen ist gibt es über den Befehl ls keinen Hinweis darauf, daß der Befehl mit zusätzlichen capabilities versehen ist. Erst mit dem Tool getcap lassen sich die capabilities von Befehlen anzeigen.

Da diese in den erweiterten Attributen der Dateien gepeichert sind lassen sie sich auch mit dem Befehl getfattr auslesen.

user@linux $ getfattr -n security.capability /bin/ping
# file: bin/ping
security.capability=0sAQAAAgAEAAAAAAAAAAAAAAAAAAA=

Genau diese erweiterten Attribute gehen bei einem normalen Backup per tar verloren. tar kann sie also auch nach dem Entpacken nicht wiederherstellen.

Sollen diese Attribute mit in das Archiv, dann muss explizit --xattrs als Parameter beim Erzeugen vorhanden sein. Aus Sicherheitsgründen stellt tar die security.capability - Attribute nur wieder her, wenn dies explizit über den Parameter --xattrs-include='security.capability' oder allgemeiner --xattrs-include='*' für alle Attribute beim Entpacken angefordert ist.

Beispiel für das Packen und Entpacken des Befehls tar mit erweiterten Attributen.

Bitte das Beispiel nicht in Live/Produktiv - Systemen ausprobieren

user@linux $ tar --xattrs -cvf /tmp/ping.tar /bin/ping
tar: Entferne führende „/“ von Elementnamen
/bin/ping

user@linux $ sudo tar --xattrs-include='*' -C / -xvf /tmp/ping.tar
bin/ping

Durch die beiden Befehle wird zunächst ein Archiv mit dem Befehl /bin/ping und dessen erweiterten Attributen erzeugt und danach auf die gleiche Datei zurückgeschrieben.

Allerdings überraschen immer mehr Distributionen und zeigen, daß es auch komplett anders geht.

Es kommen weder ein SetUID noch capabilities zum Einsatz. Trotzdem funktioniert der Befehl ping für den normalen Benutzer.

Hier hilft der Kernel mit. Über den Parameter /proc/sys/net/ipv4/ping_group_range bekommt der Kernel die Information welcher Bereich an Gruppen IDs die Erlaubnis haben den Befehl ping ohne weitere capabilities oder SetUID zu benutzen.

Obwohl der Parameter schon seit der Kernel Version 2.6.39 existiert findet er erst jetzt häufiger seinen Einsatz. Genaue Informationen dazu sind in der ICMP Manual Page zu finden.

ping_group_range (two integers; default: see below; since Linux
2.6.39)
       Range of the group IDs (minimum and maximum group IDs,
       inclusive) that are allowed to create ICMP Echo sockets.
       The default is "1 0", which means no group is allowed to
       create ICMP Echo sockets.

Bei Archlinux ist dieser Parameter so eingestellt, daß er für alle möglichen Gruppen IDs gilt.

user@linux $ cat /proc/sys/net/ipv4/ping_group_range
0	2147483647

Am sinnvollsten lässt sich der Eintrag über den Befehl sysctl verändern.

user@linux $ sudo sysctl -w net.ipv4.ping_group_range='0 2147483647'
net.ipv4.ping_group_range = 0 2147483647

Dies ist allerdings nicht persistent. Um es persistent und damit auch nach einem Neustart direkt neu einzutragen wird die Zeile mit dem Parameter und Wert in eine Datei unter /etc/sysctl.d/ abgelegt. Genauere Infos hierzu sind in der sysctl Manual Page zu finden.

Mit den nun bekannten Informationen im Hinterkopf lässt sich die Aufgabe für die Linux Administratoren neu gestalten und führt wieder zu einem Erfolgserlebnis.