diff --git a/0.0_Basic/Makefile b/0.0_Basic/Makefile deleted file mode 100644 index 4046bb8..0000000 --- a/0.0_Basic/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -obj-m += example.o - -all: - make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules - -clean: - make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean - -test: - sudo dmesg -C - sudo insmod example.ko - sudo rmmod example.ko - dmesg diff --git a/0.0_Basic/README.md b/0.0_Basic/README.md deleted file mode 100644 index 031ed96..0000000 --- a/0.0_Basic/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Linux Kernel Hacking - -## 0.0: Basic LKM Example - -This is about as simple as it gets. - -To use: -* Build with `make` -* Load with `insmod example.ko` -* Check output in kernel buffer with `dmesg` -* See the module loaded in `lsmod | grep example` -* Unload with `rmmod example.ko` -* Check the second output in the kernel buffer with `dmesg` - -Alternatively: -* Run `make test` and observe the two outputs as the module is loaded/unloaded. - -> NOTE: You'll need `build-essential` and `linux-headers-$(uname -r)` installed. - -> Followed along from [here](https://blog.sourcerer.io/writing-a-simple-linux-kernel-module-d9dc3762c234?gi=2f8d0507c4e8). diff --git a/0.0_Basic/example.c b/0.0_Basic/example.c deleted file mode 100644 index 7405b96..0000000 --- a/0.0_Basic/example.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Example"); -MODULE_DESCRIPTION("Basic"); -MODULE_VERSION("0.01"); - -static int __init example_init(void) -{ - printk(KERN_INFO "Hello, World!\n"); - return 0; -} - -static void __exit example_exit(void) -{ - printk(KERN_INFO "Goodbye, World!\n"); -} - -module_init(example_init); -module_exit(example_exit); diff --git a/0.1_device_file/Makefile b/0.1_device_file/Makefile deleted file mode 100644 index 65f9cc6..0000000 --- a/0.1_device_file/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -obj-m += example.o - -all: - make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules - -clean: - make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean - -test: - -sudo rmmod example - sudo dmesg -C - sudo insmod example.ko - dmesg diff --git a/0.1_device_file/README.md b/0.1_device_file/README.md deleted file mode 100644 index 4719d5f..0000000 --- a/0.1_device_file/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Linux Kernel Hacking - -## 0.1: Character Devices - -Simple character device file. - -To use: -* Build with `make` and load with `make test` -* Create a device file with `mknod /dev/example c 0`, replacing `` with major number returned in the kernel buffer. -* Take a look at the device with `cat /dev/example` -* Delete the device file with `rm /dev/example` and unload the module with `rmmod example` - -> Followed along from [here](https://blog.sourcerer.io/writing-a-simple-linux-kernel-module-d9dc3762c234?gi=2f8d0507c4e8). diff --git a/0.1_device_file/example.c b/0.1_device_file/example.c deleted file mode 100644 index b4b987b..0000000 --- a/0.1_device_file/example.c +++ /dev/null @@ -1,126 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Example"); -MODULE_DESCRIPTION("Device File Example"); -MODULE_VERSION("0.01"); - -#define DEVICE_NAME "example" -#define EXAMPLE_MSG "Hello, World!\n" -#define MSG_BUFFER_LEN 15 - -/* Required prototypes */ -static int device_open(struct inode *, struct file *); -static int device_release(struct inode *, struct file *); -static ssize_t device_read(struct file *, char *, size_t, loff_t *); -static ssize_t device_write(struct file *, const char *, size_t, loff_t *); - -static int major_num; -static int device_open_count = 0; -static char msg_buffer[MSG_BUFFER_LEN]; -static char *msg_ptr; - -/* Structure of all device functions */ -static struct file_operations file_ops = { - .read = device_read, - .write = device_write, - .open = device_open, - .release = device_release, -}; - -/* This function gets called whenever something reads from the device */ -static ssize_t device_read(struct file *flip, char *buffer, size_t len, loff_t *offst) -{ - int bytes_read = 0; - - /* Loop indefinitely */ - if (*msg_ptr == 0) - msg_ptr = msg_buffer; - - /* Load the buffer */ - while (len && *msg_ptr) - { - /* The buffer is in userspace, not kernel space, so - * we can't just use a normal dereference. The function - * put_user() handles moving data from the kernel, into - * userspace. */ - put_user(*(msg_ptr++), buffer++); - len--; - bytes_read++; - } - - return bytes_read; -} - -/* Ths function gets called whenever something tries to write to the device */ -static ssize_t device_write(struct file *flip, const char *buffer, size_t len, loff_t *offset) -{ - /* Read-only, so just kick them out */ - printk(KERN_ALERT "This operation is not supported.\n"); - return -EINVAL; -} - -/* This function is called whenever something tries to open the device */ -static int device_open(struct inode *inode, struct file *file) -{ - /* If it's already open, return busy */ - if (device_open_count) - { - return -EBUSY; - } - device_open_count++; - /* try_module_get() checks to see if the module is being removed, - * and if so, we need to act as if the module doesn't exist (more - * important when we reference other modules from this one). */ - try_module_get(THIS_MODULE); - return 0; -} - -/* This function is called whenever something tries to close the device */ -static int device_release(struct inode *inode, struct file *file) -{ - /* Decrement the open counter and usage count, otherwise the module - * won't unload */ - device_open_count--; - /* Alert the kernel that we are done using this module (for now). - * This will cause try_module_get() to return true, so that the - * module can be unloaded safely. */ - module_put(THIS_MODULE); - return 0; -} - -static int __init example_init(void) -{ - /* Fill buffer */ - strncpy(msg_buffer, EXAMPLE_MSG, MSG_BUFFER_LEN); - /* Set msg_ptr to start of buffer */ - msg_ptr = msg_buffer; - /* Register character device */ - major_num = register_chrdev(0, "example", &file_ops); - if (major_num < 0) - { - printk(KERN_ALERT "Could not register device: %d\n", major_num); - return major_num; - } - else - { - printk(KERN_INFO "example module loaded with device major number %d\n", major_num); - return 0; - } -} - -static void __exit example_exit(void) -{ - /* Clean up */ - unregister_chrdev(major_num, DEVICE_NAME); - printk(KERN_INFO "Goodbye, World!\n"); -} - -module_init(example_init); -module_exit(example_exit); diff --git a/0_Basic_LKMs/0.0_Basic/Makefile b/0_Basic_LKMs/0.0_Basic/Makefile new file mode 100644 index 0000000..4046bb8 --- /dev/null +++ b/0_Basic_LKMs/0.0_Basic/Makefile @@ -0,0 +1,13 @@ +obj-m += example.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean + +test: + sudo dmesg -C + sudo insmod example.ko + sudo rmmod example.ko + dmesg diff --git a/0_Basic_LKMs/0.0_Basic/README.md b/0_Basic_LKMs/0.0_Basic/README.md new file mode 100644 index 0000000..031ed96 --- /dev/null +++ b/0_Basic_LKMs/0.0_Basic/README.md @@ -0,0 +1,20 @@ +# Linux Kernel Hacking + +## 0.0: Basic LKM Example + +This is about as simple as it gets. + +To use: +* Build with `make` +* Load with `insmod example.ko` +* Check output in kernel buffer with `dmesg` +* See the module loaded in `lsmod | grep example` +* Unload with `rmmod example.ko` +* Check the second output in the kernel buffer with `dmesg` + +Alternatively: +* Run `make test` and observe the two outputs as the module is loaded/unloaded. + +> NOTE: You'll need `build-essential` and `linux-headers-$(uname -r)` installed. + +> Followed along from [here](https://blog.sourcerer.io/writing-a-simple-linux-kernel-module-d9dc3762c234?gi=2f8d0507c4e8). diff --git a/0_Basic_LKMs/0.0_Basic/example.c b/0_Basic_LKMs/0.0_Basic/example.c new file mode 100644 index 0000000..7405b96 --- /dev/null +++ b/0_Basic_LKMs/0.0_Basic/example.c @@ -0,0 +1,22 @@ +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Example"); +MODULE_DESCRIPTION("Basic"); +MODULE_VERSION("0.01"); + +static int __init example_init(void) +{ + printk(KERN_INFO "Hello, World!\n"); + return 0; +} + +static void __exit example_exit(void) +{ + printk(KERN_INFO "Goodbye, World!\n"); +} + +module_init(example_init); +module_exit(example_exit); diff --git a/0_Basic_LKMs/0.1_device_file/Makefile b/0_Basic_LKMs/0.1_device_file/Makefile new file mode 100644 index 0000000..65f9cc6 --- /dev/null +++ b/0_Basic_LKMs/0.1_device_file/Makefile @@ -0,0 +1,13 @@ +obj-m += example.o + +all: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules + +clean: + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean + +test: + -sudo rmmod example + sudo dmesg -C + sudo insmod example.ko + dmesg diff --git a/0_Basic_LKMs/0.1_device_file/README.md b/0_Basic_LKMs/0.1_device_file/README.md new file mode 100644 index 0000000..4719d5f --- /dev/null +++ b/0_Basic_LKMs/0.1_device_file/README.md @@ -0,0 +1,13 @@ +# Linux Kernel Hacking + +## 0.1: Character Devices + +Simple character device file. + +To use: +* Build with `make` and load with `make test` +* Create a device file with `mknod /dev/example c 0`, replacing `` with major number returned in the kernel buffer. +* Take a look at the device with `cat /dev/example` +* Delete the device file with `rm /dev/example` and unload the module with `rmmod example` + +> Followed along from [here](https://blog.sourcerer.io/writing-a-simple-linux-kernel-module-d9dc3762c234?gi=2f8d0507c4e8). diff --git a/0_Basic_LKMs/0.1_device_file/example.c b/0_Basic_LKMs/0.1_device_file/example.c new file mode 100644 index 0000000..b4b987b --- /dev/null +++ b/0_Basic_LKMs/0.1_device_file/example.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Example"); +MODULE_DESCRIPTION("Device File Example"); +MODULE_VERSION("0.01"); + +#define DEVICE_NAME "example" +#define EXAMPLE_MSG "Hello, World!\n" +#define MSG_BUFFER_LEN 15 + +/* Required prototypes */ +static int device_open(struct inode *, struct file *); +static int device_release(struct inode *, struct file *); +static ssize_t device_read(struct file *, char *, size_t, loff_t *); +static ssize_t device_write(struct file *, const char *, size_t, loff_t *); + +static int major_num; +static int device_open_count = 0; +static char msg_buffer[MSG_BUFFER_LEN]; +static char *msg_ptr; + +/* Structure of all device functions */ +static struct file_operations file_ops = { + .read = device_read, + .write = device_write, + .open = device_open, + .release = device_release, +}; + +/* This function gets called whenever something reads from the device */ +static ssize_t device_read(struct file *flip, char *buffer, size_t len, loff_t *offst) +{ + int bytes_read = 0; + + /* Loop indefinitely */ + if (*msg_ptr == 0) + msg_ptr = msg_buffer; + + /* Load the buffer */ + while (len && *msg_ptr) + { + /* The buffer is in userspace, not kernel space, so + * we can't just use a normal dereference. The function + * put_user() handles moving data from the kernel, into + * userspace. */ + put_user(*(msg_ptr++), buffer++); + len--; + bytes_read++; + } + + return bytes_read; +} + +/* Ths function gets called whenever something tries to write to the device */ +static ssize_t device_write(struct file *flip, const char *buffer, size_t len, loff_t *offset) +{ + /* Read-only, so just kick them out */ + printk(KERN_ALERT "This operation is not supported.\n"); + return -EINVAL; +} + +/* This function is called whenever something tries to open the device */ +static int device_open(struct inode *inode, struct file *file) +{ + /* If it's already open, return busy */ + if (device_open_count) + { + return -EBUSY; + } + device_open_count++; + /* try_module_get() checks to see if the module is being removed, + * and if so, we need to act as if the module doesn't exist (more + * important when we reference other modules from this one). */ + try_module_get(THIS_MODULE); + return 0; +} + +/* This function is called whenever something tries to close the device */ +static int device_release(struct inode *inode, struct file *file) +{ + /* Decrement the open counter and usage count, otherwise the module + * won't unload */ + device_open_count--; + /* Alert the kernel that we are done using this module (for now). + * This will cause try_module_get() to return true, so that the + * module can be unloaded safely. */ + module_put(THIS_MODULE); + return 0; +} + +static int __init example_init(void) +{ + /* Fill buffer */ + strncpy(msg_buffer, EXAMPLE_MSG, MSG_BUFFER_LEN); + /* Set msg_ptr to start of buffer */ + msg_ptr = msg_buffer; + /* Register character device */ + major_num = register_chrdev(0, "example", &file_ops); + if (major_num < 0) + { + printk(KERN_ALERT "Could not register device: %d\n", major_num); + return major_num; + } + else + { + printk(KERN_INFO "example module loaded with device major number %d\n", major_num); + return 0; + } +} + +static void __exit example_exit(void) +{ + /* Clean up */ + unregister_chrdev(major_num, DEVICE_NAME); + printk(KERN_INFO "Goodbye, World!\n"); +} + +module_init(example_init); +module_exit(example_exit);