1+ /*
2+ * The Shadow Simulator
3+ * Copyright (c) 2010-2011, Rob Jansen
4+ * See LICENSE for licensing information
5+ */
6+
7+ /* Implements an LD_PRELOAD library intended for use with Shadow. libcrypto
8+ * otherwise internally uses some entropy sources that Shadow is unable to trap
9+ * and emulate (such as the RDRAND instruction), making Shadow simulations of
10+ * software using libcrypto non-deterministic.
11+ *
12+ * To use this library, set LD_PRELOAD in the target program's `environment`
13+ * attribute in the Shadow simulation config file. e.g.:
14+ *
15+ * hosts:
16+ * torclient:
17+ * processes:
18+ * - path: ~/.local/bin/tor
19+ * # Must provide absolute path. See #1523.
20+ * environment: 'LD_PRELOAD=/home/<username>/.local/lib/libshadow_openssl_rng.so'
21+ */
22+
23+ #include <stddef.h>
24+ #include <sys/syscall.h>
25+ #include <unistd.h>
26+
27+ static int _getRandomBytes (unsigned char * buf , int numBytes ) {
28+ // shadow interposes this and will fill the buffer for us
29+ // return 1 on success, 0 otherwise
30+ return (numBytes == syscall (SYS_getrandom , buf , (size_t )numBytes , 0 )) ? 1 : 0 ;
31+ }
32+
33+ int RAND_DRBG_generate (void * drbg ,
34+ unsigned char * out , size_t outlen ,
35+ int prediction_resistance ,
36+ const unsigned char * adin , size_t adinlen ) {
37+ return _getRandomBytes (out , outlen );
38+ }
39+
40+ int RAND_DRBG_bytes (void * drbg ,
41+ unsigned char * out , size_t outlen ) {
42+ return _getRandomBytes (out , outlen );
43+ }
44+
45+ int RAND_bytes (unsigned char * buf , int num ) {
46+ return _getRandomBytes (buf , num );
47+ }
48+
49+ int RAND_pseudo_bytes (unsigned char * buf , int num ) {
50+ return _getRandomBytes (buf , num );
51+ }
52+
53+ void RAND_seed (const void * buf , int num ) {
54+ return ;
55+ }
56+
57+ void RAND_add (const void * buf , int num , double entropy ) {
58+ return ;
59+ }
60+
61+ int RAND_poll () {
62+ return 1 ;
63+ }
64+
65+ void RAND_cleanup (void ) {
66+ return ;
67+ }
68+
69+ int RAND_status (void ) {
70+ return 1 ;
71+ }
72+
73+ // Callback return type changed from void to int in OpenSSL_1_1_0-pre1.
74+ // However, since x86-64 uses rax for return values, and rax is a caller-saved
75+ // register, it's safe to return an int even if the caller is expecting void.
76+ static int nop_seed (const void * buf , int num ) { return 1 ; }
77+
78+ // Callback return type changed from void to int, and entropy from int to to
79+ // double in OpenSSL_1_1_0-pre1.
80+ //
81+ // However, since x86-64 uses rax for return values, and rax is a caller-saved
82+ // register, it's safe to return an int even if the caller is expecting void.
83+ // Similarly, since we don't actually use either parameter, it doesn't matter if
84+ // the types match.
85+ static int nop_add (const void * buf , int num , double entropy ) { return 1 ; }
86+
87+ typedef struct {
88+ int (* seed )(const void * buf , int num );
89+ int (* bytes )(unsigned char * buf , int num );
90+ void (* cleanup )(void );
91+ int (* add )(const void * buf , int num , double entropy );
92+ int (* pseudorand )(unsigned char * buf , int num );
93+ int (* status )(void );
94+ } RAND_METHOD ;
95+
96+ const RAND_METHOD * RAND_get_rand_method () {
97+ static const RAND_METHOD method = {
98+ .seed = nop_seed ,
99+ .bytes = RAND_bytes ,
100+ .cleanup = RAND_cleanup ,
101+ .add = nop_add ,
102+ .pseudorand = RAND_pseudo_bytes ,
103+ .status = RAND_status ,
104+ };
105+ return & method ;
106+ }
0 commit comments