Implementación de Linux 'add_interrupt_randomness' - ¿baja contribución de entropía por ciclos y jiffies?

3

Actualmente estoy analizando el proceso de generación de entropía de un kernel de Linux de 64 bits durante el inicio del sistema (con fines educativos). El sistema está alojado como / en una máquina virtual (64 bits) (Xen domU). Para un análisis profundo, estoy siguiendo el estado de los parámetros de entrada relevantes, es decir, cómo se procesan. En la función add_interrupt_randomness encontré algún código cuya intención no me queda clara: el manejo de cycles (valor proporcionado por el contador de ciclos de CPU) y now (jiffies). Ambos son valores de 64 bits sin firmar y se procesan de la siguiente manera:

c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0;
j_high = (sizeof(now) > 4) ? now >> 32 : 0;
fast_pool->pool[0] ^= cycles ^ j_high ^ irq;

Entonces, c_high / j_high (__u32) se asignan con los 32 bits superiores de cycles / now y luego se asignan (después de XOR) al grupo de entropía rápida. Por lo tanto, una variación máxima de los valores proporcionados por c_high y j_high debería ser deseable. Pero como c_high y j_high se basan en cycles y now / jiffies, que son variables puramente incrementadas, hay muy poca / ninguna variación en los 32 bits superiores como los valores trazados revelan:

Valores en la llamada no. 1 de add_interrupt_randomness:

cycles:0xFFFEA432A6C2CB89
c_high:0xFFFEA432
now_jiffies:0x00000000FFFEDB0A
j_high:0x00000000

Valores en la llamada no. 4265 * de add_interrupt_randomness:

cycles:0xFFFEA43FBA85B313
c_high:0xFFFEA43F
now_jiffies:0x00000000FFFEE80C
j_high:0x00000000

* (el inicio se completa en este punto)

Durante el inicio del sistema, add_interrupt_randomness se llama 4265 veces. El valor de j_high es constantemente 0x00000000 , el valor de c_high incrementos de 0xFFFEA432 a 0xFFFEA43F .
Entonces mi pregunta es: ¿por qué se procesan los 32 bits superiores en lugar de los inferiores, lo que proporcionaría más aleatoriedad?

Si está interesado: esta es la definición completa de add_interrupt_randomness :

void add_interrupt_randomness(int irq, int irq_flags)
{
    struct entropy_store    *r;
    struct fast_pool    *fast_pool = this_cpu_ptr(&irq_randomness);
    struct pt_regs      *regs = get_irq_regs();
    unsigned long       now = jiffies;
    cycles_t        cycles = random_get_entropy();
    __u32           c_high, j_high;
    __u64           ip;
    unsigned long       seed;
    int         credit = 0;

    if (cycles == 0)
        cycles = get_reg(fast_pool, regs);
    c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0;
    j_high = (sizeof(now) > 4) ? now >> 32 : 0;
    fast_pool->pool[0] ^= cycles ^ j_high ^ irq;
    fast_pool->pool[1] ^= now ^ c_high;
    ip = regs ? instruction_pointer(regs) : _RET_IP_;
    fast_pool->pool[2] ^= ip;
    fast_pool->pool[3] ^= (sizeof(ip) > 4) ? ip >> 32 :
        get_reg(fast_pool, regs);

    fast_mix(fast_pool);
    add_interrupt_bench(cycles);

    if (!crng_ready()) {
        if ((fast_pool->count >= 64) &&
            crng_fast_load((char *) fast_pool->pool,
                   sizeof(fast_pool->pool))) {
            fast_pool->count = 0;
            fast_pool->last = now;
        }
        return;
    }

    if ((fast_pool->count < 64) &&
        !time_after(now, fast_pool->last + HZ))
        return;

    r = &input_pool;
    if (!spin_trylock(&r->lock))
        return;

    fast_pool->last = now;
    __mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool));

    /*
     * If we have architectural seed generator, produce a seed and
     * add it to the pool.  For the sake of paranoia don't let the
     * architectural seed generator dominate the input from the
     * interrupt noise.
     */
    if (arch_get_random_seed_long(&seed)) {
        __mix_pool_bytes(r, &seed, sizeof(seed));
        credit = 1;
    }
    spin_unlock(&r->lock);

    fast_pool->count = 0;

    /* award one bit for the contents of the fast pool */
    credit_entropy_bits(r, credit + 1);
}

de: enlace

    
pregunta OliverJL 27.02.2018 - 09:05
fuente

1 respuesta

4

Ambos se procesan.

Tanto cycles como now se mezclan en la agrupación rápida en su totalidad. Ver las líneas relevantes:

fast_pool->pool[0] ^= cycles ^ j_high ^ irq;
fast_pool->pool[1] ^= now ^ c_high;

Para distribuir aleatoriamente un bit, el número de ciclos de CPU * se mezcla con los bits altos del número de jiffies, y el número de jiffies se mezcla con los bits altos del número de ciclos. Incluso cuando esto sucede, la cantidad total de ciclos y jiffies se insertan en la agrupación rápida con la operación XOR. No hay c_low y j_low porque esos valores no se pierden. Los bits bajos están agregados.

La agrupación rápida se define como:

struct fast_pool {
    __u32           pool[4];
    unsigned long   last;
    unsigned short  reg_idx;
    unsigned char   count;
};

El grupo rápido contiene una matriz de cuatro valores de 32 bits. El contador de ciclos, almacenado como cycles_t , puede ser un valor de 64 bits ya que es definido como unsigned long , por lo que escribir solo el contador de ciclos en uno de los elementos de la agrupación descartará los bits altos. Esto no es ideal, por lo que los bits altos se obtienen por separado y se colocan en su propio entero de 32 bits que luego se agrega a la agrupación por sí solo, en efecto conserva el valor completo de 64 bits a pesar de que solo se puede mezclar en 32- bits a la vez. Como puede ver con las siguientes dos líneas, si los dos valores ya encajan en un solo entero de 32 bits, los 32 bits altos (no existentes) se establecen en 0:

c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0;
j_high = (sizeof(now) > 4) ? now >> 32 : 0;

El proceso es así:

  1. Si las variables son más grandes que 32 bits, guarde una copia de los bits altos, de lo contrario, establezca la copia en 0.
  2. Mezcle las variables con la agrupación rápida, descartando los bits altos durante conversión de enteros .
  3. Mezcle los bits altos guardados, en efecto "plegando" los bits bajos y altos en un solo entero de 32 bits.

* En algunas arquitecturas, como ciertas versiones de MIPS , es posible que el contador de ciclos no esté disponible.

    
respondido por el forest 27.02.2018 - 09:21
fuente

Lea otras preguntas en las etiquetas