Foro de elhacker.net

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?

Citar
obj-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á.
Código
  1. #ifdef __KERNEL__
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/proc_fs.h>
  5. #include <linux/string.h>
  6. #include <linux/vmalloc.h>
  7. #include <linux/kifs.h>
  8. #include <asm-generic/uaccess.h>
  9. MODULE_LICENSE("GPL");
  10. MODULE_DESCRIPTION("List Kernel Module para DSO");
  11. MODULE_LICENSE("GPL");
  12. #else
  13. //#include <iostream>
  14. //#include <linux/list.h>
  15. #include <string.h>
  16. #include "list.h"
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include "kifs.h"
  20. #endif
  21. int counter;
  22. //typedef int (read_kifs_t)(char *user_buffer, unsigned int maxchars, void *data);
  23. //typedef int (write_kifs_t)(const char *user_buffer, unsigned int maxchars, void *data);
  24. //initialices the module
  25. int sum(char *user_buffer, unsigned int maxchars, void *data){
  26. counter++;
  27. return maxchars;
  28. }
  29. int lect(const char *user_buffer, unsigned int maxchars, void *data){
  30. char buf[32];
  31. int len=sprintf(buf,"%d\n",counter);
  32. if (len> maxchars)
  33. {
  34. return -EINVAL;
  35. }
  36. if(copy_to_user(buf, user_buffer, len)){
  37. printk(KERN_ALERT) "problemas en lect";
  38. return -EINVAL;
  39. }
  40. return len;
  41.  
  42. }
  43.  
  44. int metodoInicial(void){
  45.  
  46. counter = 0;
  47. if(create_kifs_entry("counter",sum,lect,NULL))
  48. {
  49. counter = 0;
  50. printk(KERNEL_ALERT "modulo abierto correctamente");
  51. }
  52. printk(KERNEL_ALERT "Error, módulo counter incorrectamente agregado a kifs");
  53. }
  54.  
  55. void metodoFinal(void){
  56.  
  57. if(remove_kifs_entry("counter")){
  58. printk(KERNEL_ALERT "modulo cerrado correctamente");
  59. }
  60. printk(KERNEL_ALERT "Error, módulo counter incorrectamente borrado de kifs");
  61. }
  62.  
  63. module_init(metodoInicial);
  64. module_exit(metodoFinal);
  65.  


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.
Código
  1. #include <linux/kifs.h>
  2. #include <linux/string.h>
  3. #include <linux/module.h>
  4. #include <linux/kernel.h>
  5. #include <asm-generic/errno-base.h>
  6. #include <asm-generic/errno.h>
  7. #include <asm-generic/uaccess.h>
  8. /*
  9. MODULE_LICENSE("GPL");
  10. MODULE_DESCRIPTION("Modulo KIFS para DSO");
  11. MODULE_AUTHOR("Ismel Gonjal Montero");
  12. */
  13. /* Callback prototypes for kifs entries */
  14.  
  15. /*
  16. typedef int (read_kifs_t)(char *user_buffer, unsigned int maxchars, void *data);
  17. typedef int (write_kifs_t)(const char *user_buffer, unsigned int maxchars, void *data);
  18. */
  19.  
  20. /*     Valores de lectura y escritura */
  21.  
  22. /*
  23. enum {
  24. KIFS_READ_OP=0,
  25. KIFS_WRITE_OP,
  26. KIFS_NR_OPS};
  27. */
  28. /***********************************/
  29. /*      Declaraciones de kifs      */
  30. /***********************************/
  31. #define MAX_KIFS_ENTRIES 10
  32. LIST_HEAD(entry_list);
  33. LIST_HEAD(free_list);
  34. kifs_entry_t pool[MAX_KIFS_ENTRIES];
  35.  
  36. /***********************************/
  37. /*   Declaraciones de clipboard    */
  38. /***********************************/
  39. #define MAX_KIFS_CHARS 512
  40. char clipboard[MAX_KIFS_CHARS];
  41. /************************************/
  42. /*    Declaracion de funciones    */
  43. /************************************/
  44. int read_list (char *user_buffer, unsigned int maxchars, void *data);
  45.  
  46.  
  47. /******************************************************************************/
  48. /*                           CLIPBOARD                                        */
  49. /******************************************************************************/
  50.  
  51.  
  52. int read_clipboard (char *user_buffer, unsigned int maxchars, void *data){
  53. int total = strlen(clipboard);
  54.  
  55. if (total>maxchars)
  56. {
  57. return  -EINVAL;
  58. }
  59.  
  60. if (copy_to_user(user_buffer, clipboard, total))
  61. {
  62. printk(KERN_ALERT "Fallo en copy_to_user()");
  63. return  -EINVAL;
  64. }
  65. return total;
  66. }
  67.  
  68. int write_clipboard (const char *user_buffer, unsigned int maxchars, void *data){
  69.  
  70. if (maxchars>MAX_KIFS_CHARS-1)
  71. {
  72. printk(KERN_ALERT "Excede tamanio");
  73. return  -EINVAL;
  74. }
  75.  
  76. if (copy_from_user(clipboard, user_buffer, maxchars))
  77. {
  78. printk(KERN_ALERT "Fallo en copy_from_user()");
  79. return  -EINVAL;
  80. }
  81. clipboard[maxchars]='\0';
  82.  
  83. return  maxchars;
  84. }
  85.  
  86.  
  87.  
  88. /****************************************************/
  89. /*     Código de KIFS    */
  90. /****************************************************/
  91.  
  92.  
  93. /* KIFS's global initialization */
  94. void init_kifs_entry_set(void){
  95. int i = 0;
  96. //añade a la lista todas las entradas de freelist
  97. for(i =0; i<MAX_KIFS_ENTRIES;i++){
  98. list_add_tail(&pool[i].links,&free_list);
  99. }
  100. clipboard[0]='\0';
  101. create_kifs_entry("list", read_list,NULL,NULL);
  102. create_kifs_entry("clipboard", read_clipboard,write_clipboard ,NULL);
  103. printk(KERN_ALERT "Inicializado kifs");
  104. }
  105.  
  106. /*
  107.  * Recibe un buffer de usuario, que llenará con una lista de las entradas
  108.  * de la lista entry_list
  109.  */
  110. int read_list (char *user_buffer, unsigned int maxchars, void *data){
  111. int total = 0;
  112. char buf[512];
  113. struct list_head* pos = entry_list.next;
  114. kifs_entry_t* item;
  115.  
  116. printk(KERN_ALERT "Entra en read_list");
  117.  
  118. list_for_each(pos, &entry_list){
  119. item = list_entry(pos, kifs_entry_t, links);
  120. total+= sprintf(&buf[total],"%s\n",item->entryname);
  121. }
  122.  
  123. if (copy_to_user(user_buffer,buf,total))
  124. {
  125. printk(KERN_ALERT "Fallo en copy_to_user()");
  126. return -EINVAL;
  127. }
  128.  
  129. printk(KERN_ALERT "Sale de read_list por las buenas");
  130. return total;
  131. }
  132.  
  133. /* This fuction must ensure that no entry will be created as long as another entry with the same name already exists.
  134.  * == Return Value ==
  135.  * NULL Entry name already exists or No space is availables
  136.  * Pointer to the kifs entry
  137.  * */
  138. kifs_entry_t* create_kifs_entry(const char* entryname,
  139. read_kifs_t *read_kifs,
  140. write_kifs_t *write_kifs,
  141. void* data){
  142. kifs_entry_t* item;
  143. struct list_head* pos = entry_list.next;
  144. kifs_entry_t* itemFound = NULL;
  145.  
  146. printk(KERN_ALERT "Creando entrada %s en Kifs",entryname);
  147.  
  148. //Si la lista no está vacía
  149. list_for_each(pos, &entry_list){
  150. item = list_entry(pos, kifs_entry_t, links);
  151. if (strcmp(item->entryname,entryname) ==0){
  152. itemFound = item;
  153. break;
  154. }
  155. }
  156. if (itemFound != NULL) {
  157. printk(KERN_ALERT "El item existe");
  158. return NULL;
  159. }
  160.  
  161. //No hay espacio
  162. if(free_list.next == &free_list) {
  163. printk(KERN_ALERT "Error, lista llena");
  164. return NULL;
  165. }
  166. pos = free_list.next;
  167. item = list_entry(pos, kifs_entry_t, links);
  168. item->read_kifs = read_kifs;
  169. item->write_kifs = write_kifs;
  170. item->data = NULL;
  171. strcpy(item->entryname, entryname);
  172.  
  173. list_del(pos);
  174. list_add_tail(pos,&entry_list);
  175. printk(KERN_ALERT "Entrada %s creada correctamente", entryname);
  176. return item;
  177. }
  178.  
  179.  
  180. /*  Implementation of kifs() system call
  181.  * == Return Value ==
  182.  * -EINVAL Unsupported operation (NULL callback) or Entry not exists
  183.  * -EFAULT Any other error (e.g: copy_from_user(), copy_to_user(),...)
  184.  * otherwise: Number of chars read/written (Usually maxchars value)
  185.  */
  186.  
  187. asmlinkage long sys_kifs(const char* entry_name,unsigned int op_mode, char* user_buffer,unsigned int maxchars){
  188.  
  189. struct list_head* pos;// = entry_list.next;
  190. kifs_entry_t* item;// = list_entry(pos, kifs_entry_t, links);
  191. kifs_entry_t* itemFound = NULL;
  192. int ret = 0;
  193. //char usrBfr[512];
  194.  
  195. printk(KERN_ALERT "Entrado a sys_kifs");
  196. /* Se comprueba que la llamada has sido correcta */
  197. list_for_each(pos, &entry_list){
  198. item = list_entry(pos, kifs_entry_t, links);
  199. if (strcmp(item->entryname,entry_name) ==0){
  200. itemFound = item;
  201. break;
  202. }
  203. }
  204.  
  205. if (itemFound == NULL){
  206. printk(KERN_ALERT "La entrada %s no existe", entry_name);
  207. return -EINVAL;
  208. }
  209.  
  210. /* copy_from_user(usrBfr, user_buffer, maxchars);
  211. usrBfr[maxchars]='\0';
  212.  
  213. printk(KERN_ALERT "Se ha copiado el parametro %s de la entrada %s",usrBfr, entry_name);
  214.  
  215. printk(KERN_ALERT "Hay items en la lista");
  216. */
  217. /* llamadas que dependen del valor de lectura/escritura */
  218. if(op_mode == KIFS_READ_OP &&  item->read_kifs!=NULL ){
  219. ret = itemFound->read_kifs(user_buffer,maxchars,NULL);
  220. //printk(KERN_ALERT "El item utilizado es %s, en el método de lectura",user_buffer);
  221. }else if(op_mode == KIFS_WRITE_OP &&  item->write_kifs!=NULL ){
  222. ret = itemFound->write_kifs(user_buffer,maxchars,NULL); //No sé qué pasar de valor aquí
  223. //printk(KERN_ALERT "El item utilizado es %s, en el método de escritura",usrBfr);
  224. }else{
  225. ret=-EINVAL;
  226. printk(KERN_ALERT "Algo va mal");
  227. }
  228. return ret;
  229. }
  230.  
  231. /* Remove kifs entry
  232.  * == Return Value ==
  233.  * -1 Entry does not exist
  234.  *  0 success
  235.  * */
  236. int remove_kifs_entry(const char* entry_name){
  237.  
  238. struct list_head* pos = entry_list.next;
  239. kifs_entry_t* item = list_entry(pos, kifs_entry_t, links);
  240. kifs_entry_t* itemFound = NULL;
  241. printk(KERN_ALERT "Intentando eliminar entrada de Kifs");
  242.  
  243. list_for_each(pos, &entry_list){
  244. item = list_entry(pos, kifs_entry_t, links);
  245. if (strcmp(item->entryname,entry_name) ==0){
  246. itemFound = item;
  247. break;
  248. }
  249. }
  250. if (itemFound == NULL) {
  251. printk(KERN_ALERT "La lista de kifs está vacía");
  252. return -EINVAL;
  253. }
  254.  
  255. list_del(pos);
  256. item->data = NULL;
  257. strcpy(item->entryname,"");
  258. item->read_kifs = NULL;
  259. item->write_kifs = NULL;
  260. list_add_tail(pos,&free_list);
  261. printk(KERN_ALERT "Entrada eliminada correctamente");
  262. return 0;
  263. }
  264.  

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

Código
  1. #ifndef KIFS_H
  2. #define KIFS_H
  3. #include <linux/list.h> /* list_head */
  4.  
  5. #define MAX_KIFS_ENTRY_NAME_SIZE 50
  6.  
  7. /* Callback prototypes for kifs entries */
  8. typedef int (read_kifs_t)(char *user_buffer, unsigned int maxchars, void *data);
  9. typedef int (write_kifs_t)(const char *user_buffer, unsigned int maxchars, void *data);
  10.  
  11.  
  12. /* Descriptor interface for the entries */
  13. typedef struct
  14. {
  15. char entryname[MAX_KIFS_ENTRY_NAME_SIZE];
  16. read_kifs_t *read_kifs;
  17. write_kifs_t *write_kifs;
  18. void *data;
  19. struct list_head links; /* Set of links in kifs */
  20. }kifs_entry_t;
  21.  
  22. enum {
  23. KIFS_READ_OP=0,
  24. KIFS_WRITE_OP,
  25. KIFS_NR_OPS};
  26.  
  27.  
  28. /* This fuction must ensure that no entry will be created as long as another entry with the same name already exists.
  29.  * == Return Value ==
  30.  * NULL Entry name already exists or No space is availables
  31.  * Pointer to the kifs entry
  32.  * */
  33. kifs_entry_t* create_kifs_entry(const char* entryname,
  34. read_kifs_t *read_kifs,
  35. write_kifs_t *write_kifs,
  36. void* data);
  37.  
  38.  
  39. /* Remove kifs entry
  40.  * == Return Value ==
  41.  * -1 Entry does not exist
  42.  *  0 success
  43.  * */
  44. int remove_kifs_entry(const char* entry_name);
  45.  
  46. /*  Implementation of kifs() system call
  47.  * == Return Value ==
  48.  * -EINVAL Unsupported operation (NULL callback) or Entry not exists
  49.  * -EFAULT Any other error (e.g: copy_from_user(), copy_to_user(),...)
  50.  * otherwise: Number of chars read/written (Usually maxchars value)
  51.  */
  52. asmlinkage long sys_kifs(const char* entry_name,unsigned int op_mode, char* user_buffer,unsigned int maxchars);
  53.  
  54. /* KIFS's global initialization */
  55. void init_kifs_entry_set(void);
  56.  
  57.  
  58. #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)?

Código
  1. kifs_entry_t* create_kifs_entry(const char* entryname,
  2. read_kifs_t *read_kifs,
  3. write_kifs_t *write_kifs,
  4. void* data);

Yo la paso así:

Código
  1. create_kifs_entry("counter",sum,lect,NULL)

Y la declaración es la siguiente:

Código
  1. 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":
Código
  1. EXPORT_SYMBOL(create_kifs_entry);
  2. EXPORT_SYMBOL(remove_kifs_entry);
  3.