在内核层添加USB 开关控制

在网上搜到的一些开关USB 口的,要么是通过命令echo 0 > /sys/bus/usb/devices/usbX/authorized 开关,这个前提要知道插入USB 设备的index;要么卸载usb 的ko。都不满足用户的要求

下面是通过拦截插拔USB 设备时,内核上抛uevent 消息的地方拦截,可以根据USB 设备的VID, PID 过滤哪些设备可以上抛消息,有效被mount 识别

考虑到在通用的上抛消息的地方识别PID/VID 拦截,会出现所有消息都要去判断一下,会影响系统性能。选择在USB add devices里面判断上抛消息,可以减少影响范围。最多也只是影响了USB 的性能

1. 添加过滤规则的源文件 drivers/usb/core/usb-filter.c.

可以在static_filters[] 数组里添加默认需要识别的设备。也可以在uboot启动变量bootargs添加usbfilter:setenv initargs $initargs usbfilter=1234:5678 的方式


+#include <linux/kobject.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/usb/filter.h>
+
+#ifdef CONFIG_USB_FILTER
+LIST_HEAD(usb_filter_list);
+DEFINE_MUTEX(usb_filter_mutex);
+bool usb_filtering_enabled = true;
+
+#define MAX_FILTERS 16
+static struct usb_filter static_filters[MAX_FILTERS];
+static int num_filters = 0;
+
+#define USB_CAMERA_VID		0x16da
+#define USB_CAMERA_PID		0xb72a
+
+// 检查设备是否在允许列表中
+bool usb_device_is_allowed(u16 vid, u16 pid)
+{
+	struct usb_filter *filter;
+	bool allowed = false;
+
+	if (!usb_filtering_enabled)
+		return true;
+
+	mutex_lock(&usb_filter_mutex);
+	list_for_each_entry(filter, &usb_filter_list, list) {
+		if (filter->enabled && filter->vid == vid && filter->pid == pid) {
+			allowed = true;
+			break;
+		}
+	}
+	mutex_unlock(&usb_filter_mutex);
+
+	return allowed;
+}
+//EXPORT_SYMBOL_GPL(usb_device_is_allowed);
+
+// 初始化过滤规则(从内核命令行参数解析)
+static int __init usb_filter_setup(char *str)
+{
+	char *token;
+	u16 vid, pid;
+
+	printk(KERN_INFO "USB filter: parsing command line parameters\n");
+
+	// 在内核启动早期,使用静态数组而不是动态分配
+	while ((token = strsep(&str, ",")) != NULL && num_filters < MAX_FILTERS) {
+		if (sscanf(token, "%hx:%hx", &vid, &pid) == 2) {
+			static_filters[num_filters].vid = vid;
+			static_filters[num_filters].pid = pid;
+			static_filters[num_filters].enabled = true;
+
+			// 将静态过滤器添加到链表(稍后在初始化时完成)
+			printk(KERN_INFO "USB filter: added rule for %04x:%04x\n", vid, pid);
+			num_filters++;
+		} else if (strcmp(token, "disable") == 0) {
+			usb_filtering_enabled = false;
+			printk(KERN_INFO "USB filter: disabled\n");
+		} else if (strcmp(token, "enable") == 0) {
+			usb_filtering_enabled = true;
+			printk(KERN_INFO "USB filter: enabled\n");
+		}
+	}
+
+	if (num_filters >= MAX_FILTERS) {
+		printk(KERN_WARNING "USB filter: maximum number of filters reached (%d)\n", MAX_FILTERS);
+	}
+
+	return 0;
+}
+__setup("usbfilter=", usb_filter_setup);
+
+// 在内存管理子系统初始化后,将静态过滤器添加到链表
+static int __init usb_filter_init_static(void)
+{
+	int i;
+
+	static_filters[num_filters].vid = USB_CAMERA_VID;
+	static_filters[num_filters].pid = USB_CAMERA_PID;
+	static_filters[num_filters++].enabled = true;
+	printk(KERN_INFO "USB filter: %d static filters initialized 1\n", num_filters);
+
+	for (i = 0; i < num_filters; i++) {
+		struct usb_filter *filter = kmalloc(sizeof(*filter), GFP_KERNEL);
+		if (filter) {
+			filter->vid = static_filters[i].vid;
+			filter->pid = static_filters[i].pid;
+			filter->enabled = static_filters[i].enabled;
+			INIT_LIST_HEAD(&filter->list);
+			mutex_lock(&usb_filter_mutex);
+			list_add_tail(&filter->list, &usb_filter_list);
+			mutex_unlock(&usb_filter_mutex);
+		}
+	}
+
+	printk(KERN_INFO "USB filter: %d static filters initialized\n", num_filters);
+	return 0;
+}
+// 使用rootfs_initcall确保在内存管理子系统初始化后执行
+rootfs_initcall(usb_filter_init_static);
+
+// Sysfs 显示当前过滤规则
+static ssize_t filter_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	struct usb_filter *filter;
+	ssize_t count = 0;
+
+	mutex_lock(&usb_filter_mutex);
+	if (!usb_filtering_enabled) {
+		count = snprintf(buf, PAGE_SIZE, "Filtering is disabled\n");
+		goto out;
+	}
+
+	count += snprintf(buf + count, PAGE_SIZE - count, "Enabled filters:\n");
+
+	list_for_each_entry(filter, &usb_filter_list, list) {
+		if (filter->enabled) {
+			count += snprintf(buf + count, PAGE_SIZE - count,
+							"%04x:%04x\n", filter->vid, filter->pid);
+		}
+	}
+
+	if (count == 0) {
+		count = snprintf(buf, PAGE_SIZE, "No filters defined\n");
+	}
+
+out:
+	mutex_unlock(&usb_filter_mutex);
+	return count;
+}
+
+// Sysfs 添加/删除过滤规则
+static ssize_t filter_store(struct kobject *kobj, struct kobj_attribute *attr,
+						   const char *buf, size_t count)
+{
+	char op;
+	u16 vid, pid;
+	struct usb_filter *filter, *tmp;
+	bool found = false;
+
+	if (sscanf(buf, "%c %hx %hx", &op, &vid, &pid) != 3) {
+		// 尝试解析启用/禁用整个过滤功能
+		if (sscanf(buf, "%c", &op) == 1) {
+			if (op == 'E' || op == 'e') {
+				mutex_lock(&usb_filter_mutex);
+				usb_filtering_enabled = true;
+				mutex_unlock(&usb_filter_mutex);
+				printk(KERN_INFO "USB filtering enabled\n");
+				return count;
+			} else if (op == 'D' || op == 'd') {
+				mutex_lock(&usb_filter_mutex);
+				usb_filtering_enabled = false;
+				mutex_unlock(&usb_filter_mutex);
+				printk(KERN_INFO "USB filtering disabled\n");
+				return count;
+			}
+		}
+		printk(KERN_ERR "Invalid format. Use: [A|R] VID PID or [E|D] to enable/disable filtering\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&usb_filter_mutex);
+
+	// 查找是否已存在该规则
+	list_for_each_entry_safe(filter, tmp, &usb_filter_list, list) {
+		if (filter->vid == vid && filter->pid == pid) {
+			found = true;
+			if (op == 'A' || op == 'a') {
+				filter->enabled = true;
+				printk(KERN_INFO "Filter %04x:%04x enabled\n", vid, pid);
+			} else if (op == 'R' || op == 'r') {
+				filter->enabled = false;
+				printk(KERN_INFO "Filter %04x:%04x disabled\n", vid, pid);
+			}
+			break;
+		}
+	}
+
+	// 如果是添加新规则且不存在
+	if (!found && (op == 'A' || op == 'a')) {
+		filter = kmalloc(sizeof(*filter), GFP_KERNEL);
+		if (!filter) {
+			mutex_unlock(&usb_filter_mutex);
+			return -ENOMEM;
+		}
+
+		filter->vid = vid;
+		filter->pid = pid;
+		filter->enabled = true;
+		INIT_LIST_HEAD(&filter->list);
+		list_add_tail(&filter->list, &usb_filter_list);
+
+		printk(KERN_INFO "Added filter for %04x:%04x\n", vid, pid);
+	} else if (!found) {
+		printk(KERN_ERR "Filter for %04x:%04x not found\n", vid, pid);
+		mutex_unlock(&usb_filter_mutex);
+		return -ENOENT;
+	}
+
+	mutex_unlock(&usb_filter_mutex);
+	return count;
+}
+
+static struct kobj_attribute filter_attr = __ATTR(usb_filter, 0644, filter_show, filter_store);
+
+static struct kobject *usb_filter_kobj;
+
+static int __init usb_filter_sysfs_init(void)
+{
+	int ret;
+
+	// 创建 sysfs 目录
+	usb_filter_kobj = kobject_create_and_add("usb_filter", kernel_kobj);
+	if (!usb_filter_kobj) {
+		printk(KERN_ERR "Failed to create sysfs directory\n");
+		return -ENOMEM;
+	}
+
+	// 创建 sysfs 属性文件
+	ret = sysfs_create_file(usb_filter_kobj, &filter_attr.attr);
+	if (ret) {
+		printk(KERN_ERR "Failed to create sysfs file\n");
+		kobject_put(usb_filter_kobj);
+		return ret;
+	}
+
+	printk(KERN_INFO "USB filter sysfs interface initialized\n");
+	return 0;
+}
+
+subsys_initcall(usb_filter_sysfs_init);
+
+#endif /* CONFIG_USB_FILTER */
+

2. 添加头文件include/linux/usb/filter.h

+#ifndef _LINUX_USB_FILTER_H
+#define _LINUX_USB_FILTER_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+struct usb_filter {
+    u16 vid;
+    u16 pid;
+    bool enabled;
+    struct list_head list;
+};
+
+#ifdef CONFIG_USB_FILTER
+extern bool usb_device_is_allowed(u16 vid, u16 pid);
+#else
+static inline bool usb_device_is_allowed(u16 vid, u16 pid) { return true; }
+#endif
+
+#endif /* _LINUX_USB_FILTER_H */
+

3.修改drivers/usb/core/hub.c 的 usb_new_device函数

+#include <linux/usb/filter.h>
..............
 
int usb_new_device(struct usb_device *udev)
 {
 	int err;
+#ifdef CONFIG_USB_FILTER
+	// 检查设备是否在允许列表中
+	u16 vid = le16_to_cpu(udev->descriptor.idVendor);
+	u16 pid = le16_to_cpu(udev->descriptor.idProduct);
+
+	if (!usb_device_is_allowed(vid, pid)) {
+		dev_info(&udev->dev, "USB device %04x:%04x blocked by filter\n", vid, pid);
+		return -EPERM; // 阻止设备注册
+	}
+#endif
 
 	if (udev->parent) {
 		/* Initialize non-root-hub device wakeup to disabled;

4. 修改 drivers/usb/core/driver.c

+#include <linux/usb/filter.h>
 
....................
 
int usb_probe_interface(struct device *dev)
{
..................

+#ifdef CONFIG_USB_FILTER
+	// 检查设备是否在允许列表中
+	u16 vid = le16_to_cpu(udev->descriptor.idVendor);
+	u16 pid = le16_to_cpu(udev->descriptor.idProduct);
+
+	if (!usb_device_is_allowed(vid, pid)) {
+		dev_info(dev, "USB interface %04x:%04x blocked by filter\n", vid, pid);
+		return -EPERM; // 阻止接口注册
+	}
+#endif
 
 	dev_dbg(dev, "%s\n", __func__);

5. 修改makefile。最好用built-in 的方式,确保filter 在usb add device之前就能用,否则如果插着USB 设备开机,就filter 还没起作用,add devices 已经枚举到设备,并上抛event,没法有效拦截

+++ b/drivers/usb/core/Makefile
 obj-$(CONFIG_USB)		+= usbcore.o
 
+
+obj-$(CONFIG_USB_FILTER) += usb-filter.o

6. 调试遇到的问题

设置了setenv initargs $initargs usbfilter=1d72:0002,366b:0003;saveenv;reset 重启开机过程出现一下panic报错

问题可能出现在usb_filter_setup函数中,我们在内核启动早期(在解析命令行参数时)就调用了内存分配函数,而此时内核的内存管理子系统可能还没有完全初始化,导致无法正常分配内存

[    0.000000][    T0] -(0)[0:swapper] USB filter: parsing command line parameters
[    0.000000][    T0] -(0)[0:swapper] Unable to handle kernel read from unreadable memory at virtual address 0000000000000018
[    0.000000][    T0] -(0)[0:swapper] Mem abort info:
[    0.000000][    T0] -(0)[0:swapper]   ESR = 0x96000005
[    0.000000][    T0] -(0)[0:swapper]   EC = 0x25: DABT (current EL), IL = 32 bits
[    0.000000][    T0] -(0)[0:swapper]   SET = 0, FnV = 0
[    0.000000][    T0] -(0)[0:swapper]   EA = 0, S1PTW = 0
[    0.000000][    T0] -(0)[0:swapper]   FSC = 0x05: level 1 translation fault
[    0.000000][    T0] -(0)[0:swapper] Data abort info:
[    0.000000][    T0] -(0)[0:swapper]   ISV = 0, ISS = 0x00000005
[    0.000000][    T0] -(0)[0:swapper]   CM = 0, WnR = 0
[    0.000000][    T0] -(0)[0:swapper] [0000000000000018] user address but active_mm is swapper
[    0.000000][    T0] -(0)[0:swapper] Internal error: Oops: 96000005 [#1] PREEMPT SMP
[    0.000000][    T0] -(0)[0:swapper] Modules linked in:
[    0.000000][    T0] -(0)[0:swapper] CPU: 0 PID: 0 Comm: swapper Not tainted 5.15.78-android13-8-01631-g168661d42cfb-dirty #1
[    0.000000][    T0] -(0)[0:swapper] pstate: 004000c5 (nzcv daIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[    0.000000][    T0] -(0)[0:swapper] pc : kmem_cache_alloc_trace+0x250/0x434
[    0.000000][    T0] -(0)[0:swapper] lr : kmem_cache_alloc_trace+0x8c/0x434
[    0.000000][    T0] -(0)[0:swapper] sp : ffffffeb0a853c20
[    0.000000][    T0] -(0)[0:swapper] x29: ffffffeb0a853c40 x28: ffffffeb0ac4f000 x27: ffffffeb0a85b000
[    0.000000][    T0] -(0)[0:swapper] x26: ffffffeb09b32576 x25: ffffffffffffffff x24: ffffffeb0a6c8468
[    0.000000][    T0] -(0)[0:swapper] x23: ffffffeb0a6c8468 x22: 0000000000000000 x21: 0000000000000000
[    0.000000][    T0] -(0)[0:swapper] x20: 0000000000000018 x19: 0000000000000cc0 x18: ffffffeb0a86d6e8
[    0.000000][    T0] -(0)[0:swapper] x17: ffffffffffffffff x16: 0000000000000000 x15: 0000000000000004
[    0.000000][    T0] -(0)[0:swapper] x14: ffffffeb0a8f1be8 x13: ffffffeb09cac43c x12: 00000000ffffffbf
[    0.000000][    T0] -(0)[0:swapper] x11: ffffffeb09cac460 x10: 000000001ffff33f x9 : ff80006b0a6c8468
[    0.000000][    T0] -(0)[0:swapper] x8 : 0000000000000027 x7 : 205b5d3030303030 x6 : 302e30202020205b
[    0.000000][    T0] -(0)[0:swapper] x5 : ffffffeb0acdce24 x4 : ffffffeb0a85396f x3 : 0000000000000000
[    0.000000][    T0] -(0)[0:swapper] x2 : 0000000000000001 x1 : ffffffeb0a853c28 x0 : 0000000000000001
[    0.000000][    T0] -(0)[0:swapper] Call trace:
[    0.000000][    T0] -(0)[0:swapper]  kmem_cache_alloc_trace+0x250/0x434
[    0.000000][    T0] -(0)[0:swapper]  usb_filter_setup+0xcc/0x200
[    0.000000][    T0] -(0)[0:swapper]  obsolete_checksetup+0x88/0xd0
[    0.000000][    T0] -(0)[0:swapper]  unknown_bootoption+0x44/0x134
[    0.000000][    T0] -(0)[0:swapper]  parse_args+0x17c/0x398
[    0.000000][    T0] -(0)[0:swapper]  start_kernel+0x150/0x53c
[    0.000000][    T0] -(0)[0:swapper]  __primary_switched+0xc4/0x7b80
[    0.000000][    T0] -(0)[0:swapper] Code: 940020a3 92800019 f9400b88 f24902ff (b9401aa4)

解决办法:usb_filter_init_static 改成用全局数组static_filters[16] 保存默认的USB 设备

此修改经简单验证能用,但没经过严格测试,不能保证USB性能是否受影响

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值