An Interactive Char Driver
Creating an interactive char driver is surprisingly simple, but there are a few traps along the way.
Exposing it to the File System
This is by far the hardest part to understand, but honestly a full understanding isn't really necessary. The new intro_init function looks like this:
#define DEVICE_NAME "intro"
#define CLASS_NAME "intro"
// setting up the device
int major;
static struct class* my_class = NULL;
static struct device* my_device = NULL;
static int __init intro_init(void) {
major = register_chrdev(0, DEVICE_NAME, &fops); // explained later
if ( major < 0 )
printk(KERN_ALERT "[Intro] Error assigning Major Number!");
// Register device class
my_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(my_class)) {
unregister_chrdev(major, DEVICE_NAME);
printk(KERN_ALERT "[Intro] Failed to register device class\n");
}
// Register the device driver
my_device = device_create(my_class, NULL, MKDEV(major, 0), NULL, DEVICE_NAME);
if (IS_ERR(my_device)) {
class_destroy(my_class);
unregister_chrdev(major, DEVICE_NAME);
printk(KERN_ALERT "[Intro] Failed to create the device\n");
}
return 0;
}A major number is essentially the unique identifier to the kernel module. You can specify it using the first parameter of register_chrdev, but if you pass 0 it is automatically assigned an unused major number.
We then have to register the class and the device. In complete honesty, I don't quite understand what they do, but this code exposes the module to /dev/intro.
Note that on an error it calls class_destroy and unregister_chrdev:
Cleaning it Up
These additional classes and devices have to be cleaned up in the intro_exit function, and we mark the major number as available:
Controlling I/O
In intro_init, the first line may have been confusing:
The third parameter fops is where all the magic happens, allowing us to create handlers for operations such as read and write. A really simple one would look something like:
The parameters to intro_read may be a bit confusing, but the 2nd and 3rd ones line up to the 2nd and 3rd parameters for the read() function itself:
We then use the function copy_to_user to write QWERTY to the buffer passed in as a parameter!
Full Code
Simply use sudo insmod to load it, as we did before.
Testing The Module
Create a really basic exploit.c:
If the module is successfully loaded, the read() call should read QWERTY into buffer:
Success!
Last updated
Was this helpful?