LINUX.ORG.RU

вопрос к ядрописцам

 ,


0

3

Чтобы использовать вызов strncpy_from_user для копирования __user char* нужно предварительно что-то вызвать?

проверка есть ли доступ к данным __user char * возвращает сукцесс access_ok(oldname, MAX_NAME_LEN)

а само копирование проходит с ошибкой (пишет что не удалось скопировать абсолютно ничего.

int res = strncpy_from_user(kernel_oldname, oldname,255);

Вопрос исключительно для общего образования.

Ответ на: комментарий от metawishmaster

В моем случае точно нет. Использую так же макрос copy_from_user Должен вернуть количество байт которое не удалось считать. Возвращает значение 255 - ни одного байта не удалось считать.

Запускаю на виртуалке. qemu

shimajima
() автор топика
Последнее исправление: shimajima (всего исправлений: 1)
Ответ на: комментарий от metawishmaster

Вот полный код. Если укажите что почитать чтобы поднять свои знания, буду благодарен.

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/uaccess.h>  
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/string.h>

#define MAX_NAME_LEN 255

static inline void disable_smap(void) {
    unsigned long cr4;
    asm volatile ("mov %%cr4, %0" : "=r" (cr4));   
    cr4 &= ~X86_CR4_SMAP;                         
    asm volatile ("mov %0, %%cr4" :: "r" (cr4));   
}

static inline void enable_smap(void) {
    unsigned long cr4;
    asm volatile ("mov %%cr4, %0" : "=r" (cr4));   
    cr4 |= X86_CR4_SMAP;                         
    asm volatile ("mov %0, %%cr4" :: "r" (cr4));   
}
asmlinkage long (*original_renameat2)(int olddfd, const char __user *oldname, int newdfd, const char __user *newname, unsigned int flags);

asmlinkage long custom_renameat2(int olddfd, const char __user *oldname, int newdfd, const char __user *newname, unsigned int flags) {
    char *kernel_oldname;
    struct file *filp;
    char buf[5] = {0};  // Buffer for the first 4 characters + null 

    printk(KERN_INFO "Received user pointer oldname: 0x%p\n", oldname);
    if (!access_ok(oldname, MAX_NAME_LEN)) {
        printk(KERN_ERR "Invalid user pointer for filename: 0x%p\n", oldname);
        return -EFAULT;
    }
    // Allocate memory for the old file path
	#if 1
    kernel_oldname = kmalloc(MAX_NAME_LEN + 1, GFP_ATOMIC);
    if (!kernel_oldname) {
        printk(KERN_ERR "Memory allocation failed for oldname\n");
        return -ENOMEM;
    }
#endif
    printk(KERN_INFO "Syscall args: olddfd=%d, oldname=0x%p, newdfd=%d, newname=0x%p, flags=%u\n",
           olddfd, oldname, newdfd, newname, flags);
		
    // Copy from userspace to kernel space
		if (!user_access_begin(oldname, MAX_NAME_LEN)) {
    printk(KERN_ERR "User access begin failed for oldname: 0x%p\n", oldname);
    return -EFAULT;
}
		int res = copy_from_user(kernel_oldname, oldname,MAX_NAME_LEN);
    if (res) {
        printk(KERN_ERR "Failed to copy filename from userspace, oldname=0x%p, res %d\n", oldname,res);
        kfree(kernel_oldname);
        return -EFAULT;
    }
		user_access_end();
    kernel_oldname[MAX_NAME_LEN] = '\0'; 

    printk(KERN_INFO "Filename copied from userspace: %s\n", kernel_oldname);

    filp = filp_open(kernel_oldname, O_RDONLY, 0);
    if (IS_ERR(filp)) {
        printk(KERN_ERR "Failed to open file: %s\n", kernel_oldname);
        kfree(kernel_oldname);
        return PTR_ERR(filp);
    }

    if (kernel_read(filp, buf, 4, &filp->f_pos) < 0) {
        printk(KERN_ERR "Failed to read from file: %s\n", kernel_oldname);
        filp_close(filp, NULL);
        kfree(kernel_oldname);
        return -EIO;
    }

    filp_close(filp, NULL);

    // Check if the content matches "aabb"
    if (strncmp(buf, "aabb", 4) == 0) {
        printk(KERN_INFO "File '%s' matches pattern 'aabb'. Rename blocked.\n", kernel_oldname);
        kfree(kernel_oldname);
        return -EPERM;  // some shit
    }

    printk(KERN_INFO "File '%s' does not match pattern. Proceeding with rename.\n", kernel_oldname);
    kfree(kernel_oldname);
    return original_renameat2(olddfd, oldname, newdfd, newname, flags);
}
static struct kprobe kp = {
    .symbol_name = "__x64_sys_renameat2",  // syscall x86_64
																					 // grep /proc/kallsyms 
};
static int handler_pre(struct kprobe *p, struct pt_regs *regs) {
   if (!regs ) {
        printk(KERN_ERR "some shit\n");
        return -EINVAL;
    }

		int olddfd = (int)regs->di;
    const char __user *oldname = (const char __user *)regs->si;
    int newdfd = (int)regs->dx;
    const char __user *newname = (const char __user *)regs->r10;
    unsigned int flags = (unsigned int)regs->r8;
	#if 1
    if (olddfd < 0 || newdfd < 0 || !oldname || !newname) {
        printk(KERN_INFO "Invalid syscall arguments: olddfd=%d, newdfd=%d, oldname=%p, newname=%p\n",
               olddfd, newdfd, oldname, newname);
        //return -EINVAL;  // no need to return. mv new name may be null
    }
	#endif
    return custom_renameat2(olddfd, oldname, newdfd, newname, flags);

}

static int __init hook_init(void) {
    // Register the Kprobe
    kp.pre_handler = handler_pre;

    if (register_kprobe(&kp) < 0) {
        printk(KERN_ERR "Failed to register kprobe\n");
        return -1;
    }
    printk(KERN_INFO "Kprobe registered for renameat2 syscall.\n");
    return 0;
}

static void __exit hook_exit(void) {
    unregister_kprobe(&kp);
    printk(KERN_INFO "Kprobe unregistered for renameat2 syscall.\n");
}
module_init(hook_init);
module_exit(hook_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("noname");
MODULE_DESCRIPTION("hook renameat2 system call.");
shimajima
() автор топика
Ответ на: комментарий от shimajima

Если укажите что почитать чтобы поднять свои знания, буду благодарен.

да черт его знает, все книжки, что я читал, устарели безбожно

Linux Device Drivers 3 - Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman
Understanding Linux Kernel - Daniel P. Bovet
Linux Kernel Development - Robert Love

metawishmaster ★★★★★
()
Ответ на: комментарий от metawishmaster

Вывожу в kprint что скопировано… А там пусто :-( Головой понимаю что могут быть какие-то защиты от данных из юзерспейса. Вопрос как их выключить. SMAP в виртуалке дизейблед

shimajima
() автор топика
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.