Serveur d'impression

Dépannage d'un lien symbolique – un polar pour les livres de records Git – Serveur d’impression

Le 8 février 2020 - 12 minutes de lecture

Alors que je porte normalement le fedora bien usé d'un administrateur système dur, le dimanche matin, j'échange cet accessoire néo-noir contre le tech-noir: une paire d'écouteurs pro. C'est l'histoire de la collision de ces deux rôles. Un câlin éducatif, cher lecteur. Vous voyez, mon concert hebdomadaire consiste à exécuter un flux en direct Facebook, et Facebook a récemment commencé à appliquer une nouvelle politique: tous les flux vidéo sont requis pour utiliser le cryptage. Nous avons installé Fedora sur la machine multimédia et utilisons Open Broadcaster Software (OBS) pour diffuser. Il aurait dû être facile de mettre à jour les paramètres du flux. J'ai fait les changements nécessaires et l'ai testé – pas de chance. Le message d'erreur était loin d'être utile: «Échec de la connexion au serveur». Avec un soupir, j'ai enlevé mes écouteurs, mis mon chapeau d'administrateur système et je suis sorti dans l'obscurité numérique. Il était temps de retourner au travail.

Qu'est-ce que le RTMPS?

Quelques termes, avant de plonger. RTMP est le protocole de messagerie en temps réel, développé à l'origine par Macromedia. Grâce à Adobe, une version de RTMP est désormais une spécification ouverte et de nombreux services de streaming vidéo l'utilisent désormais pour transporter l'audio et la vidéo en direct sur Internet. RTMPS est simplement la version chiffrée, où RTMP est enveloppé dans une connexion TLS / SSL. TLS, Transport Layer Security, est le même protocole qui alimente HTTPS. TLS dépend du fait que votre machine possède une bonne copie du paquet de certificats, une collection de clés publiques qui sont considérées comme fiables.

Comment peut-on essayer de résoudre ce genre de problème? Une bonne première étape consiste à obtenir un message d'erreur plus utile. L'exécution d'OBS à partir d'une ligne de commande nous permet de voir tous les messages de sortie supplémentaires qui sont généralement invisibles. Ci-dessous, j'ai supprimé tous les messages supplémentaires, pour mettre en évidence l'échec de la tentative de connexion.



Info: [rtmp stream: 'simple_stream'] Connexion à l'URL RTMP rtmps: //rtmp-api.facebook.com: 443 / rtmp / ...
info: RTMP_Connect1, TLS_Connect a échoué: -0x7680
Info: [rtmp stream: 'simple_stream'] Connexion à rtmps: //rtmp-api.facebook.com: 443 / rtmp / a échoué: -2
info: ==== Arrêt de la diffusion =========================================== ======

Nous arrivons maintenant quelque part. L'échec est spécifiquement dans la connexion TLS, que nous aurions pu deviner. Nous obtenons également un code d'erreur. Remarque rapide sur la recherche de cette erreur: Google interprètera le tiret principal comme un indicateur que vous voulez des résultats qui n'incluent pas ce terme de recherche. L'entourant de guillemets, "-0x7680" est le moyen d'obtenir des résultats utiles.

Comment identifier la cause d'une erreur

La recherche de ce numéro d'erreur fera apparaître deux résultats intéressants. Le premier est le fil conducteur du forum OBS où ceux d'entre nous confrontés à ce problème en ont discuté. L'autre hit est la documentation mbedtls, où une erreur avec ce code est définie. Il est possible que ce soit un faux positif, mais comme nous résolvons un problème TLS, il est probablement lié. Cette erreur est MBEDTLS_ERR_SSL_CA_CHAIN_REQUIREDet est décrit comme «Aucune chaîne CA n'est définie, mais requise pour fonctionner.»

Et maintenant? Nous avons appris un peu, mais nous n’avons toujours pas de réponse, alors plongeons-nous dans le code. Ma technique de débogage rapide et sale en attente consiste à ajouter printf () appels pour aider à suivre l'exécution du code, mais par où commencer? Nous avons un fil d'Ariane dans la sortie du programme, «RTMP_Connect1». La recherche dans la base de code OBS sur Github nous amène à une fonction avec ce nom. À mi-chemin de la fonction, nous pouvons voir la commande pour imprimer le message de journal qui nous a amenés ici.

Le message d'erreur indique qu'une chaîne CA n'est pas chargée. Cela ressemble à un problème d'initialisation. Peut-être que le terme «chaîne» est utilisé dans la source OBS. La recherche dans notre fichier suspect renvoie 18 résultats, dont 17 dans une fonction nommée RTMP_TLS_LoadCerts (). J'ai passé un peu de temps à rechercher le flux d'exécution de la connexion RTMP, même à faire un croquis du moment où chaque fonction est appelée. Le code m'a ramené à RTMP_TLS_LoadCerts (). Cette fonction contient un peu de code, mais nous pouvons ignorer en toute sécurité les parties spécifiques à Windows ou MacOS. Il existe une ligne évidente qui devrait charger les certificats système.

if (mbedtls_x509_crt_parse_path (chain, "/ etc / ssl / certs /") & <0) 
        erreur goto;
    

OBS fait donc un appel de fonction à la bibliothèque mbedtls, demandant que les certificats / etc / ssl / certs / sont chargés. Assurons-nous qu’un fichier de certificat approprié se trouve réellement là où OBS s’attend à ce qu’il soit:

ca-bundle.crt est là où il est censé être, mais pourquoi ce fichier est-il d'une couleur différente?

Ca-bundle.crt est le fichier que nous recherchons. Remarquez la couleur turquoise? Ces trois fichiers sont en fait des liens symboliques vers un autre emplacement. Les fichiers sur les systèmes de fichiers Linux sont liés symboliquement tout le temps, donc ce n'est probablement pas un problème. J'ai passé du temps à vérifier des choses comme les autorisations de fichiers et j'ai essayé de désactiver selinux, mais je n'ai rien trouvé. Cela ne semblait pas être un cadre de sécurité trop zélé. Tout ce qui me restait, c'était de savoir que j'avais une fonction mbedtls qui devrait charger le paquet de certificats, mais lorsque le programme a effectivement essayé de vérifier un certificat TLS, il s'est plaint que la chaîne, ca-bundle.crt, manquait. Si la fonction mbedtls échouait, ne devrait-il pas y avoir d'erreur là-bas? L'étape logique suivante consiste à consulter la documentation de cette fonction.

Nous trouvons maintenant le premier véritable indice de ce qui pourrait se produire. mbedtls_x509_crt_parse_path () peut partiellement échouer et nous fournir un code retour qui ne déclenche pas d'erreur. Donc, il est temps d'utiliser printf () pour voir ce que ce code retour est sur ma machine. J'ai ajouté le code, compilé, exécuté le binaire de sortie… et je n'ai obtenu aucune telle sortie de journal.

Il m'a fallu plus de temps que je ne le reconnais pour comprendre pourquoi mes modifications de code ne semblaient pas faire de différence lors de l'exécution du programme. C'est un piège potentiel à surveiller. OBS utilise une structure modulaire, composée du binaire OBS, ainsi que de divers modules chargeables. Les changements de code que je faisais faisaient partie de obs-outputs.so, et même lors de l'exécution du binaire compilé, ces modules étaient chargés à partir de leurs emplacements par défaut. Pour tester mes modifications, j'ai dû explicitement dire à OBS d'utiliser le module nouvellement compilé.

Appels système qui détestent les liens symboliques

Quelque chose n'allait manifestement pas avec mbedtls_x509_crt_parse_path (). Je ne voyais rien d'évident dans la documentation, mais j'ai vu une fonction similaire, mbedtls_x509_crt_parse_file (). Que se passerait-il si nous obligions mbedtls à n'essayer que de charger le seul fichier crt qui nous tient à cœur? J'ai fait le changement, compilé, et à ma grande surprise, OBS s'est finalement connecté à Facebook Live. J'avais une vraie solution, mais je ne comprenais toujours pas pourquoi elle était cassée. Il est temps de regarder le code source mbedtls.

le parse_path () se trouve facilement dans l'arborescence source de mbedtls. Assurez-vous de regarder #si défini () blocs – Nous ne sommes pas intéressés par le code pour Windows. Une fois que nous avons trouvé la boucle qui s'exécute pour chaque fichier dans le chemin d'accès donné, le code du problème peut vous sauter dessus.

        
        
        
        sinon si (stat (nom_entrée, & sb) == -1)
        
            ret = MBEDTLS_ERR_X509_FILE_IO_ERROR;
            goto cleanup;
        

        if (! S_ISREG (sb.st_mode))
            continuer;

Stat () est un appel système qui obtient le statut d'un chemin de système de fichiers, puis S_ISREG est une macro qui vérifie si ce chemin pointe vers un fichier normal. Notamment, la fonction parse_file n'effectue pas cette vérification et charge volontiers un lien symbolique.

Signaler le bug, mais à qui?

C'est, bien sûr, le problème central. Fedora utilise un lien symbolique ca-bundle.crtet mbedtls refuse de charger ca-bundle.crt lorsqu'il s'agit d'un lien symbolique. Nous comprenons le problème, mais quelle est la bonne solution? Quel projet a réellement le bug ici? OBS a correctement utilisé la fonction mbedtls selon sa documentation, et mbedtls peut avoir une bonne raison de sécurité pour refuser de charger un bundle qui est en fait un lien symbolique. Est-ce sur RPMFusion et sur le mainteneur du paquet pour corriger l'incompatibilité? Personnellement, je pense que c'est vraiment un problème mbedtls, en particulier parce que cette bizarrerie n'est mentionnée dans aucune documentation que j'ai rencontrée. En fin de compte, ce n'est pas mon appel qui doit s'approprier ce problème.

Notre dernière tâche est alors de rapporter le bug que nous avons découvert. C’est une bonne idée d’arrêter à ce stade et de vous demander si ce bogue est un problème de sécurité potentiel? Il est préférable d'essayer de signaler les problèmes de sécurité en privé, et la plupart des projets ont des instructions de contact pour divulguer ce type de problèmes. Selon l'endroit où vous avez trouvé le problème, vous pourriez même avoir droit à une récompense de prime de bogue pour avoir trouvé le problème.

En supposant qu'il n'y ait aucun angle de sécurité à considérer, vous voudrez faire un rapport de bogue. Le projet a-t-il un traqueur de bogues public? C’est probablement là où ça devrait aller. Sinon, il existe probablement une liste de diffusion où des bogues sont signalés. Incluez suffisamment d'informations pour reproduire le bogue et des détails sur ce qui se passe, mais n'incluez pas un tas de journaux dans le bogue ou la liste de diffusion. Si cela est pertinent, utilisez pastebin ou l'un des autres sites d'hébergement de texte, pour éviter d'inclure un mur de texte dans le rapport de bogue. Si vous avez une idée de la façon de résoudre le problème, mentionnez-le. Sur une liste de diffusion, les correctifs sont généralement acceptés. Si le projet utilise Github ou Gitlab, vous pouvez signaler le bogue, faire demi-tour et soumettre une demande d'extraction pour le corriger.

En particulier pour les changements triviaux, j'ai tendance à demander ce que le projet préfère, si j'envoie une demande de tirage, ou est-ce assez trivial pour corriger sans une. Si vous cherchez à faire des travaux futurs sur le projet, faire un RP est un moyen pratique pour obtenir votre nom dans l'enregistrement git. Les projets sont plus susceptibles de regarder avec bonté votre futur travail, si vous avez déjà enregistré des bugs.

La fin d'un autre conte

Celui-ci s'est assez bien passé. OBS ajoute du code de contournement pour s'assurer que le ca-bundle est correctement chargé sur les systèmes où il s'agit d'un lien symbolique. Le projet mbedtls voit ce comportement comme un bogue, et j'ai soumis un correctif pour le corriger. J'ai remarqué un bogue logique connexe dans le code de chargement du certificat, et il a également été reconnu. J'ai corrigé ma copie d'OBS pour que les diffusions en direct fonctionnent à nouveau. C'est tout en une journée de travail pour l'administrateur système. Mais pas de repos pour les fatigués. J'ai une paire de cartes Ethernet 10 Go qui meurent chaque fois qu'elles transfèrent du trafic étiqueté VLAN. Juste un autre cas.

Errata

Je sais que les programmeurs les plus expérimentés le feront remarquer dans les commentaires, stat () ne définit jamais st_mode sur S_IFLNK. Stat () suit le lien symbolique pour signaler la cible, lstat () vous parle du lien symbolique lui-même. Ma solution a fonctionné, mais le problème était légèrement différent de ce que je pensais. Mbedtls_x509_crt_parse_path () peut renvoyer une valeur positive si seulement certains des fichiers du répertoire spécifié sont chargés avec succès. OBS traitait cette valeur positive comme un échec et rejetait immédiatement les certificats qui avaient été chargés. La poursuite de fausses pistes comme celle-ci est tout à fait normale pour la recherche et la correction de bugs. Au final, le bug est corrigé, et c'est ce qui compte vraiment. Maintenant, si vous voulez bien m'excuser, je dois trouver quelque chose pour laver le goût du corbeau de ma bouche.

Commentaires

Laisser un commentaire

Votre commentaire sera révisé par les administrateurs si besoin.