📄 i810_rng.c
字号:
printk (KERN_INFO PFX "entropy bits now %d\n", rng_entropy_sysctl); } else { printk (KERN_INFO PFX "ignoring invalid entropy setting (%d)\n", rng_entropy_sysctl); }out: DPRINTK ("EXIT, returning 0\n"); return 0;}/* * rng_handle_sysctl_interval - handle a read or write of our timer interval len sysctl */static int rng_handle_sysctl_interval (ctl_table * table, int write, struct file *filp, void *buffer, size_t * lenp){ int timer_len_save, rc; DPRINTK ("ENTER\n"); spin_lock_bh (&rng_lock); rng_interval_sysctl = timer_len_save = rng_timer_len; spin_unlock_bh (&rng_lock); rc = proc_dointvec (table, write, filp, buffer, lenp); if (rc) return rc; if (timer_len_save == rng_interval_sysctl) goto out; if ((rng_interval_sysctl > 0) && (rng_interval_sysctl < (HZ*86400))) { spin_lock_bh (&rng_lock); rng_timer_len = rng_interval_sysctl; spin_unlock_bh (&rng_lock); printk (KERN_INFO PFX "timer interval now %d\n", rng_interval_sysctl); } else { printk (KERN_INFO PFX "ignoring invalid timer interval (%d)\n", rng_interval_sysctl); }out: DPRINTK ("EXIT, returning 0\n"); return 0;}/* * rng_sysctl - add or remove the rng sysctl */static void rng_sysctl (int add){#define DEV_I810_TIMER 1#define DEV_I810_ENTROPY 2#define DEV_I810_INTERVAL 3 /* Definition of the sysctl */ /* FIXME: use new field:value style of struct initialization */ static ctl_table rng_sysctls[] = { {DEV_I810_TIMER, /* ID */ RNG_MODULE_NAME "_timer", /* name in /proc */ &rng_enabled_sysctl, sizeof (rng_enabled_sysctl), /* data ptr, data size */ 0644, /* mode */ 0, /* child */ rng_handle_sysctl_enable, /* proc handler */ 0, /* strategy */ 0, /* proc control block */ 0, 0} , {DEV_I810_ENTROPY, /* ID */ RNG_MODULE_NAME "_entropy", /* name in /proc */ &rng_entropy_sysctl, sizeof (rng_entropy_sysctl), /* data ptr, data size */ 0644, /* mode */ 0, /* child */ rng_handle_sysctl_entropy, /* proc handler */ 0, /* strategy */ 0, /* proc control block */ 0, 0} , {DEV_I810_INTERVAL, /* ID */ RNG_MODULE_NAME "_interval", /* name in /proc */ &rng_interval_sysctl, sizeof (rng_interval_sysctl), /* data ptr, data size */ 0644, /* mode */ 0, /* child */ rng_handle_sysctl_interval, /* proc handler */ 0, /* strategy */ 0, /* proc control block */ 0, 0} , {0} }; /* Define the parent file : /proc/sys/dev */ static ctl_table sysctls_root[] = { {CTL_DEV, "dev", NULL, 0, 0555, rng_sysctls}, {0} }; static struct ctl_table_header *sysctls_root_header = NULL; if (add) { if (!sysctls_root_header) sysctls_root_header = register_sysctl_table (sysctls_root, 0); } else if (sysctls_root_header) { unregister_sysctl_table (sysctls_root_header); sysctls_root_header = NULL; }}static int rng_dev_open (struct inode *inode, struct file *filp){ int rc = -EINVAL; if ((filp->f_mode & FMODE_READ) == 0) return rc; if (filp->f_mode & FMODE_WRITE) return rc; /* wait for device to become free */ if (filp->f_flags & O_NONBLOCK) { if (down_trylock (&rng_open_sem)) return -EAGAIN; } else { if (down_interruptible (&rng_open_sem)) return -ERESTARTSYS; } if (rng_enable (1)) { rc = -EIO; goto err_out; } return 0;err_out: up (&rng_open_sem); return rc;}static int rng_dev_release (struct inode *inode, struct file *filp){ rng_enable(0); up (&rng_open_sem); return 0;}static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size, loff_t * offp){ int have_data; u8 data = 0; ssize_t ret = 0; while (size) { spin_lock_bh (&rng_lock); have_data = 0; if (rng_data_present ()) { data = rng_data_read (); have_data = 1; } spin_unlock_bh (&rng_lock); if (have_data) { if (put_user (data, buf++)) { ret = ret ? : -EFAULT; break; } size--; ret++; } if (current->need_resched) schedule (); if (signal_pending (current)) return ret ? : -ERESTARTSYS; if (filp->f_flags & O_NONBLOCK) return ret ? : -EAGAIN; } return ret;}/* * rng_init_one - look for and attempt to init a single RNG */static int __init rng_init_one (struct pci_dev *dev){ int rc; u8 hw_status; DPRINTK ("ENTER\n"); if (pci_enable_device (dev)) return -EIO; /* XXX currently fails, investigate who has our mem region */ if (request_mem_region (RNG_ADDR, RNG_ADDR_LEN, RNG_MODULE_NAME)) rng_have_mem_region = 1; rng_mem = ioremap (RNG_ADDR, RNG_ADDR_LEN); if (rng_mem == NULL) { printk (KERN_ERR PFX "cannot ioremap RNG Memory\n"); DPRINTK ("EXIT, returning -EBUSY\n"); rc = -EBUSY; goto err_out_free_res; } /* Check for Intel 82802 */ hw_status = rng_hwstatus (); if ((hw_status & RNG_PRESENT) == 0) { printk (KERN_ERR PFX "RNG not detected\n"); DPRINTK ("EXIT, returning -ENODEV\n"); rc = -ENODEV; goto err_out_free_map; } if (rng_entropy < 0 || rng_entropy > RNG_MAX_ENTROPY) rng_entropy = RNG_MAX_ENTROPY; /* init core RNG timer, but do not add it */ init_timer (&rng_timer); rng_timer.function = rng_timer_tick; /* turn RNG h/w off, if it's on */ rc = rng_enable (0); if (rc) { printk (KERN_ERR PFX "cannot disable RNG, aborting\n"); goto err_out_free_map; } /* add sysctls */ rng_sysctl (1); DPRINTK ("EXIT, returning 0\n"); return 0;err_out_free_map: iounmap (rng_mem);err_out_free_res: if (rng_have_mem_region) release_mem_region (RNG_ADDR, RNG_ADDR_LEN); return rc;}/* * Data for PCI driver interface * * This data only exists for exporting the supported * PCI ids via MODULE_DEVICE_TABLE. We do not actually * register a pci_driver, because someone else might one day * want to register another driver on the same PCI id. */const static struct pci_device_id rng_pci_tbl[] __initdata = { { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, }, { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, }, { 0x8086, 0x1130, PCI_ANY_ID, PCI_ANY_ID, }, { 0, },};MODULE_DEVICE_TABLE (pci, rng_pci_tbl);MODULE_AUTHOR("Jeff Garzik, Matt Sottek");MODULE_DESCRIPTION("Intel i8xx chipset Random Number Generator (RNG) driver");MODULE_PARM(rng_entropy, "1i");MODULE_PARM_DESC(rng_entropy, "Bits of entropy to add to random pool per RNG byte (range: 0-8, default 8)");static struct file_operations rng_chrdev_ops = { owner: THIS_MODULE, open: rng_dev_open, release: rng_dev_release, read: rng_dev_read,};static struct miscdevice rng_miscdev = { RNG_MISCDEV_MINOR, RNG_MODULE_NAME, &rng_chrdev_ops,};/* * rng_init - initialize RNG module */static int __init rng_init (void){ int rc; struct pci_dev *pdev; DPRINTK ("ENTER\n"); init_MUTEX (&rng_open_sem); pci_for_each_dev(pdev) { if (pci_match_device (rng_pci_tbl, pdev) != NULL) goto match; } DPRINTK ("EXIT, returning -ENODEV\n"); return -ENODEV;match: rc = rng_init_one (pdev); if (rc) return rc; rc = misc_register (&rng_miscdev); if (rc) { iounmap (rng_mem); if (rng_have_mem_region) release_mem_region (RNG_ADDR, RNG_ADDR_LEN); DPRINTK ("EXIT, returning %d\n", rc); return rc; } printk (KERN_INFO RNG_DRIVER_NAME " loaded\n"); rng_pdev = pdev; DPRINTK ("EXIT, returning 0\n"); return 0;}/* * rng_init - shutdown RNG module */static void __exit rng_cleanup (void){ DPRINTK ("ENTER\n"); assert (rng_timer_enabled == 0); assert (rng_hw_enabled == 0); misc_deregister (&rng_miscdev); rng_sysctl (0); iounmap (rng_mem); if (rng_have_mem_region) release_mem_region (RNG_ADDR, RNG_ADDR_LEN); DPRINTK ("EXIT\n");}module_init (rng_init);module_exit (rng_cleanup);/* These are the startup tests suggested by the FIPS 140-1 spec section* 4.11.1 (http://csrc.nist.gov/fips/fips1401.htm)* The Monobit, Poker, Runs, and Long Runs tests are implemented below.* This test is run at periodic intervals to verify* data is sufficiently random. If the tests are failed the RNG module* will no longer submit data to the entropy pool, but the tests will* continue to run at the given interval. If at a later time the RNG* passes all tests it will be re-enabled for the next period.* The reason for this is that it is not unlikely that at some time* during normal operation one of the tests will fail. This does not* necessarily mean the RNG is not operating properly, it is just a* statistically rare event. In that case we don't want to forever* disable the RNG, we will just leave it disabled for the period of* time until the tests are rerun and passed.** For argument sake I tested /dev/urandom with these tests and it* took 142,095 tries before I got a failure, and urandom isn't as* random as random :)*/static int poker[16] = { 0, }, runs[12] = { 0, };static int ones = 0, rlength = -1, current_bit = 0, rng_test = 0;/* * rng_fips_test_store - store 8 bits of entropy in FIPS * internal test data pool */static void rng_fips_test_store (int rng_data){ int j; static int last_bit = 0; DPRINTK ("ENTER, rng_data = %d\n", rng_data); poker[rng_data >> 4]++; poker[rng_data & 15]++; /* Note in the loop below rlength is always one less than the actual run length. This makes things easier. */ last_bit = (rng_data & 128) >> 7; for (j = 7; j >= 0; j--) { ones += current_bit = (rng_data & 1 << j) >> j; if (current_bit != last_bit) { /* If runlength is 1-6 count it in correct bucket. 0's go in runs[0-5] 1's go in runs[6-11] hence the 6*current_bit below */ if (rlength < 5) { runs[rlength + (6 * current_bit)]++; } else { runs[5 + (6 * current_bit)]++; } /* Check if we just failed longrun test */ if (rlength >= 33) rng_test &= 8; rlength = 0; /* flip the current run type */ last_bit = current_bit; } else { rlength++; } } DPRINTK ("EXIT\n");}/* * now that we have some data, run a FIPS test */static void rng_run_fips_test (void){ int j, i; DPRINTK ("ENTER\n"); /* add in the last (possibly incomplete) run */ if (rlength < 5) runs[rlength + (6 * current_bit)]++; else { runs[5 + (6 * current_bit)]++; if (rlength >= 33) rng_test &= 8; } /* Ones test */ if ((ones >= 10346) || (ones <= 9654)) rng_test &= 1; /* Poker calcs */ for (i = 0, j = 0; i < 16; i++) j += poker[i] * poker[i]; if ((j >= 1580457) || (j <= 1562821)) rng_test &= 2; if ((runs[0] < 2267) || (runs[0] > 2733) || (runs[1] < 1079) || (runs[1] > 1421) || (runs[2] < 502) || (runs[2] > 748) || (runs[3] < 223) || (runs[3] > 402) || (runs[4] < 90) || (runs[4] > 223) || (runs[5] < 90) || (runs[5] > 223) || (runs[6] < 2267) || (runs[6] > 2733) || (runs[7] < 1079) || (runs[7] > 1421) || (runs[8] < 502) || (runs[8] > 748) || (runs[9] < 223) || (runs[9] > 402) || (runs[10] < 90) || (runs[10] > 223) || (runs[11] < 90) || (runs[11] > 223)) { rng_test &= 4; } rng_test = !rng_test; DPRINTK ("FIPS test %sed\n", rng_test ? "pass" : "fail"); /* enable/disable RNG with results of the tests */ if (rng_test && !rng_trusted) printk (KERN_WARNING PFX "FIPS test passed, enabling RNG\n"); else if (!rng_test && rng_trusted) printk (KERN_WARNING PFX "FIPS test failed, disabling RNG\n"); rng_trusted = rng_test; /* finally, clear out FIPS variables for start of next run */ memset (poker, 0, sizeof (poker)); memset (runs, 0, sizeof (runs)); ones = 0; rlength = -1; current_bit = 0; rng_test = 0; DPRINTK ("EXIT\n");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -