Es gibt einen Unix-Shell-Befehl ( udevadm info -q path -n /dev/ttyUSB2
), den ich aus einem C-Programm aufrufen möchte. Nach ungefähr einer Woche Kampf könnte ich es wieder selbst implementieren, aber ich möchte das nicht tun.
Ist es allgemein anerkannt, dass ich nur anrufe popen("my_command", "r");
, oder führt dies zu inakzeptablen Sicherheitsproblemen und leitet Kompatibilitätsprobleme weiter? Es fühlt sich für mich falsch an, so etwas zu tun, aber ich kann nicht sagen, warum es schlecht wäre.
udevadm
ausführbare Datei in dasselbe Verzeichnis wie Ihr Programm stellen und sie zur Eskalation von Berechtigungen verwenden? Ich weiß nicht viel über Unix-Sicherheit, aber wird Ihr Programm mit ausgeführtsetuid root
?PATH
, muss es mit "no" ausgeführt werden./udevadm
. IIRC Windows würde jedoch ausführbare Dateien mit demselben Verzeichnis ausführen.Antworten:
Es ist nicht besonders schlimm, aber es gibt einige Einschränkungen.
LANG
etc. anders ausgegeben ?;rm -rf /
(Beachten Sie, dass Sie mit einigen APIs Argumente sicherer angeben können, als sie nur über die Befehlszeile bereitzustellen. )Ich bin im Allgemeinen froh, Binärdateien auszuführen, wenn ich mich in einer bekannten Umgebung befinde, die ich vorhersagen kann, wenn die Binärausgabe einfach zu analysieren ist (falls erforderlich - Sie benötigen möglicherweise nur einen Exit-Code), und ich muss dies auch nicht tun häufig.
Wie Sie bereits bemerkt haben, ist das andere Problem, wie viel Arbeit es kostet, die Funktionen der Binärdatei zu replizieren. Verwendet es eine Bibliothek, die Sie auch nutzen können?
quelle
Forking a binary results in a lot more load and requires more resources than executing library calls (generally speaking).
Wenn dies unter Windows wäre, würde ich zustimmen. Das OP gibt jedoch Unix an, bei dem das Forken so kostengünstig ist, dass es schwer zu sagen ist, ob das dynamische Laden einer Bibliothek schlechter ist als das Forken.exec
als von der kommen würdenfork
. Laden von Abschnitten, Verknüpfen von freigegebenen Objekten und Ausführen von Init-Code für jeden. Und dann müssen alle Daten in Text konvertiert werden, um auf der anderen Seite analysiert zu werden, sowohl für Eingaben als auch für Ausgaben.udevadm info -q path -n /dev/ttyUSB2
wird es auf Windows sowieso nicht funktionieren, daher ist die ganze Diskussion über das Gabeln ein bisschen theoretisch.Wenn Sie einen potenziellen Vektor eingeführt haben, ist äußerste Vorsicht geboten, um sich vor Anfälligkeiten durch Injektionen zu schützen. Es steht jetzt im Vordergrund Ihres Denkvermögens, aber später müssen Sie möglicherweise die Möglichkeit zur Auswahl haben. Diese
ttyUSB0-3
Liste wird dann an anderen Stellen verwendet, damit sie nach dem Prinzip der einheitlichen Verantwortung ausgeklammert wird. Dann muss ein Kunde eine Anforderung stellen Ein beliebiges Gerät in der Liste, und der Entwickler, der diese Änderung vornimmt, hat keine Ahnung, dass die Liste möglicherweise auf unsichere Weise verwendet wird.Mit anderen Worten, Code, als ob der sorgloseste Entwickler, den Sie kennen, eine unsichere Änderung an einem scheinbar nicht verwandten Teil des Codes vornimmt.
Zweitens wird die Ausgabe von CLI-Tools im Allgemeinen nicht als stabile Schnittstelle betrachtet, es sei denn, die Dokumentation kennzeichnet sie ausdrücklich als solche. Sie können sich möglicherweise auf sie verlassen, wenn Sie ein Skript ausführen, das Sie selbst beheben können, jedoch nicht auf etwas, das Sie für einen Kunden bereitstellen.
Drittens, wenn Sie auf einfache Weise einen Wert aus Ihrer Software extrahieren möchten, ist die Wahrscheinlichkeit groß, dass es auch jemand anderes möchte. Suchen Sie nach einer Bibliothek, die bereits das tut, was Sie wollen.
libudev
war bereits auf meinem System installiert:In dieser Bibliothek gibt es weitere nützliche Funktionen. Ich vermute, wenn Sie dies benötigen, könnten einige der zugehörigen Funktionen auch nützlich sein.
quelle
ttyUSB2
und verwendensprintf(buf, "udevadm info -q path -n /dev/%s", argv[1])
. Nun , da erscheint ziemlich sicher, aber was ist, wennargv[1]
ist"nul || echo OOPS"
?udevadm
Ich würde vermuten, dass Sie in Ihrem speziellen Fall, in dem Sie aufrufen möchten,udev
alternativ eine Bibliothek aufrufen und die entsprechenden Funktionsaufrufe ausführen könnten .Sie können sich beispielsweise ansehen, was udevadm selbst tut, wenn Sie im "info" -Modus aufrufen: https://github.com/gentoo/eudev/blob/master/src/udev/udevadm-info.c und gleichwertige Anrufe tätigen was diese udevadm macht.
Dies würde viele der in Brian Agnews hervorragender Antwort aufgezählten Nachteile vermeiden - z. B. sich nicht auf die Binärdatei zu verlassen, die auf einem bestimmten Pfad vorhanden ist, die Kosten für das Gabeln zu vermeiden usw.
quelle
Ihre Frage schien nach einer Waldantwort zu verlangen, und die Antworten hier scheinen wie Baumantworten zu sein. Ich dachte, ich würde Ihnen eine Waldantwort geben.
So werden C-Programme sehr selten geschrieben. Es ist immer so, wie Shell-Skripte geschrieben werden und manchmal, wie Python-, Perl- oder Ruby-Programme geschrieben werden.
Die Benutzer schreiben in der Regel in C, um die Systembibliotheken einfach zu verwenden, auf OS-Systemaufrufe zuzugreifen und die Geschwindigkeit zu erhöhen. Und C ist eine schwierige Sprache, in der man schreiben kann. Wenn die Leute diese Dinge nicht brauchen, dann benutzen sie kein C. Außerdem wird von C-Programmen normalerweise nur erwartet, dass sie von gemeinsam genutzten Bibliotheken und Konfigurationsdateien abhängen.
Das Ausschalten eines Unterprozesses ist nicht besonders schnell und erfordert keinen feinkörnigen und kontrollierten Zugriff auf Systemeinrichtungen auf niedriger Ebene. Daher ist die Abhängigkeit von einer externen ausführbaren Datei möglicherweise überraschend in C-Programmen.
Es gibt einige zusätzliche Bedenken. Die Sicherheits- und Portabilitätsbedenken, die die Leute erwähnen, sind vollständig gültig. Sie sind natürlich auch für Shell-Skripte gültig, aber die Leute erwarten solche Probleme in Shell-Skripten. Es wird jedoch normalerweise nicht erwartet, dass C-Programme diese Art von Sicherheitsbedenken haben, was sie gefährlicher macht.
Aber meiner Meinung nach haben die größten Bedenken mit der Art
popen
und Weise zu tun, wie Sie mit dem Rest Ihres Programms interagieren.popen
muss einen untergeordneten Prozess erstellen, dessen Ausgabe lesen und dessen Beendigungsstatus erfassen. In der Zwischenzeit wird dieser Prozess 'stderr mit demselben stderr wie Ihr Programm verbunden, was zu verwirrenden Ausgaben führen kann, und sein stdin entspricht dem Ihres Programms, was zu anderen interessanten Problemen führen kann. Sie können das lösen, indem</dev/null 2>/dev/null
Sie den String, an den Sie übergeben, einschließen ,popen
da er von der Shell interpretiert wird.Und
popen
erstellt einen untergeordneten Prozess. Wenn Sie selbst etwas mit Signalverarbeitung oder Gabelungsprozessen anfangen, erhalten Sie möglicherweise seltsameSIGCHLD
Signale. Ihre Aufrufe zuwait
interagieren möglicherweise seltsam mitpopen
und schaffen möglicherweise seltsame Rennbedingungen.Die Sicherheits- und Portabilitätsbedenken sind natürlich da. Wie für Shell-Skripte oder alles, was andere ausführbare Dateien auf dem System startet. Und Sie müssen darauf achten, dass Benutzer Ihres Programms keine Shell-Metazeichen in die Zeichenfolge einfügen können, in die Sie übergehen,
popen
da diese Zeichenfolge direktsh
mit übergeben wirdsh -c <string from popen as a single argument>
.Aber ich denke nicht, dass sie der Grund dafür sind, warum es seltsam ist, ein C-Programm zu verwenden
popen
. Der Grund, warum es seltsam ist, ist, dass C in der Regel eine niedrige Sprache undpopen
keine niedrige Sprache ist. Und weil die Verwendung vonpopen
Bereichen das Design Ihres Programms einschränkt, weil es seltsam mit den Standardeingaben und -ausgaben Ihres Programms interagiert und es Ihnen schwer macht, Ihr eigenes Prozessmanagement oder Ihre eigene Signalverarbeitung durchzuführen. Und weil von C-Programmen normalerweise keine Abhängigkeiten von externen ausführbaren Dateien erwartet werden.quelle
Ihr Programm kann Hacking usw. ausgesetzt sein. Eine Möglichkeit, sich vor dieser Art von Aktivität zu schützen, besteht darin, eine Kopie Ihrer aktuellen Maschinenumgebung zu erstellen und Ihr Programm mit einem System namens chroot auszuführen.
Aus Sicht Ihres Programms wird es unter normalen Sicherheitsaspekten ausgeführt. Wenn jemand Ihr Programm beschädigt, hat es nur Zugriff auf die Elemente, die Sie beim Erstellen der Kopie angegeben haben.
Ein solches Setup wird als Chroot-Gefängnis bezeichnet. Weitere Informationen finden Sie unter Chroot-Gefängnis .
Es wird normalerweise zum Einrichten von öffentlich zugänglichen Servern usw. verwendet.
quelle