mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-25 11:11:35 +01:00
start the big userland migration
This commit is contained in:
@@ -1 +0,0 @@
|
||||
https://github.com/cirosantilli/linux-kernel-module-cheat#ansi-c
|
||||
@@ -2,10 +2,10 @@
|
||||
* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-assembly-c-standard-library
|
||||
*/
|
||||
|
||||
#include "stdio.h"
|
||||
#include "stdint.h"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lkmc.h"
|
||||
#include <lkmc.h>
|
||||
|
||||
int asm_main(uint32_t *line);
|
||||
|
||||
|
||||
@@ -7,15 +7,15 @@
|
||||
_start:
|
||||
asm_main_after_prologue:
|
||||
/* write */
|
||||
mov $1, %rax /* stdout */
|
||||
mov $1, %rdi /* buffer */
|
||||
mov $msg, %rsi /* len */
|
||||
mov $len, %rdx /* syscall number */
|
||||
mov $1, %rax /* syscall number */
|
||||
mov $1, %rdi /* stdout */
|
||||
mov $msg, %rsi /* buffer */
|
||||
mov $len, %rdx /* len */
|
||||
syscall
|
||||
|
||||
/* exit */
|
||||
mov $60, %rax /* exit status */
|
||||
mov $0, %rdi /* syscall number */
|
||||
mov $60, %rax /* syscall number */
|
||||
mov $0, %rdi /* exit status */
|
||||
syscall
|
||||
msg:
|
||||
.ascii "hello\n"
|
||||
|
||||
1
userland/c/README.adoc
Normal file
1
userland/c/README.adoc
Normal file
@@ -0,0 +1 @@
|
||||
https://github.com/cirosantilli/linux-kernel-module-cheat#c
|
||||
@@ -1 +1 @@
|
||||
https://github.com/cirosantilli/linux-kernel-module-cheat#ansi-cpp
|
||||
https://github.com/cirosantilli/linux-kernel-module-cheat#cpp
|
||||
|
||||
@@ -8,19 +8,19 @@
|
||||
#include <unistd.h>
|
||||
|
||||
void signal_handler(int sig) {
|
||||
write(STDOUT_FILENO, "cad\n", 4);
|
||||
signal(sig, signal_handler);
|
||||
write(STDOUT_FILENO, "cad\n", 4);
|
||||
signal(sig, signal_handler);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
int i = 0;
|
||||
/* Disable the forced reboot, enable sending SIGINT to init. */
|
||||
reboot(RB_DISABLE_CAD);
|
||||
int i = 0;
|
||||
/* Disable the forced reboot, enable sending SIGINT to init. */
|
||||
reboot(RB_DISABLE_CAD);
|
||||
signal(SIGINT, signal_handler);
|
||||
while (1) {
|
||||
sleep(1);
|
||||
printf("%d\n", i);
|
||||
i++;
|
||||
}
|
||||
while (1) {
|
||||
sleep(1);
|
||||
printf("%d\n", i);
|
||||
i++;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Empty struct */
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#c-empty-struct */
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
20
userland/gcc/openmp.c
Normal file
20
userland/gcc/openmp.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#openmp */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <omp.h>
|
||||
|
||||
int main (void) {
|
||||
int nthreads, tid;
|
||||
#pragma omp parallel private(nthreads, tid)
|
||||
{
|
||||
tid = omp_get_thread_num();
|
||||
printf("Hello World from thread = %d\n", tid);
|
||||
if (tid == 0) {
|
||||
nthreads = omp_get_num_threads();
|
||||
printf("Number of threads = %d\n", nthreads);
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
93
userland/kernel_modules/mmap.c
Normal file
93
userland/kernel_modules/mmap.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#mmap */
|
||||
|
||||
#define _XOPEN_SOURCE 700
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h> /* uintmax_t */
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h> /* sysconf */
|
||||
|
||||
#include <userland/common.h> /* virt_to_phys_user */
|
||||
|
||||
enum { BUFFER_SIZE = 4 };
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int fd;
|
||||
long page_size;
|
||||
char *address1, *address2;
|
||||
char buf[BUFFER_SIZE];
|
||||
uintptr_t paddr;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s <mmap_file>\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
page_size = sysconf(_SC_PAGE_SIZE);
|
||||
printf("open pathname = %s\n", argv[1]);
|
||||
fd = open(argv[1], O_RDWR | O_SYNC);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
assert(0);
|
||||
}
|
||||
printf("fd = %d\n", fd);
|
||||
|
||||
/* mmap twice for double fun. */
|
||||
puts("mmap 1");
|
||||
address1 = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (address1 == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
assert(0);
|
||||
}
|
||||
puts("mmap 2");
|
||||
address2 = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (address2 == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
assert(address1 != address2);
|
||||
|
||||
/* Read and modify memory. */
|
||||
puts("access 1");
|
||||
assert(!strcmp(address1, "asdf"));
|
||||
/* vm_fault */
|
||||
puts("access 2");
|
||||
assert(!strcmp(address2, "asdf"));
|
||||
/* vm_fault */
|
||||
strcpy(address1, "qwer");
|
||||
/* Also modified. So both virtual addresses point to the same physical address. */
|
||||
assert(!strcmp(address2, "qwer"));
|
||||
|
||||
/* Check that the physical addresses are the same.
|
||||
* They are, but TODO why virt_to_phys on kernel gives a different value? */
|
||||
assert(!virt_to_phys_user(&paddr, getpid(), (uintptr_t)address1));
|
||||
printf("paddr1 = 0x%jx\n", (uintmax_t)paddr);
|
||||
assert(!virt_to_phys_user(&paddr, getpid(), (uintptr_t)address2));
|
||||
printf("paddr2 = 0x%jx\n", (uintmax_t)paddr);
|
||||
|
||||
/* Check that modifications made from userland are also visible from the kernel. */
|
||||
read(fd, buf, BUFFER_SIZE);
|
||||
assert(!memcmp(buf, "qwer", BUFFER_SIZE));
|
||||
|
||||
/* Modify the data from the kernel, and check that the change is visible from userland. */
|
||||
write(fd, "zxcv", 4);
|
||||
assert(!strcmp(address1, "zxcv"));
|
||||
assert(!strcmp(address2, "zxcv"));
|
||||
|
||||
/* Cleanup. */
|
||||
puts("munmap 1");
|
||||
if (munmap(address1, page_size)) {
|
||||
perror("munmap");
|
||||
assert(0);
|
||||
}
|
||||
puts("munmap 2");
|
||||
if (munmap(address2, page_size)) {
|
||||
perror("munmap");
|
||||
assert(0);
|
||||
}
|
||||
puts("close");
|
||||
close(fd);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
116
userland/linux/pagemap_dump.c
Normal file
116
userland/linux/pagemap_dump.c
Normal file
@@ -0,0 +1,116 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#pagemap_dump-out */
|
||||
|
||||
#define _XOPEN_SOURCE 700
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <userland/common.h> /* virt_to_phys_user */
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
char buffer[BUFSIZ];
|
||||
char maps_file[BUFSIZ];
|
||||
char pagemap_file[BUFSIZ];
|
||||
int maps_fd;
|
||||
int offset = 0;
|
||||
int pagemap_fd;
|
||||
pid_t pid;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s pid\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
pid = strtoull(argv[1], NULL, 0);
|
||||
snprintf(maps_file, sizeof(maps_file), "/proc/%ju/maps", (uintmax_t)pid);
|
||||
snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid);
|
||||
maps_fd = open(maps_file, O_RDONLY);
|
||||
if (maps_fd < 0) {
|
||||
perror("open maps");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
pagemap_fd = open(pagemap_file, O_RDONLY);
|
||||
if (pagemap_fd < 0) {
|
||||
perror("open pagemap");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("vaddr pfn soft-dirty file/shared swapped present library\n");
|
||||
for (;;) {
|
||||
ssize_t length = read(maps_fd, buffer + offset, sizeof buffer - offset);
|
||||
if (length <= 0) break;
|
||||
length += offset;
|
||||
for (size_t i = offset; i < (size_t)length; i++) {
|
||||
uintptr_t low = 0, high = 0;
|
||||
if (buffer[i] == '\n' && i) {
|
||||
const char *lib_name;
|
||||
size_t y;
|
||||
/* Parse a line from maps. Each line contains a range that contains many pages. */
|
||||
{
|
||||
size_t x = i - 1;
|
||||
while (x && buffer[x] != '\n') x--;
|
||||
if (buffer[x] == '\n') 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;
|
||||
}
|
||||
}
|
||||
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++;
|
||||
y = x;
|
||||
while (buffer[y] != '\n' && y < sizeof buffer) y++;
|
||||
buffer[y] = 0;
|
||||
lib_name = buffer + x;
|
||||
}
|
||||
/* Get info about all pages in this page range with pagemap. */
|
||||
{
|
||||
PagemapEntry entry;
|
||||
for (uintptr_t vaddr = low; vaddr < high; vaddr += sysconf(_SC_PAGE_SIZE)) {
|
||||
/* TODO always fails for the last page (vsyscall), why? pread returns 0. */
|
||||
if (!pagemap_get_entry(&entry, pagemap_fd, vaddr)) {
|
||||
printf(
|
||||
"%jx %jx %u %u %u %u %s\n",
|
||||
(uintmax_t)vaddr,
|
||||
(uintmax_t)entry.pfn,
|
||||
entry.soft_dirty,
|
||||
entry.file_page,
|
||||
entry.swapped,
|
||||
entry.present,
|
||||
lib_name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer[y] = '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
close(maps_fd);
|
||||
close(pagemap_fd);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
25
userland/linux/virt_to_phys_user.c
Normal file
25
userland/linux/virt_to_phys_user.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-physical-address-experiments */
|
||||
|
||||
#define _XOPEN_SOURCE 700
|
||||
#include <stdio.h> /* printf */
|
||||
#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE, strtoull */
|
||||
|
||||
#include <userland/common.h> /* virt_to_phys_user */
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
pid_t pid;
|
||||
uintptr_t vaddr, paddr = 0;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("Usage: %s pid vaddr\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
pid = strtoull(argv[1], NULL, 0);
|
||||
vaddr = strtoull(argv[2], NULL, 0);
|
||||
if (virt_to_phys_user(&paddr, pid, vaddr)) {
|
||||
fprintf(stderr, "error: virt_to_phys_user\n");
|
||||
return EXIT_FAILURE;
|
||||
};
|
||||
printf("0x%jx\n", (uintmax_t)paddr);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#mmap */
|
||||
|
||||
#define _XOPEN_SOURCE 700
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h> /* uintmax_t */
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h> /* sysconf */
|
||||
|
||||
#include "common_userland.h" /* virt_to_phys_user */
|
||||
|
||||
enum { BUFFER_SIZE = 4 };
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fd;
|
||||
long page_size;
|
||||
char *address1, *address2;
|
||||
char buf[BUFFER_SIZE];
|
||||
uintptr_t paddr;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s <mmap_file>\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
page_size = sysconf(_SC_PAGE_SIZE);
|
||||
printf("open pathname = %s\n", argv[1]);
|
||||
fd = open(argv[1], O_RDWR | O_SYNC);
|
||||
if (fd < 0) {
|
||||
perror("open");
|
||||
assert(0);
|
||||
}
|
||||
printf("fd = %d\n", fd);
|
||||
|
||||
/* mmap twice for double fun. */
|
||||
puts("mmap 1");
|
||||
address1 = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (address1 == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
assert(0);
|
||||
}
|
||||
puts("mmap 2");
|
||||
address2 = mmap(NULL, page_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (address2 == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
assert(address1 != address2);
|
||||
|
||||
/* Read and modify memory. */
|
||||
puts("access 1");
|
||||
assert(!strcmp(address1, "asdf"));
|
||||
/* vm_fault */
|
||||
puts("access 2");
|
||||
assert(!strcmp(address2, "asdf"));
|
||||
/* vm_fault */
|
||||
strcpy(address1, "qwer");
|
||||
/* Also modified. So both virtual addresses point to the same physical address. */
|
||||
assert(!strcmp(address2, "qwer"));
|
||||
|
||||
/* Check that the physical addresses are the same.
|
||||
* They are, but TODO why virt_to_phys on kernel gives a different value? */
|
||||
assert(!virt_to_phys_user(&paddr, getpid(), (uintptr_t)address1));
|
||||
printf("paddr1 = 0x%jx\n", (uintmax_t)paddr);
|
||||
assert(!virt_to_phys_user(&paddr, getpid(), (uintptr_t)address2));
|
||||
printf("paddr2 = 0x%jx\n", (uintmax_t)paddr);
|
||||
|
||||
/* Check that modifications made from userland are also visible from the kernel. */
|
||||
read(fd, buf, BUFFER_SIZE);
|
||||
assert(!memcmp(buf, "qwer", BUFFER_SIZE));
|
||||
|
||||
/* Modify the data from the kernel, and check that the change is visible from userland. */
|
||||
write(fd, "zxcv", 4);
|
||||
assert(!strcmp(address1, "zxcv"));
|
||||
assert(!strcmp(address2, "zxcv"));
|
||||
|
||||
/* Cleanup. */
|
||||
puts("munmap 1");
|
||||
if (munmap(address1, page_size)) {
|
||||
perror("munmap");
|
||||
assert(0);
|
||||
}
|
||||
puts("munmap 2");
|
||||
if (munmap(address2, page_size)) {
|
||||
perror("munmap");
|
||||
assert(0);
|
||||
}
|
||||
puts("close");
|
||||
close(fd);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1,15 +1,39 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#blas
|
||||
* Adapted from: https://github.com/xianyi/OpenBLAS/wiki/User-Manual/59b62f98e7400270fb03ad1d85fba5b64ebbff2b#call-cblas-interface */
|
||||
|
||||
#include "lkmc.h"
|
||||
* Adapted from: https://github.com/xianyi/OpenBLAS/wiki/User-Manual/59b62f98e7400270fb03ad1d85fba5b64ebbff2b#call-cblas-interface
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <cblas.h>
|
||||
|
||||
#include <lkmc.h>
|
||||
|
||||
int main(void) {
|
||||
double A[6] = {1.0, 2.0, 1.0, -3.0, 4.0, -1.0};
|
||||
double B[6] = {1.0, 2.0, 1.0, -3.0, 4.0, -1.0};
|
||||
double C[9] = {0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5};
|
||||
cblas_dgemm(CblasColMajor, CblasNoTrans, CblasTrans, 3, 3, 2, 1, A, 3, B, 3, 2, C, 3);
|
||||
assert(lkmc_vector_equal(9, C, (double[]){11.0, -9.0, 5.0, -9.0, 21.0, -1.0, 5.0, -1.0, 3.0}, 1e-6));
|
||||
double A[6] = {
|
||||
1.0, 2.0, 1.0,
|
||||
-3.0, 4.0, -1.0
|
||||
};
|
||||
double B[6] = {
|
||||
1.0, 2.0,
|
||||
1.0, -3.0,
|
||||
4.0, -1.0
|
||||
};
|
||||
double C[9] = {
|
||||
0.5, 0.5, 0.5,
|
||||
0.5, 0.5, 0.5,
|
||||
0.5, 0.5, 0.5
|
||||
};
|
||||
cblas_dgemm(
|
||||
CblasColMajor, CblasNoTrans, CblasTrans,
|
||||
3, 3, 2, 1, A, 3, B, 3, 2, C, 3
|
||||
);
|
||||
assert(lkmc_vector_equal(
|
||||
9,
|
||||
C,
|
||||
(double[]) {
|
||||
11.0, -9.0, 5.0,
|
||||
-9.0, 21.0, -1.0,
|
||||
5.0, -1.0, 3.0
|
||||
},
|
||||
1e-6
|
||||
));
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#openmp */
|
||||
|
||||
#include <omp.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main () {
|
||||
int nthreads, tid;
|
||||
#pragma omp parallel private(nthreads, tid)
|
||||
{
|
||||
tid = omp_get_thread_num();
|
||||
printf("Hello World from thread = %d\n", tid);
|
||||
if (tid == 0) {
|
||||
nthreads = omp_get_num_threads();
|
||||
printf("Number of threads = %d\n", nthreads);
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#pagemap_dump-out */
|
||||
|
||||
#define _XOPEN_SOURCE 700
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common_userland.h" /* pagemap_get_entry */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char buffer[BUFSIZ];
|
||||
char maps_file[BUFSIZ];
|
||||
char pagemap_file[BUFSIZ];
|
||||
int maps_fd;
|
||||
int offset = 0;
|
||||
int pagemap_fd;
|
||||
pid_t pid;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s pid\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
pid = strtoull(argv[1], NULL, 0);
|
||||
snprintf(maps_file, sizeof(maps_file), "/proc/%ju/maps", (uintmax_t)pid);
|
||||
snprintf(pagemap_file, sizeof(pagemap_file), "/proc/%ju/pagemap", (uintmax_t)pid);
|
||||
maps_fd = open(maps_file, O_RDONLY);
|
||||
if (maps_fd < 0) {
|
||||
perror("open maps");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
pagemap_fd = open(pagemap_file, O_RDONLY);
|
||||
if (pagemap_fd < 0) {
|
||||
perror("open pagemap");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
printf("vaddr pfn soft-dirty file/shared swapped present library\n");
|
||||
for (;;) {
|
||||
ssize_t length = read(maps_fd, buffer + offset, sizeof buffer - offset);
|
||||
if (length <= 0) break;
|
||||
length += offset;
|
||||
for (size_t i = offset; i < (size_t)length; i++) {
|
||||
uintptr_t low = 0, high = 0;
|
||||
if (buffer[i] == '\n' && i) {
|
||||
const char *lib_name;
|
||||
size_t y;
|
||||
/* Parse a line from maps. Each line contains a range that contains many pages. */
|
||||
{
|
||||
size_t x = i - 1;
|
||||
while (x && buffer[x] != '\n') x--;
|
||||
if (buffer[x] == '\n') 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;
|
||||
}
|
||||
}
|
||||
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++;
|
||||
y = x;
|
||||
while (buffer[y] != '\n' && y < sizeof buffer) y++;
|
||||
buffer[y] = 0;
|
||||
lib_name = buffer + x;
|
||||
}
|
||||
/* Get info about all pages in this page range with pagemap. */
|
||||
{
|
||||
PagemapEntry entry;
|
||||
for (uintptr_t vaddr = low; vaddr < high; vaddr += sysconf(_SC_PAGE_SIZE)) {
|
||||
/* TODO always fails for the last page (vsyscall), why? pread returns 0. */
|
||||
if (!pagemap_get_entry(&entry, pagemap_fd, vaddr)) {
|
||||
printf("%jx %jx %u %u %u %u %s\n",
|
||||
(uintmax_t)vaddr,
|
||||
(uintmax_t)entry.pfn,
|
||||
entry.soft_dirty,
|
||||
entry.file_page,
|
||||
entry.swapped,
|
||||
entry.present,
|
||||
lib_name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer[y] = '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
close(maps_fd);
|
||||
close(pagemap_fd);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
/* Count to infinity with 1 second sleep between each increment. */
|
||||
/* Count to infinity with 1 second sleep between each increment.
|
||||
* Sample application: https://github.com/cirosantilli/linux-kernel-module-cheat#gdb-step-debug-userland-custom-init
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE 700
|
||||
#include <limits.h>
|
||||
@@ -1,26 +0,0 @@
|
||||
/* https://github.com/cirosantilli/linux-kernel-module-cheat#userland-physical-address-experiments */
|
||||
|
||||
#define _XOPEN_SOURCE 700
|
||||
#include <stdio.h> /* printf */
|
||||
#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE, strtoull */
|
||||
|
||||
#include "common_userland.h" /* virt_to_phys_user */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
pid_t pid;
|
||||
uintptr_t vaddr, paddr = 0;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("Usage: %s pid vaddr\n", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
pid = strtoull(argv[1], NULL, 0);
|
||||
vaddr = strtoull(argv[2], NULL, 0);
|
||||
if (virt_to_phys_user(&paddr, pid, vaddr)) {
|
||||
fprintf(stderr, "error: virt_to_phys_user\n");
|
||||
return EXIT_FAILURE;
|
||||
};
|
||||
printf("0x%jx\n", (uintmax_t)paddr);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user