1 /* 2 * Copyright (c) 1999-2009 Apple, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/proc.h> 33 #include <sys/errno.h> 34 #include <sys/ioctl.h> 35 #include <sys/conf.h> 36 #include <sys/fcntl.h> 37 #include <string.h> 38 #include <miscfs/devfs/devfs.h> 39 #include <kern/locks.h> 40 #include <kern/clock.h> 41 #include <sys/time.h> 42 #include <sys/malloc.h> 43 #include <sys/sysproto.h> 44 #include <sys/uio_internal.h> 45 46 #include <dev/random/randomdev.h> 47 48 #include <libkern/OSByteOrder.h> 49 #include <libkern/OSAtomic.h> 50 51 #include <mach/mach_time.h> 52 53 #define RANDOM_MAJOR -1 /* let the kernel pick the device number */ 54 #define RANDOM_MINOR 0 55 #define URANDOM_MINOR 1 56 57 d_ioctl_t random_ioctl; 58 59 static int 60 random_stop(__unused struct tty *tp, __unused int rw) 61 { 62 return 0; 63 } 64 65 static int 66 random_reset(__unused int uban) 67 { 68 return 0; 69 } 70 71 static int 72 random_select(__unused dev_t dev, __unused int which, __unused void *wql, 73 __unused struct proc *p) 74 { 75 return ENODEV; 76 } 77 78 static const struct cdevsw random_cdevsw = 79 { 80 .d_open = random_open, 81 .d_close = random_close, 82 .d_read = random_read, 83 .d_write = random_write, 84 .d_ioctl = random_ioctl, 85 .d_stop = random_stop, 86 .d_reset = random_reset, 87 .d_select = random_select, 88 .d_mmap = eno_mmap, 89 .d_strategy = eno_strat, 90 .d_reserved_1 = eno_getc, 91 .d_reserved_2 = eno_putc, 92 }; 93 94 95 /* 96 * Called to initialize our device, 97 * and to register ourselves with devfs 98 */ 99 void 100 random_init(void) 101 { 102 int ret; 103 104 ret = cdevsw_add(RANDOM_MAJOR, &random_cdevsw); 105 if (ret < 0) { 106 panic("random_init: failed to allocate a major number!"); 107 } 108 109 devfs_make_node(makedev(ret, RANDOM_MINOR), DEVFS_CHAR, 110 UID_ROOT, GID_WHEEL, 0666, "random"); 111 112 /* 113 * also make urandom 114 * (which is exactly the same thing in our context) 115 */ 116 devfs_make_node(makedev(ret, URANDOM_MINOR), DEVFS_CHAR, 117 UID_ROOT, GID_WHEEL, 0666, "urandom"); 118 } 119 120 int 121 random_ioctl( __unused dev_t dev, u_long cmd, __unused caddr_t data, 122 __unused int flag, __unused struct proc *p ) 123 { 124 switch (cmd) { 125 case FIONBIO: 126 case FIOASYNC: 127 break; 128 default: 129 return ENODEV; 130 } 131 132 return 0; 133 } 134 135 /* 136 * Open the device. Make sure init happened, and make sure the caller is 137 * authorized. 138 */ 139 140 int 141 random_open(__unused dev_t dev, int flags, __unused int devtype, __unused struct proc *p) 142 { 143 /* 144 * if we are being opened for write, 145 * make sure that we have privledges do so 146 */ 147 if (flags & FWRITE) { 148 if (securelevel >= 2) { 149 return EPERM; 150 } 151 #ifndef __APPLE__ 152 if ((securelevel >= 1) && proc_suser(p)) { 153 return EPERM; 154 } 155 #endif /* !__APPLE__ */ 156 } 157 158 return 0; 159 } 160 161 162 /* 163 * close the device. 164 */ 165 166 int 167 random_close(__unused dev_t dev, __unused int flags, __unused int mode, __unused struct proc *p) 168 { 169 return 0; 170 } 171 172 173 /* 174 * Get entropic data from the Security Server, and use it to reseed the 175 * prng. 176 */ 177 int 178 random_write(dev_t dev, struct uio *uio, __unused int ioflag) 179 { 180 int retCode = 0; 181 char rdBuffer[256]; 182 183 if (minor(dev) != RANDOM_MINOR) { 184 return EPERM; 185 } 186 187 /* Security server is sending us entropy */ 188 189 while ((size_t)uio_resid(uio) > 0 && retCode == 0) { 190 /* get the user's data */ 191 size_t bytesToInput = MIN((size_t)uio_resid(uio), sizeof(rdBuffer)); 192 retCode = uiomove(rdBuffer, (int)bytesToInput, uio); 193 if (retCode != 0) { 194 break; 195 } 196 retCode = write_random(rdBuffer, (u_int)bytesToInput); 197 if (retCode != 0) { 198 break; 199 } 200 } 201 202 return retCode; 203 } 204 205 /* 206 * return data to the caller. Results unpredictable. 207 */ 208 int 209 random_read(__unused dev_t dev, struct uio *uio, __unused int ioflag) 210 { 211 int retCode = 0; 212 char buffer[512]; 213 214 size_t bytes_remaining = (size_t)uio_resid(uio); 215 while (bytes_remaining > 0 && retCode == 0) { 216 size_t bytesToRead = MIN(bytes_remaining, sizeof(buffer)); 217 read_random(buffer, (u_int)bytesToRead); 218 219 retCode = uiomove(buffer, (int)bytesToRead, uio); 220 if (retCode != 0) { 221 break; 222 } 223 224 bytes_remaining = (size_t)uio_resid(uio); 225 } 226 227 return retCode; 228 } 229 230 /* 231 * Return an u_int32_t pseudo-random number. 232 */ 233 u_int32_t 234 RandomULong(void) 235 { 236 u_int32_t buf; 237 read_random(&buf, sizeof(buf)); 238 return buf; 239 } 240 241 242 int 243 getentropy(__unused struct proc * p, struct getentropy_args *gap, __unused int * ret) 244 { 245 user_addr_t user_addr; 246 user_size_t user_size; 247 char buffer[256]; 248 249 user_addr = (user_addr_t)gap->buffer; 250 user_size = gap->size; 251 /* Can't request more than 256 random bytes 252 * at once. Complying with openbsd getentropy() 253 */ 254 if (user_size > sizeof(buffer)) { 255 return EINVAL; 256 } 257 read_random(buffer, (u_int)user_size); 258 return copyout(buffer, user_addr, user_size); 259 } 260