RT-Thread论坛
直播中

安德森大

9年用户 1365经验值
擅长:接口/总线/驱动
私信 关注
[问答]

如何将设USB存储设备设为只读?

rt thread 设USB存储设备设为只读的方法,已经尝试了:

  • 1、rt_device_register((rt_device_t)&_stm_udc, "usbd", RT_DEVICE_FLAG_RDONLY);
  • 2、if(rt_device_open(data->disk, RT_DEVICE_OFLAG_RDONLY) != RT_EOK);


都无法将USB设备权限改为只读,改为只读的原因是,设备的历史记录PC只有只读权限,类似黑匣子功能。

回帖(1)

王波

2025-9-19 17:50:40

在RT-Thread中将USB存储设备设为只读,需要从设备驱动层文件系统层双重控制。根据您的描述,仅设置设备标志可能不足够,以下是完整的解决方案:




根本原因分析



  1. 设备层标志(RT_DEVICE_FLAG_RDONLY):仅控制RT-Thread设备框架的访问权限,未传递到底层USB驱动。

  2. 打开标志(RT_DEVICE_OFLAG_RDONLY):同样被部分USB驱动忽略。

  3. USB大容量存储协议(MSC):需在SCSI命令层拦截写操作。




解决方案分三步实现


步骤1: 修改USB设备驱动(关键)


在USB MSC协议层拦截写命令,直接返回写保护错误。修改usb_device_msc.c中的SCSI命令处理函数:


/* 在SCSI命令分发函数中添加 */
switch (cbw->CBWCB[0]) {
    case SCSI_WRITE10:
    case SCSI_WRITE12:
    case SCSI_WRITE16:
        /* 强制返回写保护状态 */
        msc->sense_data = SENSE_DATA(WRITE_PROTECTED);
        rt_usbd_ep0_send_status(device); // 返回错误状态
        return RT_EOK;
    default:
        /* 其他命令正常处理 */
        break;
}

步骤2: 文件系统只读挂载


在挂载文件系统时指定只读标志:


#include 

/* 挂载时添加FS_READONLY标志 */
if (dfs_mount("usbd", "/", "elm", FS_READONLY, 0) != 0) {
    rt_kprintf("Mount failed!n");
}

步骤3: 读写访问双重拦截(可选加固)


在块设备操作表中拦截写操作:


static rt_err_t block_write(rt_device_t dev, rt_off_t pos, const void *buf, rt_size_t size) {
    /* 强制返回写保护错误 */
    return -RT_EPERM;
}

/* 在设备初始化中重写写操作函数 */
static struct rt_device_ops blk_ops = {
    .read  = block_read,
    .write = block_write, // 指向自定义写拦截函数
};
rt_device_register(&blk_dev, "usbd", RT_DEVICE_FLAG_RDONLY);



验证方法



  1. 驱动层验证:插入USB后尝试写入,观察是否返回WRITE_PROTECTED SENSE KEY。

  2. 文件系统验证:执行echo "test" > /file.txt 应提示Permission denied

  3. 应用层验证:在PC端连接设备,尝试格式化/删除文件应失败。




补充建议



  1. 物理写保护开关:如果硬件支持,可结合GPIO控制USB电源(如检测到写操作时切断供电)。

  2. 日志审计:在拦截写操作时记录安全事件:
    rt_kprintf("[SECURITY] Write attempt blocked at %dn", rt_tick_get());


通过以上三层防护(驱动层+文件系统层+可选块设备层),可实现可靠的黑匣子功能。最终效果取决于USB驱动对SCSI命令的处理,请重点检查驱动中的usb_device_msc.c实现。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分