All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH] kallsyms01: Utilize ksymbol table for unauthorized address access
@ 2024-04-22  5:36 Li Wang
  2024-04-29 14:42 ` Cyril Hrubis
  0 siblings, 1 reply; 2+ messages in thread
From: Li Wang @ 2024-04-22  5:36 UTC (permalink / raw
  To: ltp

Access the system symbols with root permission to test whether it's
possible to read and write the memory addresses of kernel-space
from user-space. This helps in identifying potential vulnerabilities
where user-space processes can inappropriately access kernel memory.

Signed-off-by: Li Wang <liwang@redhat.com>
---
 runtest/mm                                    |   2 +
 testcases/kernel/security/kallsyms/.gitignore |   1 +
 testcases/kernel/security/kallsyms/Makefile   |   6 +
 testcases/kernel/security/kallsyms/kallsyms.c | 161 ++++++++++++++++++
 4 files changed, 170 insertions(+)
 create mode 100644 testcases/kernel/security/kallsyms/.gitignore
 create mode 100644 testcases/kernel/security/kallsyms/Makefile
 create mode 100644 testcases/kernel/security/kallsyms/kallsyms.c

diff --git a/runtest/mm b/runtest/mm
index d859b331c..6a8cd0b9d 100644
--- a/runtest/mm
+++ b/runtest/mm
@@ -58,6 +58,8 @@ mmap10_2 mmap10 -s
 mmap10_3 mmap10 -a -s
 mmap10_4 mmap10 -a -s -i 60
 
+kallsyms kallsyms
+
 ksm01 ksm01
 ksm01_1 ksm01 -u 128
 ksm02 ksm02
diff --git a/testcases/kernel/security/kallsyms/.gitignore b/testcases/kernel/security/kallsyms/.gitignore
new file mode 100644
index 000000000..7074d4e24
--- /dev/null
+++ b/testcases/kernel/security/kallsyms/.gitignore
@@ -0,0 +1 @@
+kallsyms
diff --git a/testcases/kernel/security/kallsyms/Makefile b/testcases/kernel/security/kallsyms/Makefile
new file mode 100644
index 000000000..5ea7d67db
--- /dev/null
+++ b/testcases/kernel/security/kallsyms/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/security/kallsyms/kallsyms.c b/testcases/kernel/security/kallsyms/kallsyms.c
new file mode 100644
index 000000000..83622dea7
--- /dev/null
+++ b/testcases/kernel/security/kallsyms/kallsyms.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2024 Red Hat, Inc.
+ */
+
+/*\
+ * [Description]
+ *
+ *  Utilize kernel's symbol table for unauthorized address access.
+ *
+ *  Access the system symbols with root permission to test whether it's
+ *  possible to read and write the memory addresses of kernel-space
+ *  from user-space. This helps in identifying potential vulnerabilities
+ *  where user-space processes can inappropriately access kernel memory.
+ *
+ * Steps:
+ *  1. Start a process that reads all symbols and their addresses from
+ *     '/proc/kallsyms' and stores them in a linked list.
+ *
+ *  2. Attempt to write to each kernel address found in the linked list.
+ *     The expectation is that each attempt will fail with a SIGSEGV
+ *     (segmentation fault), indicating that the user-space process
+ *     cannot write to kernel memory.
+ *
+ *  3. Handle each SIGSEGV using a signal handler that sets a flag and
+ *     long jumps out of the faulting context.
+ *
+ *  4. If any write operation does not result in a SIGSEGV, log this as
+ *     a potential security vulnerability.
+ *
+ *  5. Observe and log the behavior and any system responses to these
+ *     unauthorized access attempts.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+#include <string.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "tst_test.h"
+#include "tst_safe_stdio.h"
+
+struct kallsym {
+	unsigned long addr;
+	char type;
+	char name[128];
+};
+
+struct ksymstbl {
+	struct kallsym symbol;
+	struct ksymstbl *next;
+};
+
+static struct ksymstbl *sym_table;
+static unsigned int nr_symbols;
+static sigjmp_buf jmpbuf;
+volatile sig_atomic_t segv_caught = 0;
+
+static void segv_handler(int sig)
+{
+	if (sig == SIGSEGV)
+		segv_caught++;
+	else
+		tst_res(TFAIL, "Unexpected signal %s", strsignal(sig));
+
+	siglongjmp(jmpbuf, 1);
+}
+
+static struct ksymstbl *read_kallsyms(unsigned int *nr_symbols)
+{
+	FILE *stream;
+	char *line = NULL;
+	size_t len = 0;
+	unsigned int nr_syms = 0;
+	struct ksymstbl *head, *item, *i;
+
+	item = head = calloc(1, sizeof(*head));
+	if (head == NULL)
+		goto out;
+
+	stream = SAFE_FOPEN("/proc/kallsyms", "r");
+
+	while (getline(&line, &len, stream) != -1) {
+		i = item;
+
+		sscanf(line, "%lx %c %s",
+				&i->symbol.addr, &i->symbol.type, i->symbol.name);
+
+		item = calloc(1, sizeof(*i));
+		if (item == NULL)
+			tst_brk(TBROK, "In calloc[]");
+
+		i->next = item;
+		nr_syms += 1;
+	}
+
+	*nr_symbols = nr_syms;
+	SAFE_FCLOSE(stream);
+out:
+	return head;
+}
+
+static void setup(void)
+{
+	sym_table = read_kallsyms(&nr_symbols);
+	if (!sym_table)
+		tst_brk(TBROK, "Failed to read kernel symbols");
+}
+
+static void access_ksymbols_address(struct ksymstbl *sym_table)
+{
+	if (sigsetjmp(jmpbuf, 1) == 0) {
+		*(volatile unsigned long *)sym_table->symbol.addr = 0;
+
+		tst_res(TFAIL, "Successfully accessed kernel addr 0x%lx (%s)",
+			sym_table->symbol.addr, sym_table->symbol.name);
+	}
+
+}
+
+static void test_access_kernel_address(void)
+{
+	struct ksymstbl *current;
+	struct sigaction sa;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = segv_handler;
+	sigaction(SIGSEGV, &sa, NULL);
+
+	current = sym_table;
+	while (current->next != NULL) {
+		access_ksymbols_address(current);
+		current = current->next;
+	}
+
+	if (segv_caught == (sig_atomic_t)nr_symbols)
+		tst_res(TPASS, "Caught %d times SIGSEGV in access ksymbols addr", segv_caught);
+}
+
+static void cleanup(void)
+{
+	while (sym_table != NULL) {
+		struct ksymstbl *temp = sym_table;
+		sym_table = sym_table->next;
+		free(temp);
+	}
+}
+
+static struct tst_test test = {
+	.needs_root = 1,
+	.setup = setup,
+	.cleanup = cleanup,
+	.max_runtime = 60,
+	.test_all = test_access_kernel_address,
+};
-- 
2.40.1


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [LTP] [PATCH] kallsyms01: Utilize ksymbol table for unauthorized address access
  2024-04-22  5:36 [LTP] [PATCH] kallsyms01: Utilize ksymbol table for unauthorized address access Li Wang
@ 2024-04-29 14:42 ` Cyril Hrubis
  0 siblings, 0 replies; 2+ messages in thread
From: Cyril Hrubis @ 2024-04-29 14:42 UTC (permalink / raw
  To: Li Wang; +Cc: ltp

Hi!
> +struct kallsym {
> +	unsigned long addr;
> +	char type;
> +	char name[128];
> +};
> +
> +struct ksymstbl {
> +	struct kallsym symbol;
> +	struct ksymstbl *next;
> +};
> +
> +static struct ksymstbl *sym_table;
> +static unsigned int nr_symbols;
> +static sigjmp_buf jmpbuf;
> +volatile sig_atomic_t segv_caught = 0;
> +
> +static void segv_handler(int sig)
> +{
> +	if (sig == SIGSEGV)
> +		segv_caught++;
> +	else
> +		tst_res(TFAIL, "Unexpected signal %s", strsignal(sig));
> +
> +	siglongjmp(jmpbuf, 1);
> +}
> +
> +static struct ksymstbl *read_kallsyms(unsigned int *nr_symbols)
> +{
> +	FILE *stream;
> +	char *line = NULL;
> +	size_t len = 0;
> +	unsigned int nr_syms = 0;
> +	struct ksymstbl *head, *item, *i;
> +
> +	item = head = calloc(1, sizeof(*head));
> +	if (head == NULL)
> +		goto out;
> +
> +	stream = SAFE_FOPEN("/proc/kallsyms", "r");
> +
> +	while (getline(&line, &len, stream) != -1) {
> +		i = item;
> +
> +		sscanf(line, "%lx %c %s",
> +				&i->symbol.addr, &i->symbol.type, i->symbol.name);
> +
> +		item = calloc(1, sizeof(*i));
> +		if (item == NULL)
> +			tst_brk(TBROK, "In calloc[]");

We should add SAFE_CALLOC() to the test library. Or maybe
SAFE_ZEROED_MALLOC() because we actually mis-use the calloc() here to
get the memory initialized to zero.

Also it may be actually faster to read the file twice, first time only
to count the addresses and allocate an array of the symbols instead.
That way we avoid all the allocation and list traversal.

static unsigned int read_kallsyms(struct ksymbtl *table, unsigned int table_size)
{
	FILE *stream = SAFE_FOPEN("/proc/kallsyms", "r");
	unsigned int nr_syms = 0;

	while (getline(&line, &len, stream) != -1) {

		if (table && nr_syms < table_size) {
			sscanf(line, "%lx %c %s",
			       &table[nr_syms].addr,
			       ...);
		}

		nr_syms++;
	}

	return nr_syms;
}


static void setup(void)
{
	unsigned int nr_syms;

	nr_syms = read_kallsyms(NULL, 0);

	sym_table = SAFE_MALLOC(sizeof(*sym_table) * nr_syms);

	if (nr_syms != read_kallsyms(sym_table, nr_syms))
		tst_res(TWARN, "/proc/kallsyms changed size!?");
}

> +		i->next = item;
> +		nr_syms += 1;
> +	}
> +
> +	*nr_symbols = nr_syms;
> +	SAFE_FCLOSE(stream);
> +out:
> +	return head;
> +}
> +
> +static void setup(void)
> +{
> +	sym_table = read_kallsyms(&nr_symbols);
> +	if (!sym_table)
> +		tst_brk(TBROK, "Failed to read kernel symbols");
> +}
> +
> +static void access_ksymbols_address(struct ksymstbl *sym_table)
> +{
> +	if (sigsetjmp(jmpbuf, 1) == 0) {
> +		*(volatile unsigned long *)sym_table->symbol.addr = 0;
> +
> +		tst_res(TFAIL, "Successfully accessed kernel addr 0x%lx (%s)",
> +			sym_table->symbol.addr, sym_table->symbol.name);
> +	}
> +
> +}
> +
> +static void test_access_kernel_address(void)
> +{
> +	struct ksymstbl *current;
> +	struct sigaction sa;
> +
> +	memset(&sa, 0, sizeof(sa));
> +	sa.sa_handler = segv_handler;
> +	sigaction(SIGSEGV, &sa, NULL);
> +
> +	current = sym_table;
> +	while (current->next != NULL) {
> +		access_ksymbols_address(current);
> +		current = current->next;
> +	}
> +
> +	if (segv_caught == (sig_atomic_t)nr_symbols)
> +		tst_res(TPASS, "Caught %d times SIGSEGV in access ksymbols addr", segv_caught);
> +}
> +
> +static void cleanup(void)
> +{
> +	while (sym_table != NULL) {
> +		struct ksymstbl *temp = sym_table;
> +		sym_table = sym_table->next;
> +		free(temp);
> +	}
> +}
> +
> +static struct tst_test test = {
> +	.needs_root = 1,
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.max_runtime = 60,
> +	.test_all = test_access_kernel_address,
> +};

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2024-04-29 14:43 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-04-22  5:36 [LTP] [PATCH] kallsyms01: Utilize ksymbol table for unauthorized address access Li Wang
2024-04-29 14:42 ` Cyril Hrubis

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.