...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <linux/init.h> #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/sched.h> #include <linux/device.h> #include <linux/slab.h> #include <asm/current.h> #include <linux/uaccess.h> MODULE_LICENSE("Dual BSD/GPL"); #define DRIVER_NAME "chardev" #define BUFFER_SIZE 64 static const unsigned int MINOR_BASE = 0; static const unsigned int MINOR_NUM = 2; static unsigned int chardev_major; static struct cdev chardev_cdev; static struct class *chardev_class = NULL; static int chardev_release(struct inode *, struct file *); static ssize_t chardev_read(struct file *, char *, size_t, loff_t *); static ssize_t chardev_write(struct file *, const char *, size_t, loff_t *); static loff_t chardev_lseek(struct file *, loff_t, int); struct file_operations chardev_fops = { .release = chardev_release, .read = chardev_read, .write = chardev_write, .llseek = chardev_lseek, }; struct data { unsigned char buffer[BUFFER_SIZE]; }; static int chardev_init(void) { int alloc_ret = 0; int cdev_err = 0; dev_t dev; printk("The chardev_init() function has been called."); alloc_ret = alloc_chrdev_region(&dev, MINOR_BASE, MINOR_NUM, DRIVER_NAME); if (alloc_ret != 0) { printk(KERN_ERR "alloc_chrdev_region = %d\n", alloc_ret); return -1; } //Get the major number value in dev. chardev_major = MAJOR(dev); dev = MKDEV(chardev_major, MINOR_BASE); //initialize a cdev structure cdev_init(&chardev_cdev, &chardev_fops); chardev_cdev.owner = THIS_MODULE; //add a char device to the system cdev_err = cdev_add(&chardev_cdev, dev, MINOR_NUM); if (cdev_err != 0) { printk(KERN_ERR "cdev_add = %d\n", alloc_ret); unregister_chrdev_region(dev, MINOR_NUM); return -1; } chardev_class = class_create(THIS_MODULE, "chardev"); if (IS_ERR(chardev_class)) { printk(KERN_ERR "class_create\n"); cdev_del(&chardev_cdev); unregister_chrdev_region(dev, MINOR_NUM); return -1; } device_create(chardev_class, NULL, MKDEV(chardev_major, MINOR_BASE), NULL, "chardev%d", MINOR_BASE); return 0; } static void chardev_exit(void) { int minor; dev_t dev = MKDEV(chardev_major, MINOR_BASE); printk("The chardev_exit() function has been called."); for (minor = MINOR_BASE; minor < MINOR_BASE + MINOR_NUM; minor++) { device_destroy(chardev_class, MKDEV(chardev_major, minor)); } class_destroy(chardev_class); cdev_del(&chardev_cdev); unregister_chrdev_region(dev, MINOR_NUM); } static int chardev_release(struct inode *inode, struct file *file) { printk("The chardev_release() function has been called."); if (file->private_data) { kfree(file->private_data); file->private_data = NULL; } return 0; } static ssize_t chardev_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { char data[BUFFER_SIZE]; printk("The chardev_write() function has been called."); printk("Before calling the copy_from_user() function : %p",data); if (_copy_from_user(&data, buf, count) != 0) { return -EFAULT; } /* if (copy_from_user(&data, buf, count) != 0) { return -EFAULT; } if (__copy_from_user(&data, buf, count) != 0) { return -EFAULT; } */ printk("After calling the copy_from_user() function : %p",data); return count; } static ssize_t chardev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { char data[BUFFER_SIZE]; printk("The chardev_read() function has been called.\n"); memset(data, 0, sizeof(data)); strcpy(data, "Welcome to the CSAW CTF challenge. Best of luck!\n"); printk("MSG : %s",data); printk("f_pos : %lld\n",*f_pos); if (memcpy(buf, data + *f_pos, BUFFER_SIZE) != 0) { return -EFAULT; } return count; } static loff_t chardev_lseek(struct file *file, loff_t offset, int orig) { loff_t new_pos = 0; printk("The chardev_lseek() function has been called."); switch(orig) { case 0 : /*seek set*/ new_pos = offset; break; case 1 : /*seek cur*/ new_pos = file->f_pos + offset; break; case 2 : /*seek end*/ new_pos = BUFFER_SIZE - offset; break; } if(new_pos > BUFFER_SIZE) new_pos = BUFFER_SIZE; if(new_pos < 0) new_pos = 0; file->f_pos = new_pos; return new_pos; } module_init(chardev_init); module_exit(chardev_exit); |
...