Blame view

lib/test_kasan_module.c 3.29 KB
73228c7ec   Patricia Alfonso   KASAN: port KASAN...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  // SPDX-License-Identifier: GPL-2.0-only
  /*
   *
   * Copyright (c) 2014 Samsung Electronics Co., Ltd.
   * Author: Andrey Ryabinin <a.ryabinin@samsung.com>
   */
  
  #define pr_fmt(fmt) "kasan test: %s " fmt, __func__
  
  #include <linux/mman.h>
  #include <linux/module.h>
  #include <linux/printk.h>
  #include <linux/slab.h>
  #include <linux/uaccess.h>
  
  #include "../mm/kasan/kasan.h"
73228c7ec   Patricia Alfonso   KASAN: port KASAN...
17
18
19
20
  static noinline void __init copy_user_test(void)
  {
  	char *kmem;
  	char __user *usermem;
756e5a47a   Andrey Konovalov   kasan: test: avoi...
21
  	size_t size = 128 - KASAN_GRANULE_SIZE;
e15665671   Andrew Morton   lib/test_kasan_mo...
22
  	int __maybe_unused unused;
73228c7ec   Patricia Alfonso   KASAN: port KASAN...
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
  
  	kmem = kmalloc(size, GFP_KERNEL);
  	if (!kmem)
  		return;
  
  	usermem = (char __user *)vm_mmap(NULL, 0, PAGE_SIZE,
  			    PROT_READ | PROT_WRITE | PROT_EXEC,
  			    MAP_ANONYMOUS | MAP_PRIVATE, 0);
  	if (IS_ERR(usermem)) {
  		pr_err("Failed to allocate user memory
  ");
  		kfree(kmem);
  		return;
  	}
  
  	pr_info("out-of-bounds in copy_from_user()
  ");
756e5a47a   Andrey Konovalov   kasan: test: avoi...
40
  	unused = copy_from_user(kmem, usermem, size + 1);
73228c7ec   Patricia Alfonso   KASAN: port KASAN...
41
42
43
  
  	pr_info("out-of-bounds in copy_to_user()
  ");
756e5a47a   Andrey Konovalov   kasan: test: avoi...
44
  	unused = copy_to_user(usermem, kmem, size + 1);
73228c7ec   Patricia Alfonso   KASAN: port KASAN...
45
46
47
  
  	pr_info("out-of-bounds in __copy_from_user()
  ");
756e5a47a   Andrey Konovalov   kasan: test: avoi...
48
  	unused = __copy_from_user(kmem, usermem, size + 1);
73228c7ec   Patricia Alfonso   KASAN: port KASAN...
49
50
51
  
  	pr_info("out-of-bounds in __copy_to_user()
  ");
756e5a47a   Andrey Konovalov   kasan: test: avoi...
52
  	unused = __copy_to_user(usermem, kmem, size + 1);
73228c7ec   Patricia Alfonso   KASAN: port KASAN...
53
54
55
  
  	pr_info("out-of-bounds in __copy_from_user_inatomic()
  ");
756e5a47a   Andrey Konovalov   kasan: test: avoi...
56
  	unused = __copy_from_user_inatomic(kmem, usermem, size + 1);
73228c7ec   Patricia Alfonso   KASAN: port KASAN...
57
58
59
  
  	pr_info("out-of-bounds in __copy_to_user_inatomic()
  ");
756e5a47a   Andrey Konovalov   kasan: test: avoi...
60
  	unused = __copy_to_user_inatomic(usermem, kmem, size + 1);
73228c7ec   Patricia Alfonso   KASAN: port KASAN...
61
62
63
  
  	pr_info("out-of-bounds in strncpy_from_user()
  ");
756e5a47a   Andrey Konovalov   kasan: test: avoi...
64
  	unused = strncpy_from_user(kmem, usermem, size + 1);
73228c7ec   Patricia Alfonso   KASAN: port KASAN...
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
  
  	vm_munmap((unsigned long)usermem, PAGE_SIZE);
  	kfree(kmem);
  }
  
  static struct kasan_rcu_info {
  	int i;
  	struct rcu_head rcu;
  } *global_rcu_ptr;
  
  static noinline void __init kasan_rcu_reclaim(struct rcu_head *rp)
  {
  	struct kasan_rcu_info *fp = container_of(rp,
  						struct kasan_rcu_info, rcu);
  
  	kfree(fp);
f16de0bcd   Andrey Konovalov   kasan: test: avoi...
81
  	((volatile struct kasan_rcu_info *)fp)->i;
73228c7ec   Patricia Alfonso   KASAN: port KASAN...
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  }
  
  static noinline void __init kasan_rcu_uaf(void)
  {
  	struct kasan_rcu_info *ptr;
  
  	pr_info("use-after-free in kasan_rcu_reclaim
  ");
  	ptr = kmalloc(sizeof(struct kasan_rcu_info), GFP_KERNEL);
  	if (!ptr) {
  		pr_err("Allocation failed
  ");
  		return;
  	}
  
  	global_rcu_ptr = rcu_dereference_protected(ptr, NULL);
  	call_rcu(&global_rcu_ptr->rcu, kasan_rcu_reclaim);
  }
214c783d5   Walter Wu   lib/test_kasan.c:...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
  static noinline void __init kasan_workqueue_work(struct work_struct *work)
  {
  	kfree(work);
  }
  
  static noinline void __init kasan_workqueue_uaf(void)
  {
  	struct workqueue_struct *workqueue;
  	struct work_struct *work;
  
  	workqueue = create_workqueue("kasan_wq_test");
  	if (!workqueue) {
  		pr_err("Allocation failed
  ");
  		return;
  	}
  	work = kmalloc(sizeof(struct work_struct), GFP_KERNEL);
  	if (!work) {
  		pr_err("Allocation failed
  ");
  		return;
  	}
  
  	INIT_WORK(work, kasan_workqueue_work);
  	queue_work(workqueue, work);
  	destroy_workqueue(workqueue);
  
  	pr_info("use-after-free on workqueue
  ");
  	((volatile struct work_struct *)work)->data;
  }
73228c7ec   Patricia Alfonso   KASAN: port KASAN...
131
132
133
134
  
  static int __init test_kasan_module_init(void)
  {
  	/*
0fd379253   Andrey Konovalov   kasan: clean up c...
135
136
137
  	 * Temporarily enable multi-shot mode. Otherwise, KASAN would only
  	 * report the first detected bug and panic the kernel if panic_on_warn
  	 * is enabled.
73228c7ec   Patricia Alfonso   KASAN: port KASAN...
138
139
140
141
142
  	 */
  	bool multishot = kasan_save_enable_multi_shot();
  
  	copy_user_test();
  	kasan_rcu_uaf();
214c783d5   Walter Wu   lib/test_kasan.c:...
143
  	kasan_workqueue_uaf();
73228c7ec   Patricia Alfonso   KASAN: port KASAN...
144
145
146
147
148
149
150
  
  	kasan_restore_multi_shot(multishot);
  	return -EAGAIN;
  }
  
  module_init(test_kasan_module_init);
  MODULE_LICENSE("GPL");