La idea, hay que reconocerlo, es buenísima: crear automáticamente el programa que explotará la vulnerabilidad que trata de solucionar un parche mediante la información del mismo parche. La generación se realiza a través de la comparación entre el programa parcheado y el original. El artículo que desarrolla las posibles técnicas es Automatic Patch-Based Exploit Generation is Possible: Techniques and Implications. Parece que la cosa últimamente va de diferencias binarias :) (como en Actualizando el kernel Linux sin reiniciar )
Más comentarios en Bruce Schneier: Reverse-Engineering Exploits from Patches, programming reddit: Automatic Patch-Based Exploit Generation y LtU: Automatic Patch-Based Exploit Generation.
Actualización: Como Apunta Drizzt en las publicaciones de la gente de bindiff se examina más detenidamente el tema de la comparación binaria. En la misma entrada Drizzt también aporta algún enlace más al respecto.
La misma entrada y más comentarios en Generación automática de "exploits" aprovechando los parches en barrapunto
martes, abril 29, 2008
lunes, abril 28, 2008
Entrevista a Mario Bunge
Nota: Si eres lector de planeta código y sólo te interesa el desarrollo, sáltate esta entrada. Pero es un enlace que me parece de interés general :)
Vía Cuchitril Literario me encuentro con una buena pero breve entrevista a Mario Bunge. En ella se dice de la filosofía de Heidegger:
Mario Bunge en la wikipedia
La misma entrada y más comentarios en Entrevista a Mario Bunge en barrapunto
Vía Cuchitril Literario me encuentro con una buena pero breve entrevista a Mario Bunge. En ella se dice de la filosofía de Heidegger:
[...] se aprovechó de la tradición académica alemana según la cual lo incomprensible es profundo.
[...] fenomenología, existencialismo, esas cosas abstrusas que nadie entiende pero si usted dice que no entiende, pasa por tontoO dicho de otro modo: no todas las veces que no entiendes algo es porque tú seas limitado. Plantéate que quizás no tenga ningún sentido...
Mario Bunge en la wikipedia
La misma entrada y más comentarios en Entrevista a Mario Bunge en barrapunto
Etiquetas:
ciencia,
existencialismo,
filosofía,
Mario Bunge
viernes, abril 25, 2008
Actualizando el kernel Linux sin reiniciar
Leyendo el blog de Daniel Stenberg me entero de que ksplice ofrece la posibilidad de hacer actualizaciones de seguridad en el kernel Linux sin reiniciar, siempre y cuando los cambios no supongan modificaciones semánticas en los datos. Según el autor este tipo de modificaciones son aproximadamente un 80% del total de vulnerabilidades críticas. Es, aparentemente, el sueño de muchos administradores de sistemas...
Más información en el artículo de presentación, Ksplice: An automatic system for rebootless Linux kernel security updates (pdf), en la lista del kernel, A system for rebootless kernel security updates y en programming.reddit.
Actualizando el kernel Linux sin reiniciar en barrapunto
Más información en el artículo de presentación, Ksplice: An automatic system for rebootless Linux kernel security updates (pdf), en la lista del kernel, A system for rebootless kernel security updates y en programming.reddit.
Actualizando el kernel Linux sin reiniciar en barrapunto
Etiquetas:
actualización,
en caliente,
hot fixes,
kernel,
linux,
reinicio,
seguridad
jueves, abril 24, 2008
La vida privada de volatile
El estándar de C(++) tiene unas cuantas esquinitas. Seguramente volatile es una de ellas. Para aclarar el significado exacto de este calificativo en Coding Relic han publicado La vida privada de volatile, en donde no solo se analiza la letra del estándar sino que se examina el código generado para MIPS en distintos casos.
Conviene recordar los posibles usos de volatile, así como para qué no debe usarse:
La vida privada de volatile en barrapunto
Conviene recordar los posibles usos de volatile, así como para qué no debe usarse:
- How does the C "volatile" keyword really work? de Ian Lance Taylor. El resumen es bastante claro
If you are using volatile for anything other than manipulating memory mapped hardware, or for very limited communication between threads, it is very likely that you are making a mistake. Think carefully about what volatile means and about what it does not mean.
- En la misma linea, Volatile: Almost Useless for Multi-Threaded Programming
- Varias discusiones en usenet: C++, volatile member functions, and threads, volatile guarantees? y Memory Barriers, Compiler Optimizations, etc., todas ellas en comp.programming.threads
- Una discusión sobre lo que es, que no es y que quizás debiera ser volatile en Should volatile Acquire Atomicity and Thread Visibility Semantics?, lo que lleva a arreglar el modelo de memoria de C++.
La vida privada de volatile en barrapunto
Etiquetas:
C,
C++,
C++0x,
corner case,
estándar,
hilos,
programación,
programadores,
threads,
volatile
miércoles, abril 09, 2008
La aritmética de punteros, su desbordamiento y la seguridad
Me he enterado vía el valle del viento helado de una nueva polémica acerca de gcc y su implementación. El hecho es que gcc cambió su comportamiento en cuanto a comparaciones entre punteros incrementados y ha provocado muchos meses después una alerta de seguridad desproporcionada y según los desarrolladores de gcc, falsa (Se puede oír desde aquí el ruido y la furia)
El caso es que, entrando en profundidad, es una optimización casi "trivial" que hace que p + C1 < p + C2 pase a ser C1 < C2 sin tener en cuenta el posible desbordamiento (overflow) de ambas operaciones. Hay que decir además que el estándar (de C y de C++) declara no definido el valor del resultado de la suma entre un puntero y un entero cuando se sobrepasa el tamaño del objeto al que apunta.
Es muy importante este último punto, porque deja traslucir un error de concepto: la comprobación de overflow propuesta en la alerta(*) es muy burda porque sólo se comprueba el desbordamiento de la operación aritmética, no que nos estamos saliendo del rango permitido. Sin embargo lo que deben saber el programador y el programa a la vez, cuando están manejando aritmética de punteros es cual es el desplazamiento (offset) máximo, de cuanta memoria se dispone. Si eso no lo sabe, es inútil cualquier otra comprobación...
Hay que hacer notar además que la optimización de la que se habla aquí la aplican casi todos los compiladores y lo que provoca la alerta es en realidad el cambio de comportamiento, no que sea incorrecto.
También recuerda esto que es muy mala política basar el código en detalles de implementación específicos de la plataforma. En este caso y en muchos otros, los desarrolladores de gcc tiran de cita del estándar para argumentar sus decisiones. Los usuarios se quejan, llamándoles abogados del lenguaje (language lawyer) pero en momentos como esos hay que recordar que probablemente están defendiendo sus decisiones de implementación y lo importante de esas decisiones para el éxito de una tecnología.
(*)char *buf;
int len;
len = 1 << 30;
if (buf+len < buf){ Overflow }
La aritmética de punteros, su desbordamiento y la seguridad en barrapunto
El caso es que, entrando en profundidad, es una optimización casi "trivial" que hace que p + C1 < p + C2 pase a ser C1 < C2 sin tener en cuenta el posible desbordamiento (overflow) de ambas operaciones. Hay que decir además que el estándar (de C y de C++) declara no definido el valor del resultado de la suma entre un puntero y un entero cuando se sobrepasa el tamaño del objeto al que apunta.
Es muy importante este último punto, porque deja traslucir un error de concepto: la comprobación de overflow propuesta en la alerta(*) es muy burda porque sólo se comprueba el desbordamiento de la operación aritmética, no que nos estamos saliendo del rango permitido. Sin embargo lo que deben saber el programador y el programa a la vez, cuando están manejando aritmética de punteros es cual es el desplazamiento (offset) máximo, de cuanta memoria se dispone. Si eso no lo sabe, es inútil cualquier otra comprobación...
Hay que hacer notar además que la optimización de la que se habla aquí la aplican casi todos los compiladores y lo que provoca la alerta es en realidad el cambio de comportamiento, no que sea incorrecto.
También recuerda esto que es muy mala política basar el código en detalles de implementación específicos de la plataforma. En este caso y en muchos otros, los desarrolladores de gcc tiran de cita del estándar para argumentar sus decisiones. Los usuarios se quejan, llamándoles abogados del lenguaje (language lawyer) pero en momentos como esos hay que recordar que probablemente están defendiendo sus decisiones de implementación y lo importante de esas decisiones para el éxito de una tecnología.
(*)char *buf;
int len;
len = 1 << 30;
if (buf+len < buf){ Overflow }
La aritmética de punteros, su desbordamiento y la seguridad en barrapunto
Etiquetas:
C,
C++,
estándar,
gcc,
programación,
programadores,
seguridad
martes, abril 01, 2008
Un par de enlaces más (sobre C++)
Sólo un par de enlaces más para complementar la entrada anterior, la entrevista con Stroustrup (lástima que hayan salido después, hubiesen quedado bien en la misma entrada...)
Un par de enlaces más (sobre C++) en barrapunto
- La entrevista de Strosutrup comentada en Slashdot, sobre todo desde el punto de vista de la enseñanza del lenguaje. Como siempre, comentarios a la vez encendidos e interesantes...
- Trip Report: February/March 2008 ISO C++ Standards Meeting de Herb Sutter en el que se repasa las últimas incorporaciones a C++0x. Destaca, por supuesto, la incorporación de funciones lambda y clausuras. Pero hay más, como la herencia de constructores...
Un par de enlaces más (sobre C++) en barrapunto
Etiquetas:
ANSI C++,
Bjarne Stroustrup,
C++,
C++0x,
clausura,
closure,
Herb Sutter,
ISO C++,
lambda
sábado, marzo 29, 2008
(Otra) entrevista a Stroustrup
Por si alguien había pensado que me había olvidado de C++0x y de Stroustrup esta entrada viene a demostrar que no :) Uno no tiene porqué estar de acuerdo con Bjarne Stroustrup, incluso puede odiar C++ por las milsetecientascincuetaydos razones por las que puede resultar odioso, pero lo que no se puede negar es que Bjarne ha tenido una gran influencia y sus opiniones son, por lo menos dignas de ser leídas. Algunas de las entrevistas que se le han hecho (incluso alguna que no le han hecho ;) ) me suelen parecer intensas y con elementos para la reflexión.
Pues bueno, en DDJ le han hecho una nueva entrevista. Extractaré lo que me ha interesado (Espero me sepan disculpar que no traduzca esta vez. Si me ha costado más de un mes hacer una nueva entrada no quiero imaginarme cuando publicaría esto con traducción...):
Sobre los distintos paradigmas de programación:
Sobre C++0x:
C++0x y el multithreading:
Consejos para el desarrollo en el mundo real. Me gusta especialmente cuando se recuerda el carácter complejo y casi orgánico de los sistemas (como Richard P. Gabriel en Objects Have Failed):
Vía programming.reddit.
"(Otra) entrevista a Stroustrup" en barrapunto
Pues bueno, en DDJ le han hecho una nueva entrevista. Extractaré lo que me ha interesado (Espero me sepan disculpar que no traduzca esta vez. Si me ha costado más de un mes hacer una nueva entrada no quiero imaginarme cuando publicaría esto con traducción...):
Sobre los distintos paradigmas de programación:
No programming paradigm is best for everything. What you have is a problem and a solution to it; then, you try to map that solution into code for execution. You do that with resource constraints and concerns for maintainability. Sometimes, that mapping is best done with OOP, sometimes with generic programming, sometimes with functional programming, etc.
OOP is appropriate where you can organize some key concepts into a hierarchy and manipulate the resulting classes through common base classes. Please note that I equate OO with the traditional use of encapsulation, inheritance, and (run time) polymorphism. You can choose alternative definitions, but this one is well-founded in history.
Sobre C++0x:
The progress on standard libraries has not been what I hoped for. We will get regular expressions, hash tables, threads, many improvements to the existing containers and algorithms, and a few more minor facilities. We will not get the networking library, the date and time library, or the file system library.
The standard will be finished in late 2008, but it takes forever to go through all the hoops of the ISO process. So, we must face the reality that "C++0x" may become C++10.
C++0x y el multithreading:
The new memory model and a task library was voted into C++0x in Kona. That provides a firm basis for share-memory multiprocessing as is essential for multicores. Unfortunately, it does not address higher-level models for concurrency such as thread pools and futures, shared memory parallel programming, or distributed memory parallel processing.
Consejos para el desarrollo en el mundo real. Me gusta especialmente cuando se recuerda el carácter complejo y casi orgánico de los sistemas (como Richard P. Gabriel en Objects Have Failed):
Think. Discuss with colleagues and potential users. Get a good first-order understanding of the problem domain. If possible, try to be a user of an existing system in that field. Then, without too much further agonizing, try to build a simplified system to try out the fundamental ideas of a design. That "simplified system" might become a throwaway experiment or it may become the nucleus of a complete system. I'm a great fan of the idea of "growing" a system from simpler, less complete, but working and tested systems. To try out all the tool chains before making too grand plans.Sobre las habilidades que les suelen faltar a los estudiantes:
I saw so many students who simply didn't have the notion that code itself is a topic of interest and that well-structured code is a major time saver. The notion of organizing code to be sure that it is correct and maybe even for someone else to use and modify is alien: They see code as simply something needed to hand in the answers to an exercise.
Vía programming.reddit.
"(Otra) entrevista a Stroustrup" en barrapunto
Etiquetas:
Bjarne Stroustrup,
C++,
C++09,
C++0x,
diseño,
programación,
programadores,
Stroustrup
miércoles, febrero 20, 2008
Firefox usará el asignador de memoria experimental de FreeBSD
Leo en (cómo no...) en programming.reddit que Firefox 3 beta 3 utiliza el asignador de memoria dinámica experimental de FreeBSD (jemalloc) en lugar del asignador de la plataforma de ejecución. Al parecer ha dado buenos resultados en cuanto velocidad y reducción de la fragmentación en los test de rendimiento para las tres plataformas mayoritarias (Windows, Mac OS X y Linux)
Para el que esté interesado en estos temas hay disponible un artículo muy interesante sobre jemalloc: A Scalable Concurrent malloc(3) Implementation for FreeBSD (pdf) en el que se explica su implementación, que coge ideas entre otros de hoard, y ciertamente tiene muy buena pinta. Hablé de hoard hace poco en Problemas de memoria (y algunas soluciones).
Firefox usará el asignador de memoria de FreeBSD en barrapunto
Para el que esté interesado en estos temas hay disponible un artículo muy interesante sobre jemalloc: A Scalable Concurrent malloc(3) Implementation for FreeBSD (pdf) en el que se explica su implementación, que coge ideas entre otros de hoard, y ciertamente tiene muy buena pinta. Hablé de hoard hace poco en Problemas de memoria (y algunas soluciones).
Firefox usará el asignador de memoria de FreeBSD en barrapunto
Etiquetas:
allocator,
asignador de memoria,
concurrencia,
firefox,
memoria
miércoles, febrero 13, 2008
Notas sobre errores fatales y portabilidad
Es escasa y dispersa la información que he encontrado acerca de la gestión de errores fatales en distintos sistemas operativos y lo que afecta al funcionamiento de los programas sobre ellos. Así que voy a juntar lo que he ido recopilando en una sola entrada. Puede ser un poco batiburrillo, pero igual le es de utilidad a alguien... (Para mi seguro, que así no pierdo los enlaces). Ordenadas de general a específico[1]:
[1]El orden es de mayor a menor, de general a específico. Debería ser obvio para un programador: a igualdad de condiciones, se debería usar lo que funcione en el estándar más aceptado y amplio ¿por qué limitar el ámbito de aplicación? Primero, buscar en ANSI, y si la funcionalidad no está elegir conscientemente una solución más específica. En el fondo para mi no es más que una consecuencia de la ley de Postel sobre el el código: "Cuanto más estricto (más estándar) es lo que escribes, más aumentarás la interoperabilidad". Puede parecer una obviedad, pero en esas pequeñas microdecisiones de los programadores no es nada extraño usar extensiones del estándar sin necesidad. Y en caso de necesidad se puede echar mano de librerías libres, muchas de ellas con un alto nivel de portabilidad.
[2]Pongo en cursiva normal porque entra la duda si en esos casos, de tan bajo nivel, una excepción, que se confunde con excepciones de de otro tipo, es lo más clarificador para el usuario-programador, máxime cuando el C++ estándar no posee excepciones para gestionar estos casos...
[3]Un blog que he descubierto hace poco... interesante. Además sobre el mismo tema: Beware of custom unhandled exception filters in DLLs y You might be using unhandled exception filters without even knowing it
[4]Cabe preguntarse porque se permite la ejecución del proceso en un caso tan excepcional... habida cuenta además de que una excepción no capturada de de C++ provoca, por defecto el fin del proceso... En este caso está sin duda justificado el Fail Fast: lo que hay que hacer es arreglar el programa, no dejarlo seguir...
(*)Me despisté al traducir. Gracias a Javier Noval por leerse los enlaces y hacerme notar el error ;)
Notas sobre errores fatales y portabilidad en barrapunto
- En ANSI C existe signal que permite cambiar la gestión este tipo eventos, entre los que se encuentran SIGSEGV, violación de segmento y SIGFPE, error aritmético. No obstante, por desgracia, su comportamiento en programas con más de un thread no está especificado. Además por si fuese poco ANSI tampoco especifica el handler por defecto, es decir, qué es lo que pasa si salta una señal de ese tipo.
- De hecho, de los que he probado, en windows con la librería de C del VisualStudio al menos, las señales funcionan por thread y en linux es global por proceso...
- En POSIX si que se define el comportamiento por defecto de las señales. En concreto SIGSEGV y SIGFPE abortan el proceso completo . Se pueden ver los comportamientos por defecto de las distintas señales en POSIX en la documentación de <signal.h> del OpenGroup. Además, POSIX(R) recomienda pasarse a sigaction (que sólo es POSIX(R), no ANSI).
- Windows NT no genera señal de violación de segmento, pero se le puede instalar handler
- En win32 un error fatal se gestiona como una excepción estructurada (SHE) que en C++ se mapea a un excepción normal[2]. Además, una excepción estructurada no capturada, por defecto, supone la muerte del thread en el que se produce, pero no del proceso global .
- Existe una forma de sobrescribir este comportamiento por defecto y es SetUnhandledExceptionFilter. Recomiendan en Nynaeve[3] no hacer cosas demasiado complicadas en el manejador, como parece lógico.
- En un artículo de DeveloperWorks comentan un modo de convertir señales en excepciones pero que es un hack completamente erróneo: C++ exception-handling tricks for Linux porque da a entender que se puede replicar el comportamiento por defecto de Windows. Sin embargo, como se puede leer en "Program Error Signals" de la documentación de la glibc:
La acción por defecto de todas estas señales es terminar el proceso. Si se bloquean o ignoran estas señales o se establece un handler que retorna normalmente, tu programa cascará espantosamente en el momento en que suceda la señal no ser que(*) haya sido generada a través de raise o kill en lugar de un error real.
cosa que he podido comprobar con el código de DW tratando de ignorar una violación de segmento. - En resumen, lo más juicioso (y homogéneo entre plataformas) sería parar el proceso completo en caso de uno de estos errores y tratar de informar lo más completamente posible del error. En caso de win32 habría que forzar el fin del proceso, ya que no es la acción por defecto[4].
[1]El orden es de mayor a menor, de general a específico. Debería ser obvio para un programador: a igualdad de condiciones, se debería usar lo que funcione en el estándar más aceptado y amplio ¿por qué limitar el ámbito de aplicación? Primero, buscar en ANSI, y si la funcionalidad no está elegir conscientemente una solución más específica. En el fondo para mi no es más que una consecuencia de la ley de Postel sobre el el código: "Cuanto más estricto (más estándar) es lo que escribes, más aumentarás la interoperabilidad". Puede parecer una obviedad, pero en esas pequeñas microdecisiones de los programadores no es nada extraño usar extensiones del estándar sin necesidad. Y en caso de necesidad se puede echar mano de librerías libres, muchas de ellas con un alto nivel de portabilidad.
[2]Pongo en cursiva normal porque entra la duda si en esos casos, de tan bajo nivel, una excepción, que se confunde con excepciones de de otro tipo, es lo más clarificador para el usuario-programador, máxime cuando el C++ estándar no posee excepciones para gestionar estos casos...
[3]Un blog que he descubierto hace poco... interesante. Además sobre el mismo tema: Beware of custom unhandled exception filters in DLLs y You might be using unhandled exception filters without even knowing it
[4]Cabe preguntarse porque se permite la ejecución del proceso en un caso tan excepcional... habida cuenta además de que una excepción no capturada de de C++ provoca, por defecto el fin del proceso... En este caso está sin duda justificado el Fail Fast: lo que hay que hacer es arreglar el programa, no dejarlo seguir...
(*)Me despisté al traducir. Gracias a Javier Noval por leerse los enlaces y hacerme notar el error ;)
Notas sobre errores fatales y portabilidad en barrapunto
Etiquetas:
ANSI C++,
C,
C++,
errores,
errores fatales,
estándar,
estándares,
planificador de linux,
POSIX,
Postel,
sistemas operativos,
UNIX,
win32,
Windows
lunes, febrero 04, 2008
(Otros) problemas con la memoria y (otras) soluciones
Alguien en programming.reddit hizo una pregunta de esas difíciles: ¿Cómo manejar en un programa en C los casos en los que la memoria se agota? Y digo que es una de esas preguntas difíciles porque depende del tipo de software que estás haciendo, de su criticidad y del nivel requerido de robustez. Ya se sabe, el difícil compromiso de la gestión de errores críticos.
Y como se ve en las respuestas de los redditenses no sólo depende de nuestro sistema, sino de detalles de implementación de más abajo, como suele ser usual en los casos no del todo raros en los que las abstracciones que usamos comienzan a flaquear. En este caso se habla del comportamiento de Linux (el kernel) a la hora de tratar la falta de memoria, que por defecto usa una estrategia optimista que deja reservar (pero no usar, claro) más memoria de la disponible. No obstante este comportamiento se puede cambiar a uno un poco más controlable a través del parámetro overcommit_memory, que se introdujo no hace tanto... El comportamiento por defecto es llamar al OOM Killer que es un método tan drástico como poco predecible. Todo esto esta muy bien explicado en When Linux Runs Out of Memory que vi referenciado por aquí en tiempos de mayor intensidad técnica :)
Además en las respuestas se apunta a un libro online de los que vienen bien cuando las condiciones son más extremas de lo usual: Small Memory Software. Patterns for systems with limited memory. Apuntado en éste mi del.icio.us particular.
(El título es "(Otros) problemas con la memoria y (otras) soluciones " porque no hace mucho escribí Problemas de memoria (y algunas soluciones), sobre el cuello de botella que supone la gestión de memoria sobre todo en sistemas multicore)
"(Otros) problemas con la memoria y (otras) soluciones" en barrapunto
Y como se ve en las respuestas de los redditenses no sólo depende de nuestro sistema, sino de detalles de implementación de más abajo, como suele ser usual en los casos no del todo raros en los que las abstracciones que usamos comienzan a flaquear. En este caso se habla del comportamiento de Linux (el kernel) a la hora de tratar la falta de memoria, que por defecto usa una estrategia optimista que deja reservar (pero no usar, claro) más memoria de la disponible. No obstante este comportamiento se puede cambiar a uno un poco más controlable a través del parámetro overcommit_memory, que se introdujo no hace tanto... El comportamiento por defecto es llamar al OOM Killer que es un método tan drástico como poco predecible. Todo esto esta muy bien explicado en When Linux Runs Out of Memory que vi referenciado por aquí en tiempos de mayor intensidad técnica :)
Además en las respuestas se apunta a un libro online de los que vienen bien cuando las condiciones son más extremas de lo usual: Small Memory Software. Patterns for systems with limited memory. Apuntado en éste mi del.icio.us particular.
(El título es "(Otros) problemas con la memoria y (otras) soluciones " porque no hace mucho escribí Problemas de memoria (y algunas soluciones), sobre el cuello de botella que supone la gestión de memoria sobre todo en sistemas multicore)
"(Otros) problemas con la memoria y (otras) soluciones" en barrapunto
Etiquetas:
abstracción no perfecta,
C,
C++,
errores,
memoria,
programación,
programadores,
tolerancia a fallos
Suscribirse a:
Entradas (Atom)
