📄 dhahelper.c
字号:
/* Direct Hardware Access kernel helper (C) 2002 Alex Beregszaszi <alex@fsn.hu> Accessing hardware from userspace as USER (no root needed!) Tested on 2.2.x (2.2.19) and 2.4.x (2.4.3,2.4.17). License: GPL WARNING! THIS MODULE VIOLATES SEVERAL SECURITY LINES! DON'T USE IT ON PRODUCTION SYSTEMS, ONLY AT HOME, ON A "SINGLE-USER" SYSTEM. NO WARRANTY! Tech: Communication between userspace and kernelspace goes over character device using ioctl. Usage: mknod -m 666 /dev/dhahelper c 180 0 Also you can change the major number, setting the "dhahelper_major" module parameter, the default is 180, specified in dhahelper.h. Note: do not use other than minor==0, the module forbids it. TODO: * do memory mapping without fops:mmap * implement unmap memory * select (request?) a "valid" major number (from Linux project? ;) * make security * is pci handling needed? (libdha does this with lowlevel port funcs) * is mttr handling needed? * test on older kernels (2.0.x (?))*/#ifndef MODULE#define MODULE#endif#ifndef __KERNEL__#define __KERNEL__#endif#include <linux/config.h>#ifdef CONFIG_MODVERSION#define MODVERSION#include <linux/modversions.h>#endif#include <linux/version.h>#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/errno.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)#include <linux/malloc.h>#else#include <linux/slab.h>#endif#include <linux/pci.h>#include <linux/ioport.h>#include <linux/init.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/io.h>#include <linux/mman.h>#include <linux/fs.h>#include <linux/unistd.h>#include "dhahelper.h"MODULE_AUTHOR("Alex Beregszaszi <alex@fsn.hu>");MODULE_DESCRIPTION("Provides userspace access to hardware (security violation!)");#ifdef MODULE_LICENSEMODULE_LICENSE("GPL");#endifstatic int dhahelper_major = DEFAULT_MAJOR;MODULE_PARM(dhahelper_major, "i");MODULE_PARM_DESC(dhahelper_major, "Major number of dhahelper characterdevice");/* 0 = silent *//* 1 = report errors (default) *//* 2 = debug */static int dhahelper_verbosity = 1;MODULE_PARM(dhahelper_verbosity, "i");MODULE_PARM_DESC(dhahelper_verbosity, "Level of verbosity (0 = silent, 1 = only errors, 2 = debug)");static dhahelper_memory_t last_mem_request;static int dhahelper_open(struct inode *inode, struct file *file){ if (dhahelper_verbosity > 1) printk(KERN_DEBUG "dhahelper: device opened\n"); if (MINOR(inode->i_rdev) != 0) return(-ENXIO); MOD_INC_USE_COUNT; return(0);}static int dhahelper_release(struct inode *inode, struct file *file){ if (dhahelper_verbosity > 1) printk(KERN_DEBUG "dhahelper: device released\n"); if (MINOR(inode->i_rdev) != 0) return(-ENXIO); MOD_DEC_USE_COUNT; return(0);}static int dhahelper_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ if (dhahelper_verbosity > 1) printk(KERN_DEBUG "dhahelper: ioctl(cmd=%x, arg=%lx)\n", cmd, arg); if (MINOR(inode->i_rdev) != 0) return(-ENXIO); switch(cmd) { case DHAHELPER_GET_VERSION: { int version = API_VERSION; if (copy_to_user((int *)arg, &version, sizeof(int))) { if (dhahelper_verbosity > 0) printk(KERN_ERR "dhahelper: failed copy to userspace\n"); return(-EFAULT); } break; } case DHAHELPER_PORT: { dhahelper_port_t port; if (copy_from_user(&port, (dhahelper_port_t *)arg, sizeof(dhahelper_port_t))) { if (dhahelper_verbosity > 0) printk(KERN_ERR "dhahelper: failed copy from userspace\n"); return(-EFAULT); } switch(port.operation) { case PORT_OP_READ: { switch(port.size) { case 1: port.value = inb(port.addr); break; case 2: port.value = inw(port.addr); break; case 4: port.value = inl(port.addr); break; default: if (dhahelper_verbosity > 0) printk(KERN_ERR "dhahelper: invalid port read size (%d)\n", port.size); return(-EINVAL); } break; } case PORT_OP_WRITE: { switch(port.size) { case 1: outb(port.value, port.addr); break; case 2: outw(port.value, port.addr); break; case 4: outl(port.value, port.addr); break; default: if (dhahelper_verbosity > 0) printk(KERN_ERR "dhahelper: invalid port write size (%d)\n", port.size); return(-EINVAL); } break; } default: if (dhahelper_verbosity > 0) printk(KERN_ERR "dhahelper: invalid port operation (%d)\n", port.operation); return(-EINVAL); } /* copy back only if read was performed */ if (port.operation == PORT_OP_READ) if (copy_to_user((dhahelper_port_t *)arg, &port, sizeof(dhahelper_port_t))) { if (dhahelper_verbosity > 0) printk(KERN_ERR "dhahelper: failed copy to userspace\n"); return(-EFAULT); } break; } case DHAHELPER_MEMORY: { dhahelper_memory_t mem; if (copy_from_user(&mem, (dhahelper_memory_t *)arg, sizeof(dhahelper_memory_t))) { if (dhahelper_verbosity > 0) printk(KERN_ERR "dhahelper: failed copy from userspace\n"); return(-EFAULT); } switch(mem.operation) { case MEMORY_OP_MAP: {#if 1 memcpy(&last_mem_request, &mem, sizeof(dhahelper_memory_t));#else mem.ret = do_mmap(file, mem.start, mem.size, PROT_READ|PROT_WRITE, MAP_SHARED, mem.offset);#endif break; } case MEMORY_OP_UNMAP: break; default: if (dhahelper_verbosity > 0) printk(KERN_ERR "dhahelper: invalid memory operation (%d)\n", mem.operation); return(-EINVAL); } if (copy_to_user((dhahelper_memory_t *)arg, &mem, sizeof(dhahelper_memory_t))) { if (dhahelper_verbosity > 0) printk(KERN_ERR "dhahelper: failed copy to userspace\n"); return(-EFAULT); } break; } default: if (dhahelper_verbosity > 0) printk(KERN_ERR "dhahelper: invalid ioctl (%x)\n", cmd); return(-EINVAL); } return(0);}static int dhahelper_mmap(struct file *file, struct vm_area_struct *vma){ if (last_mem_request.operation != MEMORY_OP_MAP) { if (dhahelper_verbosity > 0) printk(KERN_ERR "dhahelper: mapping not requested before mmap\n"); return(-EFAULT); } if (dhahelper_verbosity > 1) printk(KERN_INFO "dhahelper: mapping %x (size: %x)\n", last_mem_request.start+last_mem_request.offset, last_mem_request.size); if (remap_page_range(0, last_mem_request.start + last_mem_request.offset, last_mem_request.size, vma->vm_page_prot)) { if (dhahelper_verbosity > 0) printk(KERN_ERR "dhahelper: error mapping memory\n"); return(-EFAULT); } return(0);}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)static struct file_operations dhahelper_fops ={ /*llseek*/ NULL, /*read*/ NULL, /*write*/ NULL, /*readdir*/ NULL, /*poll*/ NULL, /*ioctl*/ dhahelper_ioctl, /*mmap*/ dhahelper_mmap, /*open*/ dhahelper_open, /*flush*/ NULL, /*release*/ dhahelper_release, /* zero out the last 5 entries too ? */};#elsestatic struct file_operations dhahelper_fops ={ owner: THIS_MODULE, ioctl: dhahelper_ioctl, mmap: dhahelper_mmap, open: dhahelper_open, release: dhahelper_release};#endif#if KERNEL_VERSION < KERNEL_VERSION(2,4,0)int init_module(void)#else static int __init init_dhahelper(void)#endif{ printk(KERN_INFO "Direct Hardware Access kernel helper (C) Alex Beregszaszi\n"); if(register_chrdev(dhahelper_major, "dhahelper", &dhahelper_fops)) { if (dhahelper_verbosity > 0) printk(KERN_ERR "dhahelper: unable to register character device (major: %d)\n", dhahelper_major); return(-EIO); } return(0);}#if KERNEL_VERSION < KERNEL_VERSION(2,4,0)void cleanup_module(void)#elsestatic void __exit exit_dhahelper(void)#endif{ unregister_chrdev(dhahelper_major, "dhahelper");}EXPORT_NO_SYMBOLS;#if KERNEL_VERSION >= KERNEL_VERSION(2,4,0)module_init(init_dhahelper);module_exit(exit_dhahelper);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -