📄 random.c
字号:
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; /* Convert bytes to words */ bytes = (bytes + 3) / sizeof(__u32); add_entropy_words(random_state, buf, bytes); } 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++)) return -EFAULT; if (get_user(size, p)) return -EFAULT; if (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*sizeof(__u32))) 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); if (retval < 0) return retval; 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 RNDZAPENTCNT: if (!capable(CAP_SYS_ADMIN)) return -EPERM; random_state->entropy_count = 0; return 0; case RNDCLEARPOOL: /* Clear the entropy pool and associated counters. */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; clear_entropy_store(random_state); init_std_data(random_state); return 0; default: return -EINVAL; }}struct file_operations random_fops = { read: random_read, write: random_write, poll: random_poll, ioctl: random_ioctl,};struct file_operations urandom_fops = { read: urandom_read, write: random_write, ioctl: random_ioctl,};/*************************************************************** * Random UUID interface * * Used here for a Boot ID, but can be useful for other kernel * drivers. ***************************************************************//* * Generate random UUID */void generate_random_uuid(unsigned char uuid_out[16]){ get_random_bytes(uuid_out, 16); /* Set UUID version to 4 --- truely random generation */ uuid_out[6] = (uuid_out[6] & 0x0F) | 0x40; /* Set the UUID variant to DCE */ uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80;}/********************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -