domingo, julio 15, 2012

El Luser que vive en la basura de mi Mac OS X

Hace ya un tiempo me topé con un comportamiento un poco extraño en mi Mac OS X Lion que no conocía, y que a día de hoy no llego a entender el porqué de que esto funcione de esta manera. He de decir que el comportamiento lo probamos también en Linux, y es análogo, y quisimos dedicarle algo más de tiempo, que a la postre nunca tuvimos.

La idea es bastante sencilla. Supongamos un usuario del sistema - en este caso se llama Luser - que tiene una carpeta en su $HOME a la que tiene conectada un sesión de terminal. Como se puede ver en  la figura 1.

Figura 1: El usuario Luser crea su nidito

En un determinado momento, mientras el usuario pace tranquilamente, el administrador del sistema, decide borrar esa carpeta y llevarla a la papelera. Como tiene privilegios puede hacerlo, por lo que la carpeta termina en el directorio .Thrash del usuario administrador, pero la sesión del usuario continúa viva.

Figura 2: El administrador borra la carpeta del usuario

Desde allí Luser puede continuar su existencia en la carpeta .Thrash, crear ficheros, y carpetas e invocar programas, tal y como se ve en la siguiente captura, por lo que podría montarse su propio ecosistema de trabajo en la basura del administrador.

Figura 3: El usuario sigue trabajando en la carpeta .Thrash del administrador

Aunque puede navegar hacia directorios hijos, hay cosas que no puede hacer, como subir a un directorio padre anterior o conectase a la carpeta con la ruta absoluta.

Figura 4: no se puede ir al directorio padre ni por ruta absoluta

Esta existencia en la basura podrá seguir hasta que la papelera se borre, momento en que el usuario se quedará con su shell, pero sin lugar donde acampar.  Es una existencia triste, pero una existencia al fin, en la carpeta de un administrador, que nunca está mal, ¿no?

Saludos Malignos!

7 comentarios:

  1. Esto es debido a la forma en que funcionan los sistemas de ficheros en sistemas *ix. Los ficheros y directorios se componen de dos partes: la entrada de directorio y el i-nodo. La entrada de directorio es la que la da nombre al fichero o carpeta y apunta al i-nodo, que contiene toda la información del elemento, como los bloques de disco que lo componen, permisos, etc. Fijaos que dos entradas de directorio diferentes pueden apuntar a un mismo i-nodo: esto es un hardlink. :D

    Con lo anterior, cuando se borra un fichero o directorio lo que se hace es borrar la entrada de directorio y descontar un contador de referencias del i-nodo, de forma que cuando no quedan referencias se borra también el propio i-nodo, desapareciendo definitivamente. Por tanto, si hay un hardlink, o sea, dos referencias, y borramos una, el i-nodo no desaparece, ya que se mantiene la otra.

    Ahora, ¿que sucede cuando abrimos una fichero o directorio? Pues que el sistema operativo busca la entrada de directorio, mira a que i-nodo apunta, y lo abre, incrementando el contador de referencias. Una vez hecho esto, podemos seguir trabajando con el fichero o directorio aunque se borre o renombre su entrada de directorio, ya que la entrada de directorio sólo se usa para abrir, no para trabajar con él. Además si se borra la entrada de directorio, al ser el contador de referencia uno más debido a que lo hemos abierto, el i-nodo no se borrará hasta que salgamos del directorio o cerremos el fichero.

    Esto permite otras cosas divertidas y muy convenientes en muchas ocasiones:

    - Puedo abrir un directorio y borrárlo luego, de forma que estoy dentro pero queda oculto a todos los efectos. Esto se puede usar para el mal }:-D o para el bien. Por ejemplo, puedo abrir un socket Unix para comunicar dos procesos y eliminarlo del sistema de ficheros, para que nadie más pueda usarlo.

    - También puedo mover o renombrar un fichero o directorio que está en uso, y su usuario no lo va a notar. Esto es lo que te está pasando al mover el directorio a la basura. Y fíjate que no solo el administrador puede hacer esto, también cualquier usuario con los permisos necesarios puede hacerlo.

    - Esto también puede servir para realizar rotación de ficheros de logs. Se renombra todo y luego se avisa al proceso de que tiene que volver a abrir el fichero de log.

    Bueno, con este rollazo espero haber aclarado el tema, y dado alguna idea sobre la potencia de este concepto. Por cierto, el modelo de bloqueo exclusivo de ficheros en Windows impide hacer lo mismo.

    ResponderEliminar
  2. @Xavi Rubio. Muchas gracias por la explicación detallada. Estuvimos investigando un poco el tema en su momento, y teníamos claro que era por diseño y el funcionamiento de los inodos.

    Bosquejamos incluso la posibilidad de hacer un brute force buscando ids de los inodos padre para poder tener el directorio a gusto, pero el tiempo nos comía.

    Esta situación en concreto nos pareció curiosa por el hecho de estar dentro de la carpeta de otro usuario.

    Gracias por el comentario. Saludos!

    ResponderEliminar
  3. que pasa cuando los directorios estan en particiones o discos distintos (donde mover cosas no es solo actualizar inodos sino copiar datos)? No se como de normal es en mac porque no he visto muchos Mac OS X servers, pero en servers linux es bastante normal que /home para los usuarios este en una particion distinta de /root.

    ResponderEliminar
  4. @Maligno: supongo que el tema de hacer un bruteforce podría funcionar, pero no tengo ni idea del rango de valores que puede tomar el número de i-nodo, así que probablemente serían bastantes millones. E igualmente diría que los permisos de acceso están en el propio i-nodo, así que si no puedes acceder de manera normal tampoco podrías acceder de la otra. Aunque conociéndote seguro que alguna historia se te ocurriría. ;)

    @palako: cuando estas en particiones distintas los hardlink no son posibles. Entonces tienes que usar symlinks (en sistemas *ix). Normalmente los directorios de las papeleras se encuentran en cada disco, y es el Finder (en el caso de OS X) quien los unifica en una sola vista de cara al usuario. De hecho, en OS X si borras algo en un pendrive el espacio no se libera (ya que va a la papelera del pendrive), y hasta que no la vacías no lo liberas, lo cual es un coñazo si quieres conservar la papelera del disco duro de sistema. Es una de las cosas que no me gustan de OS X, que no puedas borrar ficheros de la papelera, sino que tengas que vaciarla entera. Por eso yo muchas veces entro "a cuchillo" a borrarlo desde el shell, o a "vaciar" la papelera entrando desde el shell directamente al directorio y haciendo un rm. ;)

    ResponderEliminar
  5. @Xavi Rubio en el caso del inodo del padre, nuestra idea era; Estamos en directorio mierda, creamos el directorio mierda1, y nos movemos a él. ¿cómo volver a mierda en este esquema? Para ello queríamos ver si podemos sacar el inodo de mierda antes de ir a mierda1 y luego con él volver a mierda...

    Respecto a lo que dice Palako, con el USB parece claro, pero ¿en los HD también funciona así?

    Saludos!

    ResponderEliminar
  6. @Xavi,

    Cómo jode lo del pendrive... Me parece que al final todos vamos a cuchillo ;)

    ResponderEliminar
  7. @Maligno: El i-nodo del padre está referenciado mediante ".." (que es a su vez un hardlink!), aunque supongo que en el momento en que mierda1 se mueve a la papelera esta referencia se pierde. Supongo que la solución más fácil sería mantener toda la cadena de directorios abiertos, con un opendir() por ejemplo: http://linux.die.net/man/3/opendir O bien dejando procesos abiertos en cada directorio, como "miguitas de pan" ;)

    Respecto a lo de si esto pasa también en un disco duro la respuesta es si, los hardlink no funcionan entre discos (o particiones) en ningún caso. http://linux.die.net/man/2/link en el error EXDEV: "oldpath and newpath are not on the same mounted file system. (Linux permits a file system to be mounted at multiple points, but link() does not work across different mount points, even if the same file system is mounted on both.)"

    Saludos!

    ResponderEliminar