内核中启动看门狗时不加保护引起内核crack
如果直接在iTCO_wdt.c中这样开启看门狗:
static int __init iTCO_wdt_init_module(void){int err;printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s\n",DRV_VERSION);err = platform_driver_register(&iTCO_wdt_driver);if (err)return err;iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME,-1, NULL, 0);if (IS_ERR(iTCO_wdt_platform_device)) {err = PTR_ERR(iTCO_wdt_platform_device);goto unreg_platform_driver;}iTCO_wdt_start();if (iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT)){return -EINVAL;}iTCO_wdt_keepalive();return 0;unreg_platform_driver:platform_driver_unregister(&iTCO_wdt_driver);return err;}
会在某些情况下导致内核崩溃
跟踪一下:
iTCO_wdt_probe()
--> iTCO_wdt_init():
static int __devinit iTCO_wdt_init(struct pci_dev *pdev,const struct pci_device_id *ent, struct platform_device *dev){... if (iTCO_wdt_private.iTCO_version == 2) { pci_read_config_dword(pdev, 0xf0, &base_address); RCBA = base_address & 0xffffc000; iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410), 4); }.../* Check chipset's NO_REBOOT bit */if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, ""reboot disabled by hardware\n");ret = -ENODEV;/* Cannot reset NO_REBOOT bit */goto out;}...out:if (iTCO_wdt_private.iTCO_version == 2)iounmap(iTCO_wdt_private.gcs);pci_dev_put(iTCO_wdt_private.pdev);iTCO_wdt_private.ACPIBASE = 0;return ret;}
在iTCO_wdt_init()中会调用iTCO_wdt_unset_NO_REBOOT_bit()函数,如果这个函数中NO_REBOOT是硬件禁止的(这里和南桥的SPKR信号有关,即和蜂鸣器的那个信号有关),在我们产品上应该去掉SPKR上的电阻R894,否则,内核启动时会出现:
iTCO_wdt: failed to reset NO_REBOOT flag, reboot disabled by hardware
这种打印。
继续关注:如果这里出现了这种打印,也就是说这里会执行goto out
在out:中会将iTCO_wdt_private.gcs申请的内存释放掉,那么:
在iTCO_wdt_init_module()中再去调用iTCO_wdt_start(),然后iTCO_wdt_start()会调用iTCO_wdt_unset_NO_REBOOT_bit(),
在iTCO_wdt_unset_NO_REBOOT_bit()中仍会对iTCO_wdt_private.gcs进行访问,那么内核就会访问被释放掉的内存,那么内核就可能会crack!
解决方案:
需要在iTCO_wdt_init_module()中调用iTCO_wdt_start()时,先判断iTCO_wdt_private.ACPIBASE该值是否为0,如果是0,则不去调用,否则才调用:
if(0 != iTCO_wdt_private.ACPIBASE){iTCO_wdt_start();if (iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT)){return -EINVAL;}iTCO_wdt_keepalive();}