From b9a5f430a7bc11b2e2b3aa38e07c44c4c6a75e31 Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Thu, 14 Nov 2013 10:09:52 +0000
Subject: [PATCH] mllib: Add a utility function for safely reading from
/dev/urandom.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
OCaml's buffered 'in_channel' has a 64k buffer, so using it to read a
few bytes from /dev/urandom removes a lot of the system's entropy (for
example /proc/sys/kernel/random/entropy_avail goes from ~3000 to 128).
This patch was originally by Edwin Török for builder.ml. I
generalized it because there are two other places where we did
over-sized reads from /dev/urandom.
(cherry picked from commit f013b15fa1daf623cbf39007182c44c734e9bc79)
---
builder/Makefile.am | 1 +
mllib/Makefile.am | 3 +++
mllib/random_seed.ml | 9 ++-------
mllib/urandom.ml | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
mllib/urandom.mli | 22 ++++++++++++++++++++++
po/POTFILES-ml | 1 +
sysprep/Makefile.am | 1 +
7 files changed, 78 insertions(+), 7 deletions(-)
create mode 100644 mllib/urandom.ml
create mode 100644 mllib/urandom.mli
diff --git a/builder/Makefile.am b/builder/Makefile.am
index a828ffd..30ada87 100644
--- a/builder/Makefile.am
+++ b/builder/Makefile.am
@@ -65,6 +65,7 @@ OBJECTS = \
$(top_builddir)/mllib/libdir.cmx \
$(top_builddir)/mllib/common_gettext.cmx \
$(top_builddir)/mllib/common_utils.cmx \
+ $(top_builddir)/mllib/urandom.cmx \
$(top_builddir)/mllib/random_seed.cmx \
$(top_builddir)/mllib/hostname.cmx \
$(top_builddir)/mllib/firstboot.cmx \
diff --git a/mllib/Makefile.am b/mllib/Makefile.am
index 32e0ddf..bacd2bc 100644
--- a/mllib/Makefile.am
+++ b/mllib/Makefile.am
@@ -48,6 +48,8 @@ SOURCES = \
tty-c.c \
tTY.mli \
tTY.ml \
+ urandom.mli \
+ urandom.ml \
uri-c.c \
uRI.mli \
uRI.ml
@@ -70,6 +72,7 @@ OBJECTS = \
libdir.cmx \
common_gettext.cmx \
common_utils.cmx \
+ urandom.cmx \
random_seed.cmx \
hostname.cmx \
firstboot.cmx \
diff --git a/mllib/random_seed.ml b/mllib/random_seed.ml
index f90c833..9ac20eb 100644
--- a/mllib/random_seed.ml
+++ b/mllib/random_seed.ml
@@ -78,13 +78,8 @@ and make_random_seed_file g file =
(* Default to 512 bytes of randomness. *)
512 in
- let entropy =
- (* Get n bytes of randomness from the host. *)
- let chan = open_in "/dev/urandom" in
- let buf = String.create n in
- really_input chan buf 0 n;
- close_in chan;
- buf in
+ (* Get n bytes of randomness from the host. *)
+ let entropy = Urandom.urandom_bytes n in
if file_exists then (
(* Truncate the original file and append, in order to
diff --git a/mllib/urandom.ml b/mllib/urandom.ml
new file mode 100644
index 0000000..3df9b7a
--- /dev/null
+++ b/mllib/urandom.ml
@@ -0,0 +1,48 @@
+(* Read /dev/urandom.
+ * Copyright (C) 2013 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+(* Read and return N bytes (only) from /dev/urandom.
+ *
+ * As pointed out by Edwin Török, previous versions of this had a big
+ * problem. They used the OCaml buffered I/O library which would read
+ * a lot more data than requested. This version uses unbuffered I/O
+ * from the Unix module.
+ *)
+
+open Unix
+
+let open_urandom_fd () = openfile "/dev/urandom" [O_RDONLY] 0
+
+let read_byte fd =
+ let s = String.make 1 ' ' in
+ fun () ->
+ if read fd s 0 1 = 0 then (
+ close fd;
+ raise End_of_file
+ );
+ Char.code s.[0]
+
+let urandom_bytes n =
+ assert (n > 0);
+ let ret = String.make n ' ' in
+ let fd = open_urandom_fd () in
+ for i = 0 to n-1 do
+ ret.[i] <- Char.chr (read_byte fd ())
+ done;
+ close fd;
+ ret
diff --git a/mllib/urandom.mli b/mllib/urandom.mli
new file mode 100644
index 0000000..a7d7808
--- /dev/null
+++ b/mllib/urandom.mli
@@ -0,0 +1,22 @@
+(* Read /dev/urandom.
+ * Copyright (C) 2013 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+(** Read and return N bytes (only) from /dev/urandom. *)
+
+val urandom_bytes : int -> string
+(** Read N bytes from /dev/urandom and return it as a binary string. *)
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index 39ca2a0..efeb75d 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -21,6 +21,7 @@ mllib/progress.ml
mllib/random_seed.ml
mllib/tTY.ml
mllib/uRI.ml
+mllib/urandom.ml
resize/resize.ml
sparsify/sparsify.ml
sysprep/main.ml
diff --git a/sysprep/Makefile.am b/sysprep/Makefile.am
index a74d455..c42fd7d 100644
--- a/sysprep/Makefile.am
+++ b/sysprep/Makefile.am
@@ -88,6 +88,7 @@ OBJECTS = \
$(top_builddir)/mllib/uRI.cmx \
$(top_builddir)/mllib/crypt-c.o \
$(top_builddir)/mllib/crypt.cmx \
+ $(top_builddir)/mllib/urandom.cmx \
$(top_builddir)/mllib/password.cmx \
$(top_builddir)/mllib/random_seed.cmx \
$(top_builddir)/mllib/hostname.cmx \
--
1.8.3.1