Skip to content

Commit

Permalink
Handle CPU_RNG failures in OCaml:
Browse files Browse the repository at this point in the history
- Previously, a return value of "0" was treated specially, but rdrand/rdseed
  may return 0!
- If there's a failure in rdrand/rdseed during cpu_rng_bootstrap, raise an
  exception
- If there's a failure during the periodic reseeding (timer initiated feeding
  of all pools), ignore it (for now!?)
  • Loading branch information
hannesm committed Jan 8, 2025
1 parent c52a56a commit f5031a6
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 20 deletions.
2 changes: 1 addition & 1 deletion rng/async/mirage_crypto_rng_async.ml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ let periodically_collect_getrandom_entropy time_source span =
let idx = ref 0 in
let f () =
incr idx;
String.sub random ~pos:(per_pool * (pred !idx)) ~len:per_pool
Ok (String.sub random ~pos:(per_pool * (pred !idx)) ~len:per_pool)
in
Entropy.feed_pools None source f)

Expand Down
2 changes: 1 addition & 1 deletion rng/eio/mirage_crypto_rng_eio.ml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ let periodically_feed_entropy env delta source =
let idx = ref 0 in
let f () =
incr idx;
String.sub random (per_pool * (pred !idx)) per_pool
Ok (String.sub random (per_pool * (pred !idx)) per_pool)
in
Entropy.feed_pools None source f
in
Expand Down
21 changes: 13 additions & 8 deletions rng/entropy.ml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
module Cpu_native = struct

external cycles : unit -> int = "mc_cycle_counter" [@@noalloc]
external rdseed : unit -> int = "mc_cpu_rdseed" [@@noalloc]
external rdrand : unit -> int = "mc_cpu_rdrand" [@@noalloc]
external rdseed : bytes -> int -> bool = "mc_cpu_rdseed" [@@noalloc]
external rdrand : bytes -> int -> bool = "mc_cpu_rdrand" [@@noalloc]
external rng_type : unit -> int = "mc_cpu_rng_type" [@@noalloc]

let cpu_rng =
Expand Down Expand Up @@ -119,10 +119,9 @@ let cpu_rng_bootstrap =
| None -> Error `Not_supported
| Some insn ->
let cpu_rng_bootstrap id =
let r = cpu_rng insn () in
if r = 0 then failwith "Mirage_crypto_rng.Entropy: 0 is a bad CPU RNG value";
let buf = Bytes.create 10 in
Bytes.set_int64_le buf 2 (Int64.of_int r);
let r = cpu_rng insn buf 2 in
if not r then failwith "Mirage_crypto_rng.Entropy: CPU RNG broken";
write_header id buf;
Bytes.unsafe_to_string buf
in
Expand Down Expand Up @@ -150,7 +149,11 @@ let feed_pools g source f =
let g = match g with None -> Some (Rng.default_generator ()) | Some g -> Some g in
let `Acc handle = Rng.accumulate g source in
for _i = 0 to pred (Rng.pools g) do
handle (f ())
match f () with
| Ok data -> handle data
| Error `No_random_available ->
(* should we log a message? *)
()
done

let cpu_rng =
Expand All @@ -165,8 +168,10 @@ let cpu_rng =
in
let f () =
let buf = Bytes.create 8 in
Bytes.set_int64_le buf 0 (Int64.of_int (randomf ()));
Bytes.unsafe_to_string buf
if randomf buf 0 then
Ok (Bytes.unsafe_to_string buf)
else
Error `No_random_available
in
fun () -> feed_pools g source f
in
Expand Down
2 changes: 1 addition & 1 deletion rng/lwt/mirage_crypto_rng_lwt.ml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ let getrandom_task delta source =
let idx = ref 0 in
let f () =
incr idx;
String.sub random (per_pool * (pred !idx)) per_pool
Ok (String.sub random (per_pool * (pred !idx)) per_pool)
in
Entropy.feed_pools None source f
in
Expand Down
5 changes: 4 additions & 1 deletion rng/miou/mirage_crypto_rng_miou_unix.ml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ let getrandom delta source =
let size = per_pool * pools None in
let random = Mirage_crypto_rng_unix.getrandom size in
let idx = ref 0 in
let fn () = incr idx; String.sub random (per_pool * (pred !idx)) per_pool in
let fn () =
incr idx;
Ok (String.sub random (per_pool * (pred !idx)) per_pool)
in
Entropy.feed_pools None source fn in
periodic fn delta

Expand Down
4 changes: 2 additions & 2 deletions rng/mirage_crypto_rng.mli
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,14 @@ module Entropy : sig

(** {1 Periodic pulled sources} *)

val feed_pools : g option -> source -> (unit -> string) -> unit
val feed_pools : g option -> source -> (unit -> (string, [ `No_random_available ]) result) -> unit
(** [feed_pools g source f] feeds all pools of [g] using [source] by executing
[f] for each pool. *)

val cpu_rng : (g option -> unit -> unit, [`Not_supported]) Result.t
(** [cpu_rng g] uses the CPU RNG (rdrand or rdseed) to feed all pools
of [g]. It uses {!feed_pools} internally. If neither rdrand nor rdseed
are available, [fun () -> ()] is returned. *)
are available, [`Not_supported] is returned. *)

(**/**)
val id : source -> int
Expand Down
30 changes: 24 additions & 6 deletions src/native/entropy_cpu_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,27 @@
#define random_t unsigned long long
#define _rdseed_step _rdseed64_step
#define _rdrand_step _rdrand64_step
#define fill_bytes(buf, off, data) { \
(_bp_uint8_off(buf, off))[0] = (uint8_t)((data) >> 56); \
(_bp_uint8_off(buf, off))[1] = (uint8_t)((data) >> 48); \
(_bp_uint8_off(buf, off))[2] = (uint8_t)((data) >> 40); \
(_bp_uint8_off(buf, off))[3] = (uint8_t)((data) >> 32); \
(_bp_uint8_off(buf, off))[4] = (uint8_t)((data) >> 24); \
(_bp_uint8_off(buf, off))[5] = (uint8_t)((data) >> 16); \
(_bp_uint8_off(buf, off))[6] = (uint8_t)((data) >> 8); \
(_bp_uint8_off(buf, off))[7] = (uint8_t)((data)); \
}

#elif defined (__i386__)
#define random_t unsigned int
#define _rdseed_step _rdseed32_step
#define _rdrand_step _rdrand32_step
#define fill_bytes(buf, off, data) { \
(_bp_uint8_off(buf, off))[0] = (uint8_t)((data) >> 24); \
(_bp_uint8_off(buf, off))[1] = (uint8_t)((data) >> 16); \
(_bp_uint8_off(buf, off))[2] = (uint8_t)((data) >> 8); \
(_bp_uint8_off(buf, off))[3] = (uint8_t)((data)); \
}

#endif
#endif /* __i386__ || __x86_64__ */
Expand Down Expand Up @@ -229,29 +245,31 @@ static void detect (void) {
#endif
}

CAMLprim value mc_cpu_rdseed (value __unused(unit)) {
CAMLprim value mc_cpu_rdseed (value buf, value off) {
#ifdef __mc_ENTROPY__
random_t r = 0;
int ok = 0;
int i = RETRIES;
do { ok = _rdseed_step (&r); _mm_pause (); } while ( !(ok | !--i) );
return Val_long(r);
fill_bytes(buf, off, r);
return Val_bool (ok);
#else
/* ARM: CPU-assisted randomness here. */
return Val_long (0);
return Val_bool (0);
#endif
}

CAMLprim value mc_cpu_rdrand (value __unused(unit)) {
CAMLprim value mc_cpu_rdrand (value buf, value off) {
#ifdef __mc_ENTROPY__
random_t r = 0;
int ok = 0;
int i = RETRIES;
do { ok = _rdrand_step (&r); } while ( !(ok | !--i) );
return Val_long(r);
fill_bytes(buf, off, r);
return Val_bool (ok);
#else
/* ARM: CPU-assisted randomness here. */
return Val_long (0);
return Val_bool (0);
#endif
}

Expand Down

0 comments on commit f5031a6

Please sign in to comment.