Add entropy to kernel pool

Add the code to send the random bytes received from the card to the
kernel entropy pool.

This requires root privileges, while the scdaemon usually runs on
behalf on a normal user, so the program will probably have to be run
as setuid root. To reduce the amount of code running with root
privileges, a new process is started to take care of actually sending
random bytes to the kernel entropy pool. The rest of the program,
running in the parent process, can drop its root privileges, as they
are not required to communicate with scdaemon.
pull/1/head
Damien Goutte-Gattat 8 years ago
parent fba56566c9
commit 39c449cec4
  1. 92
      src/scdrand.c

@ -27,10 +27,18 @@
#include <getopt.h>
#include <err.h>
#include <xmem.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/random.h>
#include <assuan.h>
#include <xmem.h>
static void
usage(int status)
{
@ -201,10 +209,78 @@ get_challenge(const char *scd_socket_name, unsigned char *buffer, size_t len)
return c.len;
}
/*
* Fork a new process solely charged with the task of adding entropy
* to the kernel pool (the only task that requires root privileges).
* The new process will listen to a pipe opened by its parent and
* write the data it receives to the entropy pool.
*
* The function only returns in the parent process; the child process
* remains in a loop until it terminates.
*
* @return
* A file descriptor for the pipe connecting the parent process to
* its child.
*/
static int
start_privileged_process(void)
{
int fd[2];
pid_t pid;
if ( pipe(fd) == -1 )
err(EXIT_FAILURE, "Cannot create pipe");
if ( (pid = fork()) == 0 ) {
int random_fd, n;
char buffer[256];
struct rand_pool_info *rpi;
close(fd[1]);
if ( (random_fd = open("/dev/random", O_RDONLY)) == -1 )
err(EXIT_FAILURE, "Cannot open /dev/random");
rpi = xmalloc(sizeof(struct rand_pool_info) + 256);
while ( 1 ) {
n = read(fd[0], buffer, sizeof(buffer));
if ( n == -1 )
err(EXIT_FAILURE, "Cannot read from pipe");
if ( n == 0 ) /* EOF, parent process must have closed its end. */
exit(EXIT_SUCCESS);
rpi->entropy_count = n * 8;
rpi->buf_size = n;
memcpy(&(rpi->buf[0]), buffer, n);
fprintf(stderr, "adding %d bytes of entropy to the pool\n", n);
if ( ioctl(random_fd, RNDADDENTROPY, rpi) == -1 )
warn("Cannot add entropy");
}
}
else if ( pid > 0 ) {
close(fd[0]);
/* Drop privileges, then return to caller. */
if ( setgid(getgid()) == -1 || setuid(getuid()) == -1 )
err(EXIT_FAILURE, "Cannot drop privileges");
return fd[1];
}
else
err(EXIT_FAILURE, "Cannot fork");
return 0; /* Not reached. */
}
int
main(int argc, char **argv)
{
int c;
int c, fd;
char *scd_socket_name;
unsigned char random_buffer[64];
@ -232,6 +308,8 @@ main(int argc, char **argv)
}
}
fd = start_privileged_process();
#ifndef GPG_ERR_INITIALIZED
gpg_err_init();
#endif
@ -241,15 +319,13 @@ main(int argc, char **argv)
if ( scd_socket_name ) {
int n, i;
n = get_challenge(scd_socket_name, random_buffer, 12);
fprintf(stderr, "Get %d bytes\n", n);
for ( i = 0; i < n; i++ ) {
fprintf(stderr, "%02X:", random_buffer[i]);
}
fprintf(stderr, "\n");
n = get_challenge(scd_socket_name, random_buffer, 8);
write(fd, random_buffer, n);
free(scd_socket_name);
}
close(fd);
return EXIT_SUCCESS;
}

Loading…
Cancel
Save