Ikasten.IO
Learning, Aprendiendo

Disección del sistema de archivos ext3 11 Septiembre, 2010

He leído mucho sobre el funcionamiento interno del sistema de archivos ext3 y la verdad, hay muchos detalles que en distintos documentos no cuadran. Por otra parte, siendo uno de los sistemas de archivos más usados en el mundo Linux, creo que merece la pena dedicarle un artículo intentado poner por escrito, con un poco de orden y concierto, toda la información de la que dispongo.

Estructura interna de ext3

Antes de meternos en harina, conviene explicar algunos conceptos. El primero es el de inodo. Un inodo es una estructura de datos, asociada a cada fichero del sistema, que tiene el siguiente aspecto:

Original: http://www.sans.org/reading_room/whitepapers/forensics/advantage-ext3-journaling-file-system-forensic-investigation_2011

Ejemplo de inodo (Fuente: www.sans.org)

La estructura de un inodo ocupa 128 bytes y se usa para guardar metainformación sobre el fichero, directorio o enlace simbólico. En concreto:

* por una parte, algunos metadatos de un fichero (tiempos de acceso, creación, modificación), usuario y grupo al que pertenece, tamaño, y algunos datos más que no aparecen en la figura. Si el lector siente curiosidad, puede hurgar en el fichero /usr/src/linux-headers-2.6.32-24/include/linux/ext3_fs.h , en la estructura ext3_inode.

Nota: Ahí verá también que si el inodo representa un directorio, éste se trata como un fichero cuyo contenido es una lista ligada de (nombre de fichero del directorio, inodo de dicho fichero).

* por otra, punteros a los bloques de datos, es decir, al contenido propiamente dicho del fichero.
El lector aventajado seguro que se ha hecho la siguiente pregunta: “¿si un inodo sólo ocupa 128 bytes, cómo demonios podemos guardar punteros a los bloques de contenidos de aquellos ficheros realmente grandes? ¡No hay espacio!”

La solución es sencilla: indirección. En la imagen podemos ver que un inodo contiene 12 punteros directos a bloques. Es decir, los primeros 12*4096 bytes son directamente accesible. Pero a partir de ahí, tenemos que fijarnos en el siguiente bloque, el que tiene la etiqueta “Single indirect block pointer”. Ese puntero apunta a un bloque que en sus líneas contiene no el contenido del fichero, sino punteros al resto de los bloques de contenido. Es decir, es una indirección de primer nivel. ¿Que todavía no nos llega porque el fichero es grande de narices? No problem, en el inodo, tras el puntero al bloque de indirección de primer nivel, hay un puntero al bloque de indirección de 2º nivel. Es decir, apunta a un bloque que en sus líneas tiene punteros… pero no a contenido, sino a bloques con punteros, esta vez sí, a contenido. ¿Que no llega? Bueno, entonces habría que tirar del puntero de indirección de nivel 3. Y no hay más, así que más vale que ahora llegue 🙂

http://blogs.sans.org/computer-forensics/2008/12/24/understanding-indirect-blocks-in-unix-file-systems/

Indirección de bloques (Fuente: blog.sans.org)

No, en serio, un fichero de 4TB+ parecía algo de ciencia ficción cuando se ideó EXT3 – que tampoco hace tanto, Nov 2001 – , pero al parecer hoy en día ya no es ninguna tontería… (ahora mismo me viene a la cabeza alguna Rainbow Table que no andaría muy lejos)

Ooook, ya sabemos lo que es un inodo. ¿Pero dónde se guardan? ¿Cuántos hay en total?

Bien, sigamos profundizando. Si analizamos al detalle el contenido de un dispositivo (digamos una partición de disco) formateado con ext3, veremos al comienzo una estructura como la siguiente:

 estructura de un dispositivo con EXT3

Detalle de la estructura de un dispositivo con EXT3 (Fuente: cosecha propia). Pulsar para ampliar.

El superbloque ocupa normalmente 1024 bytes y está situado un poco después del comienzo de la partición (en concreto, a un offset o desplazamiento de 2*512 bytes = 1024 bytes) El superbloque guarda meta información sobre el dispositivo ext3: tamaño total, número de bloques, números inodos, tamaño de cada bloque, tamaño de cada grupo de bloques…

En esa última frase han aparecido nuevos conceptos. Uno de ellos es el de bloque. En ext3 tanto los metadatos como el contenido de los ficheros se guarda en bloques. El tamaño del bloque está definido en el superbloque pero suele ser de 4K (4.096 bytes).

La utilidad ext3grep se torna imprescindible si queremos “diseccionar” la partición desde la línea de comandos:

Por cuestiones de rendimiento, los bloques se agrupan en lo que se denomina grupos de bloques. Un grupo de bloques puede estar compuesto por miles de bloques, aunque el número exacto viene determinado en el superbloque.

Cada grupo de bloques comienza normalmente con una copia de respaldo del superbloque. Esto se hace así por seguridad: como hemos visto el superbloque contiene meta-información muy importante, y por tanto, ha de ser redundante (de otro modo, si se perdiera o corrompiera la única copia del superbloque perderíamos el control del dispositivo).

Si vemos el disco como una serie de bloques consecutivos, ¿en qué número de bloque comienza cada grupo de bloques? Bien, para responder a esa pregunta, tras el superbloque se sitúa la llamada “Tabla de Descriptores de Grupo”. Se puede ver como un array de grupos de 3 punteros: 1 puntero al primer bloque de cada grupo (o sea, un puntero al block bitmap), un puntero al segundo bloque de cada grupo (o sea, un puntero al inodes bitmap) y un tercer puntero al tercer bloque de cada grupo (o sea, a donde empieza realmente a guardarse información de cada fichero).

La siguiente figura puede aclararnos un poco este embrollo:

Tabla de Descriptores de Grupo

Tabla de Descriptores de Grupo (Fuente: cosecha propia)

Es decir, en la zona de descriptores guardamos, para cada grupo de bloques 3 punteros.

Para aquellos que lo vean mejor desde la línea de comandos, pueden probar con:

y verá algo como

A continuación, y ya que lo hemos citado varias veces, en cada grupo de bloques, tenemos un bitmap de bloques, que guarda 1 bit por cada bloque de ese grupo. Ese bit indica si el bloque está asignado o no. Lo mismo ocurre con el bitmap de inodos, indicando si el inodo está asignado o no. Aquí hay que aclarar que dado que un inodo ocupa 128 bytes (tamaño fijo), y que un bloque ocupa 4096 bytes, habrá 4096/128 = 32 inodos por bloque. Por otro lado, dado que el bloque “inode bitmap” puede guardar como máximo 4096 bytes * 8 bits/byte = 32768 bits, asumiendo que cada bit nos dice si un inodo está siendo usado o no, tendremos que en cada grupo hay, como máximo, 32768 posibles inodos. A 32 inodos/bloque salen 1024 bloques de inodos. ¿Y el resto de los bloques – hasta completar los 32768 posibles- ? El resto son bloques de datos.

Buff! si has llegado hasta aquí es que realmente te interesa el tema (¡y tienes buen café a mano!).

Lo siguiente que trataré es el archivo de Journaling, una excelente característica que aportó el sistema de archivos ext3 a su predecesor ext2 para conseguir mantener la consistencia del sistema de archivos ante “apagados fortuítos” de la forma  más eficiente posible. Pero eso será en el próximo capítulo 🙂

Referencias

El mejor documento sobre las tripas de ext3 que he visto es el de Carlo Wood, autor de la utilidad ext3grep, que usaremos en este artículo. Sin embargo, el documento de Wood no tiene ni un sólo gráfico explicativo, y tampoco se mete en mucho detalle al hablar del Journal (ya veremos qué es esto en el 2º capítulo). Otros documentos de interés y complementarios son:

How ext3grep can save you hours of work

Recovering deleted files with ext3grep

Why recovering a deleted ext3 file is difficult

Understanding indirect blocks in Unix File Systems

Taking advantage of Ext3 Journaling file system in a forensic investigation

Cómo recuperar datos en ext3

Tuning the Linux file system Ext3

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *