Implementazione Linux add_interrupt_randomness - contributo di bassa entropia per cicli e jiffies?

3

Attualmente sto analizzando il processo di generazione entropica di un kernel Linux a 64 bit durante l'avvio del sistema (per scopi didattici). Il sistema è ospitato come / su una macchina virtuale (64 bit) (Xen domU). Per un'analisi approfondita, sto monitorando lo stato dei parametri di input rilevanti, ovvero come vengono elaborati. Nella funzione add_interrupt_randomness ho trovato un codice la cui intenzione non mi è chiara: la gestione di cycles (valore fornito dal contatore dei cicli della CPU) e now (jiffies). Entrambi sono valori a 64 bit senza segno ed elaborati come segue:

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

Così c_high / j_high (__u32) sono assegnati con il massimo 32 bit di cycles / now e quindi assegnati (dopo XOR) al pool di entropia veloce. Quindi una variazione massima dei valori forniti da c_high e j_high dovrebbe essere desiderabile ?. Ma poiché c_high e j_high sono basati su cycles e now / jiffies, che sono variabili puramente incrementate, c'è una variazione molto piccola / nessuna nei 32 bit superiori come rivelano i valori tracciati:

Valori nella chiamata n. 1 di add_interrupt_randomness:

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

Valori nella chiamata n. 4265 * di add_interrupt_randomness:

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

* (l'avvio è completato a questo punto)

Durante l'avvio del sistema add_interrupt_randomness è chiamato 4265 volte. Il valore di j_high è costantemente 0x00000000 , il valore di c_high incrementi da 0xFFFEA432 a 0xFFFEA43F .
Quindi la mia domanda è: perché i 32 bit superiori vengono elaborati al posto di quelli più bassi, il che fornirebbe maggiore casualità?

Se interessati: questa è la definizione completa di 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);
}

da: link

    
posta OliverJL 27.02.2018 - 09:05
fonte

1 risposta

4

Sono entrambi elaborati.

Sia cycles che now sono mescolati nel pool veloce nella loro interezza. Vedi le righe pertinenti:

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

Per distribuire un po 'la casualità, il numero di cicli della CPU * è mescolato con i bit più alti del numero di jiffies e il numero di jiffies è mescolato con i bit più alti del numero di cicli. Anche quando ciò accade, il numero completo di cicli e jiffies viene inserito nel pool veloce con l'operazione XOR. Non c'è c_low e j_low perché questi valori non vengono persi. I bit bassi sono aggiunti.

Il pool veloce è definito come:

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

Il pool veloce contiene una matrice di quattro valori a 32 bit. Il contatore del ciclo, memorizzato come cycles_t , può essere un valore a 64 bit poiché è definito come unsigned long , quindi scrivere solo il contatore del ciclo su uno degli elementi del pool eliminerà i bit alti. Questo non è l'ideale, quindi i bit alti vengono ottenuti separatamente e inseriti nel proprio numero intero a 32 bit che viene poi aggiunto al pool da solo, in effetti preservando l'intero valore a 64 bit nonostante sia solo in grado di mixare in 32- bit alla volta. Come puoi vedere con le due righe seguenti, se i due valori sono già contenuti in un singolo numero intero a 32 bit, i 32 bit (inesistenti) sono impostati su 0:

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

Il processo è quindi:

  1. Se le variabili sono maggiori di 32 bit, salva una copia dei bit più alti, altrimenti imposta la copia su 0.
  2. Mescola le variabili con il pool veloce, scartando i bit alti durante la conversione intera .
  3. Mescola i bit alti salvati, in effetti "ripiega" i bit basso e alto in un singolo intero a 32 bit.

* Su alcune architetture, come alcune versioni di MIPS , il contatore di cicli potrebbe non essere disponibile.

    
risposta data 27.02.2018 - 09:21
fonte

Leggi altre domande sui tag