Skip to content

Instantly share code, notes, and snippets.

@cetaSYN
Created August 21, 2022 20:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cetaSYN/fd7377f13784eac02e1617bd737bf8fa to your computer and use it in GitHub Desktop.
Save cetaSYN/fd7377f13784eac02e1617bd737bf8fa to your computer and use it in GitHub Desktop.
Kernel module character device driver that always returns full bit-level 1s (0xFF...)
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#define DEVICE_NAME "one"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("cetaSYN");
MODULE_DESCRIPTION("Device driver that always returns full bit-level 1s (0xFF...)");
MODULE_VERSION("0.1");
static int major_number;
static ssize_t dev_read(struct file *, char __user *, size_t, loff_t *);
static int dev_open(struct inode *, struct file *);
static int dev_release(struct inode *, struct file *);
static struct class *device_class;
static struct file_operations fops = {
.read = dev_read,
.open = dev_open,
.release = dev_release
};
enum {
CDEV_NOT_USED = 0,
CDEV_EXCLUSIVE_OPEN = 1
};
static atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED);
int init_module(void) {
major_number = register_chrdev(0, DEVICE_NAME, &fops);
if(major_number < 0) {
pr_err("Failed to acquire major number with %i\n", major_number);
return major_number;
}
pr_debug("Successfully acquired major number %i\n", major_number);
device_class = class_create(THIS_MODULE, DEVICE_NAME);
device_create(device_class, NULL, MKDEV(major_number, 0), NULL, DEVICE_NAME);
pr_info("Device created at /dev/%s\n", DEVICE_NAME);
return 0;
}
void cleanup_module(void) {
device_destroy(device_class, MKDEV(major_number, 0));
class_destroy(device_class);
unregister_chrdev(major_number, DEVICE_NAME);
}
static int dev_open(struct inode *inode, struct file *file) {
if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN)) {
return -EBUSY;
}
try_module_get(THIS_MODULE);
return 0;
}
static int dev_release(struct inode *inode, struct file *file) {
atomic_set(&already_open, CDEV_NOT_USED);
module_put(THIS_MODULE);
return 0;
}
static ssize_t dev_read(struct file *filep, __user char *buffer, size_t length, loff_t *offset) {
int bytes_read = 0;
while (length) {
put_user(0xFF, buffer++);
length--;
bytes_read++;
}
return bytes_read;
}
@cetaSYN
Copy link
Author

cetaSYN commented Aug 21, 2022

This is probably not efficient and could break in several ways.
Highly recommend not using this in production unless vetted by someone with more kernel module experience than myself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment