mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-28 20:44:26 +01:00
pagemap_dump!
This commit is contained in:
18
README.md
18
README.md
@@ -123,20 +123,30 @@ We have not managed to track this problem down yet, but the following workaround
|
|||||||
|
|
||||||
This started happening when we switched to building QEMU through Buildroot, and has not been observed on later Ubuntu.
|
This started happening when we switched to building QEMU through Buildroot, and has not been observed on later Ubuntu.
|
||||||
|
|
||||||
|
Using text mode is another workaround if you don't need GUI features.
|
||||||
|
|
||||||
## Filesystem persistency
|
## Filesystem persistency
|
||||||
|
|
||||||
The root filesystem is persistent across:
|
The root filesystem is persistent across:
|
||||||
|
|
||||||
./runqemu
|
./runqemu
|
||||||
./runqemu
|
date >f
|
||||||
|
sync
|
||||||
|
|
||||||
However, when you do:
|
then:
|
||||||
|
|
||||||
|
./runqemu
|
||||||
|
cat f
|
||||||
|
|
||||||
|
This is particularly useful to re-run shell commands from the history of a previous session with `Ctrl + R`.
|
||||||
|
|
||||||
|
When you do:
|
||||||
|
|
||||||
./run
|
./run
|
||||||
|
|
||||||
it gets overwritten by a fresh filesystem and you lose all changes.
|
the disk image gets overwritten by a fresh filesystem and you lose all changes.
|
||||||
|
|
||||||
Using text mode is another workaround if you don't need GUI features.
|
Remember that if you forcibly turn QEMU off without `sync` or `poweroff` from inside the VM, disk changes may not be saved.
|
||||||
|
|
||||||
## Text mode
|
## Text mode
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ These programs can also be compiled and used on host.
|
|||||||
1. [myinsmod](myinsmod.c)
|
1. [myinsmod](myinsmod.c)
|
||||||
1. [myrmmod](myrmmod.c)
|
1. [myrmmod](myrmmod.c)
|
||||||
1. [init_hello](init_hello.c)
|
1. [init_hello](init_hello.c)
|
||||||
|
1. [usermem](usermem.c)
|
||||||
|
1. [pagemap_dump](pagemap_dump.c)
|
||||||
1. Module tests
|
1. Module tests
|
||||||
1. [anonymous_inode](anonymous_inode.c)
|
1. [anonymous_inode](anonymous_inode.c)
|
||||||
1. [poll](poll.c)
|
1. [poll](poll.c)
|
||||||
|
|||||||
117
kernel_module/user/pagemap_dump.c
Normal file
117
kernel_module/user/pagemap_dump.c
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
Only tested in x86_64.
|
||||||
|
|
||||||
|
Adapted from: https://github.com/dwks/pagemap/blob/8a25747bc79d6080c8b94eac80807a4dceeda57a/pagemap2.c
|
||||||
|
|
||||||
|
Dump the page map of a given process PID.
|
||||||
|
|
||||||
|
Data sources: /proc/PIC/{map,pagemap}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#define PAGE_SIZE 0x1000
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
char buffer[BUFSIZ];
|
||||||
|
char maps_file[BUFSIZ];
|
||||||
|
char pagemap_file[BUFSIZ];
|
||||||
|
int maps;
|
||||||
|
int offset = 0;
|
||||||
|
int pagemap;
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
printf("Usage: %s pid1\n", argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
pid_t pid = (pid_t)strtoul(argv[1], NULL, 0);
|
||||||
|
snprintf(maps_file, sizeof(maps_file), "/proc/%lu/maps", (unsigned long)pid);
|
||||||
|
snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%lu/pagemap", (unsigned long)pid);
|
||||||
|
maps = open(maps_file, O_RDONLY);
|
||||||
|
if (maps < 0) {
|
||||||
|
perror("open maps");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
pagemap = open(pagemap_file, O_RDONLY);
|
||||||
|
if (pagemap < 0) {
|
||||||
|
perror("open pagemap");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
printf("addr pfn soft-dirty file/shared swapped present library\n");
|
||||||
|
for (;;) {
|
||||||
|
ssize_t length = read(maps, buffer + offset, sizeof buffer - offset);
|
||||||
|
if (length <= 0) break;
|
||||||
|
length += offset;
|
||||||
|
for (size_t i = offset; i < (size_t)length; i++) {
|
||||||
|
unsigned long low = 0, high = 0;
|
||||||
|
if (buffer[i] == '\n' && i) {
|
||||||
|
size_t x = i - 1;
|
||||||
|
while(x && buffer[x] != '\n') x --;
|
||||||
|
if (buffer[x] == '\n') x++;
|
||||||
|
size_t beginning = x;
|
||||||
|
while(buffer[x] != '-' && x < sizeof buffer) {
|
||||||
|
char c = buffer[x++];
|
||||||
|
low *= 16;
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
low += c - '0';
|
||||||
|
}
|
||||||
|
else if (c >= 'a' && c <= 'f') {
|
||||||
|
low += c - 'a' + 10;
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
while(buffer[x] != '-' && x < sizeof buffer) x++;
|
||||||
|
if (buffer[x] == '-') x++;
|
||||||
|
while(buffer[x] != ' ' && x < sizeof buffer) {
|
||||||
|
char c = buffer[x++];
|
||||||
|
high *= 16;
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
high += c - '0';
|
||||||
|
}
|
||||||
|
else if (c >= 'a' && c <= 'f') {
|
||||||
|
high += c - 'a' + 10;
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *lib_name = 0;
|
||||||
|
for (int field = 0; field < 4; field++) {
|
||||||
|
x++;
|
||||||
|
while(buffer[x] != ' ' && x < sizeof buffer) x++;
|
||||||
|
}
|
||||||
|
while (buffer[x] == ' ' && x < sizeof buffer) x++;
|
||||||
|
size_t y = x;
|
||||||
|
while (buffer[y] != '\n' && y < sizeof buffer) y++;
|
||||||
|
buffer[y] = 0;
|
||||||
|
lib_name = buffer + x;
|
||||||
|
{
|
||||||
|
unsigned long data;
|
||||||
|
for (unsigned long i = low; i < high; i += PAGE_SIZE) {
|
||||||
|
unsigned long index = (i / PAGE_SIZE) * sizeof(data);
|
||||||
|
if (pread(pagemap, &data, sizeof(data), index) != sizeof(data)) {
|
||||||
|
if (errno) perror("pread");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("%lx %lx %d %d %d %d %s\n",
|
||||||
|
i,
|
||||||
|
data & 0x7fffffffffffff,
|
||||||
|
(data >> 55) & 1,
|
||||||
|
(data >> 61) & 1,
|
||||||
|
(data >> 62) & 1,
|
||||||
|
(data >> 63) & 1,
|
||||||
|
lib_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(maps);
|
||||||
|
close(pagemap);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
69
kernel_module/user/usermem.c
Normal file
69
kernel_module/user/usermem.c
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
Only tested in x86_64.
|
||||||
|
|
||||||
|
Provide an allocated userland memory address for us to test out kernel memory APIs, including:
|
||||||
|
|
||||||
|
- /proc/pid/maps
|
||||||
|
- /proc/pid/pagemap
|
||||||
|
- /dev/mem
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
/usermem.out &
|
||||||
|
|
||||||
|
Outputs address and pid, e.g.:
|
||||||
|
|
||||||
|
address 0x600800
|
||||||
|
pid 110
|
||||||
|
|
||||||
|
Now translate the virtual address to physical for the given PID:
|
||||||
|
|
||||||
|
/pagemap2.out 110 | grep 0x600000
|
||||||
|
|
||||||
|
where 0x600000 is the page that contains 0x600800.
|
||||||
|
|
||||||
|
This produces a line of type:
|
||||||
|
|
||||||
|
0x600000 0x7c7b 0 0 0 1 /pagemap_test.out
|
||||||
|
|
||||||
|
where 0x7c7b is the PFN. To get the physical address, just add three zeros back:
|
||||||
|
|
||||||
|
0x7c7b000
|
||||||
|
|
||||||
|
Examine the physical memory from the QEMU monitor: on host:
|
||||||
|
|
||||||
|
./qemumonitor
|
||||||
|
xp 0x7c7b800
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
0000000007c7b800: 0x12345678
|
||||||
|
|
||||||
|
Yes!!! We read the correct value from the physical address.
|
||||||
|
|
||||||
|
TODO: why does:
|
||||||
|
|
||||||
|
devmem2 0x7c7b800
|
||||||
|
|
||||||
|
fail on the mmap? CONFIG_STRICT_DEVMEM is not set.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _XOPEN_SOURCE 700
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
enum { I0 = 0x12345678 };
|
||||||
|
|
||||||
|
static volatile uint32_t i = I0;
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
printf("address %p\n", (void *)&i);
|
||||||
|
printf("pid %ju\n", (uintmax_t)getpid());
|
||||||
|
while (i == I0) {
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
printf("i %jx\n", (uintmax_t)i);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user