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