跳转到内容
新建笔记

项目1:单片机程序审查,控制系统安全漏洞分析和改进建议

本分析基于以下维度进行评估:

  • 严重程度: 🔴高危 🟡中危 🟢低危
  • 影响范围: 系统级 / 模块级 / 功能级
  • 利用难度: 容易 / 中等 / 困难
  • 修复优先级: P0(立即) / P1(高) / P2(中) / P3(低)

1.2 发现的主要问题类别

跳转到“1.2 发现的主要问题类别”
  1. 输入验证不足 - 缺乏参数范围检查
  2. 并发安全问题 - 竞态条件和数据竞争
  3. 内存安全问题 - 缓冲区溢出风险
  4. 错误处理不当 - 异常情况处理不完善
  5. 安全机制薄弱 - 缺乏深度防护
  6. 调试信息泄露 - 生产环境包含调试代码

2.1.1 Modbus参数无范围检查

跳转到“2.1.1 Modbus参数无范围检查”

位置: mb_slave.c:UpdateBalanceInputFromModbus() 严重程度: 🔴 高危 影响范围: 系统级

// 问题代码
case HOLD_MEASURE_SPEED:
g_servoController.balanceInput.measureSpeed = (int32_t)value; // 无验证
g_servoController.writeInOutDataCache[0] = (uint32_t)value;
break;

风险描述:

  • 恶意输入可能导致伺服电机异常运行
  • 超出安全范围的参数可能损坏设备
  • 可能触发未定义行为

修复建议:

// 改进代码
#define SPEED_MIN 0
#define SPEED_MAX 3000
#define ACCEL_MIN 1
#define ACCEL_MAX 100
case HOLD_MEASURE_SPEED:
if(value >= SPEED_MIN && value <= SPEED_MAX) {
g_servoController.balanceInput.measureSpeed = (int32_t)value;
g_servoController.writeInOutDataCache[0] = (uint32_t)value;
} else {
return MB_DATA_ERR; // 返回参数错误
}
break;

2.1.2 32位参数合成缺乏验证

跳转到“2.1.2 32位参数合成缺乏验证”

位置: mb_slave.c:mb_slave_10h_v2() 严重程度: 🟡 中危

// 问题代码
if(byte_count == 4 && size == 2) {
uint16_t high_value = (port->rx_buf[9] << 8) + port->rx_buf[10];
uint16_t low_value = (port->rx_buf[7] << 8) + port->rx_buf[8];
int32_t full_value = ((int32_t)high_value << 16) | low_value; // 无范围检查
UpdateBalanceInputFromModbus32Bit(hold_addr, high_value, low_value);
}

修复建议: 添加32位值的合理性检查

2.2.1 全局变量竞态条件

跳转到“2.2.1 全局变量竞态条件”

位置: tigerservo.c 多处 严重程度: 🔴 高危 影响范围: 系统级

// 问题代码
g_servoController.isDataDifferent = true; // 多线程访问无保护
// 在不同任务中同时访问
// servoTask: 读取和修改
// modbusTask: 读取和修改
// systemTask: 读取

风险描述:

  • 数据竞争可能导致状态不一致
  • 可能导致系统逻辑错误
  • 难以调试和重现的间歇性故障

修复建议:

// 使用原子操作或互斥锁保护
void SafeSetDataDifferent(bool value) {
osStatus_t status = osMutexAcquire(globalVarMutexHandle, osWaitForever);
if(status == osOK) {
g_servoController.isDataDifferent = value;
osMutexRelease(globalVarMutexHandle);
}
}
bool SafeGetDataDifferent(void) {
bool result = false;
osStatus_t status = osMutexAcquire(globalVarMutexHandle, osWaitForever);
if(status == osOK) {
result = g_servoController.isDataDifferent;
osMutexRelease(globalVarMutexHandle);
}
return result;
}

2.2.2 按钮状态竞态条件

跳转到“2.2.2 按钮状态竞态条件”

位置: button_control.c:ButtonControl_ProcessEvents() 严重程度: 🟡 中危

// 问题代码
static ButtonEvent_t Button_GetEvent(ButtonType_t button_type) {
return g_buttonControl.status[button_type].event; // 无锁保护
}
static void Button_ClearEvent(ButtonType_t button_type) {
g_buttonControl.status[button_type].event = BUTTON_EVENT_NONE; // 无锁保护
}

2.3.1 稀疏数组容量溢出

跳转到“2.3.1 稀疏数组容量溢出”

位置: mb_reg.c:insert_or_update() 严重程度: 🟡 中危 影响范围: 模块级

// 问题代码
if(map->count >= map->capacity) {
return -1; /* 容量已满 - 静默失败 */
}

风险描述:

  • 静默失败可能导致数据丢失
  • 无法动态扩容,系统功能受限
  • 可能导致后续操作失败

修复建议:

// 改进版本
typedef enum {
REG_OP_SUCCESS = 0,
REG_OP_CAPACITY_FULL,
REG_OP_INVALID_PARAM,
REG_OP_MEMORY_ERROR
} RegOpResult_t;
RegOpResult_t mb_reg_write_safe(RegMap_t *map, uint16_t addr, uint16_t value) {
if(map == NULL) return REG_OP_INVALID_PARAM;
int result = insert_or_update(map, addr, value);
if(result == -1) {
// 记录错误日志
printf("ERROR: Register map capacity full, addr=0x%04X\n", addr);
return REG_OP_CAPACITY_FULL;
}
return REG_OP_SUCCESS;
}

2.3.2 数组边界检查缺失

跳转到“2.3.2 数组边界检查缺失”

位置: 多个文件中的数组访问 严重程度: 🟡 中危

// 问题代码示例
g_servoController.writeInOutDataCache[g_servoController.writeIndex] = value;
// 未检查 writeIndex 是否在有效范围内

2.4.1 通信错误恢复不完善

跳转到“2.4.1 通信错误恢复不完善”

位置: tigerservo.c:ServoController_Task() 严重程度: 🟡 中危

// 问题代码
if(g_servoController.mb.commErrorCount > 10) {
servo_initialized = false; // 简单重置,可能丢失重要状态
g_servoController.mb.commErrorCount = 0;
}

修复建议:

// 改进的错误恢复机制
typedef struct {
uint32_t consecutive_errors;
uint32_t total_errors;
uint32_t last_success_time;
bool recovery_in_progress;
} CommErrorContext_t;
void ImprovedErrorRecovery(CommErrorContext_t *ctx) {
if(ctx->consecutive_errors > ERROR_THRESHOLD_RESET) {
// 执行更智能的恢复策略
SaveCurrentState(); // 保存当前状态
PerformGradualRecovery(); // 渐进式恢复
RestoreValidState(); // 恢复有效状态
ctx->recovery_in_progress = true;
}
}

位置: mb_slave.c:mb_recv_check() 严重程度: 🟡 中危

// 问题代码
if(mb_recv_check(port) == 0) {
// 处理有效数据
} else {
// 数据错误,但错误处理简单
mb_error_ack_send(uart, port, MB_DATA_ERR);
}

2.5.1 紧急停止逻辑不完善

跳转到“2.5.1 紧急停止逻辑不完善”

位置: button_control.c:Button_HandleEmergencyStop() 严重程度: 🔴 高危

// 问题代码
if(event == BUTTON_EVENT_PRESSED) {
A3Servo_EmergencyStop();
osDelay(2000); // 固定延时,未确认实际停止
Valve_SafeOpen();
}

风险描述:

  • 固定延时无法保证伺服完全停止
  • 缺乏停止确认机制
  • 可能在伺服未完全停止时释放工件

修复建议:

// 改进的急停处理
typedef enum {
ESTOP_PHASE_INIT,
ESTOP_PHASE_SERVO_STOPPING,
ESTOP_PHASE_SERVO_STOPPED,
ESTOP_PHASE_VALVE_OPENING,
ESTOP_PHASE_COMPLETE
} EstopPhase_t;
void ImprovedEmergencyStop(void) {
EstopPhase_t phase = ESTOP_PHASE_INIT;
uint32_t timeout = HAL_GetTick() + 5000; // 5秒超时
while(phase != ESTOP_PHASE_COMPLETE && HAL_GetTick() < timeout) {
switch(phase) {
case ESTOP_PHASE_INIT:
A3Servo_EmergencyStop();
phase = ESTOP_PHASE_SERVO_STOPPING;
break;
case ESTOP_PHASE_SERVO_STOPPING:
if(ConfirmServoStopped()) {
phase = ESTOP_PHASE_SERVO_STOPPED;
}
break;
case ESTOP_PHASE_SERVO_STOPPED:
Valve_SafeOpen();
phase = ESTOP_PHASE_VALVE_OPENING;
break;
case ESTOP_PHASE_VALVE_OPENING:
if(ConfirmValveOpened()) {
phase = ESTOP_PHASE_COMPLETE;
}
break;
}
osDelay(10);
}
if(phase != ESTOP_PHASE_COMPLETE) {
// 记录严重错误,进入故障保护模式
LogCriticalError("Emergency stop sequence failed");
EnterFailSafeMode();
}
}

2.5.2 气阀安全互锁不够严格

跳转到“2.5.2 气阀安全互锁不够严格”

位置: valveControl.c:Valve_IsSafeToOperate() 严重程度: 🟡 中危

// 问题代码
if(g_buttonControl.emergency_stop_active) {
return true; // 急停时允许所有气阀操作,可能不安全
}

2.6.1 生产代码包含调试输出

跳转到“2.6.1 生产代码包含调试输出”

位置: 多个文件中被注释的printf语句 严重程度: 🟢 低危

// 问题代码
//printf("📡 向伺服驱动器发送急停命令...\r\n");
//printf("✅ 伺服急停命令发送成功\r\n");

修复建议: 使用条件编译控制调试输出

2.7 看门狗机制不完善 🟡

跳转到“2.7 看门狗机制不完善 🟡”

2.7.1 看门狗喂狗逻辑简单

跳转到“2.7.1 看门狗喂狗逻辑简单”

位置: watchdog_manager.c (推测) 严重程度: 🟡 中危

修复建议:

// 改进的看门狗机制
typedef struct {
uint32_t task_id;
uint32_t last_checkin;
uint32_t timeout_threshold;
bool is_critical;
} TaskHealthInfo_t;
void WatchdogManager_TaskCheckin(uint32_t task_id) {
TaskHealthInfo_t *info = GetTaskInfo(task_id);
if(info) {
info->last_checkin = HAL_GetTick();
if(AllCriticalTasksHealthy()) {
HAL_IWDG_Refresh(&hiwdg);
}
}
}
漏洞类别严重程度修复难度优先级预计工时
Modbus参数验证🔴容易P02天
全局变量竞态条件🔴中等P03天
紧急停止逻辑🔴中等P02天
稀疏数组溢出🟡容易P11天
错误恢复机制🟡困难P15天
按钮竞态条件🟡容易P21天
调试信息清理🟢容易P30.5天
// 统一的参数验证框架
typedef struct {
int32_t min_value;
int32_t max_value;
uint32_t flags; // 验证标志
} ParamConstraint_t;
typedef enum {
VALIDATION_SUCCESS = 0,
VALIDATION_OUT_OF_RANGE,
VALIDATION_INVALID_TYPE,
VALIDATION_CONSTRAINT_VIOLATION
} ValidationResult_t;
ValidationResult_t ValidateParameter(uint16_t param_id, int32_t value) {
const ParamConstraint_t *constraint = GetParamConstraint(param_id);
if(value < constraint->min_value || value > constraint->max_value) {
LogSecurityEvent("Parameter out of range", param_id, value);
return VALIDATION_OUT_OF_RANGE;
}
// 其他约束检查...
return VALIDATION_SUCCESS;
}
// 独立的安全监控状态机
typedef enum {
SAFETY_STATE_INIT,
SAFETY_STATE_NORMAL,
SAFETY_STATE_WARNING,
SAFETY_STATE_EMERGENCY,
SAFETY_STATE_LOCKDOWN
} SafetyState_t;
typedef struct {
SafetyState_t current_state;
uint32_t warning_count;
uint32_t last_check_time;
bool override_enabled;
} SafetyContext_t;
void SafetyStateMachine_Update(SafetyContext_t *ctx) {
switch(ctx->current_state) {
case SAFETY_STATE_NORMAL:
if(DetectAbnormalCondition()) {
ctx->current_state = SAFETY_STATE_WARNING;
ctx->warning_count++;
}
break;
case SAFETY_STATE_WARNING:
if(ctx->warning_count > WARNING_THRESHOLD) {
ctx->current_state = SAFETY_STATE_EMERGENCY;
TriggerEmergencyProcedure();
}
break;
// 其他状态处理...
}
}
// 安全事件记录
typedef enum {
AUDIT_PARAM_CHANGE,
AUDIT_EMERGENCY_STOP,
AUDIT_COMM_ERROR,
AUDIT_ACCESS_VIOLATION,
AUDIT_SYSTEM_ERROR
} AuditEventType_t;
void LogSecurityEvent(AuditEventType_t type, uint32_t param1, uint32_t param2) {
AuditRecord_t record = {
.timestamp = HAL_GetTick(),
.event_type = type,
.param1 = param1,
.param2 = param2,
.checksum = CalculateChecksum(&record, sizeof(record) - sizeof(uint32_t))
};
WriteToSecureLog(&record);
}
#ifdef FAULT_INJECTION_ENABLED
// 故障注入框架用于测试
typedef enum {
FAULT_COMM_TIMEOUT,
FAULT_PARAM_CORRUPTION,
FAULT_MEMORY_ERROR,
FAULT_SENSOR_FAILURE
} FaultType_t;
void InjectFault(FaultType_t fault_type, uint32_t duration_ms) {
// 模拟各种故障情况,测试系统响应
}
#endif
  • 所有外部输入都经过验证
  • 所有数组访问都有边界检查
  • 关键数据结构有并发保护
  • 错误处理覆盖所有异常情况
  • 安全相关操作有确认机制
  • 调试代码已从生产版本移除
  • 内存分配都有失败处理
  • 通信超时有合理的重试机制
  • 状态转换逻辑完整
  • 看门狗机制覆盖所有关键任务
  • 持久化数据有完整性保护
  • 关键路径没有阻塞操作
  • 内存使用在预期范围内
  • 任务优先级设置合理
  • 中断处理函数简短高效
  1. 设计阶段: 威胁建模和安全需求分析
  2. 开发阶段: 安全编码规范和静态分析
  3. 测试阶段: 安全测试和渗透测试
  4. 部署阶段: 安全配置和监控
  5. 维护阶段: 定期安全评估和更新
  • 静态分析工具: PC-lint, Cppcheck, 或商业工具
  • 动态测试: 模糊测试和压力测试
  • 代码审查: 强制性的同行评审流程
  • 安全培训: 定期的安全意识培训
  • 实时监控: 系统行为异常检测
  • 事件响应: 安全事件的快速响应流程
  • 定期评估: 季度安全评估和改进
  • 总体评价: 中等安全水平
  • 主要优势: 架构设计合理,有基本的安全意识
  • 主要不足: 输入验证不足,并发安全有隐患
  1. 立即修复: 输入验证和并发安全问题
  2. 短期改进: 完善错误处理和安全机制
  3. 长期规划: 建立完整的安全开发体系
  • 高风险: 1个(输入验证)
  • 中风险: 5个(并发安全、内存安全等)
  • 低风险: 2个(调试信息、性能优化)

建议优先处理高风险和中风险问题,以确保系统在生产环境中的安全稳定运行。


安全分析报告生成时间: 2024年 分析深度: 详细代码审查 覆盖范围: 全系统安全评估


来源:CSDN 原文,首次发布于 2025-09-11。