全局数组未加锁访问溢出导致踩内存
在客户那里发现有些数据包被错误的转到了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_ifs
和knet_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 也就是越界的,就直接踩到了后面的三个字段