Subject: [PATCH] Fix rngd to open the entropy source with 'O_NOCTTY' flag
From: Gokturk Yuksek <[email-masked]>

When start-stop-daemon starts a rngd instance configured to use a tty
device as its entropy source, the application crashes due to not being
able to read from the entropy device. This is caused by
start-stop-daemon calling setsid() before executing rngd, which
disassociates the controlling terminal. When rngd attempts to open a
hardware entropy source that's a tty device, per POSIX rules, the
device becomes the controlling terminal for the process. Then rngd
calls daemon(), which internally calls setsid(), and consequently
disassociates the controlling terminal for the child. Meanwhile the
parent rngd process exits. This results in tty device hanging up. By
looking at the strace logs attached to the bug, it can be observed
that although the parent rngd process is able to read() from the
entropy source successfully, further attempts to read() by the child
rngd process return 0. This complies with the POSIX, which states that
read() calls on a hung up terminal shall return 0.

Note that when rngd is started without start-stop-daemon, this problem
does not happen because at the time of opening the entropy source rngd
already has a controlling terminal.

Prevent the entropy source from becoming the controlling terminal by
passing 'O_NOCTTY' flag to open() when opening an entropy source. This
flag prevents a tty device from becoming the controlling terminal for
a process without a controlling terminal at the time of open().

Thanks to John Bowler <[email-masked]> for debugging the problem and
pinpointing the issue as well as confirming the fix.

Gentoo-Bug-URL: https://bugs.gentoo.org/556456
Reported-By: John Bowler <[email-masked]>

--- rng-tools-rng-tools-6/rngd_entsource.c
+++ rng-tools-rng-tools-6/rngd_entsource.c
@@ -162,7 +162,7 @@
 	struct sysfs_attribute *rngavail;
 	char buf[16];
 
-	ent_src->rng_fd = open(ent_src->rng_fname, O_RDONLY);
+	ent_src->rng_fd = open(ent_src->rng_fname, O_RDONLY | O_NOCTTY);
 	if (ent_src->rng_fd == -1) {
 		message(LOG_DAEMON|LOG_DEBUG, "Unable to open file: %s", ent_src->rng_fname);
 		return 1;