Skip to contentSkip to conversation

linux-user: Let user specify random seed

PATCH Superseded Magnus Reftel 3 participants 6 messages Oct 9, 2014 – Oct 10, 2014

v2 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 linux-user: Let user specify random seed

This patch introduces the -seed command line option and the QEMU_RAND_SEED environment variable for setting the random seed, which is used for the AT_RANDOM ELF aux entry.

This is an updated version of the patch, addressing review comments from Eric Blake.

#1 lore raw

PATCH 1/1 linux-user: Let user specify random seed

This patch introduces the -seed command line option and the QEMU_RAND_SEED environment variable for setting the random seed, which is used for the AT_RANDOM ELF aux entry.

---
 linux-user/elfload.c |  1 -
 linux-user/main.c    | 20 ++++++++++++++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)
linux-user/elfload.c +0 -1
index 1c04fcf..f2e2197 100644
@@ -1539,7 +1539,6 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
      * Generate 16 random bytes for userspace PRNG seeding (not
      * cryptically secure but it's not the aim of QEMU).
      */
-    srand((unsigned int) time(NULL));
     for (i = 0; i < 16; i++) {
         k_rand_bytes[i] = rand();
     }
linux-user/main.c +20 -0
index 483eb3f..e80255c 100644
@@ -3546,6 +3546,18 @@ static void handle_arg_pagesize(const char *arg)
     }
 }
 
+static void handle_arg_randseed(const char *arg)
+{
+    unsigned long seed;
+    char* end;
+    seed = strtoul(arg, &end, 0);
+    if (end==arg || *end!='\0' || seed > UINT_MAX) {
+        fprintf(stderr, "Invalid seed number: %s\n", arg);
+        exit(1);
+    }
+    srand(seed);
+}
+
 static void handle_arg_gdb(const char *arg)
 {
     gdbstub_port = atoi(arg);
@@ -3674,6 +3686,8 @@ static const struct qemu_argument arg_table[] = {
      "",           "run in singlestep mode"},
     {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
      "",           "log system calls"},
+    {"seed",       "QEMU_RAND_SEED",   true,  handle_arg_randseed,
+     "",           "Seed for pseudo-random number generator"},
     {"version",    "QEMU_VERSION",     false, handle_arg_version,
      "",           "display version information and exit"},
     {NULL, NULL, false, NULL, NULL, NULL}
@@ -3856,6 +3870,8 @@ int main(int argc, char **argv, char **envp)
     cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
 #endif
 
+    srand(time(NULL));
+
     optind = parse_args(argc, argv);
 
     /* Zero out regs */
@@ -3926,6 +3942,10 @@ int main(int argc, char **argv, char **envp)
         do_strace = 1;
     }
 
+    if (getenv("QEMU_RAND_SEED")) {
+        handle_arg_randseed(getenv("QEMU_RAND_SEED"));
+    }
+
     target_environ = envlist_to_environ(envlist, NULL);
     envlist_free(envlist);
 
Signature · 1 line
1.9.1
#2 lore raw

linux-user/main.c static void handle_arg_pagesize(const char *arg) · line 3552

Quoted 12 lines · Magnus Reftel

This patch introduces the -seed command line option and the QEMU_RAND_SEED environment variable for setting the random seed, which is used for the AT_RANDOM ELF aux entry.

---

linux-user/main.c +4 -0
+static void handle_arg_randseed(const char *arg)
+{
+    unsigned long seed;
+    char* end;

Style: we prefer:

char *end;

linux-user/main.c static void handle_arg_pagesize(const char *arg) · line 3554

Quoted 2 lines
linux-user/main.c +2 -0
+    seed = strtoul(arg, &end, 0);
+    if (end==arg || *end!='\0' || seed > UINT_MAX) {

Style: spaces around operators:

if (end == arg || *end || seed > UINT_MAX) {

Bug: strtoul() sometimes reports error via errno; the only safe way to use it is to first prime errno = 0, then do strtoul, then check if errno was changed.

Reimplementation: util/cutils.c already provides parse_uint() that takes care of calling strtoul safely (hmm, that version only parses 64-bit numbers; maybe we should expand it to also parse 32-bit numbers?)

Surprising behavior: your code behaves differently on 32-bit hosts than it does on 64-bit hosts. Seriously. strotoul() has the annoying specification of requiring twos-complement wraparound according to the size of long, which means "-1" on a 32-bit platform parses as 0xffffffff (accepted), while on a 64-bit platform parses it as 0xffffffffffffffff (which you reject as > UINT_MAX); conversely "-18446744073709551615" fails to parse due to overflow on a 32-bit platform, while successfully being parsed as 1 on 64-bit.

Quoted 28 lines
linux-user/main.c +10 -0
+        fprintf(stderr, "Invalid seed number: %s\n", arg);
+        exit(1);
+    }
+    srand(seed);
+}
+
 static void handle_arg_gdb(const char *arg)
 {
     gdbstub_port = atoi(arg);
@@ -3674,6 +3686,8 @@ static const struct qemu_argument arg_table[] = {
      "",           "run in singlestep mode"},
     {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
      "",           "log system calls"},
+    {"seed",       "QEMU_RAND_SEED",   true,  handle_arg_randseed,
+     "",           "Seed for pseudo-random number generator"},
     {"version",    "QEMU_VERSION",     false, handle_arg_version,
      "",           "display version information and exit"},
     {NULL, NULL, false, NULL, NULL, NULL}
@@ -3856,6 +3870,8 @@ int main(int argc, char **argv, char **envp)
     cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
 #endif
 
+    srand(time(NULL));
+
     optind = parse_args(argc, argv);
 
     /* Zero out regs */

linux-user/main.c int main(int argc, char **argv, char **envp) · line 3947

Quoted 6 lines
linux-user/main.c +3 -0
@@ -3926,6 +3942,10 @@ int main(int argc, char **argv, char **envp)
         do_strace = 1;
     }
 
+    if (getenv("QEMU_RAND_SEED")) {
+        handle_arg_randseed(getenv("QEMU_RAND_SEED"));
+    }

Now that you have exactly one caller of the static function, it might make sense to just inline the body of that function here.

Quoted 5 lines
linux-user/main.c +1 -0
+
     target_environ = envlist_to_environ(envlist, NULL);
     envlist_free(envlist);
 
Signature · 2 lines
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org
#3 lore raw

Hi,

Thank you for your patience! I will send a third version.

Quoted 4 lines · Eric Blake
Quoted 1 line · Magnus Reftel

+ char* end;

Style: we prefer:
char *end;

Done.

Quoted 2 lines
Quoted 1 line

+ if (end==arg || *end!='\0' || seed > UINT_MAX) {

Style: spaces around operators:

Done.

Quoted 7 lines

Bug: strtoul() sometimes reports error via errno; the only safe way to use it is to first prime errno = 0, then do strtoul, then check if errno was changed.

Reimplementation: util/cutils.c already provides parse_uint() that takes care of calling strtoul safely (hmm, that version only parses 64-bit numbers; maybe we should expand it to also parse 32-bit numbers?)

Solved both by switching to parse_uint.

Quoted 2 lines
Quoted 2 lines
linux-user/main.c +2 -0
+    {"seed",       "QEMU_RAND_SEED",   true,  handle_arg_randseed,
+     "",           "Seed for pseudo-random number generator"},

...

Quoted 6 lines

linux-user/main.c int main(int argc, char **argv, char **envp) · line 3947

Quoted 3 lines
linux-user/main.c +3 -0
+    if (getenv("QEMU_RAND_SEED")) {
+        handle_arg_randseed(getenv("QEMU_RAND_SEED"));
+    }

Now that you have exactly one caller of the static function, it might make sense to just inline the body of that function here.

No, it may be called using the function pointer in the argument table, above.

Best Regards
Magnus reftel

#4 lore raw
In reply to Magnus Reftel
Quoted 7 lines · Magnus Reftel

This patch introduces the -seed command line option and the QEMU_RAND_SEED environment variable for setting the random seed, which is used for the AT_RANDOM ELF aux entry.

This is an updated version of the patch, addressing review comments from Eric Blake.

Magnus:

Possibly a dumb question: In a regular environment, is there a way for a user to control the 16 bytes of random data pointed to by AT_RANDOM? (I cannot find one).

If not, why is this capability needed in Linux user mode?

#5 lore raw
Quoted 11 lines · Tom Musta
Quoted 6 lines · Magnus Reftel

This patch introduces the -seed command line option and the QEMU_RAND_SEED environment variable for setting the random seed, which is used for the AT_RANDOM ELF aux entry.

This is an updated version of the patch, addressing review comments from Eric Blake.

Possibly a dumb question: In a regular environment, is there a way for a user to control the 16 bytes of random data pointed to by AT_RANDOM? (I cannot find one).

If not, why is this capability needed in Linux user mode?

The reason for this feature is to enable fully reproducible automatic testing. You are correct that this is currently lacking in the Linux kernel (the random bytes are always obtained using get_random_bytes). For my purposes, having reproducibility under qemu is enough, but if I'd be running on bare metal, I'd submit a patch for the kernel as well.

BR
Magnus Reftel