Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Linux 2.6.29中,如何解码ioctl()系统调用中的arg指针?_C_Linux_Linux Kernel_System Calls_Ioctl - Fatal编程技术网

在Linux 2.6.29中,如何解码ioctl()系统调用中的arg指针?

在Linux 2.6.29中,如何解码ioctl()系统调用中的arg指针?,c,linux,linux-kernel,system-calls,ioctl,C,Linux,Linux Kernel,System Calls,Ioctl,我想打印传递给linux系统调用的所有参数值。例如,对于ioctl(),我有以下原型和打印语句 asmlinkage long our_sys_ioctl(unsigned int fd , unsigned int cmd , unsigned long arg) { printk ("fd=%u, cmd=%u and arg=%lu \n ", fd, cmd, arg); return original_call_ioctl(fd , cmd , arg); } 我知

我想打印传递给
linux
系统调用的所有参数值。例如,对于
ioctl()
,我有以下原型和打印语句

asmlinkage long our_sys_ioctl(unsigned int fd ,  unsigned int cmd , unsigned long arg)
{
    printk ("fd=%u, cmd=%u and arg=%lu \n ", fd, cmd, arg);
    return original_call_ioctl(fd , cmd , arg);
}
我知道,
fd
是驱动程序文件的文件描述符,
cmd
定义驱动程序、ioctl编号、操作类型和参数大小。但是我对参数
arg
感到困惑,它要么是指向内存的指针,要么只是大多数文档所称的立即值


通过使用这个
arg
参数,如果内存内容是作为上面给出的
无符号长arg
而不是指针传递的,那么如何获取内存内容?

请记住
ioctl
的原型如下所示:

int ioctl(int fildes, unsigned long request, ...);
您只能确定前两个参数是什么。根据:

附加参数是可选的,并且可能因一个设备上的ioctl实现和另一个设备上的实现而异。据我所知,第三个论点总是存在的,我还没有找到超过三分之一的论点。第三个参数通常似乎是指向结构的指针。这允许在两个方向上传递任意数量的数据,数据由指针引用的结构定义,只需传递指针即可


…但即使假设只有第三个参数,您仍然不知道它是文本值还是指向结构的指针(缺少请求到预期参数的显式映射)。

ioctl的
arg
参数在通用vfs级别是不透明的。如何解释它取决于实际处理它的驱动程序或文件系统。因此,它可能是指向用户空间内存的指针,也可能是索引、标志,等等。它甚至可能是未使用的,并且按惯例以0传递

例如,查看
drivers/tty/tty_io.c
中的
TCSBRKP
ioctl的实现:

long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
//...
       case TCSBRKP:   /* support for POSIX tcsendbreak() */
            return send_break(tty, arg ? arg*100 : 250);
您可以查看手册页以查看各种IOCTL采用的参数;该列表中具有
int
或其他非指针参数的所有条目都是其他示例

所以你可以做一些像

    void __user *argp = (void __user *) arg;
然后使用
copy\u from\u user()
get\u user()
读取
arg
指向的内存,但如果参数不是指针,则可能会失败。在通用ioctl系统调用中,您可能并不真的希望有一个包含所有可能ioctl的大表。

,也链接到,应该在dept中更清楚地阐明这一点。一个有趣的摘录(我添加了粗体文本)可能如下所示:

在用户空间中,ioctl系统调用具有以下原型:

intioctl(intfd,unsigned long cmd,…)

原型在Unix系统调用列表中很突出,因为点通常将函数标记为具有可变数量的参数。然而,在实际系统中,系统调用实际上不能有数量可变的参数。系统调用必须有一个定义良好的原型,因为用户程序只能通过硬件“门”访问它们。因此,原型中的点代表的不是数量可变的参数,而是单个可选参数,传统上被标识为
char*argp
。点的存在只是为了防止编译过程中的类型检查第三个参数的实际性质取决于发出的特定控制命令(第二个参数)。有些命令不带参数,有些命令带整数值,有些命令带指向其他数据的指针。使用指针是向ioctl调用传递任意数据的方法;然后,该设备能够与用户空间交换任意数量的数据

ioctl调用的非结构化性质导致它在内核开发人员中不受欢迎。每个ioctl命令本质上是一个单独的、通常未记录的系统调用,并且无法以任何形式全面地审核这些调用。也很难使非结构化ioctl参数在所有系统上相同地工作;例如,考虑以32位模式运行的用户空间进程的64位系统。因此,存在着通过几乎任何其他方式实施各种控制操作的强大压力。可能的替代方案包括将命令嵌入到数据流中(我们将在本章后面讨论此方法)或使用虚拟文件系统(sysfs或特定于驱动程序的文件系统)。(我们将在第14章中介绍sysfs。)然而,事实仍然是ioctl通常是真正设备操作的最简单和最直接的选择

这意味着,如果没有对设备驱动程序惯例/内部结构的深入了解,就无法理解如何将ioctl参数解释为外部观察者。从用户空间的角度来看,ioctl参数是非类型化的,并且在内核空间中以某种方式松散地类型化,因为它被处理为
无符号长
,只是为了为它保留空间。它是一个“纯”数或任何适合
无符号长整数
空间的位序列,可以用作(非常短的)字符串、一个(小的)字符数组、一个(小的)结构-但要注意端点和特定于体系结构的大小-可以表示设备板载芯片的操作码,甚至被视为一个浮子处理的类型普宁

此外,这意味着很容易将不一致的数据传递给驱动程序(不仅是错误的数据,而且是错误类型的错误数据!),从而导致设备的未定义行为或用户空间内存损坏(例如,通过在读取ioctl中传递指向错误大小的结构的指针),从而将事情搞砸

还有几行: