Webex pone un banner amarillo en la parte de arriba de la ventana. Offline - No internet connection. Los servicios de telefonía aparecen desconectados, no se sincroniza nada, y no puedes entrar en la reunión que empezó hace noventa segundos.
Eso no es una molestia cuando la cosa es tu teléfono de trabajo. Por Webex entran mis llamadas, y mi línea VoIP va por ahí, así que un cliente que no se autentica es un teléfono de mesa que no suena, una reunión en la que no estoy, y un compañero que acaba en el buzón. Me impidió trabajar. No más lento, no degradado. Parado.
Y nada de esto estaba en mi mano ni causarlo ni evitarlo. Una jornada de trabajo se torció por un control de calidad que no se aplicó, en un proveedor al que se le paga, en un producto vendido con contrato de soporte, contra una plataforma que su propia página de requisitos dice que está soportada. No configuré nada mal. Instalé el paquete del fabricante, desde el repositorio del fabricante, en una plataforma que el fabricante lista, y no pudo abrir una conexión TLS. Luego me gasté una tarde de mi propio tiempo en averiguar por qué, que es el tiempo que no gastó la gente que firmó el paquete.
La máquina no está desconectada. El navegador de al lado carga páginas. Tu correo llega, tu terminal descarga de un remoto, y si le preguntas al sistema operativo si llega a internet dice que sí. Webex está de acuerdo, en su propio registro, once segundos antes de decirte lo contrario.
Lo que ha pasado en realidad es que la copia de OpenSSL que Cisco incluye dentro de Webex no encuentra ni una sola autoridad de certificación, porque se compiló para buscarlas en /workspace/.conan2/p/b/cisco8ee8b59cf93de/p/ssl. Eso es un directorio de un contenedor de compilación de Cisco. Nunca ha existido en tu ordenador y nunca existirá. Toda conexión TLS de la aplicación falla en la verificación del certificado, el token de sesión no puede renovarse, expira un temporizador de quince segundos, y la interfaz echa mano de la única explicación para la que tiene una cadena de texto.
Así que el banner está equivocado de una manera concreta y poco útil. Señala tu red. El fallo es una ruta dentro de su compilación.
Esto es la versión 46.8.0.35631, en Fedora 44, kernel 7.2.4. Es una plataforma soportada. Cisco publica requisitos de sistema para Linux y entrega un .rpm firmado, webex-46.8.0.35631-1.x86_641. Lo que sigue es cómo demostrarlo en unos diez minutos, por qué no funciona ninguno de los arreglos obvios, el que sí, y luego la parte que importa más que todo lo anterior: esto no es un fallo sutil. Es una compilación que nadie ejecutó nunca en una máquina que no la hubiera construido.
Lo que el banner te dice en realidad
Webex mueve su indicador de conectividad con una máquina de estados compuesta, siete submáquinas con sus propios temporizadores. Al arrancar se inicializan así:
ConnectivityStateMachine::ConnectivityBanner - Initializing with state: Connected
ConnectivityStateMachine::Network - Initializing with state: NoNetwork
ConnectivityStateMachine::Services - Initializing with state: Connected
ConnectivityStateMachine::Mercury - Initializing with state: Disconnected
ConnectivityStateMachine::Authentication - Initializing with state: UserNotAuthenticated
ConnectivityStateMachine::Syncing - Initializing with state: Synced
ConnectivityStateMachine::Survivability - Initializing with state: SurvivabilityHide
Cuarenta milisegundos después el sistema operativo responde, y la aplicación lo anota:
NetworkManagerPowerNetworkWatcher.cpp:93 onConnectivityCheckSuccess::
The host is connected to a network, that appears to be able to reach the full Internet.
Esa línea está en el mismo archivo, en la misma sesión, que el banner que afirma que no hay conexión a internet. La aplicación lo sabía. Tenía la respuesta en la mano a las 08:25:12.131 y mostró lo contrario a las 08:25:27.132.
Entre esos dos momentos, esto:
| Hora | Qué pasó |
|---|---|
| 08:25:12.131 | El sistema operativo confirma acceso completo a internet |
| 08:25:12.218 | Detección de proxy: ninguno configurado, conexión directa |
| 08:25:12.241 | La primera petición HTTPS falla, errorCode: 167772294 Error in SSL handshake |
| 08:25:12.569 | La renovación del token de CloudApps falla, mismo código |
| 08:25:12.571 | La renovación del token de Kms falla, mismo código |
| 08:25:15.684 | Reintento, fallan las dos |
| 08:25:21.745 | Reintento, fallan las dos |
| 08:25:27.132 | Expira el temporizador de quince segundos, el banner pasa a NoInternet |
| 08:26:12.091 | Expiran los temporizadores de sesenta segundos, los servicios caen a DisconnectedShortTerm |
La submáquina de autenticación nunca sale de UserNotAuthenticated, así que Services se deduce como desconectado, así que salta el banner. Cada una de esas etapas es un comportamiento correcto dada la entrada. La entrada está mal, y la entrada es un número: 167772294, en cada petición fallida, desde la primera hasta la última.
Ese número es toda la entrada. Quédatelo.
Tres rutas, y ninguna existe
Webex no usa el OpenSSL del sistema. Trae el suyo, junto con su propia libcurl, y esa libcurl enlaza contra la incluida y no contra la tuya:
$ ldd /opt/Webex/bin/libcurl.so | grep -E 'ssl|crypto'
libssl.so.3 => /opt/Webex/bin/../lib/libssl.so.3
libcrypto.so.3 => /opt/Webex/bin/../lib/libcrypto.so.3
Hasta aquí bien. Incluir una biblioteca TLS propia es una decisión defendible y un montón de fabricantes lo hacen. Lo que importa es qué se coció dentro, y OpenSSL te lo dice si preguntas:
$ strings /opt/Webex/lib/libcrypto.so.3 | grep -E 'OPENSSLDIR|ENGINESDIR|MODULESDIR'
OPENSSLDIR: "/workspace/.conan2/p/b/cisco8ee8b59cf93de/p/ssl"
ENGINESDIR: "/workspace/.conan2/p/b/cisco8ee8b59cf93de/p/lib/engines-3"
MODULESDIR: "/workspace/.conan2/p/b/cisco8ee8b59cf93de/p/lib/ossl-modules"
Tres. No es un ajuste que se escapó. El prefijo de instalación entero, arrastrado desde la máquina que lo compiló, en una biblioteca que llega al cliente como paquete firmado en una plataforma soportada.
OPENSSLDIR se fija una vez, al configurar, con --openssldir, y la propia documentación de compilación de OpenSSL es tajante sobre para qué sirve: «Directory for OpenSSL configuration files, and also the default certificate and key store.»2 Todo lo que cuelga de la confianza cuelga de ahí. El archivo CA por defecto es cert.pem dentro y el directorio CA por defecto es certs dentro3. /workspace es una caché de compilación de Conan. Conan es el gestor de paquetes de C++ con el que compila Cisco, y guarda cada paquete bajo un hash de sus entradas de compilación4. El hash cisco8ee8b59cf93de es un hecho sobre un contenedor que probablemente se borró a los pocos minutos de terminar la compilación.
Pregúntale a la biblioteca qué es, y ni siquiera es OpenSSL de serie:
VERSION CiscoSSL 3.5.5.8.5.4 27 Jan 2026
BUILT_ON built on: Wed Feb 25 06:29:18 2026 UTC
PLATFORM platform: conan-Release-Linux-x86_64-gcc-13
DIR OPENSSLDIR: "/workspace/.conan2/p/b/cisco8ee8b59cf93de/p/ssl"
Un fork propio mantenido, con su propio esquema de versiones, compilado en febrero, entregado en agosto, y todavía arrastrando el directorio de trabajo en el que se hizo.
No te quedes con strings como respuesta. Pregúntale a la biblioteca
strings encuentra texto en un archivo. No demuestra que la biblioteca lo use. Así que carga la biblioteca incluida y pregúntale directamente, lo que lleva unas doce líneas de Python y ningún permiso de root:
import ctypes
c = ctypes.CDLL("/opt/Webex/lib/libcrypto.so.3")
for f in ("X509_get_default_cert_file", "X509_get_default_cert_dir",
"X509_get_default_cert_file_env", "X509_get_default_cert_dir_env"):
getattr(c, f).restype = ctypes.c_char_p
print(f"{f:34} {getattr(c, f)().decode()}")
X509_get_default_cert_file /workspace/.conan2/p/b/cisco8ee8b59cf93de/p/ssl/cert.pem
X509_get_default_cert_dir /workspace/.conan2/p/b/cisco8ee8b59cf93de/p/ssl/certs
X509_get_default_cert_file_env SSL_CERT_FILE
X509_get_default_cert_dir_env SSL_CERT_DIR
Ahí está, de boca de la propia biblioteca. Cuando algo dentro de Webex le pide a esta copia de OpenSSL el almacén de confianza por defecto, se le entrega un archivo y un directorio que no existen. Eso es lo que hace SSL_CTX_set_default_verify_paths, y es lo que hace casi cualquier cliente salvo que se le haya dicho otra cosa.
Las dos últimas líneas merecen atención, porque son la salida de emergencia: la biblioteca deja que SSL_CERT_FILE y SSL_CERT_DIR sobrescriban las dos5. Acuérdate también de eso. Se vuelve importante, y no de la manera que esperarías.
Reproducir el código de error exacto
La prueba por inspección no es prueba. Coge las libssl.so.3 y libcrypto.so.3 incluidas, haz un saludo TLS de verdad contra un servidor de verdad con nada más que los valores por defecto de la biblioteca, y mira qué vuelve.
La ejecución interesante es aquella en la que los valores por defecto no apuntan a nada. SSL_CERT_FILE y SSL_CERT_DIR sobrescriben exactamente los dos valores que un OPENSSLDIR ausente deja colgando, así que apuntarlos a una ruta que no existe reproduce la condición entregada con precisión:
$ SSL_CERT_FILE=/nonexistent/cert.pem SSL_CERT_DIR=/nonexistent/certs python3 tls.py
set_default_verify_paths -> 1
set_fd -> 1
SNI -> 1
SSL_connect -> -1 SSL_get_error -> 1
verify result 20: unable to get local issuer certificate
err: 0xa000086 error:0A000086:SSL routines::certificate verify failed
0x0A000086 en decimal es 167772294.
Ese es el número de cada línea fallida del registro de Webex, y no vino de Webex. Vino de la propia biblioteca TLS de Cisco, ejecutándose fuera de su aplicación, fallando por exactamente un motivo: no tenía anclas de confianza contra las que comprobar la cadena. Misma biblioteca, mismo error, ninguna aplicación de por medio.
Apunta esas dos mismas variables al paquete real de Fedora y el mismo camino de código llega hasta el final:
$ SSL_CERT_FILE=/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem python3 tls.py
SSL_connect -> 1 SSL_get_error -> 0
verify result 0: ok
Nada de la red cambió entre esas dos ejecuciones. Una ruta de archivo sí.
Por qué nada te avisó
Dos cosas se confabulan para que esto sea silencioso, y solo una de ellas es culpa de Cisco.
| Lo que nunca dice una palabra | Diseño de quién | Por qué se queda callado |
|---|---|---|
| Cargar un almacén de confianza que no está | De OpenSSL, deliberadamente | SSL_CTX_set_default_verify_paths devuelve 1 tanto si las rutas son reales como si no. «A missing default location is still treated as a success»3 |
| No tener nada a lo que recurrir | De Cisco, y correcto | Certificados validados, autofirmados rechazados, reintento SSL desactivado, así que no existe un modo degradado que enmascare un fallo |
Lo primero es razonable. Un programa que incluye sus propias anclas aparte no debería verse obligado a preocuparse, así que la llamada tiene éxito, el almacén está vacío, y en ninguna parte de la pila hay nada que diga he cargado cero autoridades de certificación. Lo primero que se entera es un fallo de verificación medio segundo después. Ejecuté esa llamada contra la biblioteca incluida con las rutas apuntando a /nonexistent y devolvió 1. Está en la salida de arriba.
Lo segundo es una política que baja desde el servicio, y el registro la deja escrita:
Wdm.cpp:1162 parseDeviceJson: Adding policy << allowSelfSignedCertificate with value: false
NetworkManager.cpp:1738 onConfigReady: ...httpRequestSSLRetryEnabled: 0
HttpRequestManager.cpp:1883 rawHttpRequest: {"validateCertificates":"true","useClientCertificate":"false"}
Esos tres interruptores son la única razón de que este fallo sea una caída y no algo mucho peor, y merece la pena quedarse ahí en vez de pasar de largo.
Piénsalo. La biblioteca incluida carga cero anclas de confianza, y nada por debajo de la capa de política iba a darse cuenta jamás, porque el fallo es silencioso por diseño de arriba abajo. Lo que lo convirtió en un banner fueron tres interruptores. Dale la vuelta a uno solo, como los entregan muchos clientes, y la misma compilación no falla en absoluto. Se conecta, a cualquier cosa que sostenga cualquier certificado, porque no tiene nada contra lo que comprobar uno.
El problema es cómo sale a la superficie. El usuario recibe «Offline - No internet connection». El registro recibe «Error in SSL handshake» y un entero decimal. La palabra certificado no aparece en ningún sitio donde vaya a mirar un usuario o un técnico de primer nivel, y la única miga de diagnóstico es un número que tienes que pasar a hexadecimal para que signifique algo.
Los arreglos que no funcionaron
Los dos obvios fallan, y las razones son distintas y ambas merecen conocerse.
Editar el openssl.cnf que viene incluido
Webex incluye un archivo de configuración en /opt/Webex/lib/openssl.cnf, y tal como se entrega activa un solo proveedor:
[provider_sect]
fips = fips_sect
Solo FIPS. No el proveedor default, que es donde viven los algoritmos TLS corrientes6. Volver a añadirlo es un cambio de una línea y no cambia absolutamente nada, porque el OpenSSL incluido nunca lee ese archivo. Busca openssl.cnf dentro de OPENSSLDIR7, y OPENSSLDIR es la ruta que no existe. El archivo está en el directorio de instalación con pinta de autoridad. Nada lo lee.
Es un segundo defecto escondido detrás del primero. Aunque el problema de la ruta se arreglara mañana apuntando OPENSSLDIR a /opt/Webex/lib, esta configuración se cargaría entonces y activaría solo FIPS. Y el propio módulo FIPS se carga desde MODULESDIR, la tercera ruta muerta del mismo árbol, así que el fips.so que viene en /opt/Webex/lib tampoco se encuentra. Tres rutas, un prefijo equivocado, y cada una rota de forma que esconde la siguiente.
Poner las variables de entorno
La biblioteca respeta SSL_CERT_FILE y SSL_CERT_DIR. Lo demostré arriba. La ejecución con éxito está ahí mismo. Así que el movimiento obvio es ponerlas en la entrada de escritorio, que es lo que se intentó:
Exec=env OPENSSL_CONF=/opt/Webex/lib/openssl.cnf \
SSL_CERT_FILE=/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem \
SSL_CERT_DIR=/etc/pki/tls/certs/ /opt/Webex/bin/CiscoCollabHost %U
Ningún cambio. Y la razón no es que Webex ignore las variables. La razón es que el proceso nunca las recibió:
$ tr '\0' '\n' < /proc/20293/environ | grep -E 'SSL|OPENSSL|CURL'
$ tr '\0' '\n' < /proc/20293/environ | wc -l
99
Noventa y nueve variables en el proceso de Webex en ejecución, y ni una sola de las tres que se habían puesto. Porque hay dos entradas de escritorio con el mismo nombre en esta máquina:
| Archivo | Qué ejecuta su línea Exec | Escrito por |
|---|---|---|
/usr/share/applications/webex.desktop | la línea env de tres variables de arriba, entera | el .rpm, luego editado a mano |
~/.local/share/applications/webex.desktop | /opt/Webex/bin/CiscoCollabHost %U, y ningún entorno | el propio lanzador de Webex |
Y la especificación no es ambigua sobre cuál gana: «The base directory defined by $XDG_DATA_HOME is considered more important than any of the base directories defined by $XDG_DATA_DIRS.»8 $XDG_DATA_HOME es ~/.local/share. La copia del usuario tapa a la del paquete, siempre, en cualquier escritorio que siga la especificación9.
Así que Webex instala una segunda copia de su propio lanzador en tu directorio personal, y esa copia es la que ejecuta tu escritorio. Cambia el archivo del paquete todo lo que quieras. Estás editando un documento que no lee nadie.
El arreglo que sí funciona
Si la biblioteca insiste en una ruta, dale la ruta. Crea el directorio que se compiló para querer y llénalo de enlaces simbólicos a lo de verdad:
#!/bin/bash
# Point the bundled CiscoSSL at the system trust store by building the
# directory it was compiled to look for. Tested: Fedora 44, Webex 46.8.0.35631.
set -euo pipefail
OPENSSLDIR=$(strings /opt/Webex/lib/libcrypto.so.3 \
| grep -oP '(?<=OPENSSLDIR: ")[^"]+')
[ -n "$OPENSSLDIR" ] || { echo "no OPENSSLDIR found in the shipped library"; exit 1; }
for p in /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem \
/etc/ssl/certs/ca-certificates.crt \
/etc/pki/tls/certs/ca-bundle.crt \
/etc/ssl/cert.pem; do
[ -f "$p" ] && { CA_BUNDLE="$p"; break; }
done
[ -n "${CA_BUNDLE:-}" ] || { echo "no system CA bundle found"; exit 1; }
echo "OPENSSLDIR: $OPENSSLDIR"
echo "CA bundle: $CA_BUNDLE"
sudo mkdir -p "$OPENSSLDIR"
sudo ln -sf "$CA_BUNDLE" "$OPENSSLDIR/cert.pem"
sudo ln -sf "$(dirname "$CA_BUNDLE")" "$OPENSSLDIR/certs"
sudo tee "$OPENSSLDIR/openssl.cnf" > /dev/null <<'CONF'
openssl_conf = openssl_init
[openssl_init]
providers = provider_sect
[provider_sect]
default = default_sect
fips = fips_sect
[default_sect]
activate = 1
CONF
echo "done. now restart Webex"
Reinícialo, y la misma secuencia de arranque produce el resultado contrario. El mismo binario. Las mismas líneas de registro. La renovación del token, que antes fallaba en menos de sesenta milisegundos, ahora termina en trescientos treinta:
AuthTokenRequester.cpp:579 Managed to fetch a new Kms access token.
AuthTokenRequester.cpp:579 Managed to fetch a new CloudApps access token.
AuthTokenSupervisor.cpp:310 Auth tokens refreshed. Expires in [64799 secs].
AuthenticationManager.cpp:1860 onUserAuthenticated: User authenticated.
ConnectivityStateMachine::Authentication - UserNotAuthenticated -> UserAuthenticated
Autenticado en unos 750 ms, así que el temporizador de quince segundos no salta nunca y el banner no aparece nunca. Los servicios de telefonía pasan de Disconnected a Connecting, un estado que la sesión rota no alcanzó en un minuto de intentos.
| Antes | Después | |
|---|---|---|
| Comprobación de red | pasa | pasa |
| Primera petición HTTPS | 167772294 Error in SSL handshake | HTTP 200 |
| Token de CloudApps | fallido | obtenido |
| Token de Kms | fallido | obtenido |
| Autenticación | atascada en UserNotAuthenticated | UserAuthenticated |
| Banner a los 15 s | «Offline - No internet connection» | ninguno |
| Servicios de telefonía | nunca intentados | conectando |
| Tiempo hasta autenticar | nunca | ~750 ms |
Fíjate en lo que el arreglo le hace a tu sistema de archivos, porque debería molestarte. Crea en tu máquina un directorio de primer nivel llamado /workspace, un nombre para el que el Filesystem Hierarchy Standard no tiene sitio10, con dentro una ruta de caché de Conan y un hash de compilación que pertenecen a una empresa a la que le compraste software. Esa es la forma del remedio que te ha dejado Cisco: montar el entorno de compilación de otro en la raíz del tuyo.
También se va a romper. De tres maneras:
| Cuándo se rompe | Por qué | Qué haces |
|---|---|---|
| Una actualización de Webex | cisco8ee8b59cf93de se deriva de las entradas de compilación, así que una dependencia recompilada significa un directorio nuevo | Volver a ejecutar el script; lee la ruta del binario nuevo en vez de suponer la vieja |
| Un cambio de distribución | El destino del enlace simbólico es una decisión de la distribución, no un estándar11 | Reapuntarlo; el script tantea cuatro ubicaciones conocidas |
| Una reinstalación | /workspace no lo respalda, empaqueta ni posee nada | Ejecutarlo otra vez, siempre, para siempre |
Nada de eso es mantenimiento. Eres tú haciendo de sustituto de un paso en la cadena de compilación de otro, indefinidamente, sin cobrar. Parchear un defecto en tiempo de ejecución, en cada máquina que tengas, porque el fabricante no quiso parchearlo una vez en tiempo de compilación.
Conocían la regla y la aplicaron a la mitad de la compilación
Aquí está lo que convierte esto de un informe de fallo en un argumento.
Lee la sección dinámica de los binarios entregados:
$ readelf -d /opt/Webex/bin/libcurl.so | grep RUNPATH
0x1d (RUNPATH) Library runpath: [$ORIGIN:$ORIGIN/../lib]
$ readelf -d /opt/Webex/bin/CiscoCollabHost | grep RUNPATH
0x1d (RUNPATH) Library runpath: [$ORIGIN/../lib]
$ORIGIN se expande en tiempo de carga al directorio que contiene el propio objeto12. Es la herramienta correcta para un paquete reubicable y la usaron bien. No les quedaba otra: Webex entrega el mismo árbol dos veces, una en /opt/Webex y otra en ~/.local/share/WebexLauncher/46.8.0.35631_9e6196c9-…/, y un lanzador elige entre ambos al arrancar. Dos prefijos, una compilación, y el enlazador encuentra sus bibliotecas en los dos.
Así que la gente que hizo este paquete entendía el problema exactamente. Las rutas absolutas no sobreviven a la entrega. Lo resolvieron para el código.
Luego dejaron las rutas de datos como cadenas absolutas que nombran el contenedor que las compiló. La misma compilación. La misma tarde.
Así que esto no se puede archivar bajo no lo sabían. En $ORIGIN no se tropieza uno. Se echa mano de él porque se ha entendido que una ruta absoluta cocida dentro de un artefacto entregado es un defecto, y se ha entendido lo bastante bien como para ir a arreglarlo en el enlazador. Y luego la misma compilación escribe tres rutas absolutas en las mismas bibliotecas, y las entrega.
Conocer la regla y aplicarla a la mitad de la compilación es peor que no conocerla. No saber es un problema de formación y la formación tiene solución. Esto es un paquete que llevaba dentro la idea correcta, por escrito, en la cabecera ELF donde cualquiera podía leerla, y salió por la puerta roto igualmente. Lo que te dice que nada por debajo del compilador estaba mirando el resultado. Nada lo hizo.
El contenedor ya estaba ahí
De dónde salió /workspace no es un misterio, y no hace falta adivinarlo. Está en la cabecera del paquete:
$ rpm -qi webex | grep -E 'Build Host|Build Date|Vendor'
Build Date : Sat 08 Aug 2026 20:47:43 BST
Build Host : c964ea9239ae
Vendor : Cisco
c964ea9239ae no es un nombre de host que haya tecleado nadie. Son doce caracteres hexadecimales, que es lo que un contenedor informa como nombre de host cuando nadie le pone uno. Así que el paquete se compiló dentro de un contenedor, por una empresa que claramente tiene las imágenes, el registro y la orquestación para hacerlo, y tres artefactos distintos en esta máquina lo dicen de forma independiente:
| Prueba, leída del paquete instalado | Valor | Qué demuestra |
|---|---|---|
Build Host en la cabecera del RPM | c964ea9239ae | un identificador de contenedor, no una máquina de compilación |
OPENSSLDIR en libcrypto.so.3 | /workspace/.conan2/… | una ruta que solo existe dentro de ese contenedor |
PLATFORM en la misma biblioteca | conan-Release-Linux-x86_64-gcc-13 | una cadena de herramientas Conan en contenedor |
Requires en el RPM | glibc >= 2.28 | un suelo de ABI muy antiguo, elegido a propósito |
Luego lo firmaron. La compilación terminó a las 20:47:43 y la firma está fechada a las 21:02:07 de esa misma tarde, identificador de clave 9995e5bbb5ccde3c. Quince minutos. Así que hay una puerta de publicación, alguien o algo la maneja, y lo que atestigua es quién hizo el paquete, no si el paquete funciona. Una firma es una declaración sobre la procedencia. Nunca ha sido una declaración sobre la aptitud, y un proceso que tiene una y no la otra tiene las prioridades en el orden equivocado.
Porque el paso que falta es el barato. El contenedor ya está en la cadena. Coge el artefacto que acaba de salir, arranca una imagen limpia de cada distribución que dices soportar, instálalo, lánzalo, y lee las primeras cien líneas del registro:
docker run --rm fedora:44 sh -c '
dnf -y install ./webex-46.8.0.35631-1.x86_64.rpm &&
timeout 25 /opt/Webex/bin/CiscoCollabHost &
sleep 20
grep -c "Error in SSL handshake" ~/.local/share/Webex/current_log.txt'
Distinto de cero, siempre, en esta compilación. La instalación son 1,1 GB, así que cuenta un minuto por objetivo con la caché caliente. Seis distribuciones son seis minutos de una máquina que ya está funcionando, en hardware que Cisco ya tiene, en una cadena que ya existe. No se hizo. Ni una sola vez.
Y esa es la respuesta a eso que la gente sigue diciendo de Linux, que soportar varias distribuciones es difícil. Dejó de ser difícil el día que llegaron estas herramientas, y las herramientas son las mismas con las que compilan. Una imagen base por objetivo. El mismo artefacto en cada una. La matriz es un bucle.
Una cadena que compila en un contenedor y nunca ejecuta el resultado en uno no es una cadena. Es un compilador con una tarea programada delante y una clave de firma detrás, y lo que produzca es una suposición.
¿Por qué una versión de 2026 se compila contra una libc de 2018?
El paquete declara lo que necesita, y la línea interesante es la primera:
$ rpm -q --requires webex | grep glibc
glibc >= 2.28
glibc 2.28 salió el 1 de agosto de 201813. Es la versión de Red Hat Enterprise Linux 814, una edición cuyo soporte completo terminó en 2024. Esto es un producto de 2026, compilado en 2026, apuntando a la biblioteca C de 2018. Y encima entregando su propia copia de 2,5 MB de libstdc++.so.6 en el directorio personal del usuario, porque el entorno de ejecución de C++ que acompaña a una base tan vieja no puede sostener el código.
¿Por qué iba nadie a seguir haciendo eso? Porque no quieren enlazar estáticamente.
Eso es todo. En el momento en que enlazas dinámicamente contra la biblioteca C del anfitrión, la distribución más antigua que estás dispuesto a soportar se convierte en una restricción sobre la máquina en la que compilas. No puedes usar un símbolo del que el objetivo más antiguo nunca ha oído hablar, así que clavas la compilación a una imagen base antigua y ahí te quedas. Cada año la brecha se ensancha. Cada función nueva de lenguaje o biblioteca llega con una discusión sobre si el suelo puede moverse. Entrega tu propia libstdc++ para tapar lo peor, y ahora además mantienes un entorno de ejecución privado.
Ese trato tenía sentido cuando un servidor de compilación era una máquina física en un armario que alguien tenía que reinstalar. Lleva una década sin tenerlo. Si tienes que enlazar contra la libc del anfitrión, un contenedor por objetivo te da una compilación real sobre una versión real de cada plataforma, y ninguna restringe a las demás.
Pero mira lo que la disciplina del objetivo antiguo compró aquí en realidad. Es conservadurismo de ABI a un coste considerable: un suelo de ocho años, un entorno de C++ incluido, una matriz de soporte congelada alrededor. Y el cliente sigue sin arrancar. Porque lo que se rompió fue una ruta de archivo, y ningún cuidado con las versiones de símbolos protege una ruta de archivo. Pagaron el impuesto de compatibilidad y el impuesto del empaquetado, y se saltaron la única comprobación que no cuesta nada. Las dos facturas. Ningún producto.
Pagaron por un paquete autónomo y no lo consiguieron
La manera de toda la vida de entregar software comercial en Linux es depender de lo menos posible del anfitrión. Estático donde puedas, un árbol autónomo donde no, y ninguna suposición sobre la distribución de debajo. No es elegante y nadie pretende que lo sea. Existe por culpa de la alternativa. Un binario que necesita una versión concreta de una biblioteca concreta en un sitio concreto convierte la máquina de cada cliente en un caso de soporte.
Cisco tomó la segunda vía y lo incluyó todo. Esta es la factura:
| Lo que contiene el paquete | Tamaño o número |
|---|---|
Objetos compartidos en /opt/Webex/lib | 150 |
| Su propia libcurl, CiscoSSL, zlib-ng, ICU, Kerberos, cliente CUPS, hunspell y motor de inferencia | todos |
Instalado en /opt/Webex | 1,1 GB |
Una segunda copia en ~/.local/share/WebexLauncher, por usuario | 1,1 GB |
| En disco para un cliente de chat y llamadas | 2,2 GB |
Dos gigabytes de dependencias. Ese es el precio completo de incluirlo todo: la descarga, el disco, la duplicación, la carga de seguridad de ser la única parte que puede parchear cualquiera de ellas, todo el lote. Paga eso y lo que compras es un programa al que le da igual lo que tenga instalado el anfitrión, que se comporta igual en Fedora y Debian y Arch y en lo que un cliente haya estandarizado este año, y que no puede romper una actualización de distribución de la que nunca oyó hablar.
Salvo que sí le da igual. Le importa muchísimo un directorio, y es un directorio de un servidor de compilación.
Entregaron su propio Kerberos y su propia ICU y su propio corrector ortográfico, y no supieron entregar una ruta funcional a los certificados. El propósito entero del paquete es ser autónomo, y no lo es en el único aspecto que lo deja sin funcionar. Cada uno de esos 1,1 GB se encuentra correctamente a través de $ORIGIN. Los cuarenta y pico bytes que más importan, no.
Y esta es la parte que me puede. Incluirlo todo es la opción cara. Asumieron el gasto, hicieron la ingeniería difícil, acertaron con la reubicación de ciento cincuenta bibliotecas en dos prefijos de instalación. Y luego apuntaron la única parte que decide si algo de eso funciona a una máquina que ningún cliente ha tenido jamás.
Tampoco lo documentó nadie
Junto al primer fallo hay un segundo, y es el que habría cazado al primero.
Pregúntale al paquete qué documentación entrega:
$ rpm -qd webex | wc -l
0
$ rpm -qc webex | wc -l
0
Ningún archivo de documentación. Y ningún archivo de configuración. Cero entradas marcadas %config en un paquete que entrega un openssl.cnf. Eso no es cosmético. Un RPM marca un archivo como %config para que el gestor de paquetes conserve lo que cambió el administrador, guardando un .rpmsave en vez de machacarlo1516. /opt/Webex/lib/openssl.cnf se entrega como archivo corriente, así que la siguiente actualización sobrescribe cualquier cambio que le hayas hecho y no te dice nada. El único archivo que un cliente podría necesitar ajustar legítimamente es el que el empaquetado trata como desechable.
Nada publicado dice qué almacén de confianza usa el cliente, qué variables de entorno respeta, ni de dónde lee su configuración TLS. No hay ninguna página que consultar. No se escribió ninguna. La única forma en que establecí algo de esto fueron strings, readelf, ldd y ctypes contra los binarios entregados. Aplicar ingeniería inversa a un producto soportado para responder a una pregunta que su documentación debería haber respondido en una frase.
Y esta es la razón por la que eso importa más de lo que parece. Escribir esa documentación es en sí una prueba. Pon a cualquiera del fabricante delante de una página en blanco titulada de dónde lee Webex para Linux sus certificados de autoridad, y lo primero que tiene que hacer es ir a mirar. En el momento en que mira, encuentra /workspace/.conan2/p/b/cisco8ee8b59cf93de/p/ssl, y lo siguiente que sale de él es una pregunta. Las rutas de configuración documentadas no son papeleo en beneficio del cliente. Son la auditoría más barata que un fabricante puede pasarle a su propia compilación, y saltársela es como una ruta así sobrevive hasta una publicación.
Nada de eso es mucho pedir. Di dónde vive tu configuración. Di qué variables de entorno respetas. Marca tus archivos de configuración como configuración para que una actualización no se los coma. Entonces el cliente que se topa con un fallo tiene dónde mirar que no sea un editor hexadecimal.
Nadie lo ejecutó
El paso que falta se ha nombrado suficientes veces arriba. Lo que merece preguntarse es por qué faltó en esta plataforma y no en las otras.
En Fedora no, desde luego. En macOS y en el Fisher-Price OS (Windows) esta clase de fallo no puede aparecer de la misma manera, porque esas plataformas tienen una pila TLS de sistema con un almacén de confianza que gestiona el sistema operativo. Linux no tiene tal cosa. OpenSSL es el almacén de confianza, y por tanto quien lo entrega es dueño de dónde mira. Así que la única plataforma donde la biblioteca incluida es la que aguanta es la plataforma que se entregó sin probar, que es una decisión sobre qué clientes merecen una prueba de humo.
Toda la investigación llevó una tarde: leer el registro, ver que la detección de red pasaba antes de que el banner afirmara lo contrario, sacar la ruta compilada del binario, reproducir el código de error exacto contra la biblioteca entregada. Todo ello con un agente de IA haciendo la correlación de registros y el andamiaje de ctypes mientras yo decidía qué preguntarle. Lo menciono por una razón: el diagnóstico que un fabricante nunca hizo antes de firmar este paquete y meterlo en su propio repositorio está ahora al alcance de una tarde para cualquier cliente con la paciencia de mirar. Los ingenieros de Cisco tienen Claude a su disposición igual que todo el mundo, y lo habría construido bien. No puedes pedirle que cueza /workspace/.conan2 dentro de un artefacto que se va a entregar sin que te diga qué va a pasar cuando el artefacto salga del workspace. Las herramientas para cazar esto ya no escasean, y el conocimiento tampoco. Lo que falta es alguien en el fabricante cuyo trabajo fuera mirar.
Mientras tanto, la vía de soporte para quien se topa con esto es un banner que dice que su internet está caído. Reiniciará el router. Llamará a su operador. Abrirá un aviso que no llevará a ninguna parte, porque el síntoma que Cisco eligió mostrar apunta lejos de Cisco.
Esa es la lista completa de lo que salió mal. Merece la pena decir cómo habría sido hacerlo bien, porque cada punto de ella tiene una respuesta asentada que es anterior a este producto.
Cómo debería haberse construido
Basta de lo que salió mal. Esta es la norma, y nada de ella es novedoso. Es lo que entregar un binario al ordenador de otra persona lleva veinte años pidiéndote.
Empieza por la decisión que Cisco acertó en el principio y erró en la ejecución: cuánto del anfitrión estás dispuesto a dar por supuesto. Enlazar estáticamente es la respuesta más fuerte, y merece la pena ser concreto, porque «pues enlázalo estáticamente» lo agitan quienes nunca han tenido que hacerlo y lo despachan quienes nunca lo han intentado.
| Qué elimina | Qué cuesta |
|---|---|
RUNPATH, y todas las formas de equivocarse con él, porque no hay búsqueda en tiempo de carga | glibc no enlaza limpiamente en estático: la resolución de nombres y usuarios pasa por dlopen, así que el binario sigue echando mano de los módulos NSS del anfitrión17 |
| El suelo de glibc, con lo que la distribución más antigua deja de dictar sobre qué puedes compilar | las partes LGPL traen una obligación de reenlazado, así que siguen dinámicas o entregas lo necesario para reenlazar |
Roturas por una actualización de distribución, una biblioteca renombrada o una caché de ldconfig obsoleta | Eres dueño de cada parche: ninguna actualización de seguridad de distribución llega a tus clientes |
El dlopen de un .so versionado desde un directorio que puede no estar | Una descarga mayor, y ningún reparto de páginas entre procesos |
Y una línea de la columna izquierda a la que las demás solo dan apoyo: el artefacto que produjo tu cadena es el artefacto que ejecuta el cliente, byte a byte. Pruébalo y habrás probado lo que entregaste. Esa es la propiedad cuya ausencia trata toda esta entrada.
La columna de la derecha merece honestidad. Costes reales, y la razón de que la gente eche mano de musl o acepte un híbrido. Pero mira la tercera fila. Ser dueño de cada parche se aplica igual a lo que Cisco ya hizo: un árbol incluido de 150 bibliotecas es el mismo compromiso sin ninguna de las garantías en tiempo de carga. Se apuntaron a ser dueños de cada parche de cualquier forma y no sacaron nada a cambio.
Así que la regla es sencilla, y es la regla que rompieron: lo que no puedas enlazar dentro, tienes que encontrarlo por una ruta relativa al binario. $ORIGIN para el código, y la misma disciplina, a propósito, para cada ruta de datos que la biblioteca vaya a buscar. En este caso son cuatro y cada una tiene un asidero documentado:
| Lo que la biblioteca va a buscar | Lo que se entregó | Lo que debería haber sido |
|---|---|---|
| Anclas de confianza | OPENSSLDIR/cert.pem, fijado al compilar | entregadas en el árbol, o SSL_CERT_FILE puesto al arrancar5 |
| Configuración | OPENSSLDIR/openssl.cnf, misma ruta, nunca encontrada | OPENSSL_CONF, apuntado a la copia del paquete5 |
| Proveedores, incluido FIPS | MODULESDIR, absoluto, así que fips.so es inalcanzable | OPENSSL_MODULES, «the directory from which cryptographic providers are loaded»5 |
| Motores | ENGINESDIR, absoluto | OPENSSL_ENGINES, o nada, ya que OpenSSL 4.0 retiró el soporte de motores por completo5 |
Cuatro rutas, cuatro variables de entorno, todas en una única página de manual que su propia biblioteca entrega. Si alguna cadena de tu artefacto empieza por / y se decidió al compilar, es un defecto esperando a que lo encuentre un cliente. No hay una tercera opción en la que una ruta de compilación absoluta esté bien.
Los arreglos para este, y la comprobación que lo caza
Del principio bajamos a este defecto concreto. Seis cambios, y ninguno es investigación:
| Arreglo | Esfuerzo | Por qué es lo correcto |
|---|---|---|
Poner --openssldir=/opt/Webex/lib/ssl y entregar el árbol | una opción de configuración | La ruta existe entonces en el paquete, que es para lo que está la opción2 |
Poner SSL_CERT_FILE/SSL_CERT_DIR en CiscoSSLUtils al arrancar, tanteando las rutas conocidas de las distribuciones | una docena de líneas | Estándar, documentado, ya soportado por su propia biblioteca5 |
| Entregar ellos mismos el paquete de CA dentro del paquete | solo empaquetado | Control total de la confianza, al precio de encargarse de su frescura |
Corregir el openssl.cnf para que active el proveedor default | una línea | Necesario de todos modos, y ahora mismo enmascarado por el fallo de ruta6 |
Marcar openssl.cnf como %config | una línea de spec | Evita que una actualización se coma en silencio el cambio de un administrador15 |
| Publicar las rutas y las variables respetadas | una página | La auditoría más barata que hay, y encuentra este fallo mientras se escribe |
El primero es el arreglo de una opción y habría entregado el producto funcionando. Es un único valor en un script de compilación, puesto una vez, que tuvieron mal porque nada aguas abajo lo comprobó jamás.
La comprobación es más pequeña que el arreglo:
# in CI, on the packaged artefact, in a clean container
test -d "$(strings lib/libcrypto.so.3 | grep -oP '(?<=OPENSSLDIR: ")[^"]+')" \
|| { echo "shipping a trust store path that does not exist"; exit 1; }
Una línea. Habría hecho fallar esta publicación a gritos, en febrero, en la máquina que la hizo, en el contenedor que la hizo, antes de que el paquete se firmara. La razón de que no esté no es la dificultad ni el coste. Es que a nadie se le pidió escribirla, y por tanto si el artefacto empaquetado se comportaba como software no era trabajo de nadie.
Lo que un proceso de compilación descuidado le cuesta a todos los demás
Todo lo anterior es el proceso de compilación de un producto visto por dentro, y no voy a repasártelo otra vez. La pregunta que merece la pena es si ese nivel de cuidado es probable que se pare en un equipo.
Así que pon al lado el registro de fuera. CISA mantiene un catálogo de vulnerabilidades que se sabe que se están explotando en el mundo real. No teóricas, no puntuadas. Observadas usándose contra gente. A 14 de septiembre de 2026 tiene 1 710 entradas18:
| Fabricante | Entradas en el catálogo KEV |
|---|---|
| Microsoft | 388 |
| Cisco | 98 |
| Apple | 94 |
| Adobe | 81 |
| 74 | |
| Oracle | 46 |
| Fortinet | 30 |
| VMware | 26 |
Segundo, por detrás de un monopolio de sistemas operativos y por delante de todos los demás. La entrada más reciente de Cisco entró el 14 de septiembre de 2026, el día antes de escribir esto.
Conté el mismo archivo tres semanas antes para /es/random/is-your-msp-lying-to-you-part2/: versión 2026.08.27, 1 685 entradas, Cisco en 96. Dos más desde entonces, en veintiún días.
Sé justo con lo que esa tabla demuestra y no demuestra por sí sola. Una base instalada grande en sitios de alto valor atrae atención, y la atención encuentra fallos, así que cualquier fabricante de ese tamaño arrastrará una lista larga. El número es un indicio previo, no un veredicto.
La composición es más difícil de despachar que el total. Veinticinco de las noventa y ocho de Cisco están en las líneas de seguridad: los cortafuegos, los equipos, los concentradores VPN, las pasarelas de correo y web, los servicios de identidad. Y las cuatro entradas más recientes contra ellos, seguidas, son Secure Firewall Management Center dos veces, Secure Firewall ASA, y Secure Email Gateway, esta última el 14 de septiembre de 202618. No los conmutadores. No el equipo de colaboración. Los productos vendidos específicamente para ser lo que mantiene seguro a todo el mundo.
Que es la frase hacia la que toda esta entrada venía caminando, así que aquí está sin rodeos. Esta es una empresa cuyo negocio es vender equipos de seguridad, y no consigue que un cliente de escritorio compruebe un certificado. No es un caso difícil. No es un ataque novedoso. La operación de seguridad más rutinaria de la informática, que hace cualquier navegador en cada carga de página, en una biblioteca que ellos mismos bifurcaron, y la entregaron apuntando a un directorio que nunca ha existido en una máquina de cliente. Y luego la firmaron.
Lo que esta entrada añade es una muestra del proceso que hay detrás. No una vulnerabilidad. Un simple defecto de empaquetado, la clase de fallo menos sutil que existe, en una plataforma soportada, cazable por cualquier prueba de humo que alguien se hubiera molestado en correr, y entregado igualmente. Si una cadena de compilación le pone eso delante a un cliente que paga, no está claro qué detendría. No lo detuvo nada.
¿Puedo preguntar por qué se firmó esto?
¿Puedo preguntar por qué un paquete que no puede completar un saludo TLS se firmó y se publicó contra una plataforma que vuestra propia página de requisitos lista como soportada? No quién lo firmó. No tengo interés en un nombre y no va de una persona. Qué lo permitió, porque algo lo hizo, quince minutos después de terminar la compilación, y sea lo que sea sigue funcionando hoy.
Ahora la versión sin rodeos. Esto no es un proyecto que me haya bajado de un repositorio público probando suerte. Está pagado. Detrás hay un contrato, una línea de soporte, una página de requisitos que hace una afirmación sobre Linux, y una clave de firma que asegura que el paquete viene de Cisco y es apto para instalarse. Cada una de esas cosas es una declaración a un cliente, y en esta publicación cada una valía cero, porque el resultado nunca se abrió.
Y la norma que se está incumpliendo aquí no es la mía. Es la vuestra. Las cuatro variables que habrían llevado esas rutas están documentadas en una página de manual que entregáis dentro del propio paquete. Vuestro propio formato de paquete tiene un marcador %config que no usasteis y una sección de documentación que dejasteis vacía. Vuestra propia compilación corrió en un contenedor que nunca usasteis para ejecutar la salida. No le estoy pidiendo a una empresa de redes y colaboración que invente nada. Estoy preguntando por qué no leyó sus propios manuales.
Así pues, la excusa que no voy a aceptar es que esto sea difícil. No es difícil para nadie, y desde luego no lo es para una empresa que hace esto a diario, a esta escala, por este dinero. Los profesionales que hacen esto todos los días no tienen excusa, y ser grande no es una.
Y ¿puedo hacer una más?, porque es la que de verdad importa. Vendéis cortafuegos. Vendéis una pasarela de correo, un concentrador VPN, un servicio de identidad, un centro de gestión para todo ello, y el argumento en todos es que entendéis esto mejor que vuestro cliente. Entonces, ¿cómo entrega una empresa que se presenta como autoridad en seguridad de redes un cliente incapaz de validar un certificado? No que falle al validarlo con astucia. Que no pueda buscar uno, porque el directorio nunca estuvo ahí.
No hay ninguna versión de esa respuesta que quiera oír que empiece por que el equipo de escritorio está separado del de equipos. Son la misma firma, la misma cadena, la misma afirmación publicada sobre una plataforma soportada, y el mismo paso que falta al final, que es abrir la caja. Si la validación de certificados no se comprueba antes de entregar en el producto donde la rotura es ruidosa e inofensiva, no tengo razón para creer que se comprueba en el producto donde la rotura es silenciosa y cara.
Y la parte honesta, dicha sin adornos. Nada de esto me sorprendió. He llegado a esperar este nivel de este fabricante, y por eso, donde la elección es mía, no compro su equipo ni construyo sobre él. Eso no es una preferencia por insignias. Es el mismo juicio que haría sobre cualquier proveedor: he medido su trabajo, más de una vez, y sale igual una y otra vez. El catálogo de arriba es una medición. Lo que costó la primera mitad de esta entrada es otra.
La razón de que yo estuviera en Webex es que la elección no era mía, y eso merece nombrarse, porque es la posición en la que está la mayoría de quienes leen esto. Rara vez puedes evitar a un fabricante cuya calidad ya has medido. Otro firma el contrato, el equipo llega, y el primero en enterarse de qué se saltaron en la compilación eres tú, en tu mesa, con una reunión empezando.
Entregar algo que nunca ejecutaste
Habrá una explicación interna. Un sprint cargado, una cadena que cambió de manos, una plataforma sin dueño. Ninguna merece oírse, porque todas describen lo mismo: el trabajo no se hizo y nada en el proceso exigía que se hiciera.
Hay una norma vieja en los oficios que nunca ha llegado al software: no te vas de la obra hasta haber puesto la cosa en marcha. Llenas la instalación y compruebas cada junta. Das tensión al cuadro y pruebas cada circuito. No porque dudes de tu trabajo. Porque el cliente va a usarlo, y enterarse delante de él no es un resultado profesional. Nadie te mira mientras lo haces. Lo haces igual. Ese es el significado entero de la palabra.
El software lleva treinta años argumentando que es distinto, que la compilación es el entregable y la instalación es problema de otro, que una cadena en verde es lo mismo que un producto que funciona, y no lo es. Una compilación que nunca se ha ejecutado fuera del contenedor que la produjo no se ha terminado, se ha abandonado en el punto en que terminar se vuelve aburrido. Todo lo que viene después es una afirmación sobre un trabajo que no se hizo.
El arreglo es una opción de configuración. La comprobación es una línea de shell. El coste de ninguna de las dos es lo interesante; el número interesante es cuánta gente tecleó sus credenciales en una ventana de Webex, la vio decir que su internet estaba caído, y se lo creyó, porque Cisco se lo decía y Cisco es una empresa de redes. Eso es lo que compró de verdad la prueba que faltaba: no un fallo, una mentira que el producto cuenta con aplomo, en cada arranque, a gente que no tiene manera de saber más.
Y esa es la línea que merece trazarse antes de cerrar la pestaña, porque las dos mitades de esta entrada no son dos temas. Una ruta de confianza que apunta a un contenedor de compilación y un salto de autenticación en un equipo de perímetro son el mismo fallo con distinto riesgo. Los dos son un valor que nadie comprobó, en un artefacto que nadie ejecutó, firmado por un proceso que atestigua procedencia y no aptitud. El que tuve delante era de la clase inofensiva. Se rompió a gritos, en mi propia mesa, y yo fui el primero en saberlo. La otra clase no te hace ese favor.
Nadie en Cisco decidió entregar un cortafuegos explotable, igual que nadie decidió entregar un cliente incapaz de llegar a internet. Eso no es una defensa. Es la acusación. Ninguno de los dos necesita decidirse, y ese es precisamente el problema: los dos son lo que sale por el otro extremo cuando una cadena compila, firma y publica sin que se haga a nadie responsable de abrir el resultado. Un proceso que no caza un directorio que no existe nunca iba a cazar una longitud que no se comprueba, y un fabricante que te vende el equipo que guarda tu perímetro no tiene derecho a ese proceso.
Así que cuando el nombre de un fabricante aparece una y otra vez en esa lista, resiste la explicación cómoda de que simplemente es grande y está muy apuntado. La escala explica el volumen. No explica la clase. Mira en cambio qué hace su proceso de compilación con las cosas aburridas, porque las cosas aburridas son medibles desde fuera, por ti, hoy, con material que ya tienes.
Comprueba tus propios paquetes. strings y readelf y veinte minutos te dirán cuáles de tus proveedores entregan una ruta a una máquina que nunca verás. Lo que estás midiendo en realidad no es la ruta. Es si allí había alguien mirando, y si la respuesta es no en algo tan barato de cazar, ya sabes cuál es en las cosas que no lo son.
Cisco — Webex App system requirements — la lista de plataformas soportadas, Linux incluido. ↩︎
OpenSSL — INSTALL.md,
--openssldir— «Directory for OpenSSL configuration files, and also the default certificate and key store.» ↩︎ ↩︎OpenSSL — SSL_CTX_load_verify_locations(3) — el archivo CA por defecto es
cert.pemy el directorio CA por defectocerts, ambos dentro del directorio OpenSSL por defecto; y sobre los valores de retorno, «A missing default location is still treated as a success.» ↩︎ ↩︎Conan 2 —
conan cache— los binarios de paquete viven bajo una ruta con hash en la caché local, de donde sale/workspace/.conan2/p/b/<hash>/p. ↩︎OpenSSL — openssl-env(7) —
SSL_CERT_DIRySSL_CERT_FILE«specify the default directory or file containing CA certificates». ↩︎ ↩︎ ↩︎ ↩︎ ↩︎ ↩︎OpenSSL — provider(7) — el proveedor por defecto y qué deja indisponible una configuración que lo omite. ↩︎ ↩︎
OpenSSL — config(5) — el archivo de configuración que OpenSSL carga al inicializarse, y dónde lo busca. ↩︎
freedesktop.org — XDG Base Directory Specification — «The base directory defined by
$XDG_DATA_HOMEis considered more important than any of the base directories defined by$XDG_DATA_DIRS.» ↩︎freedesktop.org — Desktop Entry Specification — dónde se buscan los archivos
.desktopy cómo uno tapa a otro del mismo nombre. ↩︎Filesystem Hierarchy Standard 3.0 — los directorios que se espera que contenga un sistema de archivos raíz, sin
/workspaceentre ellos. ↩︎update-ca-trust(8) — cómo se produce el paquete consolidado bajo
/etc/pki/ca-trust/extracteden Fedora y sus parientes. ↩︎ld.so(8) —
$ORIGINse expande al directorio que contiene el programa u objeto compartido, que es lo que hace reubicable un árbol incluido. ↩︎glibc timeline — «2018-08-01 GLIBC 2.28 — The GNU C Library version 2.28 is now available». ↩︎
glibc — Release wiki — la tabla de versión a distribución; Red Hat Enterprise Linux 8 es glibc 2.28. ↩︎
RPM — spec file reference —
%configy qué hace el gestor de paquetes con un archivo marcado como configuración. ↩︎ ↩︎Fedora packaging guidelines — configuration files — cuándo un archivo entregado debe marcarse como
%config. ↩︎glibc FAQ — por qué un binario de glibc enlazado estáticamente sigue necesitando los módulos NSS del anfitrión en tiempo de ejecución. ↩︎
CISA — Known Exploited Vulnerabilities Catalog — contado desde el flujo JSON publicado, versión de catálogo 2026.09.14, 1 710 entradas. ↩︎ ↩︎