全局数组未加锁访问溢出导致才内存

发布时间 2023-09-25 11:49:07作者: 枝桠

在客户那里发现有些数据包被错误的转到了standby SMM上,后面查看 proc 发现是 knet.ko 中的 role 字段被踩
后面再检查发现有三个字段都被踩:

zyc@fish smm_arm64 (/≧▽≦)/ ~/do_not_remove/aarch64-marvell-linux-gnu-nm linux-casa-knet.ko | grep smm_role
0000000006925110 B smm_role
zyc@fish smm_arm64 (/≧▽≦)/ ~/do_not_remove/aarch64-marvell-linux-gnu-nm linux-casa-knet.ko | grep 0000000692
0000000006925108 B protocol_flap_enabled     <====== 0x26f8bdc8
000000000692510c B product_type              <====== 0x133000b7
0000000006925110 B smm_role                  <====== 0xffff8002
0000000006925118 B knet_active_ifs
0000000006925120 B knet_ifs

后面的knet_active_ifsknet_ifs看起来是没问题的
也就是说,内存被踩的时候是从低往高处踩,那么就看看 protocol_flap_enabled 前面的是什么

zyc@fish smm_arm64 (/≧▽≦)/ ~/do_not_remove/aarch64-marvell-linux-gnu-nm linux-casa-knet.ko | grep -E  "000000069[12]|000000068[abcdef]"
..........
00000000068a10ec b tx_free_buf_to_user_cnt
00000000068a1078 b tx_oom_drops
00000000068a5108 B casa_events
0000000006925108 B protocol_flap_enabled
000000000692510c B product_type
0000000006925110 B smm_role
0000000006925120 B knet_ifs
0000000006925118 B knet_active_ifs

casa_events 是一个全局数组,占用内存 0.5M

检查代码发现, casa_events 只在一个函数中会修改其内容:

 540 void
 541 casa_event_tracer(int trace_id, unsigned int arg0, unsigned int arg1)
 542 {
 543     int i;
 544     casa_event_t *ev;
 545     struct timespec event_time;
 546
 547     // if not tracing (like when dumping), stop tracing
 548     if (!casa_tracing_events)
 549     {
 550         return;
 551     }
 552
 553     i = casa_cur_event++;       <--- casa_cur_event 指向最新的一个空槽位。 先赋值,再自增
 554     casa_cur_event &= (CASA_EVENT_ARRAY_SIZE-1);       <--- 超出界限,则回滚到起点
 555
 556     // set the time
 557     ev = &casa_events[i];
 558     getnstimeofday(&event_time);
 559
 560     ev->time_ns = event_time.tv_nsec;
 561
 562     // fill in event id (with time seconds)
 563     ev->event = (unsigned int)(trace_id | (event_time.tv_sec << 16));
 564
 565     // fill in the data
 566     ev->data1 = (unsigned int)arg0;
 567     ev->data2 = (unsigned int)arg1;
 568
 569 }


事实上,确实就是上面553、554两行出的问题
casa_cur_event == CASA_EVENT_ARRAY_SIZE 指向最后一个槽位时
如果两个线程同时去执行 553、554行
线程 A 执行完 553 行但是还没有执行 554 行时,此刻casa_cur_event 就会越出边界
如果这时调度到线程 B 去运行,那么执行 553 行时,得到的 i 也就是越界的,就直接踩到了后面的三个字段