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
() автор топика
Ответ на: комментарий от metawishmaster

https://manpages.debian.org/testing/linux-manual-4.8/__copy_from_user.9.en.html

Тут пишут, что вы не правы.

Returns number of bytes that could not be copied. On success, this will be zero.


If some data could not be copied, this function will pad the copied data to the requested size using zero bytes.

да и мой последний опыт показывает, что успех это 0

yax123 ★★★★★
()