cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
tandem.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Tandem Randomness-Gathering Code *
4 * Copyright Peter Gutmann 2002-2004 *
5 * *
6 ****************************************************************************/
7 
8 /* This module is part of the cryptlib continuously seeded pseudorandom
9  number generator. For usage conditions, see random.c */
10 
11 /* Define the following to print diagnostic information on where randomness
12  is coming from */
13 
14 /* #define DEBUG_RANDOM */
15 
16 /* General includes */
17 
18 #include "crypt.h"
19 #include "random/random.h"
20 
21 /* OS-specific includes */
22 
23 #include <cextdecs>
24 #include <tal.h>
25 
26 /* The size of the intermediate buffer used to accumulate polled data */
27 
28 #define RANDOM_BUFSIZE 4096
29 
30 /* The number of processes per CPU that we fetch attributes for. We set an
31  upper limit on this to make sure that we don't take too much time doing
32  it */
33 
34 #define NO_PROCESSES 50
35 
36 /* The CPU attributes that we fetch. This typically yields 150 words
37  of attribute data */
38 
39 static const short int cpuAttrList[] = {
40  2, /* INT: Processor type */
41  7, /* INT_32: Swappable pages */
42  8, /* INT_32: Free pages */
43  9, /* INT_32: Current locked pages */
44  11, /* INT_32: Max.locked memory pages */
45  12, /* INT_32: No.page faults */
46  13, /* INT_32: Scans per memory manager call */
47  14, /* INT_32: No.mem manager scans */
48  15, /* INT_32: Page fault frequency indicator */
49  16, /* INT_32: Paging queue length */
50  18, /* FIXED: Wall clock time */
51  19, /* FIXED: CPU time */
52  20, /* FIXED: Idle time */
53  21, /* FIXED: Interrupt time */
54  22, /* INT: Process queue length */
55  23, /* INT_32: No.dispatch interrupts */
56  24, /* INT[]: Process Control Blocks (PCBs) in low PINs */
57  25, /* INT[]: Process Control Blocks (PCBs) in high PINs */
58  26, /* INT_32[]: Time List Elements (TLEs) */
59  27, /* INT_32[]: Process Time List Elements (TLEs) */
60  28, /* INT: No.breakpoints currently set */
61  29, /* FIXED: Time spent in message sends */
62  35, /* INT_32[24]: Interrupt count */
63  36, /* FIXED: Disk cache hits */
64  37, /* FIXED: Disk I/Os */
65  38, /* INT,INT,/* FIXED: Processor queue state */
66  39, /* INT,INT,/* FIXED: Memory queue state */
67  40, /* INT_32: IPC sequenced messages */
68  41, /* INT_32: IPC unsequenced messages */
69  42, /* INT_32: Correctable memory errors */
70  43, /* INT_32: VM pages created */
71  44, /* FIXED: Time spent in interpreter (for NSR-L CPUs) */
72  45, /* INT_32: Interpreter transitions (for NSR-L CPUs) */
73  46, /* INT_32: Transactions since Measure product started */
74  50, /* FIXED: Time in accelerated mode (for TNS/R CPUs) */
75  58, /* INT_32: Kernel segments in use */
76  59 /* INT_32: Maximum segments used */
77  };
78 
79 #define NO_CPU_ATTRS ( sizeof( cpuAttrList ) / sizeof( short int ) )
80 
81 /* The process attributes that we fetch. This typically yields 80 words
82  of attribute data */
83 
84 static const short int procAttrList[] = {
85  1, /* INT: Creator access ID */
86  2, /* INT: Process access ID */
87  6, /* INT[10]: gmom process handle */
88  7, /* INT: Job ID */
89  8, /* INT: Process subtype */
90  10, /* INT: Process state */
91  11, /* INT[2]: System process type */
92  15, /* INT: Process list */
93  28, /* INT: Process type */
94  30, /* FIXED: Process time */
95  31, /* INT: Wait state */
96  32, /* INT: Process state */
97  35, /* INT: Context switches */
98  41, /* INT: Process file security */
99  42, /* INT: Current priority */
100  43, /* INT: Initial priority */
101  44, /* INT: Remote creator */
102  45, /* INT: Logged-on state */
103  47, /* INT: Prim. or sec.in process pair */
104  48, /* INT: Process handle */
105  53, /* FIXED: Creation timestamp */
106  54, /* INT: No resident pages */
107  55, /* INT_32: Messages sent */
108  56, /* INT_32: Messages received */
109  57, /* INT: Receive queue length */
110  58, /* INT: Receive queue max.length */
111  59, /* INT_32: Page faults */
112  63, /* INT: Stop mode */
113  64, /* INT: Stop request queue */
114  72, /* INT: Logon flags and states */
115  73, /* INT: Applicable attributes */
116  76, /* INT_32: Curr.process file segment (PFS) size */
117  77, /* INT_32: Max.process file segment (PFS) extent */
118  102, /* INT_32: Base addr.of main stack */
119  103, /* INT_32: Current main stack size */
120  104, /* INT_32: Max.main stack extent */
121  105, /* INT_32: Base addr.of privileged stack */
122  106, /* INT_32: Current privileged stack size */
123  107, /* INT_32: Max.privileged stack extent */
124  108, /* INT_32: Base addr. of global data */
125  109, /* INT_32: Size of global data */
126  110, /* INT_32: Base addr.of native heap */
127  111, /* INT_32: Current native heap size */
128  112 /* INT_32: Max.native heap extent */
129  };
130 
131 #define NO_PROC_ATTRS ( sizeof( procAttrList ) / sizeof( short int ) )
132 
133 /* Get a list of process IDs of all running processes */
134 
135 static int getProcessList( const short int cpuNo, short int *pidBuffer,
136  const short int pidBufSize )
137  {
138  const static short int retAttrList[] = { 38 }; /* Process ID */
139  const static short int srchAttrList[] = { 9 }; /* Minimum priority */
140  const static short int srchValList[] = { 0 }; /* Priority >= 0 */
141  short int error, pin = 0, noAttrs;
142 
143  /* Get a list of active processes by searching for all processes with
144  a minimum priority (attribute 9) >= 0, returning a list of all
145  process IDs. The search can return error code 7 (no more matches)
146  if we run out of processes before we run out of buffer space, this
147  isn't an error since we still got some matches */
148  error = PROCESS_GETINFOLIST_( cpuNo /* CPU no.*/
149  ,&pin /* Process ID */
150  , /* Node name */
151  , /* Node name length */
152  , /* Process handle */
153  ,( short int * ) retAttrList
154  /* Attrs.to read */
155  ,1 /* No.attrs.to read */
156  ,pidBuffer /* Returned attrs.*/
157  ,pidBufSize /* Ret.attrs.buffer size */
158  ,&noAttrs /* No.returned attrs.*/
159  , /* Error info */
160  ,2 /* Find as many as will fit */
161  ,( short int * ) srchAttrList
162  /* Attrs.to search for */
163  ,1 /* No.attrs.to search for */
164  ,( short int * ) srchValList
165  /* Attr.value to search for */
166  ,1 /* No.attr.values */
167  );
168  return( ( error == 0 || error == 7 ) ? noAttrs : 0 );
169  }
170 
171 /* Get various quick pieces of info */
172 
173 void fastPoll( void )
174  {
175  RANDOM_STATE randomState;
176  BYTE buffer[ RANDOM_BUFSIZE + 8 ];
177  long long totalTime, busyTime, intTime, idleTime;
178  _cc_status cc;
179  short int value, error;
180  int quality = 0;
181 
182  initRandomData( randomState, buffer, RANDOM_BUFSIZE );
183 
184  /* CPU usage info */
185  cc = CPUTIMES( /* Local CPU */
186  , /* Local system */
187  ,&totalTime /* Wall clock time */
188  ,&busyTime /* CPU time */
189  ,&intTime /* Interrupt time */
190  ,&idleTime /* Idle time */
191  );
192  if( _status_eq( cc ) )
193  {
194  addRandomData( randomState, &totalTime, sizeof( long long ) );
195  addRandomData( randomState, &busyTime, sizeof( long long ) );
196  addRandomData( randomState, &intTime, sizeof( long long ) );
197  addRandomData( randomState, &idleTime, sizeof( long long ) );
198  quality = 2;
199  }
200 
201  /* Message queue info */
202  error = MESSAGESYSTEMINFO( 4 /* Messages in rcv.queue */
203  ,&value /* No.messages */
204  );
205  if( error == 0 )
206  {
207  addRandomValue( randomState, value );
208  quality++;
209  }
210  error = MESSAGESYSTEMINFO( 5 /* Messages in send.queue */
211  ,&value /* No.messages */
212  );
213  if( error == 0 )
214  {
215  addRandomValue( randomState, value );
216  quality++;
217  }
218 
219  /* Runtime of current process in microseconds */
220  totalTime = MYPROCESSTIME();
221  addRandomData( randomState, &totalTime, sizeof( long long ) );
222 
223  /* Flush any remaining data through */
224 #ifdef DEBUG_RANDOM
225  printf( "fastPoll: quality = %d.\n", quality );
226 #endif /* DEBUG_RANDOM */
227  endRandomData( randomState, quality );
228  }
229 
230 /* Enumerate all processes running on all CPUs and fetch the statistics
231  that are likely to be high-entropy */
232 
233 void slowPoll( void )
234  {
235  RANDOM_STATE randomState;
236  BYTE buffer[ RANDOM_BUFSIZE + 8 ];
237  const long cpuStatus = PROCESSORSTATUS() & 0xFFFFUL;
238  long cpuStatusMask;
239  short int cpuNo;
240  int attrCount = 0;
241 
242  initRandomData( randomState, buffer, RANDOM_BUFSIZE );
243 
244  /* Enumerate all available CPUs. Although the docs indicate that
245  PROCESSORSTATUS() starts numbering CPUs from bit 0, it actually
246  appears to number them from bit 15 */
247  for( cpuStatusMask = 0x8000, cpuNo = 0; \
248  cpuStatusMask > 0; \
249  cpuStatusMask >>= 1, cpuNo++ )
250  {
251  short int pidBuffer[ NO_PROCESSES + 8 ];
252  short int noAttrs, error;
253  int i, noProcesses;
254 
255  /* If this CPU isn't available, continue */
256  if( !( cpuStatusMask & cpuStatus ) )
257  continue;
258 
259 #ifdef DEBUG_RANDOM
260  printf( "Getting info for CPU #%d.\n", cpuNo );
261 #endif /* DEBUG_RANDOM */
262  /* Get status info for this CPU */
263  error = PROCESSOR_GETINFOLIST_( /* Node name */
264  , /* Node name length */
265  ,cpuNo /* CPU no.*/
266  ,( short int * ) cpuAttrList
267  /* Attrs.to read */
268  ,NO_CPU_ATTRS /* No.attrs.to read */
269  ,( short int * ) buffer
270  /* Returned attrs.*/
271  ,RANDOM_BUFSIZE / sizeof( short int )
272  /* Ret.attrs.buffer size */
273  ,&noAttrs /* No.returned attrs.*/
274  );
275  if( error == 0 )
276  {
277 #ifdef DEBUG_RANDOM
278  printf( "PROCESSOR_GETINFOLIST returned %d attributes.\n",
279  noAttrs );
280 #endif /* DEBUG_RANDOM */
281  addRandomData( randomState, buffer,
282  noAttrs * sizeof( short int ) );
283  attrCount += noAttrs / 2;
284  }
285 
286  /* Get status info for the first NO_PROCESSES processes on this
287  CPU */
288  noProcesses = getProcessList( cpuNo, pidBuffer, NO_PROCESSES );
289  if( noProcesses <= 0 )
290  {
291  /* If the process-list read fails for some reason, we can still
292  get info for at least the first two processes, which are
293  always present */
294  noProcesses = 2;
295  pidBuffer[ 0 ] = 0;
296  pidBuffer[ 1 ] = 1;
297  }
298  for( i = 0; i < noProcesses; i++ )
299  {
300  short int pin = pidBuffer[ i ];
301 
302  error = PROCESS_GETINFOLIST_( cpuNo /* CPU no.*/
303  ,&pin /* Process ID */
304  , /* Node name */
305  , /* Node name length */
306  , /* Process handle */
307  ,( short int * ) procAttrList
308  /* Attrs.to read */
309  ,NO_PROC_ATTRS/* No.attrs.to read */
310  ,( short int * ) buffer
311  /* Returned attrs.*/
312  ,RANDOM_BUFSIZE / sizeof( short int )
313  /* Ret.attrs.buffer size */
314  ,&noAttrs /* No.returned attrs.*/
315  );
316  if( error == 0 )
317  {
318 #ifdef DEBUG_RANDOM
319  printf( "PROCESS_GETINFOLIST returned %d attributes for "
320  "process %d.\n", noAttrs, pin );
321 #endif /* DEBUG_RANDOM */
322  addRandomData( randomState, buffer,
323  noAttrs * sizeof( short int ) );
324  attrCount += max( noAttrs / 5, 10 );
325  }
326  }
327  }
328 
329  /* Flush any remaining data through. Quality = attrCount */
330  endRandomData( randomState, min( attrCount, 100 ) );
331  }