2016-03-10 3 views
0

Je veux essayer d'utiliser les contrôles d'entrée/sortie d'un module de noyau chargeable, ici un périphérique de caractères. La question est: Comment vérifier si l'appel ioctl sur le côté de l'espace utilisateur a un argument ou non. J'ai trouvé que sur ioctl un argument est facultatif.Comment vérifier l'argument existant sur ioctl

Dans la fonction de l'espace utilisateur:

// set a parameter - this is a proper call 
if(ioctl(fd, IOCTL_SET_PARAM1, 5)<0) 
{ 
    fprintf(stderr,"Error while ioctl: %s\n", strerror(errno)); 
} 

// call a setter without argument - this should cause an error 
if(ioctl(fd, IOCTL_SET_PARAM1)<0) 
{ 
    fprintf(stderr,"Error while ioctl: %s\n", strerror(errno)); 
} 

Le gestionnaire de module de noyau correspondant:

long 
fops_unlocked_ioctl (struct file *p_file, 
        unsigned int cmd, 
        unsigned long arg) 
{ 
    switch(cmd) 
    { 
    case IOCTL_SET_PARAM1: 
    printk(KERN_INFO "IOCTL called with IOCTL_SET_PARAM1\n"); 
    if(/* how to check for the argument here? */) 
    { 
     printk(KERN_WARNING "Missing argument\n"); 
     return -EINVAL; 
    } 
    param1 = (unsigned short) arg; 
    printk(KERN_INFO "param1 set to %d\n",param1); 
    break; 
    default: 
    printk(KERN_WARNING "IOCTL called with wrong request code.\n"); 
    return -EINVAL; 
    } 
    return 0; 
} 

Cordialement, Alex

+1

L'utilisateur trouve et lit le manuel de l'appareil qu'il cherche à 'ioctl()'. Si l'utilisateur ne trouve pas le manuel, l'utilisateur trouve le code source. Si l'utilisateur ne peut pas trouver le manuel ou le code source, l'utilisateur qui a du sens ne fait rien tant qu'il n'a pas trouvé une source d'information plus ou moins définitive sur ce que le 'ioctl()' qu'ils prévoient use, et le (s) argument (s) qu'il faut. Il n'y a rien dans la convention d'appel C qui permet au code appelé de déterminer facilement le nombre d'arguments avec lesquels il a été appelé. Vous devez supposer que l'utilisateur a bien compris. –

+0

La seule chose que vous pouvez faire est de vérifier que 'arg' est un nombre valide. Par exemple, si 'arg' est supposé être' 0' ou '1', alors toute autre valeur indique que l'utilisateur ne sait pas ce qu'il fait. Cependant, l'utilisateur peut avoir de la chance (ou malchance selon votre point de vue), et 'arg' peut être une valeur valide même si l'utilisateur n'a pas passé de valeur. – user3386109

Répondre

0

Jonathan Leffler est tout à fait à droite, puis il dit, que l'utilisateur doit savoir quoi faire et quoi non. Par ailleurs, en passant,

J'ai élaboré une solution qui remplace l'argument par un tableau avec le compte et l'argument original. Côté utilisateur, rien ne change pour l'utilisateur. Du côté du noyau, il y a deux macros pour obtenir l'argument original et le nombre d'arguments.

vient Voici le code:

expdev.h

#ifndef EXPDEV_H_INCLUDED 
#define EXPDEV_H_INCLUDED 

#ifndef __KERNEL__ 
    #include <stdint.h> 
#endif // __KERNEL__ 

#include "pp_narg.h" 

enum { 
    IOCTL_SET_PARAM1, 
}; 

/* ioctl - wrapper *************************************************** */ 

#ifndef __KERNEL__ 
    long int argW[2]={0}; 

    long int PP_IOCTL_WRAPARG(long int narg, long int arg) 
    { 
    argW[0] = narg; 
    argW[1] = arg; 
    return (long int)(argW); 
    } 

    #define PP_IOCTL_NARG(n,fd,cmd,arg,...) \ 
    ((n==3) ? \ 
     (ioctl(fd,cmd,(long int)(PP_IOCTL_WRAPARG(1,(long int)arg)))) : \ 
     (ioctl(fd,cmd,(long int)(PP_IOCTL_WRAPARG(0,(long int)arg))))) 

    #define ioctl(...) \ 
    (PP_IOCTL_NARG(PP_NARG(__VA_ARGS__),   \ 
        __VA_ARGS__, (long int)(0),(long int)(0))) 

#else // __KERNEL__ 

    #define IOCTL_ARGC(argW) (((long int*)argW)[0]) 
    #define IOCTL_ARG(argW) (((long int*)argW)[1]) 

#endif // __KERNEL__ 

#endif // EXPDEV_H_INCLUDED 

Pour compter les arguments que je suivre cette post.

pp_narg.h

/* 
Source: https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s 
*/ 

#ifndef PP_NARG_INCLUDED 
#define PP_NARG_INCLUDED 

#define PP_NARG(...) \ 
     PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) 
#define PP_NARG_(...) \ 
     PP_ARG_N(__VA_ARGS__) 
#define PP_ARG_N(\ 
      _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \ 
     _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \ 
     _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \ 
     _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ 
     _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ 
     _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ 
     _61,_62,_63,N,...) N 
#define PP_RSEQ_N() \ 
     63,62,61,60,     \ 
     59,58,57,56,55,54,53,52,51,50, \ 
     49,48,47,46,45,44,43,42,41,40, \ 
     39,38,37,36,35,34,33,32,31,30, \ 
     29,28,27,26,25,24,23,22,21,20, \ 
     19,18,17,16,15,14,13,12,11,10, \ 
     9,8,7,6,5,4,3,2,1,0 

#endif // PP_NARG_INCLUDED 

maintenant un appel dans une fonction de l'espace utilisateur (comme d'habitude):

#include "expdev.h" 

// set a parameter 
if(ioctl(fd, IOCTL_SET_PARAM1, 5)<0) 
{ 
    fprintf(stderr,"Error while ioctl: %s\n", strerror(errno)); 
} 

// call a setter without argument - this should cause an error 
if(ioctl(fd, IOCTL_SET_PARAM1)<0) 
{ 
    fprintf(stderr,"Error while ioctl: %s\n", strerror(errno)); 
} 

et le côté du kernel (esprit IOCTL_ARGC(arg) et IOCTL_ARG(arg)):

#include "expdev.h" 

long 
fops_unlocked_ioctl (struct file *p_file, 
        unsigned int cmd, 
        unsigned long arg) 
{ 
    switch(cmd) 
    { 
    case IOCTL_SET_PARAM1: 
    printk(KERN_INFO "IOCTL called with IOCTL_SET_PARAM1\n"); 
    if(IOCTL_ARGC(arg)!=1) 
    { 
     printk(KERN_ERR "Missing argument.\n"); 
     return -EINVAL; 
    } 
    param1 = (unsigned short) IOCTL_ARG(arg); 
    printk(KERN_INFO "param1 set to %d\n",param1); 
    break; 
    default: 
    printk(KERN_WARNING "IOCTL called with wrong request code.\n"); 
    return -EINVAL; 
    } 
    return 0; 
} 

Ceci conduit t o la sortie suivante sur la kern.log:

kernel: [18577.042438] IOCTL called with IOCTL_SET_PARAM1 
kernel: [18577.042439] param1 set to 5 
kernel: [18577.042442] IOCTL called with IOCTL_SET_PARAM1 
kernel: [18577.042443] Missing argument. 

et sur le côté userspace:

Error while ioctl: Invalid argument 

REMARQUE:

Les macros redéfinissent ioctl. Cela signifie que l'utilisation de ioctl sur différents périphériques à l'intérieur de la même source entraînera des erreurs sur le périphérique qui ne prend pas en charge cette macro (par exemple si vous utilisez un tty standard).