Los argumentos del ejemplo de enganche de llamadas al sistema son incorrectos

3 minutos de lectura

avatar de usuario
md.jamal

Escribí un ejemplo de conexión de llamadas al sistema desde nuestro módulo Linux Kernel.

Se actualizó la llamada al sistema abierto en la tabla de llamadas del sistema para usar mi punto de entrada en lugar del predeterminado.

#include <linux/module.h>
#include <linux/kallsyms.h>

MODULE_LICENSE("GPL");
char *sym_name = "sys_call_table";

typedef asmlinkage long (*sys_call_ptr_t)(const struct pt_regs *);
static sys_call_ptr_t *sys_call_table;
typedef asmlinkage long (*custom_open) (const char __user *filename, int flags, umode_t mode);


custom_open old_open;

static asmlinkage long my_open(const char __user *filename, int flags, umode_t mode)
{
    char user_msg[256];
    pr_info("%s\n",__func__);
    memset(user_msg, 0, sizeof(user_msg));
    long copied = strncpy_from_user(user_msg, filename, sizeof(user_msg));
    pr_info("copied:%ld\n", copied);
    pr_info("%s\n",user_msg);

    return old_open(filename, flags, mode);
}



static int __init hello_init(void)
{
    sys_call_table = (sys_call_ptr_t *)kallsyms_lookup_name(sym_name);
    old_open = (custom_open)sys_call_table[__NR_open];
    // Temporarily disable write protection
    write_cr0(read_cr0() & (~0x10000));
    sys_call_table[__NR_open] = (sys_call_ptr_t)my_open;
    // Re-enable write protection
    write_cr0(read_cr0() | 0x10000);

    return 0;
}

static void __exit hello_exit(void)
{
    // Temporarily disable write protection
    write_cr0(read_cr0() & (~0x10000));
    sys_call_table[__NR_open] = (sys_call_ptr_t)old_open;
    // Re-enable write protection
    write_cr0(read_cr0() | 0x10000);

}

module_init(hello_init);
module_exit(hello_exit);

Escribí un programa de usuario simple para verificar.

#define _GNU_SOURCE
#include <sys/syscall.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
    int fd = syscall(__NR_open, "hello.txt", O_RDWR|O_CREAT, 0777);

    exit(EXIT_SUCCESS);
}

El archivo se crea en mi carpeta, pero strncpy_user falla con una dirección incorrecta

[  927.415905] my_open
[  927.415906] copied:-14

¿Cuál es el error en el código anterior?

  • Estilo: ¿Por qué querrías tener un no-const / global no estático char *sym_name? También, char user_msg[256] = {0} sería más fácil que memset. También para un experimento único, podría haber asumido que la entrada de la tabla syscall sería sys_open, en lugar de guardar el puntero antiguo. (a una variable no estática por alguna razón).

    – Peter Cordes

    22 de enero de 2020 a las 3:49


  • -14 devuelto por strncpy_from_user es -EFAULT. ¿Estás seguro de que tu syscall wrapper realmente está pasando un puntero a una cadena válida? Verifícalo con strace.

    – Peter Cordes

    22 de enero de 2020 a las 3:50

  • Desde strace: open(“hello.txt”, O_RDWR|O_CREAT, 0777) = 3 . El archivo se crea correctamente

    – md.jamal

    22 de enero de 2020 a las 3:59


  • Ah, también, tiene un posible error de sobrelectura de búfer: strncpy no terminará en 0 el destino si la cadena de origen es demasiado grande para caber. Poner a cero el búfer antes de tiempo es inútil; en su lugar, debe verificar que el valor devuelto no sea un error y <= tamaño. O simplemente incondicionalmente user_msg[sizeof(user_msg)-1] = 0 after strncpy para poner siempre a cero el último byte después y el primer byte antes de copiar. Dado que es pequeño y está en la pila, ni siquiera es malo para el rendimiento.

    – Peter Cordes

    22 de enero de 2020 a las 4:24

  • Reemplazas la función original con una firma por tu función con firma diferente y pregunte por qué tiene parámetros incorrectos? ¿En serio? Reparto explícito a (sys_call_ptr_t) que usa para superar las advertencias/errores del compilador es la señal directa de “algo sale mal”.

    – Tsyvarev

    22 de enero de 2020 a las 10:30

  • Gracias por la explicación detallada. Entendí claramente el error que cometí. Entonces, ¿cuál es la forma de obtener los parámetros de la función?

    – md.jamal

    23 de enero de 2020 a las 1:13

  • ¿Puede proporcionar más información sobre quién realmente asigna pt_regs a los argumentos del controlador de llamadas del sistema?

    – md.jamal

    23 de enero de 2020 a las 1:23

  • Implementar la convención de llamadas usted mismo (tomando el primer argumento de RDI) es un poco complicado, pero sí, probablemente sea más fácil que obtener macros del kernel para generar un contenedor para usted. Todavía expone el mismo error de pasar un búfer posiblemente no terminado a un %s cadena de formato; tal vez usar %.256s para establecer un máximo. no tiene sentido = {0} inicie toda la matriz antes de pasar su tamaño completo a strncpy; eso es solo trabajo de puesta a cero desperdiciado.

    – Peter Cordes

    25 de enero de 2020 a las 5:19

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad