Test Foro de elhacker.net SMF 2.1

Programación => Programación C/C++ => Mensaje iniciado por: kaostias en 30 Noviembre 2013, 12:55 PM

Título: Módulo del kernel que interactúa con llamada al sistema (C)
Publicado por: kaostias en 30 Noviembre 2013, 12:55 PM
Buenas, estoy programando un módulo propio para el kernel de linux (Estoy trabajando sobre debian 6 con kernel 2.6.39.4) que interactúa con una llamada al sistema. Son dos muy sencillos. La llamada funciona perfectamente y exporta funcionalidad que permite a un módulo insertarse en una lista de entradas y registrar en ella dos funciones, una de escritura y otra de lectura.

El módulo es un contador, y las funciones de lectura y escritura son la suma del contador y la consulta del número actual. Su escritura sólo suma si todo va bien, y su lectura devuelve en el buffer del usuario la copia del valor. El problema es que al hacer el makefile del módulo recibo el error:

Citar
"insmod: error inserting 'ModuloUsaKifs.ko': -1 Unknown symbol in module"

Y no sé exáctamente por qué no reconoce Kifs, que según creo, está integrado en el sistema correctamente (Incluidas las fuentes, modificado el planificador, añadido a la tabla de llamadas, incluida la cabecera, compilado el kernel, instalado el nuevo, y probado con un programa aparte, aunque sólo pruebo sys_kifs, mi llamada al sistema, exporto también create_kifs_entry y remove_kifs_entry mediante <linux/kifs.h>)
Este es mi makefile, es muy estándar y no contemplo nada especial, porque se supone que kifs ya está en las fuentes de linux y así lo incluyo en el módulo.
¿Podría alguien orientarme hacia dónde está mi fallo?

Citarobj-m = ModuloUsaKifs.o

all :
   make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean :
   make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean


Este es el módulo. Siento la falta de comentarios, todavía no lo he acabado y está un poco guarro(Esto es como tener visita con la casa sucia) Tengo algunos includes de más porque aún no los he borrado, he reutilizado algo de código de aquí y allá.

#ifdef __KERNEL__
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/kifs.h>
#include <asm-generic/uaccess.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("List Kernel Module para DSO");
MODULE_LICENSE("GPL");
#else
//#include <iostream>
//#include <linux/list.h>
#include <string.h>
#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include "kifs.h"
#endif
int counter;
//typedef int (read_kifs_t)(char *user_buffer, unsigned int maxchars, void *data);
//typedef int (write_kifs_t)(const char *user_buffer, unsigned int maxchars, void *data);
//initialices the module
int sum(char *user_buffer, unsigned int maxchars, void *data){
counter++;
return maxchars;
}
int lect(const char *user_buffer, unsigned int maxchars, void *data){
char buf[32];
int len=sprintf(buf,"%d\n",counter);
if (len> maxchars)
{
return -EINVAL;
}
if(copy_to_user(buf, user_buffer, len)){
printk(KERN_ALERT) "problemas en lect";
return -EINVAL;
}
return len;

}

int metodoInicial(void){

counter = 0;
if(create_kifs_entry("counter",sum,lect,NULL))
{
counter = 0;
printk(KERNEL_ALERT "modulo abierto correctamente");
}
printk(KERNEL_ALERT "Error, módulo counter incorrectamente agregado a kifs");
}

void metodoFinal(void){

if(remove_kifs_entry("counter")){
printk(KERNEL_ALERT "modulo cerrado correctamente");
}
printk(KERNEL_ALERT "Error, módulo counter incorrectamente borrado de kifs");
}

module_init(metodoInicial);
module_exit(metodoFinal);



Esta es la llamada al sistema, por si pudiese ser algo relacionado con esto, sinceramente ya no sé qué puede ser porque me estoy volviendo loco.

#include <linux/kifs.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm-generic/errno-base.h>
#include <asm-generic/errno.h>
#include <asm-generic/uaccess.h>
/*
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Modulo KIFS para DSO");
MODULE_AUTHOR("Ismel Gonjal Montero");
*/
/* Callback prototypes for kifs entries */

/*
typedef int (read_kifs_t)(char *user_buffer, unsigned int maxchars, void *data);
typedef int (write_kifs_t)(const char *user_buffer, unsigned int maxchars, void *data);
*/

/*     Valores de lectura y escritura */

/*
enum {
KIFS_READ_OP=0,
KIFS_WRITE_OP,
KIFS_NR_OPS};
*/
/***********************************/
/*      Declaraciones de kifs      */
/***********************************/
#define MAX_KIFS_ENTRIES 10
LIST_HEAD(entry_list);
LIST_HEAD(free_list);
kifs_entry_t pool[MAX_KIFS_ENTRIES];

/***********************************/
/*   Declaraciones de clipboard    */
/***********************************/
#define MAX_KIFS_CHARS 512
char clipboard[MAX_KIFS_CHARS];
/************************************/
/*    Declaracion de funciones    */
/************************************/
int read_list (char *user_buffer, unsigned int maxchars, void *data);


/******************************************************************************/
/*                           CLIPBOARD                                        */
/******************************************************************************/


int read_clipboard (char *user_buffer, unsigned int maxchars, void *data){
int total = strlen(clipboard);

if (total>maxchars)
{
return  -EINVAL;
}

if (copy_to_user(user_buffer, clipboard, total))
{
printk(KERN_ALERT "Fallo en copy_to_user()");
return  -EINVAL;
}
return total;
}

int write_clipboard (const char *user_buffer, unsigned int maxchars, void *data){

if (maxchars>MAX_KIFS_CHARS-1)
{
printk(KERN_ALERT "Excede tamanio");
return  -EINVAL;
}

if (copy_from_user(clipboard, user_buffer, maxchars))
{
printk(KERN_ALERT "Fallo en copy_from_user()");
return  -EINVAL;
}
clipboard[maxchars]='\0';

return  maxchars;
}



/****************************************************/
/*     Código de KIFS    */
/****************************************************/


/* KIFS's global initialization */
void init_kifs_entry_set(void){
int i = 0;
//añade a la lista todas las entradas de freelist
for(i =0; i<MAX_KIFS_ENTRIES;i++){
list_add_tail(&pool[i].links,&free_list);
}
clipboard[0]='\0';
create_kifs_entry("list", read_list,NULL,NULL);
create_kifs_entry("clipboard", read_clipboard,write_clipboard ,NULL);
printk(KERN_ALERT "Inicializado kifs");
}

/*
* Recibe un buffer de usuario, que llenará con una lista de las entradas
* de la lista entry_list
*/
int read_list (char *user_buffer, unsigned int maxchars, void *data){
int total = 0;
char buf[512];
struct list_head* pos = entry_list.next;
kifs_entry_t* item;

printk(KERN_ALERT "Entra en read_list");

list_for_each(pos, &entry_list){
item = list_entry(pos, kifs_entry_t, links);
total+= sprintf(&buf[total],"%s\n",item->entryname);
}

if (copy_to_user(user_buffer,buf,total))
{
printk(KERN_ALERT "Fallo en copy_to_user()");
return -EINVAL;
}

printk(KERN_ALERT "Sale de read_list por las buenas");
return total;
}

/* This fuction must ensure that no entry will be created as long as another entry with the same name already exists.
* == Return Value ==
* NULL Entry name already exists or No space is availables
* Pointer to the kifs entry
* */
kifs_entry_t* create_kifs_entry(const char* entryname,
read_kifs_t *read_kifs,
write_kifs_t *write_kifs,
void* data){
kifs_entry_t* item;
struct list_head* pos = entry_list.next;
kifs_entry_t* itemFound = NULL;

printk(KERN_ALERT "Creando entrada %s en Kifs",entryname);

//Si la lista no está vacía
list_for_each(pos, &entry_list){
item = list_entry(pos, kifs_entry_t, links);
if (strcmp(item->entryname,entryname) ==0){
itemFound = item;
break;
}
}
if (itemFound != NULL) {
printk(KERN_ALERT "El item existe");
return NULL;
}

//No hay espacio
if(free_list.next == &free_list) {
printk(KERN_ALERT "Error, lista llena");
return NULL;
}
pos = free_list.next;
item = list_entry(pos, kifs_entry_t, links);
item->read_kifs = read_kifs;
item->write_kifs = write_kifs;
item->data = NULL;
strcpy(item->entryname, entryname);

list_del(pos);
list_add_tail(pos,&entry_list);
printk(KERN_ALERT "Entrada %s creada correctamente", entryname);
return item;
}


/*  Implementation of kifs() system call
* == Return Value ==
* -EINVAL Unsupported operation (NULL callback) or Entry not exists
* -EFAULT Any other error (e.g: copy_from_user(), copy_to_user(),...)
* otherwise: Number of chars read/written (Usually maxchars value)
*/

asmlinkage long sys_kifs(const char* entry_name,unsigned int op_mode, char* user_buffer,unsigned int maxchars){

struct list_head* pos;// = entry_list.next;
kifs_entry_t* item;// = list_entry(pos, kifs_entry_t, links);
kifs_entry_t* itemFound = NULL;
int ret = 0;
//char usrBfr[512];

printk(KERN_ALERT "Entrado a sys_kifs");
/* Se comprueba que la llamada has sido correcta */
list_for_each(pos, &entry_list){
item = list_entry(pos, kifs_entry_t, links);
if (strcmp(item->entryname,entry_name) ==0){
itemFound = item;
break;
}
}

if (itemFound == NULL){
printk(KERN_ALERT "La entrada %s no existe", entry_name);
return -EINVAL;
}

/* copy_from_user(usrBfr, user_buffer, maxchars);
usrBfr[maxchars]='\0';

printk(KERN_ALERT "Se ha copiado el parametro %s de la entrada %s",usrBfr, entry_name);

printk(KERN_ALERT "Hay items en la lista");
*/
/* llamadas que dependen del valor de lectura/escritura */
if(op_mode == KIFS_READ_OP &&  item->read_kifs!=NULL ){
ret = itemFound->read_kifs(user_buffer,maxchars,NULL);
//printk(KERN_ALERT "El item utilizado es %s, en el método de lectura",user_buffer);
}else if(op_mode == KIFS_WRITE_OP &&  item->write_kifs!=NULL ){
ret = itemFound->write_kifs(user_buffer,maxchars,NULL); //No sé qué pasar de valor aquí
//printk(KERN_ALERT "El item utilizado es %s, en el método de escritura",usrBfr);
}else{
ret=-EINVAL;
printk(KERN_ALERT "Algo va mal");
}
return ret;
}

/* Remove kifs entry
* == Return Value ==
* -1 Entry does not exist
*  0 success
* */
int remove_kifs_entry(const char* entry_name){

struct list_head* pos = entry_list.next;
kifs_entry_t* item = list_entry(pos, kifs_entry_t, links);
kifs_entry_t* itemFound = NULL;
printk(KERN_ALERT "Intentando eliminar entrada de Kifs");

list_for_each(pos, &entry_list){
item = list_entry(pos, kifs_entry_t, links);
if (strcmp(item->entryname,entry_name) ==0){
itemFound = item;
break;
}
}
if (itemFound == NULL) {
printk(KERN_ALERT "La lista de kifs está vacía");
return -EINVAL;
}

list_del(pos);
item->data = NULL;
strcpy(item->entryname,"");
item->read_kifs = NULL;
item->write_kifs = NULL;
list_add_tail(pos,&free_list);
printk(KERN_ALERT "Entrada eliminada correctamente");
return 0;
}


Y por si acaso también subo el .h de kifs, mi llamada al sistema.

#ifndef KIFS_H
#define KIFS_H
#include <linux/list.h> /* list_head */

#define MAX_KIFS_ENTRY_NAME_SIZE 50

/* Callback prototypes for kifs entries */
typedef int (read_kifs_t)(char *user_buffer, unsigned int maxchars, void *data);
typedef int (write_kifs_t)(const char *user_buffer, unsigned int maxchars, void *data);


/* Descriptor interface for the entries */
typedef struct
{
char entryname[MAX_KIFS_ENTRY_NAME_SIZE];
read_kifs_t *read_kifs;
write_kifs_t *write_kifs;
void *data;
struct list_head links; /* Set of links in kifs */
}kifs_entry_t;

enum {
KIFS_READ_OP=0,
KIFS_WRITE_OP,
KIFS_NR_OPS};


/* This fuction must ensure that no entry will be created as long as another entry with the same name already exists.
* == Return Value ==
* NULL Entry name already exists or No space is availables
* Pointer to the kifs entry
* */
kifs_entry_t* create_kifs_entry(const char* entryname,
read_kifs_t *read_kifs,
write_kifs_t *write_kifs,
void* data);


/* Remove kifs entry
* == Return Value ==
* -1 Entry does not exist
*  0 success
* */
int remove_kifs_entry(const char* entry_name);

/*  Implementation of kifs() system call
* == Return Value ==
* -EINVAL Unsupported operation (NULL callback) or Entry not exists
* -EFAULT Any other error (e.g: copy_from_user(), copy_to_user(),...)
* otherwise: Number of chars read/written (Usually maxchars value)
*/
asmlinkage long sys_kifs(const char* entry_name,unsigned int op_mode, char* user_buffer,unsigned int maxchars);

/* KIFS's global initialization */
void init_kifs_entry_set(void);


#endif


Muchas gracias por vuestro tiempo




Para ser concretos el mensaje del sistema es:
Citar


make -C /lib/modules/2.6.39.4.mikernel/build M=/home/dsouser/Escritorio/FuturaEntrega/ModuloUsaKifs modules
make[1]: se ingresa al directorio `/usr/src/linux-headers-2.6.39.4.mikernel'
 Building modules, stage 2.
 MODPOST 1 modules
WARNING: "create_kifs_entry" [/home/dsouser/Escritorio/FuturaEntrega/ModuloUsaKifs/ModuloUsaKifs.ko] undefined!
WARNING: "remove_kifs_entry" [/home/dsouser/Escritorio/FuturaEntrega/ModuloUsaKifs/ModuloUsaKifs.ko] undefined!
make[1]: se sale del directorio `/usr/src/linux-headers-2.6.39.4.mikernel'


Título: Re: Módulo del kernel que interactúa con llamada al sistema (C)
Publicado por: dato000 en 30 Noviembre 2013, 14:19 PM
No termino de entender en que consiste el archivo del modulo ModuloUsaKifs.ko

No se que tipo de variable es esta:

kifs_entry_t* create_kifs_entry

Y en cambio en el remove_kifs_entry hay un retorno de cero siempre.


No se tanto sobre el uso de makefile, pero creo que debe ser un problema con la libreria kifs.h
Título: Re: Módulo del kernel que interactúa con llamada al sistema (C)
Publicado por: kaostias en 30 Noviembre 2013, 14:25 PM
Gracias por tu respuesta dato000

remove_kifs_entry devuelve -EINVAL cuando no se encuentra el dato o la lista está vacía, es un valor de la librería errno.h (Creo), echale un ojo y lo verás

kifs_entry_t* te devuelve un puntero a la propia entrada de kifs que yo he creado (No me gusta mucho, yo devolvería un entero pero las indicaciones me obligan a ello). kifs_entry_t es una estructura, puedes comprobar su forma en el .h que está subido.

ModuloUsaKifs es el .c primero que he subido. Consta de dos métodos, sum y lect:
-sum
Lo único que hace es incrementar un contador que se inicializa en 0 en la carga del módulo
-Escritura
Devuelve en el buffer del usuario el valor del contador en una cadena de caracteres y devuelve el número de caracteres de la cadena


Muchas gracias por tu tiempo

Por si a alguien más le sirve de guía, dmesg | tail me da la siguiente info

Citar
[ 1818.076342] ModuloUsaKifs: Unknown symbol remove_kifs_entry (err 0)
[ 1818.076590] ModuloUsaKifs: Unknown symbol create_kifs_entry (err 0)





¿Podría ser algo relacionado con la siguiente línea? ¿Cómo paso la función por parámetro? (*read_kifs o write_kifs)?

kifs_entry_t* create_kifs_entry(const char* entryname,
read_kifs_t *read_kifs,
write_kifs_t *write_kifs,
void* data);


Yo la paso así:

create_kifs_entry("counter",sum,lect,NULL)

Y la declaración es la siguiente:

int sum(char *user_buffer, unsigned int maxchars, void *data)

¿Puede alguien con más experiencia que yo orientarme?




Gracias por la respuesta. Investigando y preguntando en otros foros, alguien me dio la solución al problema, y es añadir las siguientes dos líneas al final del todo de mi llamada al sistema, "kifs.c":

EXPORT_SYMBOL(create_kifs_entry);
EXPORT_SYMBOL(remove_kifs_entry);