Chinaunix首页 | 论坛 | 博客
  • 博客访问: 534316
  • 博文数量: 103
  • 博客积分: 2024
  • 博客等级: 上尉
  • 技术积分: 1294
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-08 21:17
文章分类

全部博文(103)

文章存档

2012年(2)

2011年(21)

2010年(80)

分类: LINUX

2010-08-04 14:42:06

Description of problem:
Almost all igmp functions accessing inet->mc_list are protected by
rtnl_lock(), but there is one exception which is ip_mc_sf_allow(),
so there is a chance of either ip_mc_drop_socket or ip_mc_leave_group
remove an entry while ip_mc_sf_allow is running causing a crash.

call-trace
ip_mc_sf_allow()
udp_v4_mcast_next()
__udp4_lib_mcast_deliver()
__udp4_lib_rcv()
udp_rcv()
[] ip_local_deliver+0x159/0x204
[] ip_rcv+0x46f/0x4a9
[] netif_receive_skb+0x30c/0x330
[] e1000_clean_rx_irq+0xf0/0x3e0 [e1000]
[] e1000_clean_rx_irq+0x0/0x3e0 [e1000]
[] e1000_clean+0xf4/0x340 [e1000]
[] do_IRQ+0xb5/0xc3
[] net_rx_action+0x92/0x175
[] __do_softirq+0x87/0x114
[] do_softirq+0x52/0x9c
[] apic_timer_interrupt+0x1f/0x24

so when recevice upd-mc packate,and ip_mc_sf_allow is called,there is a race that
when ip_mc_leave_group,and ip_mc_leave_group has the following code:


   1865 rtnl_lock();
1866 in_dev = ip_mc_find_dev(net, imr);
1867 ifindex = imr->imr_ifindex;
1868 for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) {
1869 if (iml->multi.imr_multiaddr.s_addr != group)
1870 continue;
1871 if (ifindex) {
1872 if (iml->multi.imr_ifindex != ifindex)
1873 continue;
1874 } else if (imr->imr_address.s_addr && imr->imr_address.s_addr !=
1875 iml->multi.imr_address.s_addr)
1876 continue;
1877
1878 (void) ip_mc_leave_src(sk, iml, in_dev);
1879
1880 rcu_assign_pointer(*imlp, iml->next);
1881
1882 if (in_dev)
1883 ip_mc_dec_group(in_dev, group);
1884 rtnl_unlock();
1885 /* decrease mem now to avoid the memleak warning */
1886 atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
1887 call_rcu(&iml->rcu, ip_mc_socklist_reclaim);
1888 return 0;
1889 }
1890 if (!in_dev)
1891 ret = -ENODEV;
1892 rtnl_unlock();

is protected by rtnl_lock,and here is the ip_mc_sf_allow():

2169 for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
2170 if (pmc->multi.imr_multiaddr.s_addr == loc_addr &&
2171 pmc->multi.imr_ifindex == dif)
2172 break;
2173 }

and new version

2248 rcu_read_lock();
2249 for (pmc=rcu_dereference(inet->mc_list); pmc; pmc=rcu_dereference(pmc->next)) {
2250 if (pmc->multi.imr_multiaddr.s_addr == loc_addr &&
2251 pmc->multi.imr_ifindex == dif)
2252 break;
2253 }

and the matter left is how to trigger this
1,recive multicast date
2,leave multicast group


and this is the core test code:

167 pid = fork();
168 while (1) {
169
170 if (pid == 0) {
171 join(fd, MY_GROUP1);
172 join(fd, MY_GROUP2);
173 join(fd, MY_GROUP3);
174 join(fd, MY_GROUP4);
175 usleep(15);
176 drop(fd, MY_GROUP3);
177 drop(fd, MY_GROUP2);
178 drop(fd, MY_GROUP4);
179 drop(fd, MY_GROUP1);
180 usleep(5);
181 }
182 else {
183 nbytes = recvfrom(fd, buffer, MSGSIZE, 0,
184 (struct sockaddr *) &addr,&addrlen);
185 printf("%s\n",buffer);
186 if (nbytes < 0) {
187 perror("recvfrom");
188 exit(1);
189 }
190 }
191 }


19 void join(int fd, char *address)
20 {
21 struct ip_mreq mreq;
22 struct sockaddr_in addr;
23 struct in_addr local;
24 int addrlen;
25 int ret;
26
27 mreq.imr_multiaddr.s_addr = inet_addr(address);
28 mreq.imr_interface.s_addr = inet_addr("10.66.65.173");
29 addrlen = sizeof(addr);
30 /* join the multicast group */
31 ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
32 &mreq, sizeof(mreq));
33 if (ret < 0) {
34 perror("setsockopt IP_ADD_MEMBERSHIP");
35 exit(1);
36 }
37 }

so greate
文件:repro.tar.bz2
大小:1KB
下载:下载
阅读(1224) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~