linuxtestingrandomchroot

bypass dev/urandom|random for testing


I want to write a functional test case that tests a program with a known value for random numbers. I have already tested it with mocks during the unit testing. But I would like that for functional testing as well (not all of them, of course :)

What is the easiest way to have /dev/urandom overridden for just one process? Is there a way to do something like a chroot for a single file and let all the others 'pass through'?


Solution

  • If your system is new enough (e.g. RHEL 7) and supports setns syscall it can be done with the help of mount namespaces. Root access is required.

    The idea is to create a separate mount namespace for the process, and inside that namespace bind-mount some other file or FIFO over /dev/random so that the processes from this mount namespace would read the data from this bind-mounted file. Other processes will see the regular /dev/random.

    Here is how to do that.

    Preparation: run the following command to make all this stuff work (as it may not work by default, see this question for details).

    # mount --make-rprivate /
    

    Now let's create a shell running inside a new mount namespace.

    # unshare -m /bin/bash
    

    You have the new bash started which has its own mount namespace. You can compare the result of the following command from inside this shell and from some other shell:

    This shell:

    # ls -l /proc/self/ns/mnt
    lrwxrwxrwx. 1 root root 0 Sep 26 16:06 /proc/self/ns/mnt -> mnt:[4026532148]
    

    Other shell:

    $ ls -l /proc/self/ns/mnt
    lrwxrwxrwx. 1 ec2-user ec2-user 0 Sep 26 16:06 /proc/self/ns/mnt -> mnt:[4026531840]
    

    Note that the numbers differ, so the two shells are in the different mount namespaces and the mounts performed from the first shell will not be visible to other processes in the system (except all the children of this shell).

    Now in this shell we can bind-mount something over the existing /dev/random.

    # echo 'some large text' > /tmp/fakerandom
    # mount --bind /tmp/fakerandom /dev/random
    

    Other processes don't see that, for them /dev/random works as usual:

    $ ls -l /dev/random
    crw-rw-rw-. 1 root root 1, 8 Sep 26 15:45 /dev/random
    $ cat /dev/random
    �Znp7�v�c��Ω^C
    

    But in our shell it's special:

    # ls -l /dev/random
    -rw-r--r--. 1 root root 16 Sep 26 16:18 /dev/random
    # cat /dev/random
    some large text
    

    For the functional testing you may want to substitute /dev/random with some FIFO and write some known data to that FIFO in some other process (see mkfifo(1) for more information on that if needed).

    More information about mount namespaces can be found in this excellent article.