Linux debugging

Check our new training course

Linux debugging, tracing, profiling & perf. analysis

Check our new training course
with Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

/*
 * Parts derived from tests/kernel/fatal/src/main.c, which has the
 * following copyright and license:
 *
 * Copyright (c) 2017 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr.h>
#include <ztest.h>
#include <kernel_structs.h>
#include <string.h>
#include <stdlib.h>

#define INFO(fmt, ...) printk(fmt, ##__VA_ARGS__)

/* ARM is a special case, in that k_thread_abort() does indeed return
 * instead of calling _Swap() directly. The PendSV exception is queued
 * and immediately fires upon completing the exception path; the faulting
 * thread is never run again.
 */
#ifndef CONFIG_ARM
FUNC_NORETURN
#endif
void _SysFatalErrorHandler(unsigned int reason, const NANO_ESF *pEsf)
{
	INFO("Caught system error -- reason %d\n", reason);
	ztest_test_pass();
#ifndef CONFIG_ARM
	CODE_UNREACHABLE;
#endif
}

static void is_usermode(void)
{
	/* Confirm that we are in fact running in user mode. */
	zassert_true(_is_user_context(), "thread left in kernel mode\n");
}

static void priv_insn(void)
{
	/* Try to invoke what should require a privileged instruction. */
	unsigned int key = irq_lock();

	irq_unlock(key); /* just in case we succeeded */
	zassert_unreachable("irq_lock did not fault\n");
}

static void write_control(void)
{
	/* Try to write to a control register. */
#if defined(CONFIG_X86)
	__asm__ volatile (
		"mov %cr0, %eax;\n\t"
		"and $0xfffeffff, %eax;\n\t"
		"mov %eax, %cr0;\n\t"
		);
#elif defined(CONFIG_ARM)
	__asm__ volatile (
		"mrs r2, CONTROL;\n\t"
		"bic r2, #1;\n\t"
		"msr CONTROL, r2;\n\t"
		);
#else
#error "Not implemented for this architecture"
#endif
	zassert_unreachable("Write to control register did not fault\n");
}

static void disable_mmu_mpu(void)
{
	/* Try to disable memory protections. */
#if defined(CONFIG_X86)
	__asm__ volatile (
		"mov %cr0, %eax;\n\t"
		"and $0x7ffeffff, %eax;\n\t"
		"mov %eax, %cr0;\n\t"
		);
#elif defined(CONFIG_ARM)
	arm_core_mpu_disable();
#else
#error "Not implemented for this architecture"
#endif
	zassert_unreachable("Disable MMU/MPU did not fault\n");
}

static void read_kernram(void)
{
	/* Try to read from kernel RAM. */
	void *p = _current->init_data;

	printk("%p\n", p);
	zassert_unreachable("Read from kernel RAM did not fault\n");
}

static void write_kernram(void)
{
	/* Try to write to kernel RAM. */
	_current->init_data = NULL;
	zassert_unreachable("Write to kernel RAM did not fault\n");
}

extern int _k_neg_eagain;

#include <linker/linker-defs.h>

static void write_kernro(void)
{
	/* Try to write to kernel RO. */
	const char *const ptr = (const char *const)&_k_neg_eagain;

	zassert_true(ptr < _image_rodata_end &&
		     ptr >= _image_rodata_start,
		     "_k_neg_eagain is not in rodata\n");
	_k_neg_eagain = -EINVAL;
	zassert_unreachable("Write to kernel RO did not fault\n");
}

static void write_kerntext(void)
{
	/* Try to write to kernel text. */
	memcpy(&_is_thread_essential, 0, 4);
	zassert_unreachable("Write to kernel text did not fault\n");
}

__kernel static int kernel_data;

static void read_kernel_data(void)
{
	/* Try to read from embedded kernel data. */
	int value = kernel_data;

	printk("%d\n", value);
	zassert_unreachable("Read from __kernel data did not fault\n");
}

static void write_kernel_data(void)
{
	kernel_data = 1;
	zassert_unreachable("Write to  __kernel data did not fault\n");
}

/*
 * volatile to avoid compiler mischief.
 */
volatile int *ptr = NULL;
#if defined(CONFIG_X86)
volatile size_t size = MMU_PAGE_SIZE;
#elif defined(CONFIG_ARM) && defined(CONFIG_PRIVILEGED_STACK_SIZE)
volatile size_t size = CONFIG_PRIVILEGED_STACK_SIZE;
#else
volatile size_t size = 512;
#endif

static void read_kernel_stack(void)
{
	/* Try to read from kernel stack. */
	int s[1];

	s[0] = 0;
	ptr = &s[0];
	ptr = (int *)((unsigned char *)ptr - size);
	printk("%d\n", *ptr);
	zassert_unreachable("Read from kernel stack did not fault\n");
}

static void write_kernel_stack(void)
{
	/* Try to write to kernel stack. */
	int s[1];

	s[0] = 0;
	ptr = &s[0];
	ptr = (int *)((unsigned char *)ptr - size);
	*ptr = 42;
	zassert_unreachable("Write to kernel stack did not fault\n");
}


static struct k_sem sem;

static void pass_user_object(void)
{
	/* Try to pass a user object to a system call. */
	k_sem_init(&sem, 0, 1);
	zassert_unreachable("Pass a user object to a syscall did not fault\n");
}

__kernel static struct k_sem ksem;

static void pass_noperms_object(void)
{
	/* Try to pass a object to a system call w/o permissions. */
	k_sem_init(&ksem, 0, 1);
	zassert_unreachable("Pass an unauthorized object to a "
			    "syscall did not fault\n");
}

__kernel struct k_thread kthread_thread;

#define STACKSIZE 512
K_THREAD_STACK_DEFINE(kthread_stack, STACKSIZE);

void thread_body(void)
{
}

static void start_kernel_thread(void)
{
	/* Try to start a kernel thread from a usermode thread */
	k_thread_create(&kthread_thread, kthread_stack, STACKSIZE,
			(k_thread_entry_t)thread_body, NULL, NULL, NULL,
			K_PRIO_PREEMPT(1), K_INHERIT_PERMS,
			K_NO_WAIT);
	zassert_unreachable("Create a kernel thread did not fault\n");
}

void test_main(void)
{
	k_thread_access_grant(k_current_get(),
			      &kthread_thread, &kthread_stack,
			      NULL);
	ztest_test_suite(test_userspace,
			 ztest_user_unit_test(is_usermode),
			 ztest_user_unit_test(priv_insn),
			 ztest_user_unit_test(write_control),
			 ztest_user_unit_test(disable_mmu_mpu),
			 ztest_user_unit_test(read_kernram),
			 ztest_user_unit_test(write_kernram),
			 ztest_user_unit_test(write_kernro),
			 ztest_user_unit_test(write_kerntext),
			 ztest_user_unit_test(read_kernel_data),
			 ztest_user_unit_test(write_kernel_data),
			 ztest_user_unit_test(read_kernel_stack),
			 ztest_user_unit_test(write_kernel_stack),
			 ztest_user_unit_test(pass_user_object),
			 ztest_user_unit_test(pass_noperms_object),
			 ztest_user_unit_test(start_kernel_thread)
		);
	ztest_run_test_suite(test_userspace);
}