2014-12-05 16 views
7

Jestem w trakcie pisania modułu jądra Linux (LKM) służącego jako pseudo-sterownik - nie jestem w stanie wymyślić, jak wykonać wywołania IOCTL między LKM (wait.c) i program na poziomie użytkownika (user.c).Moduł jądra Linux/IOCTL: niewłaściwe ioctl dla urządzenia

Magiczna liczba dla sterownika urządzenia to 0xBF - LKM nie komunikuje się z fizycznym urządzeniem blokowym/char, jest po prostu ćwiczeniem. Z tego, co mogę powiedzieć, wywołanie IOCTL do KERN_IOCTL_CREATE_EVENT nie jest poprawnie sformatowane & magiczna liczba jest niepoprawna.

Wywołanie IOCTL że jestem próbuje użyć to:

#include <sys/ioctl.h> 
#define KERN_IOCTL_CREATE_EVENT _IOWR(WAIT_DEVICE_MAGIC, 1, int) 

int main(){ 
int ret; 
int fd; 
fd = open("/dev/wait", 0); 
if(fd < 0){ 
    return -1; 
} 
ret = ioctl(fd, KERN_IOCTL_CREATE_EVENT, 0); 

Błąd:

[fail]: KERN_IOCTL_CREATE_EVENT: Inappropriate ioctl for device 

Zastosowanie trybu użytkownika można otworzyć/zamknąć deskryptor pliku wskazujący na urządzeniu: /dev/wait ale instrukcja nie przyjmuje wywołania IOCTL. Jakieś sugestie?

Oto wyjściowy # uname -a

Linux vagrant-ubuntu-trusty-64 3.13.11.11+ #1 SMP Mon Dec 1 20:50:23 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux 

wait.c

#include <linux/miscdevice.h> 
#include <linux/moduleparam.h> 
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/string.h> 
#include <asm/uaccess.h> 
#include <linux/sched.h> 
#include <linux/ioctl.h> 
#include <linux/cdev.h> 
#include <linux/init.h> 
#include <linux/wait.h> 
#include <linux/fs.h> 

#include "wait.h" 

MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("Tyler Fisher <[email protected]>"); 
MODULE_DESCRIPTION("In-kernel wait queue"); 

static unsigned long event_table_size = 50; 
module_param(event_table_size, ulong, (S_IRUSR | S_IRGRP | S_IROTH)); 
MODULE_PARM_DESC(event_table_size, "Size of event table (i.e. how many processes can be blocking)"); 

/* IOCTL function headers */ 
static int wait_open(struct inode *, struct file *); 
static int wait_close(struct inode *, struct file *); 
static long wait_ioctl(struct inode *, struct file *, unsigned int, unsigned long); 

/* other function headers */ 
static long event_open(int event_id); 

/* file operations */ 
static struct file_operations wait_fops = { 
    .owner = THIS_MODULE, 
    .open = wait_open, 
    .release = wait_close, 
    .llseek = noop_llseek, 
    .unlocked_ioctl = wait_ioctl 
}; 

/* device handler */ 
static struct miscdevice wait_misc_device = { 
    .minor = MISC_DYNAMIC_MINOR, 
    .name = WAIT_DEVICE_NAME, 
    .fops = &wait_fops 
}; 

/* open wait device */ 
static int wait_open(struct inode *inode, struct file *file){ 
    dev_t node = iminor(inode); 
    if(MINOR(node) != WAIT_DEVICE_MINOR){ 
     return -ENODEV; 
    } 
    return 0; 
} 

static int wait_close(struct inode *inode, struct file *file){ 
    return 0; 
} 

static long wait_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long sub_cmd){ 
switch(cmd){ 
    case KERN_IOCTL_CREATE_EVENT: 
     printk(KERN_INFO "[wait device]: create event %lu\n", sub_cmd); 
     return event_open(sub_cmd); 

    default: 
     return -ENOENT; 
    } 
} 

static long event_open(int id){ 
    return 0; 
} 

static long __init wait_init(void){ 
    if(misc_register(&wait_misc_device) < 0){ 
     printk(KERN_ERR "[wait device] failed to register device\n"); 
     return -1; 
    } 
    printk(KERN_INFO "[wait device] has been registered\n"); 
    return 0; 
} 

static void __exit wait_exit(void){ 
    misc_deregister(&wait_misc_device); 
    printk(KERN_INFO "[wait device] has been unregistered\n"); 
} 

module_init(wait_init); 
module_exit(wait_exit); 

wait.h

#include <linux/ioctl.h> 

#define WAIT_DEVICE_NAME "wait" 
#define WAIT_DEVICE_MAGIC 0xBF 
#define WAIT_DEVICE_MAJOR 200 
#define WAIT_DEVICE_MINOR 0 

#define KERN_IOCTL_CREATE_EVENT  _IOWR(WAIT_DEVICE_MAGIC, 0x01, int) 

#define MAX_WAITING 5 

Program testowy dla IOCTL wzywa:

user.c

#include <sys/ioctl.h> 
#include <fcntl.h> 
#include <stdio.h> 

#define WAIT_DEVICE_MAGIC 0xBF 
#define KERN_IOCTL_CREATE_EVENT _IOWR(WAIT_DEVICE_MAGIC, 0x01, int) 
#define KERN_IOCTL_DESTROY_EVENT _IOWR(WAIT_DEVICE_MAGIC, 0x02, int) 
#define KERN_IOCTL_LOCK_EVENT  _IOWR(WAIT_DEVICE_MAGIC, 0x03, int) 
#define KERN_IOCTL_UNLOCK_EVENT _IOWR(WAIT_DEVICE_MAGIC, 0x04, int) 

int main(){ 
    int fd; 
    if(fd = open("/dev/wait", O_RDWR) < 0){ 
     perror("failed to open /dev/wait"); 
     return -1; 
    } 

    /* test IOCTL: event creation */ 
    if(ioctl(fd, KERN_IOCTL_CREATE_EVENT, 0) < 0){ 
     perror("[fail]: KERN_IOCTL_CREATE_EVENT"); 
     return -1; 
    } 
    return 0; 
} 

Makefile

obj-m += wait.o 
CFLAGS_wait.o += -DDEBUG 

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

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

W celu przetestowania LKM - Clear dmesg, kompilacji & wykonać user.cw/GCC:

# dmesg -c > /dev/null 2>&1 
# make 
# rmmod wait.ko 
# insmod wait.ko 
# gcc user.c -o user && ./user 

Ilość błędów debugowania jest kłopotliwa. Czuję się źle, dzieląc się tym - i zdaję sobie sprawę, że może to spowodować zamknięcie sprawy/zaniechanie jej w niepamięć.

# sh test.sh 
[+] cleared dmesg 
make -C /lib/modules/3.13.11.11+/build M=/home/vagrant/PROG40000-kernel-synchronization modules 
make[1]: Entering directory `/home/vagrant/ubuntu-trusty' 
    CC [M] /home/vagrant/PROG40000-kernel-synchronization/wait.o 
/home/vagrant/PROG40000-kernel-synchronization/wait.c:61:1: warning: initialization from incompatible pointer type [enabled by default] 
}; 
^ 
/home/vagrant/PROG40000-kernel-synchronization/wait.c:61:1: warning: (near initialization for ‘wait_fops.unlocked_ioctl’) [enabled by default] 
In file included from include/linux/moduleparam.h:4:0, 
       from /home/vagrant/PROG40000-kernel-synchronization/wait.c:11: 
/home/vagrant/PROG40000-kernel-synchronization/wait.c: In function ‘__inittest’: 
include/linux/init.h:297:4: warning: return from incompatible pointer type [enabled by default] 
    { return initfn; }  \ 
    ^
/home/vagrant/PROG40000-kernel-synchronization/wait.c:167:1: note: in expansion of macro ‘module_init’ 
module_init(wait_init); 
^ 
    Building modules, stage 2. 
    MODPOST 1 modules 
    CC  /home/vagrant/PROG40000-kernel-synchronization/wait.mod.o 
    LD [M] /home/vagrant/PROG40000-kernel-synchronization/wait.ko 
make[1]: Leaving directory `/home/vagrant/ubuntu-trusty' 
[--dmesg--] 
[13112.810008] [wait device] has been unregistered 
[13112.819049] [wait device] has been registered 
[-/dmesg--] 
[+] compiled user-mode program 
----- 
[fail]: KERN_IOCTL_CREATE_EVENT: Inappropriate ioctl for device 
[fail]: KERN_IOCTL_CREATE_EVENT: Inappropriate ioctl for device 
[+] executed user-mode program 
----- 
[--dmesg--] 
[13112.810008] [wait device] has been unregistered 
[13112.819049] [wait device] has been registered 
[13112.893049] SOMEONE DARE READ FROM ME!? 
[13112.893057] [wait device] invalid magic number: 0:0:191 
[13112.893535] [wait device] invalid magic number: 0:0:191 
[-/dmesg--] 
+0

Może być konieczne zainstalowanie zaktualizowanych nagłówków jądra. Bez tego program przestrzeni użytkownika nie jest w stanie zlokalizować poprawnego ioctl, z jakiegoś powodu miałem podobny problem w systemie Ubuntu i jedyną rzeczą, która działała była instalacja zaktualizowanych nagłówków jądra. – askb

+0

Zaktualizowałem jądro za pomocą polecenia sudo make modules_install install - i zainstalowałem pakiet genericów linux-generic - obecna wersja jądra to 3.13.11.11+ – Tyler

Odpowiedz

2

OK. Więc. Oto rozwiązanie.

W jądrze Linux 2.6.x deklaracja dla połączeń _ioctl zmieniło od

static long wait_ioctl(struct inode *, struct file *, unsigned int, unsigned long); 

Do:

static long wait_ioctl(struct file *, unsigned int, unsigned long); 

poprawka jest więc:

... 
static long wait_ioctl(struct file *, unsigned int, unsigned long); 
... 
static long wait_ioctl(struct file *file, unsigned int cmd, unsigned long sub_cmd){ 
    if(_IOC_TYPE(cmd) != WAIT_DEVICE_MAGIC){ 
     printk(KERN_INFO "[wait device] invalid magic number: %u:%u:%u", _IOC_TYPE(cmd), cmd, WAIT_DEVICE_MAGIC); 
     return -ENOTTY; 
    } 
.... 
0

.compat_ioctl

Upewnij się także do wdrożenia tego file_operation jeśli robisz 32-b wywołuje jądro 64-bitowe.

Objawem jest to, że Twoja procedura ioctl nigdy nie jest uruchamiana.

Powiązane problemy