USB设备访问管理

主题是面向某一用户空间的设备访问管理。

大家都知道通常的设备访问流程是:内核设备驱动,包括usb驱动,一般情况下是通过kobject_uevent接口上报uevent消息到用户空间,由用户管理进程,如udevd、ueventd等接收uevent消息,然后解析,创建设备文件节点。之后,设备访问程序才能通过设备文件节点访问操作设备。

管理方法讨论

如果不希望用户空间访问某设备,最直接的方法是不提供相应设备驱动;次之,在koject_uevent接口过滤设备上报消息;再次之,由用户空间的设备管理进程过滤设备上报消息。


多用户空间下,如果不希望某一用户空间访问某设备,沿用上一思路,可以在具体的用户空间的设备管理进程过滤设备上报消息。那么问题来了,是否还有其他方法呢?答案是肯定的。linux2.6.24引入内核的cgroup功能,有1个device cgroup子系统,可以管理进程控制组内的进程是否能够访问某些设备节点。devices.allow指定 cgroup 中的任务可访问的设备,devices.deny指定 cgroup 中的任务禁止访问的设备。每个条目有四个字段:type、major、minor 和 access。type、major 和 minor 字段中使用的值对应 Linux 分配的设备,也称 Linux 设备列表中指定的设备类型和节点数。控制条目如下:

 a 8:* rwm

其中,

a,  代表所有设备类型,也可以为b或c分别代表block块设备、character字符设备

b,  8代表设备的主设备号

c,  *代表主设备号下的所有次设备号,可以根据需要指定为具体的值

d,  r代表读权限、w代表写权限、m代表生成设备文件权限

将该条目写入dev cgroup组A的devices.allow,组A中的所有进程都可以操作该条目所匹配的设备;将该条目写入dev cgroup组A的devices.deny,组A中的所有进程都被禁止操作该条目所匹配的设备。

判定条件选取

通过venderId和productId作为判定条件,难以穷举所有的设备。我们就希望能够可以通过usb的接口设备类型来作为判定条件,而且usb驱动本身是定义了不同的接口类型(在ch9.h中)。

1个简单usb设备插入主机后,usb驱动上报消息的流程依次为:

usb_device、usb_interface、(分层封装设备)

它们也依次为父子关系,所以,可以通过寻找父亲的方式,找到设备对应的usb_interface、usb_device。(

InterfaceClass定义在usb_interface中,venderId和productId定义在usb_device中)

调整验证代码如下:

/*获取设备的venderIdproductId和接口类型*/

    dev = container_of(kobj, struct device,kobj);

    if (NULL != dev)

    {

        structdevice *tdev = dev;

          do{

              if (tdev->type && tdev->type->name)

              {

                if(!strcmp("usb_interface", tdev->type->name))

                {

                    intf =to_usb_interface(tdev);

                    iClass =intf->cur_altsetting->desc.bInterfaceClass;

                }

                if(!strcmp("usb_device", tdev->type->name))

                {

                    udev = container_of(tdev,struct usb_device, dev);

                    Vid  = le16_to_cpu(udev->descriptor.idVendor);

                    Pid  = le16_to_cpu(udev->descriptor.idProduct);

                    break;

                }

               }

               tdev = tdev->parent;

          }while(tdev);

       }

/*以或的方式判定*/

       if ( iClass || ( Vid && Pid) )

       {

          if (MAJOR(dev->devt)) {

            if ( (0x090c == Vid &&0x1000== Pid)||\

                (0x10c4 == Vid &&0xea60== Pid) ||\

               USB_CLASS_MASS_STORAGE == iClass)

            {

                /*wangshixin, modify dev cgroupto control device access*/

                file =filp_open(DEV_CG_ANDROID, O_WRONLY|O_APPEND, 0644);

                if (IS_ERR(file))

                {

                    printk("error occuredwhile opening file %s", DEV_CG_ANDROID);

                }

                else

                {

                    sprintf(buf, "a %d:%drwm", MAJOR(dev->devt), MINOR(dev->devt));

                    printk(KERN_DEBUG"#uevent---%d:%d\n",  MAJOR(dev->devt),MINOR(dev->devt));

                    old_fs = get_fs();

                    set_fs(KERNEL_DS);

                    retval =file->f_op->write(file, (char*)buf, 15, &file->f_pos);

                    set_fs(old_fs);

                    filp_close(file, NULL);

                }

            }

          }

       }

经过调测,以上代码是可信的。不仅对内核无具体驱动的usb设备有效,而且对通用的多层驱动设备(如通用U盘)有效。这是比较理想的结果。

课题诞生初期就产生了两个思路:1)不同用户空间独立控制访问;2)通过device cgroup内核集中控制访问。思路1)优点是比较简单,用户空间逻辑便于理解,缺点是不同用户空间要维护多份,而且存在一致的情况;思路2)缺点是技术难度相对较大,在有限的时间内可能难以取得比较理想的控制效果,优点是取得理想效果后,维护简单、易于移植。

这里的验证没有涉及控制配置文件的设计与读写,因为这不是很难的事情。这里给出建议:控制配置文件做成1个内核驱动(配置条目做成链表),上述实施的条件判断修改为遍历链表比对,对控制配置文件的写只有1个实体(可以是对外的控制中心),实施时使用锁避免链表访问异常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值