-
Un fallo que solo ocurría en ARM64
- Durante el proceso de portar el código de I/O de red de EdgeDB de Python a Rust, surgió un problema en el que las pruebas fallaban de forma intermitente en los runners de CI con ARM64.
- Al principio parecía un deadlock, pero en realidad el proceso se estaba cerrando por un crash y el runner de pruebas no lograba detectarlo.
-
Teoría inicial
- Para entender por qué el problema ocurría solo en ARM64, se consideraron las diferencias en el modelo de memoria.
- El modelo de memoria de Intel es estricto, mientras que ARM tiene un modelo de memoria más débil.
-
Depuración en la máquina de CI
- Se conectaron directamente al runner ARM64 en AWS para investigar el problema.
- El proceso se cerraba por un crash y dejaba un core dump, que se analizó para identificar la causa del problema.
-
La causa real: setenv y getenv
setenv no es seguro en entornos multihilo y puede provocar crashes al interactuar con getenv.
- Se descubrió que la reasignación de variables de entorno era la causa del problema.
-
Conexión con openssl_probe
- El problema ocurría cuando
openssl-probe configuraba las variables de entorno SSL_CERT_FILE y SSL_CERT_DIR.
- El crash se producía durante el proceso en que
rust-native-tls de Rust configuraba esas variables de entorno.
-
Por qué solo ocurrió en ARM64 Linux
- El crash solo ocurre cuando coinciden varias condiciones, entre ellas la cantidad de variables de entorno y fallos de I/O.
-
Solución
- Se decidió cambiar del backend
rust-native-tls/openssl de reqwest a rustls.
- El proyecto Rust planea volver inseguras las funciones de configuración del entorno, y el proyecto glibc mejorará la seguridad de
getenv en entornos multihilo.
4 comentarios
setenvno es thread-safe y C no quiere corregirloLa función
setenvestá causando problemas otra vez.Yo pondría el título como: "La falta de seguridad para hilos de la stdlib de C es algo que ni Rust, por muy seguro que sea, puede remediar". :)
Lo entendí claramente.
Comentarios de Hacker News
En la próxima edición de Rust, los modificadores del entorno pasarán a ser inseguros. Esto podría afectar a crates que provoquen conflictos
set_varyremove_varrequerirán usar un bloqueunsafe {}en la edición 2024Un parche para glibc hizo que
getenvfuera más seguro, pero C todavía permite acceso directo al entorno, así que no es completamente segurosetenvseguro para multihilo, pero como mínimo debería definirse una nueva API segura para hilosSufrir bugs relacionados con el entorno en Linux se considera casi un rito de paso
getenv_r(), sincronizarlo consetenv()y emitir advertencias al compilar/enlazar habría ayudado a resolver el problemaLa configuración mediante variables de entorno formó parte del movimiento de las "12-factor app", pero parece un método tonto
Las máquinas de CI que corren en Amazon AWS tienen la ventaja de ofrecer un usuario root real
Es un gran artículo que profundiza en un bug poco intuitivo
env::set_varahora es inseguroset_varniremove_varHace recordar una experiencia en la que
setproctitleno funcionaba en cierta base de códigonumpy,setproctitledejó de funcionar porque la dirección de environ cambió debido a una llamada agetenvosetenvdurante la inicialización denumpy