El kernel de linux es muy complejo, provee de muchos mecanismos para tratar con lo más difícil
del hardware usando distintos metodos como por ejemplo IRQ, IPC, RCU, sincronizacion en SMP,
etc...

Un clara prueba de una tarea planificada(para un futuro) son los "timer_list" o timers del kernel,
su API contiene funciónes para la ayuda de la programación-re-programación de tareas,
ahora bien, esta API tiene algunas limitaciones, como que por ejemplo algunos eventos del timer
no se puede sincronizar ni tampoco hay nada que garantize la exclusion mutua(o datos atomicos),
dentro de otras cosas...

Por eso se me ocurrió programar ésta estructura, la cual contiene algunas caracteristicas:
[+]Programación de tarea para un futuro(calibrada en segundos).
[+]Lanzamiento de procesos externos con hilos del kernel.
[+]loopeo de una función en el kernel con/sin exclusion mutua.
[+]Detecta cuando el tiempo de caducidad de la función a terminado y se optimiza a si mismo para liberar memoria del procesador.
[+]Optimizado, no congela el procesador en multiples tareas de ciclos repetitivos(como lo son los bucles).
[+]facil y libre configuración.

y bueno aca el código del driver:
/*
 * ************************************************
 * Autor: NvK
 * Funcion: Estructura para la optimizacion de timers en el kernel.
 * Fecha: 14-1-2014
 * ************************************************
 */

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/kthread.h>

struct tnvk_kernel_struct {
	struct timer_list kern_timer;
	
	int(*cpu_cycle)(struct tnvk_kernel_struct *tks, unsigned int secs);
	
	bool free_timer;
	bool lock_scheduler;
	bool interrupt_cycle;
	spinlock_t lock;
};

#define ELF_INITED ".text.data"
static struct task_struct *kthread_timer;
static struct tnvk_kernel_struct __attribute__((__section__(ELF_INITED), cold))*set_tnvk(struct tnvk_kernel_struct *tks,void (*callback_function), void *param, unsigned int aprox_secs);
static struct tnvk_kernel_struct __attribute__((__section__(ELF_INITED)))*__sync_timer_schedule (struct tnvk_kernel_struct *tks);
static void __attribute__((__section__(ELF_INITED)))tnvk_cpu_cycle(struct tnvk_kernel_struct *tks, unsigned aprox_secs);
static void __attribute__((__section__(ELF_INITED)))wu_process_tnvk(struct tnvk_kernel_struct *tks, void(*callback_func));
static const char KTHRD_TNVK_NAME[] __section(.init_rodata)= "TNVK_THREAD";

/*Loopear cpu funcion*/
#define tnvk_cpu_spin_cycle(tks, aprox_secs)({ \
	spin_lock(&tks->lock); \
	tnvk_cpu_cycle(tks, aprox_secs); \
	spin_unlock(&tks->lock); \
	})
	
static void __attribute__((__section__(ELF_INITED)))tnvk_cpu_cycle(struct tnvk_kernel_struct *tks,unsigned int aprox_secs)
{
    if (tks->interrupt_cycle!=true)
        tks->cpu_cycle= mod_timer((struct tnvk_kernel_struct *)&tks->kern_timer, jiffies+(aprox_secs*HZ)+0x1);
}

static struct tnvk_kernel_struct __attribute__((__section__(ELF_INITED)))
__attribute__((cold))*set_tnvk(struct tnvk_kernel_struct *tks, void (*callback_function),
									void *param,
									unsigned int aprox_secs)
{
	init_timer(&(*tks).kern_timer);
	(*tks).kern_timer.function= (callback_function);
	(*tks).kern_timer.data= param;
	(*tks).kern_timer.expires= jiffies+(aprox_secs*HZ)+0x1;
	/* -- PRE -- */
	tks->free_timer= true;
	tks->lock_scheduler= false;
	tks->interrupt_cycle= false;
	return 0;
}

#define begin_tnvk(tks) \
	add_timer(&tks->kern_timer);
#define start_tnvk(tks, callback_function, param, aprox_secs)({ \
        set_tnvk(tks, callback_function, param, aprox_secs); \
        add_timer(&tks->kern_timer); \
    })
#define free_tnvk(tks)({ \
	del_timer_sync(&tks->kern_timer); \
  if (tks) \
  	kfree(tks); \
  })
  
/* Para uso interno NO USAR */
static struct tnvk_kernel_struct 
	__attribute__((__section__(ELF_INITED)))*__sync_timer_schedule(struct tnvk_kernel_struct *tks)
{
	if((*tks).lock_scheduler) spin_lock(&tks->lock);
	for(;;)
	{
		schedule();
		if (timer_pending(&tks->kern_timer)!=1)
			break;
	}
	if(tks->free_timer)
		del_timer_sync(&tks->kern_timer);
	if((*tks).lock_scheduler) spin_unlock(&tks->lock);
	__asm__("nop;");
	if(kthread_timer)kthread_stop((struct task_struct*)kthread_timer);
	return 0;
}
static void
	__attribute__((__section__(ELF_INITED)))wu_process_tnvk(struct tnvk_kernel_struct *tks,void(*callback_func))
{
	kthread_timer= kthread_create(callback_func, (struct tnvk_kernel_struct *)tks, (const char *)KTHRD_TNVK_NAME);
	wake_up_process(kthread_timer);
}

#define schedule_tnvk(tks) {wu_process_tnvk((struct tnvk_kernel_struct *)tks, __sync_timer_schedule);}

/*****************************************************************/
Algúnos ejemplos:

Ejemplo 1 - llama a la funcion timer_callback_func y la ejecuta cuando han pasado 5 segs,
Y además use schedule_tnvk(tks) el cual espera asincrónicamente que finalize la funcion
llamada, una vez hecho ésto la libera automaticamente.

NOTA: Dense cuenta como use .free_timer para liberar el timer al finalizar la función-callback y
crea una zona de exclusion mutua con .lock_scheduler.
Éstos 2 registros son opcionales.
#include ...
#include "tnvk_kernel_struct.h"

struct tnvk_kernel_struct *tks;

static void timer_callback_func()
{
   printk("\n*funcion 1 llamada desde kernel_timer");
}

static int __section(.init.text) __cold notrace INIT_KERNEL(void)
{
	/* ejemplo 1 */
	tks= kmalloc(sizeof(*tks), GFP_KERNEL);
	start_tnvk(tks, timer_callback_func, NULL, 5); // lanza el timer.
	/* Una vez inicializado se configura la estructura */
	tks->free_timer= true; // liberar al terminar (por defecto en true)
	tks->lock_scheduler= true // crear una zona de exclusion mutua dentro de la función scheduler_tnvk
	schedule_tnvk(tks);
	
	return 0x0;
}

static void __section(.exit.data) EXIT_KERNEL(void)
{
  // fin de seccion
  free_tnvk(tks); // liberar memoria y timer.
}

module_init(INIT_KERNEL);
module_exit(EXIT_KERNEL);

Ejemplo 2 - llama a una funcion indefinidamente. Fijense que para activar el loop
hay que usar la función tnvk_cpu_cycle dentro de la función/procedimiento que se quiera
repetir.

NOTA: si usan éste metodo NO usen schedule_tnvk(tks) ya que esta sirve para optimizar la función
una vez terminada!.
#include ...
#include "tnvk_kernel_struct.h"
struct tnvk_kernel_struct *tks;
int i;

static void timer_callback_func()
{
   printk("\n*funcion 1 llamada desde kernel_timer %d", i);
   i++;
   tnvk_cpu_cycle(tks, 5); // para loopear la funcion
}

static int __section(.init.text) __cold notrace INIT_KERNEL(void)
{
	tks= kmalloc(sizeof(*tks), GFP_KERNEL);
	start_tnvk(tks, timer_callback_func, NULL, 5);
	return 0x0;
}

static void __section(.exit.data) EXIT_KERNEL(void)
{
  // fin de seccion
  free_tnvk(tks);
}
Imagen



Ejemplo 3 - llama a 2 funciones(o las que se quieran), indefinidamente.
#include ...
#include "tnvk_kernel_struct.h"
struct tnvk_kernel_struct *tks, *tks2;
int i, x;

static void timer_callback_func()
{
   printk("\n*funcion 1 llamada desde kernel_timer %d", i);
   i++;
   tnvk_cpu_cycle(tks, 5); // para loopear la funcion
}

static void timer_callback_func2()
{
   printk("\n#funcion 2 llamada desde kernel_timer %d", x);
   x++;
   tnvk_cpu_cycle(tks2, 3); // para loopear la funcion
}

static int __section(.init.text) __cold notrace INIT_KERNEL(void)
{
	tks= kmalloc(sizeof(*tks), GFP_KERNEL);
	tks2= kmalloc(sizeof(*tks2), GFP_KERNEL);
	start_tnvk(tks, timer_callback_func, NULL, 5);
	start_tnvk(tks2, timer_callback_func2, NULL, 3);
  
	return 0x0;
}

static void __section(.exit.data) EXIT_KERNEL(void)
{
  // fin de seccion
  free_tnvk(tks);
  free_tnvk(tks2);
}
Imagen



Ejemplo 4 - En ésta ocacion uso tnvk_cpu_spin_cycle(tks, 5); que es muy parecido a
hacer tnvk_cpu_cycle(tks, 5); con la diferencia que ésta vez creo una zona de exclusión
mutua dentro del loop de la función.

Ademas uso .interrupt_cycle lo cual detiene la función, y como ejemplo lo hago cuando int i a
llegado a 5, es decir que la función solo se repite 5 veces.
#include ...
#include "tnvk_kernel_struct.h"
struct tnvk_kernel_struct *tks;
int i;

static void timer_callback_func()
{
   printk("\n*funcion 1 llamada desde kernel_timer %d", i);
   i++;
   tnvk_cpu_spin_cycle(tks, 5);
   if (i==5) {
	tks->interrupt_cycle= true;
	}
}

static int __section(.init.text) __cold notrace INIT_KERNEL(void)
{
	tks= kmalloc(sizeof(*tks), GFP_KERNEL);
	start_tnvk(tks, timer_callback_func, NULL, 5);
  
	return 0x0;
}

static void __section(.exit.data) EXIT_KERNEL(void)
{
  // fin de seccion
  free_tnvk(tks);

}
Imagen
Te digo yo que si me dicen que eres uno de los muchos programadores del kernel de debian o el mismisimo linus torvalds, te juro que me lo creo
estos trabajos que tanto cuestan deberian de ser mas comentados, por que aqui hay horas de esfuerzo y de cabeza calentita
Abolición para el torneo del toro de la vega. Death to the murderers of bulls.
Gracias por los comentario strup
Y si me gustaría tener más comentarios, espero algún dia(con mi grano de arena) lograr que la gente se interese más en éstos temas,
ademas del malware... que no solo implican conocimientos en programación si no en hardware, y electronica.
Me olvidaba comentarles que con ésta estructura también se pueden crear keyloggers en ring0 (tema que tocare más adelante).
Saludos
Ya tienes editado el tema NvK ;), buen aporte!, la verdad es que es una maravilla, pero si tienen razón que los chicos parece que usan mucho windows. Seguro que cuando toques temas de keyloggers o rootkits se les cae la baba jajaj

Saludos!
Soy un camaleón, en tu cama, leona ♪
Responder

Volver a “Fuentes”