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 108 int 109 random_ioctl( __unused dev_t dev, u_long cmd, __unused caddr_t data, 110 __unused int flag, __unused struct proc *p ) 111 { 112 switch (cmd) { 113 case FIONBIO: 114 case FIOASYNC: 115 break; 116 default: 117 return ENODEV; 118 } 119 120 return (0); 121 } 122 123 /* 124 * Open the device. Make sure init happened, and make sure the caller is 125 * authorized. 126 */ 127 128 int 129 random_open(__unused dev_t dev, int flags, __unused int devtype, __unused struct proc *p) 130 { 131 /* 132 * if we are being opened for write, 133 * make sure that we have privledges do so 134 */ 135 if (flags & FWRITE) { 136 if (securelevel >= 2) 137 return (EPERM); 138 #ifndef __APPLE__ 139 if ((securelevel >= 1) && proc_suser(p)) 140 return (EPERM); 141 #endif /* !__APPLE__ */ 142 } 143 144 return (0); 145 } 146 147 148 /* 149 * close the device. 150 */ 151 152 int 153 random_close(__unused dev_t dev, __unused int flags, __unused int mode, __unused struct proc *p) 154 { 155 return (0); 156 } 157 158 159 /* 160 * Get entropic data from the Security Server, and use it to reseed the 161 * prng. 162 */ 163 int 164 random_write (dev_t dev, struct uio *uio, __unused int ioflag) 165 { 166 int retCode = 0; 167 char rdBuffer[256]; 168 169 if (minor(dev) != RANDOM_MINOR) 170 return EPERM; 171 172 /* Security server is sending us entropy */ 173 174 while (uio_resid(uio) > 0 && retCode == 0) { 175 /* get the user's data */ 176 int bytesToInput = MIN(uio_resid(uio), 177 (user_ssize_t) sizeof(rdBuffer)); 178 retCode = uiomove(rdBuffer, bytesToInput, uio); 179 if (retCode != 0) 180 break; 181 retCode = write_random(rdBuffer, bytesToInput); 182 if (retCode != 0) 183 break; 184 } 185 186 return retCode; 187 } 188 189 /* 190 * return data to the caller. Results unpredictable. 191 */ 192 int 193 random_read(__unused dev_t dev, struct uio *uio, __unused int ioflag) 194 { 195 int retCode = 0; 196 char buffer[512]; 197 198 user_ssize_t bytes_remaining = uio_resid(uio); 199 while (bytes_remaining > 0 && retCode == 0) { 200 int bytesToRead = MIN(bytes_remaining, 201 (user_ssize_t) sizeof(buffer)); 202 read_random(buffer, bytesToRead); 203 204 retCode = uiomove(buffer, bytesToRead, uio); 205 if (retCode != 0) 206 break; 207 208 bytes_remaining = uio_resid(uio); 209 } 210 211 return retCode; 212 } 213 214 /* 215 * Return an u_int32_t pseudo-random number. 216 */ 217 u_int32_t 218 RandomULong(void) 219 { 220 u_int32_t buf; 221 read_random(&buf, sizeof (buf)); 222 return (buf); 223 } 224 225 226 int 227 getentropy(__unused struct proc * p, struct getentropy_args *gap, __unused int * ret) { 228 user_addr_t user_addr; 229 uint32_t user_size; 230 char buffer[256]; 231 232 user_addr = (vm_map_offset_t)gap->buffer; 233 user_size = gap->size; 234 /* Can't request more than 256 random bytes 235 * at once. Complying with openbsd getentropy() 236 */ 237 if (user_size > sizeof(buffer)) { 238 return EINVAL; 239 } 240 read_random(buffer, user_size); 241 return copyout(buffer, user_addr, user_size); 242 } 243