L'entropia non si perde solo con /dev/{,u}random
, anche il kernel ne prende alcuni. Ad esempio, i nuovi processi hanno indirizzi randomizzati (ASLR) ei pacchetti di rete necessitano di numeri di sequenza casuali. Anche il modulo del filesystem può rimuovere un po' di entropia. Vedi i commenti in drivers/char/random.c. Nota anche che entropy_avail
si riferisce al pool di input, non ai pool di output (fondamentalmente il /dev/urandom
non bloccante e il blocco /dev/random
).
Se hai bisogno di guardare il pool di entropia, non usare watch cat
, che consumerà entropia ad ogni invocazione di cat
. In passato volevo anche guardare questo pool poiché GPG era molto lento nel generare chiavi, quindi ho scritto un programma C con l'unico scopo di guardare il pool di entropia:https://git.lekensteyn.nl/c-files/tree /entropy-watcher.c.
Si noti che potrebbero esserci processi in background che consumano anche entropia. Usando i tracepoint su un kernel appropriato puoi vedere i processi che modificano il pool di entropia. Esempio di utilizzo che registra tutti i tracepoint relativi al sottosistema casuale inclusa la callchain (-g
) su tutte le CPU (-a
) che inizia a misurare dopo 1 secondo per ignorare il proprio processo (-D 1000
) e inclusi i timestamp (-T
):
sudo perf record -e random:\* -g -a -D 1000 -T sleep 60
Leggilo con uno di questi comandi (cambia proprietario di perf.data
secondo necessità):
perf report # opens an interactive overview
perf script # outputs events after each other with traces
Il perf script
output fornisce una visione interessante e mostra quando circa 8 byte (64 bit) di entropia vengono periodicamente scaricati sulla mia macchina:
kworker/0:2 193 [000] 3292.235908: random:extract_entropy: ffffffff8173e956 pool: nbytes 8 entropy_count 921 caller _xfer_secondary_pool 5eb857 extract_entropy (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 5eb984 _xfer_secondary_pool (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 5ebae6 push_to_pool (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 293a05 process_one_work (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 293ce8 worker_thread (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 299998 kthread (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 7c7482 ret_from_fork (/lib/modules/4.6.2-1-ARCH/build/vmlinux) kworker/0:2 193 [000] 3292.235911: random:debit_entropy: ffffffff8173e956: debit_bits 64 5eb3e8 account.part.12 (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 5eb770 extract_entropy (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 5eb984 _xfer_secondary_pool (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 5ebae6 push_to_pool (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 293a05 process_one_work (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 293ce8 worker_thread (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 299998 kthread (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 7c7482 ret_from_fork (/lib/modules/4.6.2-1-ARCH/build/vmlinux) ... swapper 0 [002] 3292.507720: random:credit_entropy_bits: ffffffff8173e956 pool: bits 2 entropy_count 859 entropy_total 2 caller add_interrupt_randomness 5eaab6 credit_entropy_bits (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 5ec644 add_interrupt_randomness (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 2d5729 handle_irq_event_percpu (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 2d58b9 handle_irq_event (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 2d8d1b handle_edge_irq (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 230e6a handle_irq (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 7c9abb do_IRQ (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 7c7bc2 ret_from_intr (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 6756c7 cpuidle_enter (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 2bd9fa call_cpuidle (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 2bde18 cpu_startup_entry (/lib/modules/4.6.2-1-ARCH/build/vmlinux) 2510e5 start_secondary (/lib/modules/4.6.2-1-ARCH/build/vmlinux)
Apparentemente questo accade per prevenire lo spreco di entropia trasferendo l'entropia dal pool di input ai pool di output:
/*
* Credit (or debit) the entropy store with n bits of entropy.
* Use credit_entropy_bits_safe() if the value comes from userspace
* or otherwise should be checked for extreme values.
*/
static void credit_entropy_bits(struct entropy_store *r, int nbits)
{
...
/* If the input pool is getting full, send some
* entropy to the two output pools, flipping back and
* forth between them, until the output pools are 75%
* full.
*/
...
schedule_work(&last->push_work);
}
/*
* Used as a workqueue function so that when the input pool is getting
* full, we can "spill over" some entropy to the output pools. That
* way the output pools can store some of the excess entropy instead
* of letting it go to waste.
*/
static void push_to_pool(struct work_struct *work)
{
...
}
lsof non è lo strumento migliore per monitorare /dev/random
come una lettura da parte di un processo finisce in un molto breve lasso di tempo. Non conosco un buon metodo per ottenere quale processo sta eseguendo una lettura, ma usando inotify
puoi monitorare se c'è una lettura.
Qui ci sono fondamentalmente due modi:
-
Ottieni un riepilogo dopo N secondi con:
inotifywatch -v -t 60 /dev/random
-
Visualizza dal vivo eventi di accesso:
inotifywait -m --timefmt '%H:%M:%S' --format '%T: %e' /dev/random
Nessuno dei due ti darà un processo e quest'ultimo non ti darà la dimensione della lettura. Il primo ti fornirà un riepilogo come in:
total access close_nowrite open filename
18 16 1 1 /dev/random
Se lo hai in esecuzione e fai un dd if=/dev/random of=/tmp/foo bs=1 count=3
, hai capito.
Comunque. Questo non ti darà tick quando il kernel consuma dal pool.
Quando si tratta di controllare lo stato dell'entropia utilizzando
watch cat /proc/sys/kernel/random/entropy_avail
non è la migliore idea dato che ogni cat
consumerà entropia. (Vedo ora che è spuntata un'altra risposta che menziona anche questo.) Ho anche del codice C per questo e ho provato a individuarlo ieri. Vedrò se riesco a trovarlo e aggiornerò la risposta più tardi.