📄 random.c
字号:
sizeof(tmp) / 4); DEBUG_ENT("xfer %d from primary to %s (have %d, need %d)\n", nwords * 32, r == sec_random_state ? "secondary" : "unknown", r->entropy_count, nbytes * 8); extract_entropy(random_state, tmp, nwords * 4, 0); add_entropy_words(r, tmp, nwords); credit_entropy_store(r, nwords * 32); } if (r->extract_count > 1024) { DEBUG_ENT("reseeding %s with %d from primary\n", r == sec_random_state ? "secondary" : "unknown", sizeof(tmp) * 8); extract_entropy(random_state, tmp, sizeof(tmp), 0); add_entropy_words(r, tmp, sizeof(tmp) / 4); r->extract_count = 0; }}/* * This function extracts randomness from the "entropy pool", and * returns it in a buffer. This function computes how many remaining * bits of entropy are left in the pool, but it does not restrict the * number of bytes that are actually obtained. If the EXTRACT_ENTROPY_USER * flag is given, then the buf pointer is assumed to be in user space. * * If the EXTRACT_ENTROPY_SECONDARY flag is given, then we are actually * extracting entropy from the secondary pool, and can refill from the * primary pool if needed. * * Note: extract_entropy() assumes that .poolwords is a multiple of 16 words. */static ssize_t extract_entropy(struct entropy_store *r, void * buf, size_t nbytes, int flags){ ssize_t ret, i; __u32 tmp[TMP_BUF_SIZE]; __u32 x; add_timer_randomness(&extract_timer_state, nbytes); /* Redundant, but just in case... */ if (r->entropy_count > r->poolinfo.POOLBITS) r->entropy_count = r->poolinfo.POOLBITS; if (flags & EXTRACT_ENTROPY_SECONDARY) xfer_secondary_pool(r, nbytes); DEBUG_ENT("%s has %d bits, want %d bits\n", r == sec_random_state ? "secondary" : r == random_state ? "primary" : "unknown", r->entropy_count, nbytes * 8); if (r->entropy_count / 8 >= nbytes) r->entropy_count -= nbytes*8; else r->entropy_count = 0; if (r->entropy_count < random_write_wakeup_thresh) wake_up_interruptible(&random_write_wait); r->extract_count += nbytes; ret = 0; while (nbytes) { /* * Check if we need to break out or reschedule.... */ if ((flags & EXTRACT_ENTROPY_USER) && current->need_resched) { if (signal_pending(current)) { if (ret == 0) ret = -ERESTARTSYS; break; } schedule(); } /* Hash the pool to get the output */ tmp[0] = 0x67452301; tmp[1] = 0xefcdab89; tmp[2] = 0x98badcfe; tmp[3] = 0x10325476;#ifdef USE_SHA tmp[4] = 0xc3d2e1f0;#endif /* * As we hash the pool, we mix intermediate values of * the hash back into the pool. This eliminates * backtracking attacks (where the attacker knows * the state of the pool plus the current outputs, and * attempts to find previous ouputs), unless the hash * function can be inverted. */ for (i = 0, x = 0; i < r->poolinfo.poolwords; i += 16, x+=2) { HASH_TRANSFORM(tmp, r->pool+i); add_entropy_words(r, &tmp[x%HASH_BUFFER_SIZE], 1); } /* * In case the hash function has some recognizable * output pattern, we fold it in half. */ for (i = 0; i < HASH_BUFFER_SIZE/2; i++) tmp[i] ^= tmp[i + (HASH_BUFFER_SIZE+1)/2];#if HASH_BUFFER_SIZE & 1 /* There's a middle word to deal with */ x = tmp[HASH_BUFFER_SIZE/2]; x ^= (x >> 16); /* Fold it in half */ ((__u16 *)tmp)[HASH_BUFFER_SIZE-1] = (__u16)x;#endif /* Copy data to destination buffer */ i = min(nbytes, HASH_BUFFER_SIZE*sizeof(__u32)/2); if (flags & EXTRACT_ENTROPY_USER) { i -= copy_to_user(buf, (__u8 const *)tmp, i); if (!i) { ret = -EFAULT; break; } } else memcpy(buf, (__u8 const *)tmp, i); nbytes -= i; buf += i; ret += i; add_timer_randomness(&extract_timer_state, nbytes); } /* Wipe data just returned from memory */ memset(tmp, 0, sizeof(tmp)); return ret;}/* * This function is the exported kernel interface. It returns some * number of good random numbers, suitable for seeding TCP sequence * numbers, etc. */void get_random_bytes(void *buf, int nbytes){ if (sec_random_state) extract_entropy(sec_random_state, (char *) buf, nbytes, EXTRACT_ENTROPY_SECONDARY); else if (random_state) extract_entropy(random_state, (char *) buf, nbytes, 0); else printk(KERN_NOTICE "get_random_bytes called before " "random driver initialization\n");}/********************************************************************* * * Functions to interface with Linux * *********************************************************************//* * Initialize the random pool with standard stuff. * * NOTE: This is an OS-dependent function. */static void init_std_data(struct entropy_store *r){ struct timeval tv; __u32 words[2]; char *p; int i; do_gettimeofday(&tv); words[0] = tv.tv_sec; words[1] = tv.tv_usec; add_entropy_words(r, words, 2); /* * This doesn't lock system.utsname. However, we are generating * entropy so a race with a name set here is fine. */ p = (char *) &system_utsname; for (i = sizeof(system_utsname) / sizeof(words); i; i--) { memcpy(words, p, sizeof(words)); add_entropy_words(r, words, sizeof(words)/4); p += sizeof(words); }}void __init rand_initialize(void){ int i; if (create_entropy_store(DEFAULT_POOL_SIZE, &random_state)) return; /* Error, return */ if (batch_entropy_init(BATCH_ENTROPY_SIZE, random_state)) return; /* Error, return */ if (create_entropy_store(SECONDARY_POOL_SIZE, &sec_random_state)) return; /* Error, return */ clear_entropy_store(random_state); clear_entropy_store(sec_random_state); init_std_data(random_state);#ifdef CONFIG_SYSCTL sysctl_init_random(random_state);#endif for (i = 0; i < NR_IRQS; i++) irq_timer_state[i] = NULL; for (i = 0; i < MAX_BLKDEV; i++) blkdev_timer_state[i] = NULL; memset(&keyboard_timer_state, 0, sizeof(struct timer_rand_state)); memset(&mouse_timer_state, 0, sizeof(struct timer_rand_state)); memset(&extract_timer_state, 0, sizeof(struct timer_rand_state)); extract_timer_state.dont_count_entropy = 1;}void rand_initialize_irq(int irq){ struct timer_rand_state *state; if (irq >= NR_IRQS || irq_timer_state[irq]) return; /* * If kmalloc returns null, we just won't use that entropy * source. */ state = kmalloc(sizeof(struct timer_rand_state), GFP_KERNEL); if (state) { memset(state, 0, sizeof(struct timer_rand_state)); irq_timer_state[irq] = state; }}void rand_initialize_blkdev(int major, int mode){ struct timer_rand_state *state; if (major >= MAX_BLKDEV || blkdev_timer_state[major]) return; /* * If kmalloc returns null, we just won't use that entropy * source. */ state = kmalloc(sizeof(struct timer_rand_state), mode); if (state) { memset(state, 0, sizeof(struct timer_rand_state)); blkdev_timer_state[major] = state; }}static ssize_trandom_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos){ DECLARE_WAITQUEUE(wait, current); ssize_t n, retval = 0, count = 0; if (nbytes == 0) return 0; add_wait_queue(&random_read_wait, &wait); while (nbytes > 0) { set_current_state(TASK_INTERRUPTIBLE); n = nbytes; if (n > SEC_XFER_SIZE) n = SEC_XFER_SIZE; if (n > random_state->entropy_count / 8) n = random_state->entropy_count / 8; if (n == 0) { if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; break; } if (signal_pending(current)) { retval = -ERESTARTSYS; break; } schedule(); continue; } n = extract_entropy(sec_random_state, buf, n, EXTRACT_ENTROPY_USER | EXTRACT_ENTROPY_SECONDARY); if (n < 0) { retval = n; break; } count += n; buf += n; nbytes -= n; break; /* This break makes the device work */ /* like a named pipe */ } current->state = TASK_RUNNING; remove_wait_queue(&random_read_wait, &wait); /* * If we gave the user some bytes, update the access time. */ if (count != 0) { UPDATE_ATIME(file->f_dentry->d_inode); } return (count ? count : retval);}static ssize_turandom_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos){ return extract_entropy(sec_random_state, buf, nbytes, EXTRACT_ENTROPY_USER | EXTRACT_ENTROPY_SECONDARY);}static unsigned intrandom_poll(struct file *file, poll_table * wait){ unsigned int mask; poll_wait(file, &random_read_wait, wait); poll_wait(file, &random_write_wait, wait); mask = 0; if (random_state->entropy_count >= random_read_wakeup_thresh) mask |= POLLIN | POLLRDNORM; if (random_state->entropy_count < random_write_wakeup_thresh) mask |= POLLOUT | POLLWRNORM; return mask;}static ssize_trandom_write(struct file * file, const char * buffer, size_t count, loff_t *ppos){ int ret = 0; size_t bytes; __u32 buf[16]; const char *p = buffer; size_t c = count; while (c > 0) { bytes = min(c, sizeof(buf)); bytes -= copy_from_user(&buf, p, bytes); if (!bytes) { ret = -EFAULT; break; } c -= bytes; p += bytes; add_entropy_words(random_state, buf, (bytes + 3) / 4); } if (p == buffer) { return (ssize_t)ret; } else { file->f_dentry->d_inode->i_mtime = CURRENT_TIME; mark_inode_dirty(file->f_dentry->d_inode); return (ssize_t)(p - buffer); }}static intrandom_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg){ int *p, size, ent_count; int retval; switch (cmd) { case RNDGETENTCNT: ent_count = random_state->entropy_count; if (put_user(ent_count, (int *) arg)) return -EFAULT; return 0; case RNDADDTOENTCNT: if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (get_user(ent_count, (int *) arg)) return -EFAULT; credit_entropy_store(random_state, ent_count); /* * Wake up waiting processes if we have enough * entropy. */ if (random_state->entropy_count >= random_read_wakeup_thresh) wake_up_interruptible(&random_read_wait); return 0; case RNDGETPOOL: if (!capable(CAP_SYS_ADMIN)) return -EPERM; p = (int *) arg; ent_count = random_state->entropy_count; if (put_user(ent_count, p++) || get_user(size, p) || put_user(random_state->poolinfo.poolwords, p++)) return -EFAULT; if (size < 0) return -EINVAL; if (size > random_state->poolinfo.poolwords) size = random_state->poolinfo.poolwords; if (copy_to_user(p, random_state->pool, size * 4)) return -EFAULT; return 0; case RNDADDENTROPY: if (!capable(CAP_SYS_ADMIN)) return -EPERM; p = (int *) arg; if (get_user(ent_count, p++)) return -EFAULT; if (ent_count < 0) return -EINVAL; if (get_user(size, p++)) return -EFAULT; retval = random_write(file, (const char *) p, size, &file->f_pos);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -