Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.14.15.
  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/sched.h>
 10
 11struct lkdtm_list {
 12	struct list_head node;
 13};
 14
 15/*
 16 * Make sure our attempts to over run the kernel stack doesn't trigger
 17 * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we
 18 * recurse past the end of THREAD_SIZE by default.
 19 */
 20#if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0)
 21#define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2)
 22#else
 23#define REC_STACK_SIZE (THREAD_SIZE / 8)
 24#endif
 25#define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2)
 26
 27static int recur_count = REC_NUM_DEFAULT;
 28
 29static DEFINE_SPINLOCK(lock_me_up);
 30
 31static int recursive_loop(int remaining)
 32{
 33	char buf[REC_STACK_SIZE];
 34
 35	/* Make sure compiler does not optimize this away. */
 36	memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE);
 37	if (!remaining)
 38		return 0;
 39	else
 40		return recursive_loop(remaining - 1);
 41}
 42
 43/* If the depth is negative, use the default, otherwise keep parameter. */
 44void __init lkdtm_bugs_init(int *recur_param)
 45{
 46	if (*recur_param < 0)
 47		*recur_param = recur_count;
 48	else
 49		recur_count = *recur_param;
 50}
 51
 52void lkdtm_PANIC(void)
 53{
 54	panic("dumptest");
 55}
 56
 57void lkdtm_BUG(void)
 58{
 59	BUG();
 60}
 61
 62void lkdtm_WARNING(void)
 63{
 64	WARN_ON(1);
 65}
 66
 67void lkdtm_EXCEPTION(void)
 68{
 69	*((int *) 0) = 0;
 70}
 71
 72void lkdtm_LOOP(void)
 73{
 74	for (;;)
 75		;
 76}
 77
 78void lkdtm_OVERFLOW(void)
 79{
 80	(void) recursive_loop(recur_count);
 81}
 82
 83noinline void lkdtm_CORRUPT_STACK(void)
 84{
 85	/* Use default char array length that triggers stack protection. */
 86	char data[8];
 87
 88	memset((void *)data, 'a', 64);
 89	pr_info("Corrupted stack with '%16s'...\n", data);
 90}
 91
 92void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void)
 93{
 94	static u8 data[5] __attribute__((aligned(4))) = {1, 2, 3, 4, 5};
 95	u32 *p;
 96	u32 val = 0x12345678;
 97
 98	p = (u32 *)(data + 1);
 99	if (*p == 0)
100		val = 0x87654321;
101	*p = val;
102}
103
104void lkdtm_SOFTLOCKUP(void)
105{
106	preempt_disable();
107	for (;;)
108		cpu_relax();
109}
110
111void lkdtm_HARDLOCKUP(void)
112{
113	local_irq_disable();
114	for (;;)
115		cpu_relax();
116}
117
118void lkdtm_SPINLOCKUP(void)
119{
120	/* Must be called twice to trigger. */
121	spin_lock(&lock_me_up);
122	/* Let sparse know we intended to exit holding the lock. */
123	__release(&lock_me_up);
124}
125
126void lkdtm_HUNG_TASK(void)
127{
128	set_current_state(TASK_UNINTERRUPTIBLE);
129	schedule();
130}
131
132void lkdtm_ATOMIC_UNDERFLOW(void)
133{
134	atomic_t under = ATOMIC_INIT(INT_MIN);
135
136	pr_info("attempting good atomic increment\n");
137	atomic_inc(&under);
138	atomic_dec(&under);
139
140	pr_info("attempting bad atomic underflow\n");
141	atomic_dec(&under);
142}
143
144void lkdtm_ATOMIC_OVERFLOW(void)
145{
146	atomic_t over = ATOMIC_INIT(INT_MAX);
147
148	pr_info("attempting good atomic decrement\n");
149	atomic_dec(&over);
150	atomic_inc(&over);
151
152	pr_info("attempting bad atomic overflow\n");
153	atomic_inc(&over);
154}
155
156void lkdtm_CORRUPT_LIST_ADD(void)
157{
158	/*
159	 * Initially, an empty list via LIST_HEAD:
160	 *	test_head.next = &test_head
161	 *	test_head.prev = &test_head
162	 */
163	LIST_HEAD(test_head);
164	struct lkdtm_list good, bad;
165	void *target[2] = { };
166	void *redirection = &target;
167
168	pr_info("attempting good list addition\n");
169
170	/*
171	 * Adding to the list performs these actions:
172	 *	test_head.next->prev = &good.node
173	 *	good.node.next = test_head.next
174	 *	good.node.prev = test_head
175	 *	test_head.next = good.node
176	 */
177	list_add(&good.node, &test_head);
178
179	pr_info("attempting corrupted list addition\n");
180	/*
181	 * In simulating this "write what where" primitive, the "what" is
182	 * the address of &bad.node, and the "where" is the address held
183	 * by "redirection".
184	 */
185	test_head.next = redirection;
186	list_add(&bad.node, &test_head);
187
188	if (target[0] == NULL && target[1] == NULL)
189		pr_err("Overwrite did not happen, but no BUG?!\n");
190	else
191		pr_err("list_add() corruption not detected!\n");
192}
193
194void lkdtm_CORRUPT_LIST_DEL(void)
195{
196	LIST_HEAD(test_head);
197	struct lkdtm_list item;
198	void *target[2] = { };
199	void *redirection = &target;
200
201	list_add(&item.node, &test_head);
202
203	pr_info("attempting good list removal\n");
204	list_del(&item.node);
205
206	pr_info("attempting corrupted list removal\n");
207	list_add(&item.node, &test_head);
208
209	/* As with the list_add() test above, this corrupts "next". */
210	item.node.next = redirection;
211	list_del(&item.node);
212
213	if (target[0] == NULL && target[1] == NULL)
214		pr_err("Overwrite did not happen, but no BUG?!\n");
215	else
216		pr_err("list_del() corruption not detected!\n");
217}