]> git.saurik.com Git - apple/security.git/blob - SecurityServer/MacYarrow/YarrowServer/systemEntropy.c
Security-28.tar.gz
[apple/security.git] / SecurityServer / MacYarrow / YarrowServer / systemEntropy.c
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 /*
20 File: systemEntropy.c
21
22 Contains: System entropy collector, using
23 sysctl(CTL_KERN:KERN_KDEBUG) trace info
24
25 Copyright: (C) 2000 by Apple Computer, Inc., all rights reserved
26
27 Written by: Doug Mitchell <dmitch@apple.com>
28 */
29
30 #include "systemEntropy.h"
31 #include "debug.h"
32
33 /* support for sysctl */
34 #include <stdlib.h>
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/time.h>
38 //#include <libc.h>
39 #include <sys/kdebug.h>
40 #include <sys/sysctl.h>
41 #include <sys/errno.h>
42 #include <unistd.h>
43
44 /* this should eventually come from private system headers */
45 #include "kdebug_private.h"
46
47 /* time to gather trace info */
48 #define MS_TO_SLEEP 100
49
50 static int set_remove();
51 static int set_init();
52 static int set_enable(int val);
53 static int set_numbufs(int nbufs);
54
55 /* start collecting system entropy */
56 int systemEntropyBegin(UInt32 bufSize)
57 {
58 int rtn;
59
60 /* start from clean slate */
61 set_remove();
62
63 /*
64 * This will result in a ENOENT error if we're not root.
65 * That's OK, the kernel will use its default of an 8K
66 * buffer in that case.
67 */
68 set_numbufs(bufSize);
69 if(rtn = set_init()) {
70 return rtn;
71 }
72 if(rtn = set_enable(1)) {
73 return rtn;
74 }
75 return 0;
76 }
77
78
79 int systemEntropyCollect(
80 UInt8 *buf,
81 UInt32 bufSize,
82 UInt32 *numBytes, // RETURNED - number of bytes obtained
83 UInt32 *bitsOfEntropy) // RETURNED - est. amount of entropy
84 {
85 int rtn = 0;
86 size_t mallocdSize;
87 UInt8 *cp = buf;
88 kd_buf *kd = NULL;
89 int i;
90 int mib[6];
91 size_t numEntries;
92
93 *numBytes = 0;
94 *bitsOfEntropy = 0;
95
96
97 /*
98 * We use one byte from each entry, which is a kd_buf.
99 * Thus, malloc bufSize kd_bufs.
100 * FIXME : this should use a secure nonswapping malloc.
101 */
102 mallocdSize = bufSize * sizeof(kd_buf);
103 kd = (kd_buf *)malloc(mallocdSize);
104 if(kd == NULL) {
105 rtn = ENOMEM;
106 goto errOut;
107 }
108
109 mib[0] = CTL_KERN;
110 mib[1] = KERN_KDEBUG;
111 mib[2] = KERN_KDREADTR;
112 mib[3] = 0;
113 mib[4] = 0;
114 mib[5] = 0; /* no flags */
115
116 /*
117 * Snag the trace buffer, up to caller's limit.
118 * On call to sysctl, numEntries is byte count, on return,
119 * it's buffer count.
120 */
121 numEntries = mallocdSize;
122 if (sysctl(mib, 3, kd, &numEntries, NULL, 0) < 0) {
123 /* ENOMEM means we didn't have room for everything in
124 * the kernel trace buffer, which is fine */
125 int err = errno;
126 if(err != ENOMEM) {
127 errorLog1("sysctl-KERN_KDREADTR: %d\n", err);
128 rtn = err;
129 goto errOut;
130 }
131 }
132 if(numEntries == 0) {
133 rtn = ENOENT;
134 goto errOut;
135 }
136
137 /*
138 * First entropy byte is the low byte of the first entry's
139 * timestamp. Subsequent bytes are the deltas between successive
140 * entries' timestamps.
141 */
142 *cp++ = (UInt8)kd[0].timestamp.tv_nsec;
143 for (i=1; i<numEntries; i++) {
144 *cp++ = kd[i].timestamp.tv_nsec - kd[i-1].timestamp.tv_nsec;
145 }
146
147 *numBytes = numEntries;
148 *bitsOfEntropy = numEntries * 4; // half random?
149
150 /* and finally, turn off tracing */
151 errOut:
152 set_enable(0);
153 set_remove(); // ignore errors
154 return rtn;
155 }
156
157 /*
158 * The remainder of this file is based on code provided by Joe Sokol.
159 * All functions return a UNIX errno, zero on success.
160 */
161
162 static int set_remove()
163 {
164 int mib[6];
165 size_t needed;
166
167 mib[0] = CTL_KERN;
168 mib[1] = KERN_KDEBUG;
169 mib[2] = KERN_KDREMOVE; /* protocol */
170 mib[3] = 0;
171 mib[4] = 0;
172 mib[5] = 0; /* no flags */
173
174 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0) {
175 int err = errno;
176 errorLog1("sysctl-KERN_KDREMOVE: %d\n", err);
177 return err;
178 }
179 return 0;
180 }
181
182 static int set_init()
183 {
184 kd_regtype kr;
185 int mib[6];
186 size_t needed;
187
188 kr.type = KDBG_RANGETYPE;
189 kr.value1 = 0;
190 kr.value2 = -1;
191 needed = sizeof(kd_regtype);
192 mib[0] = CTL_KERN;
193 mib[1] = KERN_KDEBUG;
194 mib[2] = KERN_KDSETREG;
195 mib[3] = 0;
196 mib[4] = 0;
197 mib[5] = 0; /* no flags */
198
199 if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) {
200 int err = errno;
201 errorLog1("sysctl-KERN_KDSETREG: %d\n", err);
202 return err;
203 }
204
205 mib[0] = CTL_KERN;
206 mib[1] = KERN_KDEBUG;
207 mib[2] = KERN_KDSETUP;
208 mib[3] = 0;
209 mib[4] = 0;
210 mib[5] = 0; /* no flags */
211
212 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0) {
213 int err = errno;
214 errorLog1("sysctl-KERN_KDSETUP: %d\n", err);
215 return err;
216 }
217 return 0;
218 }
219
220 static int set_enable(int val)
221 {
222 int mib[6];
223 size_t needed;
224
225 mib[0] = CTL_KERN;
226 mib[1] = KERN_KDEBUG;
227 mib[2] = KERN_KDENABLE; /* protocol */
228 mib[3] = val;
229 mib[4] = 0;
230 mib[5] = 0; /* no flags */
231 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) {
232 int err = errno;
233 errorLog1("sysctl-KERN_KDENABLE: %d\n", err);
234 return err;
235 }
236 return 0;
237 }
238
239 static int set_numbufs(int nbufs)
240 {
241 int mib[6];
242 size_t needed;
243
244 mib[0] = CTL_KERN;
245 mib[1] = KERN_KDEBUG;
246 mib[2] = KERN_KDSETBUF;
247 mib[3] = nbufs;
248 mib[4] = 0;
249 mib[5] = 0; /* no flags */
250 if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) {
251 int err = errno;
252 errorLog2("ERROR: sysctl-KERN_KDSETBUF(%d): %s\n",
253 nbufs, strerror(err));
254 return err;
255 }
256
257 mib[0] = CTL_KERN;
258 mib[1] = KERN_KDEBUG;
259 mib[2] = KERN_KDSETUP;
260 mib[3] = 0;
261 mib[4] = 0;
262 mib[5] = 0; /* no flags */
263 if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0) {
264 int err = errno;
265 errorLog1("ERROR: sysctl-KERN_KDSETUP: %s\n",
266 strerror(err));
267 return err;
268 }
269 return 0;
270 }