168 lines
4.4 KiB
C
168 lines
4.4 KiB
C
#include <linux/kernel.h>
|
||
#include <linux/module.h>
|
||
#include <linux/slab.h>
|
||
#include <linux/delay.h>
|
||
#include <linux/vmalloc.h>
|
||
#include <linux/rcupdate.h>
|
||
#include <linux/kthread.h>
|
||
#include <linux/mutex.h>
|
||
|
||
static unsigned int test_type;
|
||
module_param(test_type, uint, 0400);
|
||
MODULE_PARM_DESC(test_type, "set to 1 to try to OOM (default 0)");
|
||
|
||
static int trigger_oops(void)
|
||
{
|
||
int *ptr = (int *)0; // 强制类型转换0地址为指针并尝试读取
|
||
|
||
printk(KERN_ALERT "Dereferenced NULL pointer value: %d\n", *ptr);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int trigger_oob(void) {
|
||
char *buffer;
|
||
int *out_of_bounds;
|
||
|
||
printk(KERN_INFO "Out-of-bounds memory access test module loaded\n");
|
||
|
||
// Allocate a small buffer
|
||
// buffer = kmalloc(256, GFP_KERNEL);
|
||
buffer = vmalloc(PAGE_SIZE * 2);
|
||
if (!buffer) {
|
||
printk(KERN_ERR "Failed to allocate memory\n");
|
||
return -ENOMEM;
|
||
}
|
||
|
||
// Attempt to access memory out of bounds
|
||
out_of_bounds = (int *)(buffer + PAGE_SIZE * 3); // Move pointer to the end of the buffer
|
||
*out_of_bounds = 0; // This should cause an out-of-bounds write
|
||
|
||
printk(KERN_INFO "Out-of-bounds Ofst[%lu] memory access performed\n", 256 + PAGE_SIZE);
|
||
|
||
kfree(buffer);
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int trigger_oom(void)
|
||
{
|
||
void *memory = NULL;
|
||
size_t memory_size = 0;
|
||
|
||
printk(KERN_INFO "oom_trigger: Initializing the oom_trigger LKM\n");
|
||
|
||
memory_size = 100*1024*1024;
|
||
while (1) { // 尝试分配大块内存
|
||
memory = vmalloc(memory_size);
|
||
if (!memory) {
|
||
printk(KERN_ALERT "oom_trigger: Memory allocation failed\n");
|
||
break;
|
||
}
|
||
|
||
// 仅为防止编译器优化,实际不访问分配的内存
|
||
memset(memory, 0, memory_size);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int test_data = 0;
|
||
static struct rcu_head test_rcu_head;
|
||
|
||
static void bad_rcu_callback(struct rcu_head *head)
|
||
{
|
||
// 违规操作:在RCU回调函数中睡眠,这可能导致RCU grace period过长
|
||
msleep(1000);
|
||
|
||
// 违规操作:修改被RCU保护的数据结构
|
||
test_data++; // 不应在RCU回调中修改全局变量
|
||
|
||
pr_info("Bad RCU callback executed\n");
|
||
}
|
||
|
||
static void trigger_rcu(void)
|
||
{
|
||
pr_info("RCU error module loaded\n");
|
||
|
||
call_rcu(&test_rcu_head, bad_rcu_callback);
|
||
}
|
||
|
||
static int is_ready_thread1, is_ready_thread2;
|
||
static struct task_struct *thread1;
|
||
static struct task_struct *thread2;
|
||
|
||
static DEFINE_MUTEX(mutex_a);
|
||
static DEFINE_MUTEX(mutex_b);
|
||
|
||
static int thread_func(void *data)
|
||
{
|
||
char *name = (char *) data;
|
||
|
||
if (!strcmp(name, "Thread1")) {
|
||
printk(KERN_INFO "%s: Acquiring mutex A...\n", name);
|
||
mutex_lock(&mutex_a);
|
||
is_ready_thread1 = 1;
|
||
while (!is_ready_thread2);
|
||
printk(KERN_INFO "%s: Got mutex A. Now trying to acquire mutex B...\n", name);
|
||
mutex_lock(&mutex_b); // This will block, causing deadlock
|
||
printk(KERN_INFO "%s: Got mutex B.\n", name);
|
||
} else {
|
||
printk(KERN_INFO "%s: Acquiring mutex B...\n", name);
|
||
mutex_lock(&mutex_b);
|
||
is_ready_thread2 = 1;
|
||
while (!is_ready_thread1);
|
||
printk(KERN_INFO "%s: Got mutex B. Now trying to acquire mutex A...\n", name);
|
||
mutex_lock(&mutex_a); // This will block, causing deadlock
|
||
printk(KERN_INFO "%s: Got mutex A.\n", name);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int trigger_deadlock(void)
|
||
{
|
||
thread1 = kthread_run(thread_func, (void *) "Thread1", "thread1");
|
||
if (IS_ERR(thread1)) {
|
||
printk(KERN_ERR "Failed to create thread1\n");
|
||
return PTR_ERR(thread1);
|
||
}
|
||
|
||
thread2 = kthread_run(thread_func, (void *) "Thread2", "thread2");
|
||
if (IS_ERR(thread2)) {
|
||
printk(KERN_ERR "Failed to create thread2\n");
|
||
kthread_stop(thread1);
|
||
return PTR_ERR(thread2);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
static int trigger_init(void) {
|
||
if (test_type == 0)
|
||
trigger_oops();
|
||
else if (test_type == 1)
|
||
trigger_oom();
|
||
else if (test_type == 2)
|
||
trigger_rcu();
|
||
else if (test_type == 3)
|
||
trigger_deadlock();
|
||
else if (test_type == 4)
|
||
trigger_oob();
|
||
|
||
return 0; // 加载模块不应该有返回值,但这里返回0避免编译警告。
|
||
}
|
||
|
||
static void __exit trigger_exit(void) {
|
||
if (test_type == 3) {
|
||
kthread_stop(thread1);
|
||
kthread_stop(thread2);
|
||
printk(KERN_INFO "Deadlock trigger exit.\n");
|
||
}
|
||
}
|
||
|
||
module_init(trigger_init);
|
||
module_exit(trigger_exit);
|
||
|
||
MODULE_LICENSE("GPL");
|