1 /*
2  * Checks if LibreSSL's PRNG is fork-safe.
3  * From https://www.agwa.name/blog/post/libressls_prng_is_unsafe_on_linux
4  * This code is in the public domain.
5  *
6  * Original source: https://gist.github.com/AGWA/eb84e55ca25a7da1deb0
7  */
8 
9 #undef LIBRESSL_INTERNAL
10 #include <openssl/rand.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <sys/wait.h>
15 
random_bytes(unsigned char * p,size_t len)16 static void random_bytes (unsigned char* p, size_t len)
17 {
18 	if (RAND_bytes(p, len) != 1) {
19 		fprintf(stderr, "RAND_bytes failed\n");
20 		abort();
21 	}
22 }
23 
random_stir(void)24 static void random_stir (void)
25 {
26 	if (RAND_poll() != 1) {
27 		fprintf(stderr, "RAND_poll failed\n");
28 		abort();
29 	}
30 }
31 
print_buffer(unsigned char * p,size_t len)32 static void print_buffer (unsigned char* p, size_t len)
33 {
34 	while (len--) {
35 		printf("%02x", (unsigned int)*p++);
36 	}
37 }
38 
main()39 int main ()
40 {
41 	char c = 0;
42 	int	pipefd[2];
43 	pipe(pipefd);
44 	setbuf(stdout, NULL);
45 
46 	if (fork() == 0) {
47 		unsigned char buffer[32];
48 		pid_t grandparent_pid = getpid();
49 
50 		random_bytes(buffer, sizeof(buffer));
51 
52 		if (fork() == 0) {
53 			random_stir();
54 			setsid();
55 			while (1) {
56 				pid_t	grandchild_pid = fork();
57 				if (grandchild_pid == 0) {
58 					random_stir();
59 					if (getpid() == grandparent_pid) {
60 						random_bytes(buffer, sizeof(buffer));
61 						print_buffer(buffer, sizeof(buffer));
62 						printf("\n");
63 					}
64 					_exit(0);
65 				}
66 				wait(NULL);
67 				if (grandchild_pid == grandparent_pid) {
68 					break;
69 				}
70 			}
71 			write(pipefd[1], &c, 1);
72 			_exit(0);
73 		}
74 
75 		random_bytes(buffer, sizeof(buffer));
76 		print_buffer(buffer, sizeof(buffer));
77 		printf(" ");
78 		_exit(0);
79 	}
80 	wait(NULL);
81 	close(pipefd[1]);
82 	read(pipefd[0], &c, 1);
83 	return 0;
84 }
85 
86