You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32 AsyncUDP回调调用libsodium解密触发Stack canary观测点报错

问题根因

AsyncUDP的收包回调执行在LwIP内置的UDP处理任务上下文中,该任务默认栈大小通常仅为2~4KB。你调用的Argon2密码哈希算法属于计算密集型操作,内部会占用大量栈空间,非回调场景(比如loop函数)测试时,Arduino ESP32核心默认给loop任务分配的栈大小在8KB以上,所以足够运行,但是在UDP回调的小栈环境下就会发生栈溢出,触发栈金丝雀检测报错。

具体解决方案

1. 先修复已知代码错误

你的代码目前存在两个会直接触发崩溃的逻辑问题:

  • 修复decode_packet函数语法错误:校验包合法性的if分支缺少闭合大括号,导致后续解密逻辑永远不会执行,修正后代码如下:
if (size != 70 || pkt->id[0] != 0xDE || pkt->id[1] != 0xAD || pkt->id[2] != 0xBE) {
  return decrypted;
}
// 后续解密逻辑放在if分支外
  • 修复空指针访问漏洞:stretchPasswordArgon返回NULL时直接终止解密,不要把空指针传入解密函数:
unsigned char* stretchPass = stretchPasswordArgon(truncatedPassword, pkt->salt, &opslimit, &memlimit); 
if (stretchPass == NULL) {
  Serial.println("Error making stretchpass!\n");
  return decrypted;
}
decrypted = decryptBroadcastNotification(pkt, stretchPass);

2. 异步处理重计算逻辑(核心解决方案)

不要在AsyncUDP的onPacket回调中直接执行解密、密码拉伸这类重负载操作,改为用FreeRTOS队列转存收到的UDP包,交给单独创建的解密任务处理:

  • 创建FreeRTOS队列用于缓存待处理的UDP数据包
  • 创建独立的解密处理任务,将任务栈大小设置为至少16KB(可根据实际运行情况调整)
  • onPacket回调中仅做数据包拷贝,将数据包推送到队列后立即返回
  • 解密任务循环从队列取数据,执行解密、密码拉伸、业务逻辑处理

3. 优化冗余计算降低资源消耗

Doorbird的广播包中salt、opslimit、memlimit参数通常不会频繁变更,你可以将第一次拉伸后的密钥缓存起来,后续收到同参数的包时直接复用,不需要每次都执行高开销的Argon2计算,大幅降低栈占用和CPU消耗。

4. 可选临时测试方案(不推荐长期使用)

如果仅需要临时测试验证,可以在Arduino SDK配置中增大LwIP任务的栈大小,但修改系统内置任务的栈参数可能引发其他未知兼容性问题,不建议在生产环境使用。

内容的提问来源于stack exchange,提问作者user2761903

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 16:15:02