usb智能管控

USB智能管控方案

mtp和ptp协议

1
2
3
4
5
6
7
struct mtp_struct {
u32 container_length;
u16 container_type;
u16 operation_code;
u32 transaction_id;
void *payload;
};

手机只读禁用

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb,
struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
void __user *arg, sigval_t userurb_sigval)
{
......
if (usb_endpoint_xfer_bulk(&ep->desc)) {
spin_lock_irq(&ps->lock);
......
/* Don't accept continuation URBs if the endpoint is
* disabled because of an earlier error.
*/
if (ps->disabled_bulk_eps & (1 << as->bulk_addr))
ret = -EREMOTEIO;
else{
if (!check_phone_read_access(ps->dev, ifnum, uurb->buffer)) { //添加对urb提交检测
ret = -EACCES;
}
else {
ret = usb_submit_urb(as->urb, GFP_ATOMIC);
}
}
.....
}
......
}

/* forbid mtp && ptp && adb methods write command */
bool check_phone_read_access(struct usb_device *dev, int ifnum, void __user *buffer)
{
struct usb_interface *intf;
bool ret = true;
struct mtp_struct mtp;
char *usb_path = NULL;

if (dev->devpath) {
usb_path = dev->devpath;

if (check_usb_normal(usb_path)) //正常模式直接退出
return ret;

intf = usb_ifnum_to_if(dev, ifnum);
if (intf->cur_altsetting && intf->cur_altsetting->string && (strstr(intf->cur_altsetting->string, "ADB Interface"))) {
return false;
} //ADB管控

//判断mtp和ptp协议 部分手机获取设备描述符获取mtp和ptp的方式不同需都加判断,例如iPhone、HUAWEI、Xiaomi、Samsung
if ((dev->config && dev->config->string && ((strstr(dev->config->string, "mtp")) || (strstr(dev->config->string, "ptp")))) ||
(intf->cur_altsetting->desc.bInterfaceClass == USB_CLASS_STILL_IMAGE && intf->cur_altsetting->desc.bInterfaceProtocol == 0x01) ||
(intf->cur_altsetting->string && (strstr(intf->cur_altsetting->string, "MTP") || strstr(intf->cur_altsetting->string, "PTP")))) {

if (check_usb_rejects(usb_path)) //存储拒绝直接退出
return false;

if (!copy_from_user(&mtp, buffer, sizeof(mtp))) {
/* MTP Operation Codes
* MTP_OPERATION_GET_DEVICE_INFO 0x1001
* MTP_OPERATION_OPEN_SESSION 0x1002
* MTP_OPERATION_CLOSE_SESSION 0x1003
* MTP_OPERATION_GET_STORAGE_IDS 0x1004
* MTP_OPERATION_GET_STORAGE_INFO 0x1005
* MTP_OPERATION_GET_NUM_OBJECTS 0x1006
* MTP_OPERATION_GET_OBJECT_HANDLES 0x1007
* MTP_OPERATION_GET_OBJECT_INFO 0x1008
* MTP_OPERATION_GET_OBJECT 0x1009
* MTP_OPERATION_GET_THUMB 0x100A
* MTP_OPERATION_DELETE_OBJECT 0x100B
* MTP_OPERATION_SEND_OBJECT_INFO 0x100C
* MTP_OPERATION_SEND_OBJECT 0x100D
* MTP_OPERATION_INITIATE_CAPTURE 0x100E
* MTP_OPERATION_FORMAT_STORE 0x100F
* MTP_OPERATION_RESET_DEVICE 0x1010
* MTP_OPERATION_SELF_TEST 0x1011
* MTP_OPERATION_SET_OBJECT_PROTECTION 0x1012
* MTP_OPERATION_POWER_DOWN 0x1013
* MTP_OPERATION_GET_DEVICE_PROP_DESC 0x1014
* MTP_OPERATION_GET_DEVICE_PROP_VALUE 0x1015
* MTP_OPERATION_SET_DEVICE_PROP_VALUE 0x1016
* MTP_OPERATION_RESET_DEVICE_PROP_VALUE 0x1017
* MTP_OPERATION_SET_OBJECT_PROP_VALUE 0x9804
* MTP_OPERATION_SET_OBJECT_PROP_LIST 0x9806
*/
if (mtp.operation_code == 0x100b || mtp.operation_code == 0x100c || mtp.operation_code == 0x100d || mtp.operation_code == 0x100f || mtp.operation_code == 0x9804 || mtp.operation_code == 0x9806) { //针对只读禁用特定传输
ret = false;
}
}
}
}
return ret;
}

禁用USB光盘刻录

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
static char* find_usb_device_path_from_dev(struct device *dev)
{
struct usb_device *usb_dev = NULL;

while (dev) {
if (dev->bus) {
if (strcmp(dev->bus->name, "usb") == 0) {

usb_dev = to_usb_device(dev);

if (!usb_dev || !usb_dev->devpath) {
dev = dev->parent;
continue;
}

if (usb_dev->bus && usb_dev->bus->busnum) {
return usb_dev->devpath;
}
}
}
dev = dev->parent;
}
return NULL;
}

/* forbid use scsi write command when cd is read only */
void check_sr_read_access(struct scsi_cd *cd, fmode_t *mode, unsigned cmd, void __user *argp)
{
struct sg_io_hdr hdr;
u8 opcode;

if (!cd->writeable && cmd == SG_IO) {
if (!copy_from_user(&hdr, argp, sizeof(hdr)) && !copy_from_user(&opcode, hdr.cmdp, sizeof(opcode))) {
if (opcode == WRITE_10 || opcode == WRITE_BLANK || opcode == FORMAT_UNIT || \
opcode == WRITE_LONG || opcode == WRITE_12 || opcode == WRITE_LONG_2 || \
opcode == WRITE_16 || opcode == WRITE_ATTRIBUTE) {
*mode &= ~FMODE_WRITE;
}
}
}
}

static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
unsigned long arg)
{
struct scsi_cd *cd = scsi_cd(bdev->bd_disk);
struct scsi_device *sdev = cd->device;
void __user *argp = (void __user *)arg;
int ret;

mutex_lock(&cd->lock);

......

switch (cmd) {
case SCSI_IOCTL_GET_IDLUN:
case SCSI_IOCTL_GET_BUS_NUMBER:
ret = scsi_ioctl(sdev, cmd, argp);
goto put;
}
#ifdef CONFIG_USB_SMARTCTL
if (strstr(cd->device->host->hostt->name, "usb"))
check_sr_read_access(cd, &mode, cmd, argp);
#endif
......
}

#ifdef CONFIG_COMPAT
static int sr_block_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
unsigned long arg)
{
struct scsi_cd *cd = scsi_cd(bdev->bd_disk);
struct scsi_device *sdev = cd->device;
void __user *argp = compat_ptr(arg);
int ret;

......

switch (cmd) {
case SCSI_IOCTL_GET_IDLUN:
case SCSI_IOCTL_GET_BUS_NUMBER:
ret = scsi_compat_ioctl(sdev, cmd, argp);
goto put;
}

#ifdef CONFIG_HUAWEI_ARMPC_SMART_USB
if (strstr(cd->device->host->hostt->name, "usb"))
check_sr_read_access(cd, &mode, cmd, argp);
#endif
......
}

static void get_capabilities(struct scsi_cd *cd)
{
......
/*
* if DVD-RAM, MRW-W or CD-RW, we are randomly writable
*/
if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) !=
(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) {
cd->writeable = 1;
}

#ifdef CONFIG_USB_SMARTCTL
char *usb_path = NULL;

if ((cd->device) && (&(cd->device->sdev_gendev)))
usb_path = find_usb_device_path_from_dev(&(cd->device->sdev_gendev));

if (usb_path && check_usb_smart_status(usb_path)) {
cd->writeable = 0;
set_disk_ro(cd->disk, 1);
}
#endif
......
}

U盘存储只读

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
static void
sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
{
......
if (res < 0) {
sd_first_printk(KERN_WARNING, sdkp,
"Test WP failed, assume Write Enabled\n");
} else {
sdkp->write_prot = ((data.device_specific & 0x80) != 0);
#ifdef CONFIG_USB_SMARTCTL
/*
* Check whether the SCSI device is a "usb-storage" device
* and whether the read-only switch is enabled for the Smart usb.
*/
if (check_usb_smart_status(sdp))
set_sd_ro(sdkp); //设置只读
#endif
set_disk_ro(sdkp->disk, sdkp->write_prot);
if (sdkp->first_scan || old_wp != sdkp->write_prot) {
sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n",
sdkp->write_prot ? "on" : "off");
sd_printk(KERN_DEBUG, sdkp, "Mode Sense: %4ph\n", buffer);
}
}
}

/* set scsi disk read only */
void set_sd_ro(struct scsi_disk *sdkp)
{
struct us_data *us;
struct usb_device *udev;
int flag;

if (!strcmp(sdkp->device->host->hostt->name, "usb-storage")) {
us = host_to_us(sdkp->device->host);
flag = usb_rule_storage_match(us->pusb_dev->bus->bus_name, us->pusb_dev->devpath, get_raw_devpath(us->pusb_dev));
if (flag) {
sdkp->write_prot = 1;
sd_printk(KERN_NOTICE, sdkp, "usb rule match,set sd Write Protect");
}
}
else if (!strcmp(sdkp->device->host->hostt->name, "uas"))
{
udev = get_uas_udev(sdkp->device->host);
flag = usb_rule_storage_match(udev->bus->bus_name, udev->devpath, get_raw_devpath(udev));
if (flag) {
sdkp->write_prot = 1;
sd_printk(KERN_NOTICE, sdkp, "usb rule match,set sd Write Protect");
}
}
}
EXPORT_SYMBOL(set_sd_ro);

ext4文件系统针对usb智能管控修复

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
64
65
66
67
68
69
70
71
72
73
char *find_usb_port_path(struct super_block *sb) {
struct device *dev;
struct device *parent;
char *raw_path = NULL;
char *converted_path = NULL;
int i = 0, j = 0;
bool first_segment_skipped = false;

if (!sb->s_bdev || !sb->s_bdev->bd_disk) {
return NULL;
}

dev = disk_to_dev(sb->s_bdev->bd_disk);
if (!dev) {
return NULL;
}

for (parent = dev->parent; parent; parent = parent->parent) {
if (parent->bus && strcmp(parent->bus->name, "usb") == 0) {
raw_path = dev_name(parent);
if (!raw_path) {
return NULL;
}

converted_path = kzalloc(strlen(raw_path) + 1, GFP_KERNEL);
if (!converted_path) {
return NULL;
}

while (raw_path[i] != '\0') {
if (!first_segment_skipped) {
if (raw_path[i] == '-') {
first_segment_skipped = true;
}
} else {
if (raw_path[i] == '-') {
converted_path[j++] = '.';
} else if (raw_path[i] == ':') {
break;
} else {
converted_path[j++] = raw_path[i];
}
}
i++;
}
converted_path[j] = '\0';
return converted_path;
}
}
return NULL;
}

static int ext4_fill_super(struct super_block *sb, void *data, int silent)
{
......
if (ext4_has_feature_mmp(sb) && !sb_rdonly(sb))
if (ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block)))
goto failed_mount3a;

#ifdef CONFIG_USB_SMARTCTL
char *usb_path = NULL;
usb_path = find_usb_port_path(sb);
if (usb_path) {
if (check_usb_smart_status(usb_path)) {
set_opt(sb, NOLOAD); //禁用日志恢复功能
}
kfree(usb_path);
} else {
kfree(usb_path);
}
#endif
......
}

xfs文件系统修复

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include <linux/genhd.h>
#include <linux/blkdev.h>

static char *xfs_find_usb_port_path(struct xfs_mount *mp)
{
struct device *dev;
struct device *parent;
char *raw_path = NULL;
char *converted_path = NULL;
int i = 0, j = 0;
bool first_segment_skipped = false;

if (!mp->m_ddev_targp || !mp->m_ddev_targp->bt_bdev || !mp->m_ddev_targp->bt_bdev->bd_disk)
return NULL;

dev = disk_to_dev(mp->m_ddev_targp->bt_bdev->bd_disk);
if (!dev) {
return NULL;
}

for (parent = dev->parent; parent; parent = parent->parent) {
if (parent->bus && strcmp(parent->bus->name, "usb") == 0) {
raw_path = dev_name(parent);
if (!raw_path) {
return NULL;
}

converted_path = kzalloc(strlen(raw_path) + 1, GFP_KERNEL);
if (!converted_path) {
return NULL;
}

while (raw_path[i] != '\0') {
if (!first_segment_skipped) {
if (raw_path[i] == '-') {
first_segment_skipped = true;
}
} else {
if (raw_path[i] == '-') {
converted_path[j++] = '.';
} else if (raw_path[i] == ':') {
break;
} else {
converted_path[j++] = raw_path[i];
}
}
i++;
}
converted_path[j] = '\0';
return converted_path;
}
}
return NULL;
}

int
xfs_mountfs(
struct xfs_mount *mp)
{
struct xfs_sb *sbp = &(mp->m_sb);
struct xfs_inode *rip;
struct xfs_ino_geometry *igeo = M_IGEO(mp);
uint64_t resblks;
uint quotamount = 0;
uint quotaflags = 0;
int error = 0;
......
if (XFS_IS_CORRUPT(mp, !sbp->sb_logblocks)) {
xfs_warn(mp, "no log defined");
error = -EFSCORRUPTED;
goto out_free_perag;
}

/*
* Log's mount-time initialization. The first part of recovery can place
* some items on the AIL, to be handled when recovery is finished or
* cancelled.
*/
#ifdef CONFIG_USB_SMARTCTL
char *usb_path = NULL;
usb_path = xfs_find_usb_port_path(mp);
if (usb_path) {
if (check_usb_smart_status(usb_path)) {
mp->m_flags |= XFS_MOUNT_NORECOVERY; //禁用日志恢复功能
}
kfree(usb_path);
}
#endif

usb智能管控
https://tomwithkernel.github.io/bug/usb智能管控/
作者
Tom
发布于
2025年5月7日
更新于
2025年5月7日
许可协议