//------------------------------------------------------------------- // iopl.c // // The sole purpose of this character-mode device-driver is for // our "proof-of-concept" demonstration of a technique we shall // employ in our subsequent "uhci.c" module whereby a user-mode // program can acquire the ability to directly access I/O-ports // as a 'side-effect' of opening the '/dev/uhci' device-file. // // NOTE: Written and tested with Linux kernel version 2.6.31.5. // // programmer: ALLAN CRUSE // written on: 19 MAR 2010 //------------------------------------------------------------------- #include // for init_module() #include // for create_proc_read_entry() #include // for thread_struct char modname[] = "uhci"; char devname[] = "uhci"; int my_major = 74; int my_open( struct inode *inode, struct file *file ) { // As a 'side-effect' of opening the device-file, the // task's I/O Privilege-Level will be set equal to 3. // This code below closely follows ideas from Linux's // 'sys_iopl()' implementation, but without checks on // CAP_SYS_RAWIO and without options for IOPL values unsigned long structsize = sizeof( struct pt_regs ); struct thread_struct *ts = ¤t->thread; unsigned long regsp = ts->sp0 - structsize; struct pt_regs *regs = (struct pt_regs *)regsp; // For the i386 architecture (or in "compatibility mode" // of the x86_64 architecture) the user's FLAGS-register // is saved and restored during system-calls from fields // in its kernel data-structures (which we modify here) regs->flags |= (3 << 12); ts->iopl = (3 << 12); set_iopl_mask( ts->iopl ); #ifndef i386 // In the x86_64 architecture, the 'syscall' instruction // saves the user's RFLAGS values in register R11. Then // the Linux kernel pushes %r11 onto its stack and later // restores R11 from its stack before executing 'sysret' regs->r11 |= (3 << 12); // sets IOPL-image to 3 #endif return 0; // SUCCESS } struct file_operations my_fops = { owner: THIS_MODULE, open: my_open, }; static int __init iopl_init( void ) { printk( "<1>\nInstalling \'%s\' module ", modname ); printk( "(major=%d) \n", my_major ); return register_chrdev( my_major, devname, &my_fops ); } static void __exit iopl_exit(void ) { unregister_chrdev( my_major, devname ); printk( "<1>Removing \'%s\' module\n", modname ); } module_init( iopl_init ); module_exit( iopl_exit ); MODULE_LICENSE("GPL");