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 const struct cdevsw random_cdevsw = 60 { 61 .d_open = random_open, 62 .d_close = random_close, 63 .d_read = random_read, 64 .d_write = random_write, 65 .d_ioctl = random_ioctl, 66 .d_stop = (stop_fcn_t *)nulldev, 67 .d_reset = (reset_fcn_t *)nulldev, 68 .d_select = eno_select, 69 .d_mmap = eno_mmap, 70 .d_strategy = eno_strat, 71 .d_reserved_1 = eno_getc, 72 .d_reserved_2 = eno_putc, 73 }; 74 75 76 /* 77 * Called to initialize our device, 78 * and to register ourselves with devfs 79 */ 80 void 81 random_init(void) 82 { 83 int ret; 84 85 ret = cdevsw_add(RANDOM_MAJOR, &random_cdevsw); 86 if (ret < 0) { 87 panic("random_init: failed to allocate a major number!"); 88 } 89 90 devfs_make_node(makedev(ret, RANDOM_MINOR), DEVFS_CHAR, 91 UID_ROOT, GID_WHEEL, 0666, "random", 0); 92 93 /* 94 * also make urandom 95 * (which is exactly the same thing in our context) 96 */ 97 devfs_make_node(makedev(ret, URANDOM_MINOR), DEVFS_CHAR, 98 UID_ROOT, GID_WHEEL, 0666, "urandom", 0); 99 } 100 101 int 102 random_ioctl( __unused dev_t dev, u_long cmd, __unused caddr_t data, 103 __unused int flag, __unused struct proc *p ) 104 { 105 switch (cmd) { 106 case FIONBIO: 107 case FIOASYNC: 108 break; 109 default: 110 return ENODEV; 111 } 112 113 return 0; 114 } 115 116 /* 117 * Open the device. Make sure init happened, and make sure the caller is 118 * authorized. 119 */ 120 121 int 122 random_open(__unused dev_t dev, int flags, __unused int devtype, __unused struct proc *p) 123 { 124 /* 125 * if we are being opened for write, 126 * make sure that we have privledges do so 127 */ 128 if (flags & FWRITE) { 129 if (securelevel >= 2) { 130 return EPERM; 131 } 132 #ifndef __APPLE__ 133 if ((securelevel >= 1) && proc_suser(p)) { 134 return EPERM; 135 } 136 #endif /* !__APPLE__ */ 137 } 138 139 return 0; 140 } 141 142 143 /* 144 * close the device. 145 */ 146 147 int 148 random_close(__unused dev_t dev, __unused int flags, __unused int mode, __unused struct proc *p) 149 { 150 return 0; 151 } 152 153 154 /* 155 * Get entropic data from the Security Server, and use it to reseed the 156 * prng. 157 */ 158 int 159 random_write(dev_t dev, struct uio *uio, __unused int ioflag) 160 { 161 int retCode = 0; 162 char rdBuffer[256]; 163 164 if (minor(dev) != RANDOM_MINOR) { 165 return EPERM; 166 } 167 168 /* Security server is sending us entropy */ 169 170 while ((size_t)uio_resid(uio) > 0 && retCode == 0) { 171 /* get the user's data */ 172 size_t bytesToInput = MIN((size_t)uio_resid(uio), sizeof(rdBuffer)); 173 retCode = uiomove(rdBuffer, (int)bytesToInput, uio); 174 if (retCode != 0) { 175 break; 176 } 177 retCode = write_random(rdBuffer, (u_int)bytesToInput); 178 if (retCode != 0) { 179 break; 180 } 181 } 182 183 return retCode; 184 } 185 186 /* 187 * return data to the caller. Results unpredictable. 188 */ 189 int 190 random_read(__unused dev_t dev, struct uio *uio, __unused int ioflag) 191 { 192 int retCode = 0; 193 char buffer[512]; 194 195 size_t bytes_remaining = (size_t)uio_resid(uio); 196 while (bytes_remaining > 0 && retCode == 0) { 197 size_t bytesToRead = MIN(bytes_remaining, sizeof(buffer)); 198 read_random(buffer, (u_int)bytesToRead); 199 200 retCode = uiomove(buffer, (int)bytesToRead, uio); 201 if (retCode != 0) { 202 break; 203 } 204 205 bytes_remaining = (size_t)uio_resid(uio); 206 } 207 208 return retCode; 209 } 210 211 /* 212 * Return an u_int32_t pseudo-random number. 213 */ 214 u_int32_t 215 RandomULong(void) 216 { 217 u_int32_t buf; 218 read_random(&buf, sizeof(buf)); 219 return buf; 220 } 221 222 223 int 224 getentropy(__unused struct proc * p, struct getentropy_args *gap, __unused int * ret) 225 { 226 user_addr_t user_addr; 227 user_size_t user_size; 228 char buffer[256]; 229 230 user_addr = (user_addr_t)gap->buffer; 231 user_size = gap->size; 232 /* Can't request more than 256 random bytes 233 * at once. Complying with openbsd getentropy() 234 */ 235 if (user_size > sizeof(buffer)) { 236 return EINVAL; 237 } 238 read_random(buffer, (u_int)user_size); 239 return copyout(buffer, user_addr, user_size); 240 } 241