¿Es seguro analizar un archivo / proc/?


Quiero analizar /proc/net/tcp/, pero es seguro?

¿Cómo debo abrir y leer archivos desde /proc/ y no tener miedo de que algún otro proceso (o el propio sistema operativo) lo cambie al mismo tiempo?

Author: Kiril Kirov, 2011-04-19

7 answers

En general, no. (Así que la mayoría de las respuestas aquí están equivocadas.) It might be safe, depending on what property you want. Pero es fácil terminar con errores en su código si asume demasiado sobre la consistencia de un archivo en /proc. Por ejemplo, vea este error que vino de asumir que /proc/mounts era una instantánea consistente.

Por ejemplo:

  • /proc/uptime es totalmente atómica, como alguien mencionó en otra respuesta -- pero solo desde Linux 2.6.30, que tiene menos de dos años. Así que incluso este pequeño archivo trivial estaba sujeto a una condición de carrera hasta entonces, y todavía está en la mayoría de los núcleos empresariales. Véase fs/proc/uptime.c para la fuente actual, o el commit que lo hizo atómico. En un kernel pre-2.6.30, puedes open el archivo, read un poco de él, entonces si luego regresas y read de nuevo, la pieza que obtienes será inconsistente con la primera pieza. (Acabo de demostrar esto try es por diversión.)

  • /proc/mounts es atómica dentro de una sola read llamada al sistema. Así que si read todo el archivo a la vez, se obtiene una sola instantánea coherente de los puntos de montaje en el sistema. Sin embargo, si usa varias llamadas al sistema read {y si el archivo es grande, esto es exactamente lo que sucederá si usa bibliotecas de E/S normales y no presta especial atención a este problema.estará sujeto a una condición de carrera. No solo no conseguirás un instantánea consistente, pero los puntos de montaje que estaban presentes antes de empezar y nunca dejaron de estar presentes podrían perderse en lo que ves. Para ver que es atómico para uno read(), mira m_start() en fs/namespace.c y vea que toma un semáforo que guarda la lista de puntos de montaje, que mantiene hasta m_stop(), que se llama cuando el read() se hace. Para ver qué puede salir mal, vea este error del año pasado (el mismo que enlacé anteriormente) en software de alta calidad que alegremente leer /proc/mounts.

  • /proc/net/tcp, que es el que realmente estás preguntando, es incluso menos consistente que eso. Es atómico solo dentro de cada fila de la tabla. Para ver esto, mira listening_get_next() en net/ipv4/tcp_ipv4.c y established_get_next() justo debajo en el mismo archivo, y ver los bloqueos que sacan en cada entrada a su vez. No tengo un código de reproducción a mano para demostrar la falta de consistencia de una fila a otra, pero no hay bloqueos allí (o cualquier otra cosa) que lo hagan coherente. Lo cual tiene sentido si lo piensas networking la red es a menudo una parte súper ocupada del sistema, por lo que no vale la pena la sobrecarga para presentar una vista consistente en esta herramienta de diagnóstico.

La otra pieza que mantiene /proc/net/tcp atómico dentro de cada fila es el búfer en seq_read(), que se puede leer en fs/seq_file.c. Esto asegura que una vez que read() forma parte de una fila, el texto de toda la fila se mantiene en un búfer para que la siguiente read() obtenga el resto de esa fila antes de comenzar uno nuevo. El mismo mecanismo se usa en /proc/mounts para mantener cada fila atómica incluso si haces múltiples llamadas read(), y también es el mecanismo que /proc/uptime en núcleos más nuevos usa para permanecer atómico. Ese mecanismo hace no buffer todo el archivo, porque el núcleo es cauteloso sobre el uso de memoria.

La mayoría de los archivos en /proc serán al menos tan consistentes como /proc/net/tcp, con cada fila una imagen consistente de una entrada en cualquier información que estén proporcionando, porque la mayoría de ellos utilice la misma abstracción seq_file. Como ilustra el ejemplo /proc/uptime, sin embargo, algunos archivos todavía se estaban migrando para usar seq_file tan recientemente como 2009; apuesto a que todavía hay algunos que usan mecanismos más antiguos y ni siquiera tienen ese nivel de atomicidad. Estas advertencias rara vez se documentan. Para un archivo dado, su única garantía es leer la fuente.

En el caso de /proc/net/tcp, puedes leerlo y analizar cada línea sin miedo. Pero si tratas de sacar conclusiones de múltiples líneas a la vez -- cuidado, otros procesos y el kernel están cambiándolo mientras lo lees, y probablemente estés creando un bug.

 104
Author: Greg Price,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-04 20:31:25

Aunque los archivos en /proc aparecen como archivos regulares en el espacio de usuario, no son realmente archivos, sino entidades que soportan las operaciones de archivos estándar desde el espacio de usuario (open, read, close). Tenga en cuenta que esto es bastante diferente a tener un archivo ordinario en el disco que está siendo cambiado por el núcleo.

Todo lo que hace el núcleo es imprimir su estado interno en su propia memoria usando una función similar a sprintf, y esa memoria se copia en el espacio de usuario cada vez que emite un read(2) llamada al sistema.

El núcleo maneja estas llamadas de una manera completamente diferente que para los archivos normales, lo que podría significar que toda la instantánea de los datos que leerá podría estar lista en el momento en que lo open(2), mientras que el núcleo se asegura de que las llamadas simultáneas sean consistentes y atómicas. No lo he leído en ninguna parte, pero no tiene sentido ser de otra manera.

Mi consejo es echar un vistazo a la implementación de un archivo proc en su sabor Unix particular. Esto es realmente un problema de implementación (al igual que el formato y el contenido de la salida) que no se rige por un estándar.

El ejemplo más simple sería la implementación de la uptime archivo proc en Linux. Observe cómo se produce todo el búfer en la función de devolución de llamada suministrada a single_open.

 42
Author: Blagovest Buyukliev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-11 08:19:14

/proc es un sistema de archivos virtual : de hecho, solo proporciona una vista conveniente de las funciones internas del núcleo. Definitivamente es seguro leerlo (por eso está aquí), pero es arriesgado a largo plazo, ya que el interno de estos archivos virtuales puede evolucionar con una versión más reciente del kernel.

EDITAR

Más información disponible en documentación proc en Linux kernel doc , capítulo 1.4 Redes No puedo encontrar si la información cómo la información evoluciona con el tiempo. Pensé que se congeló en abierto, pero no puede tener una respuesta definitiva.

EDIT2

De acuerdo con Sco doc (no linux, pero estoy bastante seguro de que todos los sabores de *nix se comportan así)

Aunque el estado del proceso y en consecuencia, el contenido de / proc los archivos pueden cambiar de instante a instantánea, una sola lectura (2) de a / proc el archivo está garantizado para devolver un representación "sana" del Estado, que es, la lectura será una atómica instantánea del estado de la proceso. Dicha garantía no se aplica a lecturas sucesivas aplicadas a a / proc archivo para un proceso en ejecución. En además, la atomicidad es específicamente no se garantiza ninguna E / S aplicada a el archivo as (espacio de direcciones); el contenido de la dirección de cualquier proceso el espacio puede modificarse simultáneamente por un LWP de ese proceso o cualquier otro proceso en el sistema.

 16
Author: Bruce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-19 08:40:32

La API procfs en el núcleo Linux proporciona una interfaz para asegurarse de que las lecturas devuelven datos consistentes. Lea los comentarios en __proc_file_read. Item 1) en el bloque de comentarios grandes explica esta interfaz.

Dicho esto, por supuesto depende de la implementación de un archivo proc específico usar esta interfaz correctamente para asegurarse de que sus datos devueltos sean consistentes. Por lo tanto, para responder a su pregunta: no, el núcleo no garantiza la consistencia de los archivos proc durante una lectura, pero proporciona los medios para que las implementaciones de esos archivos proporcionen consistencia.

 14
Author: Job,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-19 08:56:38

Tengo a mano el código fuente para Linux 2.6.27.8 ya que estoy desarrollando controladores en este momento en un destino ARM incrustado.

El archivo ...linux-2.6.27.8-lpc32xx/net/ipv4/raw.c en la línea 934 contiene, por ejemplo

    seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
            " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
            i, src, srcp, dest, destp, sp->sk_state,
            atomic_read(&sp->sk_wmem_alloc),
            atomic_read(&sp->sk_rmem_alloc),
            0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
            atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));

Que produce

[wally@zenetfedora ~]$ cat /proc/net/tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                     
   0: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 15160 1 f552de00 299
   1: 00000000:C775 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 13237 1 f552ca00 299
...

In function raw_sock_seq_show()que forma parte de una jerarquía de procfs funciones de manejo. El texto no se genera hasta que se hace una solicitud read() del archivo /proc/net/tcp, un mecanismo razonable ya que procfs las lecturas son seguramente mucho menos comunes que actualización de la información.

Algunos controladores (como el mío) implementan la función proc_read con un solo sprintf(). La complicación adicional en la implementación de los controladores principales es manejar una salida potencialmente muy larga que puede no caber en el búfer intermedio del espacio del núcleo durante una sola lectura.

Lo probé con un programa que usa un búfer de lectura de 64K, pero resulta en un búfer de espacio del núcleo de 3072 bytes en mi sistema para que proc_read devuelva los datos. Múltiples llamadas con avance se necesitan punteros para obtener más que esa cantidad de texto devuelto. No se cuál es la manera correcta de hacer que los datos devueltos sean consistentes cuando se necesita más de una e/s. Ciertamente cada entrada en /proc/net/tcp es auto-consistente. Existe cierta probabilidad de que las líneas de lado a lado sean instantáneas en diferentes momentos.

 6
Author: wallyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-20 04:57:16

A excepción de errores desconocidos, no hay condiciones de carrera en /proc que llevarían a la lectura de datos dañados o una mezcla de datos antiguos y nuevos. En este sentido, es seguro. Sin embargo, todavía existe la condición de carrera de que gran parte de los datos que se leen de /proc es potencialmente obsoleta tan pronto como se genera, e incluso más para el momento en que se llega a la lectura/procesamiento de la misma. Por ejemplo, los procesos pueden morir en cualquier momento y a un nuevo proceso se le puede asignar el mismo pid; los únicos ID de proceso que puede usar sin las condiciones de carrera son tus propios procesos hijos. Lo mismo ocurre con la información de la red (puertos abiertos, etc.) y realmente la mayor parte de la información en /proc. Consideraría una práctica mala y peligrosa confiar en que cualquier dato en /proc sea preciso, excepto los datos sobre su propio proceso y potencialmente sus procesos hijos. Por supuesto, todavía puede ser útil presentar otra información de /proc al usuario / administrador para información / registro / etc. propósito.

 3
Author: R..,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-19 12:41:19

Cuando lee desde un archivo /proc, el núcleo está llamando a una función que ha sido registrada de antemano para ser la función "read" para ese archivo proc. Vea la función __proc_file_read en fs/proc/generic.c.

Por lo tanto, la seguridad del proc read es tan segura como la función que el núcleo llama para satisfacer la solicitud de lectura. Si esa función bloquea correctamente todos los datos que toca y te devuelve en un búfer, entonces es completamente seguro leer usando esa función. Desde archivos proc como el que se utiliza para satisfacer las solicitudes de lectura a/proc/net / tcp ha existido por un tiempo y ha sido objeto de una revisión escrupulosa, son casi tan seguros como podría pedir. De hecho, muchas utilidades comunes de Linux se basan en leer desde el sistema de archivos proc y formatear la salida de una manera diferente. (En la parte superior de mi cabeza, creo que ' ps ' y 'netstat' hacen esto).

Como siempre, no tienes que creer en mi palabra; puedes mirar la fuente para calmar tus miedos. La siguiente documentación de proc_net_tcp.txt le indica dónde funcionan las funciones de" lectura " de /proc/net/tcp, para que pueda ver el código real que se ejecuta cuando lee ese archivo proc y verificar por sí mismo que no hay riesgos de bloqueo.

Este documento describe las interfaces /proc/net/tcp y /proc/net/tcp6.
Tenga en cuenta que estas interfaces son obsoleto a favor de tcp_diag. Estas interfaces / proc proporcionan información sobre TCP actualmente activo conexiones, y son ejecutadas por tcp4_seq_show () en net / ipv4 / tcp_ipv4.c y tcp6_seq_show() en net / ipv6 / tcp_ipv6.c, respectivamente.

 2
Author: heath,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-22 03:53:14