Linux-libre 4.13.7-gnu
[librecmc/linux-libre.git] / drivers / misc / lkdtm_bugs.c
1 /*
2  * This is for all the tests related to logic bugs (e.g. bad dereferences,
3  * bad alignment, bad loops, bad locking, bad scheduling, deep stacks, and
4  * lockups) along with other things that don't fit well into existing LKDTM
5  * test source files.
6  */
7 #include "lkdtm.h"
8 #include <linux/list.h>
9 #include <linux/refcount.h>
10 #include <linux/sched.h>
11 #include <linux/sched/signal.h>
12 #include <linux/uaccess.h>
13
14 struct lkdtm_list {
15         struct list_head node;
16 };
17
18 /*
19  * Make sure our attempts to over run the kernel stack doesn't trigger
20  * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we
21  * recurse past the end of THREAD_SIZE by default.
22  */
23 #if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0)
24 #define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2)
25 #else
26 #define REC_STACK_SIZE (THREAD_SIZE / 8)
27 #endif
28 #define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2)
29
30 static int recur_count = REC_NUM_DEFAULT;
31
32 static DEFINE_SPINLOCK(lock_me_up);
33
34 static int recursive_loop(int remaining)
35 {
36         char buf[REC_STACK_SIZE];
37
38         /* Make sure compiler does not optimize this away. */
39         memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE);
40         if (!remaining)
41                 return 0;
42         else
43                 return recursive_loop(remaining - 1);
44 }
45
46 /* If the depth is negative, use the default, otherwise keep parameter. */
47 void __init lkdtm_bugs_init(int *recur_param)
48 {
49         if (*recur_param < 0)
50                 *recur_param = recur_count;
51         else
52                 recur_count = *recur_param;
53 }
54
55 void lkdtm_PANIC(void)
56 {
57         panic("dumptest");
58 }
59
60 void lkdtm_BUG(void)
61 {
62         BUG();
63 }
64
65 void lkdtm_WARNING(void)
66 {
67         WARN_ON(1);
68 }
69
70 void lkdtm_EXCEPTION(void)
71 {
72         *((volatile int *) 0) = 0;
73 }
74
75 void lkdtm_LOOP(void)
76 {
77         for (;;)
78                 ;
79 }
80
81 void lkdtm_OVERFLOW(void)
82 {
83         (void) recursive_loop(recur_count);
84 }
85
86 static noinline void __lkdtm_CORRUPT_STACK(void *stack)
87 {
88         memset(stack, 'a', 64);
89 }
90
91 noinline void lkdtm_CORRUPT_STACK(void)
92 {
93         /* Use default char array length that triggers stack protection. */
94         char data[8];
95         __lkdtm_CORRUPT_STACK(&data);
96
97         pr_info("Corrupted stack with '%16s'...\n", data);
98 }
99
100 void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void)
101 {
102         static u8 data[5] __attribute__((aligned(4))) = {1, 2, 3, 4, 5};
103         u32 *p;
104         u32 val = 0x12345678;
105
106         p = (u32 *)(data + 1);
107         if (*p == 0)
108                 val = 0x87654321;
109         *p = val;
110 }
111
112 void lkdtm_SOFTLOCKUP(void)
113 {
114         preempt_disable();
115         for (;;)
116                 cpu_relax();
117 }
118
119 void lkdtm_HARDLOCKUP(void)
120 {
121         local_irq_disable();
122         for (;;)
123                 cpu_relax();
124 }
125
126 void lkdtm_SPINLOCKUP(void)
127 {
128         /* Must be called twice to trigger. */
129         spin_lock(&lock_me_up);
130         /* Let sparse know we intended to exit holding the lock. */
131         __release(&lock_me_up);
132 }
133
134 void lkdtm_HUNG_TASK(void)
135 {
136         set_current_state(TASK_UNINTERRUPTIBLE);
137         schedule();
138 }
139
140 void lkdtm_REFCOUNT_SATURATE_INC(void)
141 {
142         refcount_t over = REFCOUNT_INIT(UINT_MAX - 1);
143
144         pr_info("attempting good refcount decrement\n");
145         refcount_dec(&over);
146         refcount_inc(&over);
147
148         pr_info("attempting bad refcount inc overflow\n");
149         refcount_inc(&over);
150         refcount_inc(&over);
151         if (refcount_read(&over) == UINT_MAX)
152                 pr_err("Correctly stayed saturated, but no BUG?!\n");
153         else
154                 pr_err("Fail: refcount wrapped\n");
155 }
156
157 void lkdtm_REFCOUNT_SATURATE_ADD(void)
158 {
159         refcount_t over = REFCOUNT_INIT(UINT_MAX - 1);
160
161         pr_info("attempting good refcount decrement\n");
162         refcount_dec(&over);
163         refcount_inc(&over);
164
165         pr_info("attempting bad refcount add overflow\n");
166         refcount_add(2, &over);
167         if (refcount_read(&over) == UINT_MAX)
168                 pr_err("Correctly stayed saturated, but no BUG?!\n");
169         else
170                 pr_err("Fail: refcount wrapped\n");
171 }
172
173 void lkdtm_REFCOUNT_ZERO_DEC(void)
174 {
175         refcount_t zero = REFCOUNT_INIT(1);
176
177         pr_info("attempting bad refcount decrement to zero\n");
178         refcount_dec(&zero);
179         if (refcount_read(&zero) == 0)
180                 pr_err("Stayed at zero, but no BUG?!\n");
181         else
182                 pr_err("Fail: refcount went crazy\n");
183 }
184
185 void lkdtm_REFCOUNT_ZERO_SUB(void)
186 {
187         refcount_t zero = REFCOUNT_INIT(1);
188
189         pr_info("attempting bad refcount subtract past zero\n");
190         if (!refcount_sub_and_test(2, &zero))
191                 pr_info("wrap attempt was noticed\n");
192         if (refcount_read(&zero) == 1)
193                 pr_err("Correctly stayed above 0, but no BUG?!\n");
194         else
195                 pr_err("Fail: refcount wrapped\n");
196 }
197
198 void lkdtm_REFCOUNT_ZERO_INC(void)
199 {
200         refcount_t zero = REFCOUNT_INIT(0);
201
202         pr_info("attempting bad refcount increment from zero\n");
203         refcount_inc(&zero);
204         if (refcount_read(&zero) == 0)
205                 pr_err("Stayed at zero, but no BUG?!\n");
206         else
207                 pr_err("Fail: refcount went past zero\n");
208 }
209
210 void lkdtm_REFCOUNT_ZERO_ADD(void)
211 {
212         refcount_t zero = REFCOUNT_INIT(0);
213
214         pr_info("attempting bad refcount addition from zero\n");
215         refcount_add(2, &zero);
216         if (refcount_read(&zero) == 0)
217                 pr_err("Stayed at zero, but no BUG?!\n");
218         else
219                 pr_err("Fail: refcount went past zero\n");
220 }
221
222 void lkdtm_CORRUPT_LIST_ADD(void)
223 {
224         /*
225          * Initially, an empty list via LIST_HEAD:
226          *      test_head.next = &test_head
227          *      test_head.prev = &test_head
228          */
229         LIST_HEAD(test_head);
230         struct lkdtm_list good, bad;
231         void *target[2] = { };
232         void *redirection = &target;
233
234         pr_info("attempting good list addition\n");
235
236         /*
237          * Adding to the list performs these actions:
238          *      test_head.next->prev = &good.node
239          *      good.node.next = test_head.next
240          *      good.node.prev = test_head
241          *      test_head.next = good.node
242          */
243         list_add(&good.node, &test_head);
244
245         pr_info("attempting corrupted list addition\n");
246         /*
247          * In simulating this "write what where" primitive, the "what" is
248          * the address of &bad.node, and the "where" is the address held
249          * by "redirection".
250          */
251         test_head.next = redirection;
252         list_add(&bad.node, &test_head);
253
254         if (target[0] == NULL && target[1] == NULL)
255                 pr_err("Overwrite did not happen, but no BUG?!\n");
256         else
257                 pr_err("list_add() corruption not detected!\n");
258 }
259
260 void lkdtm_CORRUPT_LIST_DEL(void)
261 {
262         LIST_HEAD(test_head);
263         struct lkdtm_list item;
264         void *target[2] = { };
265         void *redirection = &target;
266
267         list_add(&item.node, &test_head);
268
269         pr_info("attempting good list removal\n");
270         list_del(&item.node);
271
272         pr_info("attempting corrupted list removal\n");
273         list_add(&item.node, &test_head);
274
275         /* As with the list_add() test above, this corrupts "next". */
276         item.node.next = redirection;
277         list_del(&item.node);
278
279         if (target[0] == NULL && target[1] == NULL)
280                 pr_err("Overwrite did not happen, but no BUG?!\n");
281         else
282                 pr_err("list_del() corruption not detected!\n");
283 }
284
285 void lkdtm_CORRUPT_USER_DS(void)
286 {
287         pr_info("setting bad task size limit\n");
288         set_fs(KERNEL_DS);
289
290         /* Make sure we do not keep running with a KERNEL_DS! */
291         force_sig(SIGKILL, current);
292 }