Я пытаюсь создать небольшой демонстрационный модуль ядра для Linux, который находит указанный процесс c и считывает значение из памяти этого процесса.
Я собрал следующий код:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/init.h>
#include <linux/highmem.h>
#include <asm/uaccess.h>
static void read_process_memory(struct task_struct *task) {
char buf[1024];
unsigned long size;
unsigned long ret;
void __user *addr;
struct mm_struct *mm = get_task_mm(task);
struct vm_area_struct *vma;
if (!mm) {
// Abort
return;
}
// Lock for reading
down_read(&mm->mmap_sem);
vma = mm->mmap;
memset(buf, 0, 1024);
// Make sure read is enabled for this region
if (vma && vma->vm_flags & VM_READ) {
// Read without overflowing
size = vma->vm_end - vma->vm_start;
if (size > 1023) {
size = 1023;
}
// Attempt to get the data from the start of the vma
addr = (void __user *)vma->vm_start;
if (access_ok(VERIFY_READ, addr, size)) {
ret = copy_from_user(buf, addr, size);
if (ret == 0) {
// Probably doesn't contain anything relevent
printk(KERN_ALERT "mymodule: Read '%s'\n", buf);
} else {
printk(KERN_ALERT "mymodule: Failed to copy %lu bytes from userspace\n", ret);
}
} else {
printk(KERN_ALERT "mymodule: access_ok check failed\n");
}
// Release the lock
up_read(&mm->mmap_sem);
mmput(mm);
}
}
static int __init mymodule_init(void) {
struct task_struct *task;
bool found = false;
printk(KERN_ALERT "mymodule: Starting\n");
// Find the process
rcu_read_lock();
for_each_process(task) {
if (strcmp(task->comm, "example-process") == 0) {
printk(KERN_ALERT "mymodule: Found pid %d for process %s\n", task->pid, task->comm);
found = true;
break;
}
}
rcu_read_unlock();
if (!found) {
printk(KERN_ALERT "mymodule: Process not found, aborting\n");
return -1;
}
read_process_memory(task);
return 0;
}
static void __exit mymodule_exit(void) {
printk(KERN_ALERT "mymodule: Stopped\n");
}
module_init(mymodule_init);
module_exit(mymodule_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("user");
Все работает нормально до вызова copy_from_user
, который возвращает ненулевой счет (фактически, он возвращает size
, что означает, что он не подготовил никаких данных), независимо от процесса и vma
Я пытаюсь читать с.
Есть ли недоразумение с моей стороны, или что-то я делаю неправильно?
РЕДАКТИРОВАТЬ: Вот рабочая версия read_process_memory
:
static void read_process_memory(struct task_struct *task) {
char buf[1024];
unsigned long size;
int ret;
void *addr;
struct mm_struct *mm = get_task_mm(task);
struct vm_area_struct *vma;
struct page *pages[1];
if (!mm) {
// Abort
return;
}
// Lock for reading
down_read(&mm->mmap_sem);
vma = mm->mmap;
memset(buf, 0, 1024);
// Make sure read is enabled for this region
if (vma && vma->vm_flags & VM_READ) {
// Get the first page
ret = get_user_pages_remote(task, mm, vma->vm_start, 1, FOLL_FORCE, pages, NULL);
if (ret > 0) {
// We got our page, we should now be able to map it and read directly
addr = kmap(*pages);
// Read without overflowing
size = vma->vm_end - vma->vm_start;
if (size > 1023) {
size = 1023;
}
strncpy(buf, addr, size);
// Probably doesn't contain anything relevent
printk(KERN_ALERT "mymodule: Read '%s'\n", buf);
// Make sure to release our page
kunmap(*pages);
put_page(*pages);
} else {
printk(KERN_ALERT "mymodule: Failed to read page at %p (errno=%d)\n", (void *)vma->vm_start, ret);
}
// Release the lock
up_read(&mm->mmap_sem);
mmput(mm);
}
}