2

I have a MIPSEL ci20 dev-board that's suffering entropy depletion. The board has a JZ4780 SoC with an hardware rng (the register is mapped at address 0x100000DC). The Ingenic driver has some issue, so I wrote a userland program to read the register and replenish the pool.

After running the program I observed:

$ sudo ./ci20-rng.exe && for((i=1;i<=20;i+=1)); do (cat /proc/sys/kernel/random/entropy_avail; sleep 5); done
3968
3712
3456
3200
2944
2688
2432
2176
1920
1664
1408
1152
896
640
384
128
128
...

A similar question is What keeps draining entropy? The explanation of the drain mostly makes sense. I think its happening at too fast a rate given the explanations. But it seems like the drain should continue to 0, and not stabilize around 160 or 128.

Why does entropy_avail stabilize around 160 or 128?


The program below uses the ioctl(fd, RNDADDENTROPY, &entropy), where fd is a descriptor for /dev/random. entropy is the expected struct:

typedef struct {
    int bit_count;
    int byte_count;
    unsigned char buf[4096];
} entropy_t;

Toggling of the control register (*ctrl = 0x00 and *ctrl = 0x01) followed by a delay is due to reading the JZ4780 Programmer's Manual. The idea is to write to the SC-ROM Controller but push it high for less than 1 second due to "... The maximum 2.5V supply time to VDDQ must be strictly controlled less than 1sec". I hope I am not hacking it too badly or misreading it.

Here's the program:

#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/random.h>

typedef struct {
    int bit_count;               /* number of bits of entropy in data */
    int byte_count;              /* number of bytes of data in array */
    unsigned char buf[4096];
} entropy_t;

static int print_only;

/* gcc -g2 -O2 -std=c99 ci20-rng.c -o ci20-rng.exe */
int main(int argc, char* argv[])
{
    int ret = 1, fd1 = -1, fd2 = -1, fd3 = -1;
    void *map1 = MAP_FAILED, *map2 = MAP_FAILED;

    const int PAGE_SIZE = sysconf(_SC_PAGESIZE);
    const int PAGE_MASK = ~(PAGE_SIZE - 1);

    #define CTRL_ADDR 0x100000D8
    #define DATA_ADDR 0x100000DC

    if(argc >= 2)
    {
        if(0 == strcmp(argv[1], "-p") || 0 == strcmp(argv[1], "/p") || 0 == strcmp(argv[1], "--print"))
            print_only = 1;
    }

    fd1 = open("/dev/mem", O_RDWR | O_SYNC);
    if(fd1 == -1)
    {
        fprintf(stderr, "Failed to open /dev/mem for reading and writing (error %d)\n", errno);
        goto cleanup;
    }

    fd2 = open("/dev/mem", O_RDONLY | O_SYNC);
    if(fd2 == -1)
    {
        fprintf(stderr, "Failed to open /dev/mem for reading (error %d)\n", errno);
        goto cleanup;
    }

    fd3 = open("/dev/random", O_RDWR);
    if(fd3 == -1)
    {
        fprintf(stderr, "Failed to open /dev/random for writing (error %d)\n", errno);
        goto cleanup;
    }

    map1 = mmap (NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd1, CTRL_ADDR & PAGE_MASK);
    if(map1 == MAP_FAILED)
    {
        fprintf(stderr, "Failed to map 0x100000D8 for control (error %d)\n", errno);
        goto cleanup;
    }

    map2 = mmap (NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd2, DATA_ADDR & PAGE_MASK);
    if(map2 == MAP_FAILED)
    {
        fprintf(stderr, "Failed to map 0x100000DC for data (error %d)\n", errno);
        goto cleanup;
    }

    const int off1 = CTRL_ADDR % PAGE_SIZE;
    volatile uint32_t* volatile ctrl = (uint32_t*)((uint8_t*)map1+off1);

    const int off2 = DATA_ADDR % PAGE_SIZE;
    volatile uint32_t* volatile data = (uint32_t*)((uint8_t*)map2+off2);

    entropy_t entropy = { .bit_count = 4096*8, .byte_count = 4096 };
    int count = 4096/4, idx = 0;

    while(count--)
    {
        /* If the delay from the loop drops too low, then we */
        /*  can watch the random values being shifted in.    */
        #define DELAY 5000

        *ctrl = 0x01;        
        for(unsigned int i = 0; i < DELAY; i++) {
            volatile uint32_t unused = *ctrl;
        }

        if(!print_only)
        {
            memcpy(entropy.buf+idx, (const void *)data, 4);
            idx += 4;
        }
        else
        {
            if(isatty(fileno(stdout)))
                fprintf(stdout, "0x%08x\n", *data);
            else
                write(fileno(stdout), (const void *)data, 4);
        }

        *ctrl = 0x00;
        for(unsigned int i = 0; i < DELAY; i++) {
            volatile uint32_t unused = *ctrl;
        }
    }

    if(!print_only)
    {
        int rc = ioctl(fd3, RNDADDENTROPY, &entropy);
        if(rc != 0)
        {
            fprintf(stderr, "Failed to add entropy (error %d)\n", errno);
            goto cleanup;
        }
    }

    ret = 0;

  cleanup:

    if(map2 != MAP_FAILED) { munmap(map2, PAGE_SIZE); }
    if(map1 != MAP_FAILED) { munmap(map1, PAGE_SIZE); }

    if(fd3 != -1) { close(fd3); }
    if(fd2 != -1) { close(fd2); }
    if(fd1 != -1) { close(fd1); }

    return ret;
}
  • How does your program work? Does it increase the kernel's “entropy” count? – Gilles Aug 14 '16 at 21:13
  • @Gilles - Yes, the program uses ioctl and RNDADDENTROPY to increase the count. The question was updated to include the program. – user56041 Aug 14 '16 at 21:38
1

I would guess there is threshold at which the device changes (weakens?) the algorithm for producing "random" data so that you don't run out completely. Namely, skimping on "real" random data and relying on a CSPNRG instead.

I just asked a related question and then found the answer on the rngd man page:

The rnd-tools service invokes the program /usr/sbin/rngd. Looking that in up the Ubuntu documentation it can be seen to have a parameter:

-W n, --fill-watermark=nnn

      Once we start doing it, feed entropy to random-device until at least fill-watermark bits of entropy are available in its entropy pool (default: 2048).  Setting this too high will cause rngd to dominate the contents of the entropy pool.  Low values will hurt system performance during entropy starves.  Do not set fill-watermark above the size of the entropy pool (usually 4096 bits).

My question/answer are here.

  • Thanks @G-Man. Anything is an improvement over the link that took people to editing the other answer. – user56041 Apr 29 '18 at 4:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy