Il y a une commande shell unix udevadm info -q path -n /dev/ttyUSB2
que je veux appeler depuis un programme C. Avec probablement environ une semaine de lutte, je pourrais le ré-appliquer moi-même, mais je ne veux pas le faire.
Est-ce une bonne pratique largement acceptée pour moi d'appeler popen("my_command", "r");
, ou est-ce que cela introduira des problèmes de sécurité inacceptables et des problèmes de compatibilité? Je me sens mal de faire quelque chose comme ça, mais je ne peux pas comprendre du doigt pourquoi ce serait mauvais.
udevadm
fichier exécutable malveillant dans le même répertoire que votre programme et l'utiliser pour élever les privilèges? Je ne connais pas grand chose à la sécurité Unix, mais votre programme sera-t-il exécutésetuid root
?PATH
, alors non - il devrait être exécuté avec./udevadm
. IIRC Windows exécuterait cependant les exécutables du même répertoire.Réponses:
Ce n'est pas particulièrement grave, mais il y a quelques réserves.
LANG
etc.?;rm -rf /
(par exemple) (notez que certaines API vous permettent de spécifier des arguments de manière plus sécurisée que de simplement les fournir sur la ligne de commande)Je suis généralement heureux d’exécuter des fichiers binaires lorsque je suis dans un environnement connu que je peux prédire, lorsque la sortie binaire est facile à analyser (si nécessaire - vous n’avez peut-être besoin que d’un code de sortie) et je n’ai pas besoin de le faire aussi. souvent.
Comme vous l'avez noté, l'autre problème est de savoir combien de travail est nécessaire pour répliquer ce que le binaire fait. Utilise-t-il une bibliothèque que vous pouvez également utiliser?
la source
Forking a binary results in a lot more load and requires more resources than executing library calls (generally speaking).
Si cela était sur Windows, je serais d'accord. Cependant, l'OP spécifie Unix où le coût du forking est suffisamment bas pour qu'il soit difficile de dire si le chargement dynamique d'une bibliothèque est pire que le forking.exec
que de lafork
. Chargement de sections, liens dans des objets partagés, exécution du code init pour chacun. Et ensuite, avoir à convertir toutes les données en texte à analyser de l'autre côté, à la fois pour les entrées et les sorties.udevadm info -q path -n /dev/ttyUSB2
ne fonctionnera pas sous Windows de toute façon, donc toute la discussion sur la fourche est un peu théorique.Il est extrêmement prudent de se prémunir contre les vulnérabilités liées à l’injection une fois que vous avez introduit un vecteur potentiel. C’est au centre de vos préoccupations maintenant, mais plus tard, vous aurez peut-être besoin de la possibilité de choisir
ttyUSB0-3
. Cette liste sera utilisée ailleurs, afin que le principe de la responsabilité unique soit appliqué, puis qu'un client sera tenu de mettre un périphérique arbitraire dans la liste et le développeur qui effectue cette modification n'aura aucune idée du fait que la liste sera finalement utilisée de manière non sécurisée.En d'autres termes, code comme si le développeur le plus imprudent que vous connaissez effectue un changement dangereux dans une partie du code apparemment sans rapport.
Deuxièmement, les outils de la CLI ne sont généralement pas considérés comme des interfaces stables, à moins que la documentation les marque spécifiquement. Vous pouvez peut-être compter sur eux pour un script que vous exécutez et que vous pouvez résoudre vous-même, mais pas pour quelque chose que vous déployez chez un client.
Troisièmement, si vous souhaitez extraire facilement une valeur de votre logiciel, il est fort probable que quelqu'un d'autre le souhaite également. Cherchez une bibliothèque qui fait déjà ce que vous voulez.
libudev
était déjà installé sur mon système:Il existe d'autres fonctionnalités utiles dans cette bibliothèque. À mon avis, si vous en aviez besoin, certaines fonctions connexes pourraient également s'avérer utiles.
la source
ttyUSB2
et utilisezsprintf(buf, "udevadm info -q path -n /dev/%s", argv[1])
. Maintenant, cela semble assez sûr, mais queargv[1]
se passe-"nul || echo OOPS"
t -il ?Dans votre cas spécifique, où vous souhaitez invoquer
udevadm
, je soupçonne que vous pourriez vous connecter enudev
tant que bibliothèque et faire les appels de fonction appropriés en guise d'alternative?Par exemple, vous pouvez jeter un coup d'œil à ce que fait udevadm quand il appelle en mode "info": https://github.com/gentoo/eudev/blob/master/src/udev/udevadm-info.c et faire des appels équivalents quant à ceux udevadm fait.
Cela éviterait beaucoup de compromis négatifs énumérés dans l'excellente réponse de Brian Agnew - par exemple, ne pas compter sur le binaire existant sur une certaine trajectoire, éviter les frais de forking, etc.
la source
Votre question semblait appeler une réponse de la forêt, et les réponses ici ressemblent à des réponses d'arbres, alors j'ai pensé vous donner une réponse de la forêt.
C’est très rarement la façon dont les programmes C sont écrits. C'est toujours comment les scripts shell sont écrits, et parfois comment les programmes Python, perl ou Ruby sont écrits.
Les utilisateurs écrivent généralement en C pour une utilisation facile des bibliothèques système et un accès direct de bas niveau aux appels système du système d'exploitation, ainsi que pour la rapidité. C étant un langage difficile à écrire, si les utilisateurs n'en ont pas besoin, ils n'utilisent pas C. De plus, les programmes C ne doivent généralement dépendre que de bibliothèques partagées et de fichiers de configuration.
Faire appel à un sous-processus n'est pas particulièrement rapide, il ne nécessite pas un accès fin et contrôlé aux installations système de bas niveau, et il introduit une dépendance éventuellement surprenante à un exécutable externe. Il est donc rare de voir dans les programmes en C.
Il y a quelques préoccupations supplémentaires. Les problèmes de sécurité et de portabilité que les gens mentionnent sont tout à fait valables. Bien sûr, ils sont également valables pour les scripts shell, mais les gens s’attendent à ce genre de problèmes dans les scripts shell. Mais les programmes C ne sont généralement pas censés présenter ce type de problème de sécurité, ce qui le rend plus dangereux.
Mais, à mon avis, la plus grande préoccupation concerne la manière dont le système
popen
va interagir avec le reste de votre programme.popen
doit créer un processus enfant, lire sa sortie et collecter son statut de sortie. Dans l'intervalle, le processus stderr de ce processus sera connecté au même réseau que votre programme, ce qui peut entraîner des résultats confus, et son stdin sera identique à votre programme, ce qui pourrait entraîner d'autres problèmes intéressants. Vous pouvez résoudre ce problème en incluant</dev/null 2>/dev/null
dans la chaîne à laquelle vous passezpopen
car elle est interprétée par le shell.Et
popen
crée un processus enfant. Si vous faites vous-même quelque chose avec des processus de traitement du signal ou de traitement du signal, vous risquez de recevoir desSIGCHLD
signaux étranges . Vos appels àwait
peuvent interagir étrangementpopen
et éventuellement créer d’étranges conditions de concurrence.Les problèmes de sécurité et de portabilité sont bien sûr présents. Comme pour les scripts shell ou tout ce qui lance d'autres exécutables sur le système. Et vous devez faire attention que les personnes utilisant votre programme ne sont pas en mesure d'obtenir des méta-charcaters shell dans la chaîne que vous passez en
popen
car cette chaîne est donnée directementsh
avecsh -c <string from popen as a single argument>
.Mais je ne pense pas que ce soit la raison pour laquelle il est étrange de voir un programme C utiliser
popen
. La raison pour laquelle c'est étrange, c'est parce que C est généralement un langage de bas niveau etpopen
n'est pas un bas niveau. Et parce que l'utilisation depopen
contraintes de conception sur votre programme entraîne des interactions étranges avec les entrées et sorties standard de votre programme, ce qui complique la gestion de votre propre processus ou de la gestion du signal. Et parce que les programmes C ne sont généralement pas censés avoir des dépendances sur les exécutables externes.la source
Votre programme peut être sujet au piratage, etc. Une façon de vous protéger de ce type d'activité consiste à créer une copie de votre environnement informatique actuel et à exécuter votre programme à l'aide d'un système appelé chroot.
Du point de vue de votre programme, il s'exécute dans un environnement normal, du point de vue de la sécurité, si quelqu'un casse votre programme, il n'a accès qu'aux éléments que vous avez fournis lors de la copie.
Une telle configuration s'appelle une prison chroot. Pour plus de détails, reportez-vous à la rubrique prison chroot .
Il est normalement utilisé pour configurer des serveurs accessibles au public, etc.
la source