开启辅助访问 切换到窄版

打印 上一主题 下一主题

当运行Linux内核的机器死机时…

[复制链接]
作者:Ds—shiqi 
版块:
嵌入式操作系统 linux 发布时间:2020-12-22 04:55:30
11490
楼主
跳转到指定楼层
| 只看该作者 回帖奖励 |倒序浏览 |阅读模式
【CSDN 编者按】事件陷入死地无可挽救之际,可能会有人选择不了了之,有人选择就此放弃……但换个思路想一想,既然都无可挽回了,那干嘛不试试弄点有价值的信息回来?

作者 |dog250 责编 | 张文
头图 | CSDN 下载自视觉中国
出品 | CSDN(ID:CSDNnews)曾经写过一个模块,当运行 Linux 内核的机器死机时,SSH肯定无法登录了,但只要它还响应中断,就尽力让它可以通过网络带回一些信息。陈年的事了:
http://blog.csdn.net/dog250/article/details/43370611
今日重提这件事,不陌生,但纠结。本文不谈 sysrq,也不谈别的。Linux 内核在发生 soft lockup 的时候,是可以 ping 通的,只要没有关中断,ping 通一般没有问题。既然可以 ping 通,何必不带回一些真正重要的信息而不仅仅是 echo 的 reply?且慢,你可能会觉得这一切没有意义,懂 kdump 的人都会这么抬杠,毕竟如果这个时候让内核 panic 掉,保留一个 vmcore,事后便可以随便分析了。哈哈,我也不是不懂 kdump,我当然懂得如何分析 vmcore,我只是不信任它而已。我不觉得它保留有足够的信息,相比之下,我只想知道在事故发生的当时,到底发生了什么。因此,我需要尽可能的去 debug 将死未死的系统,也就是说,我想要获取已经 soft lockup 的内核的信息。如果你重启了内核,保留了一具 vmcore 尸体,如果是攻击的情况,很可能在系统重启的过程中,攻击者就发觉了,暂停了攻击或者更改了方式…不要在既有的框架内就事论事,找些没文化的流氓一起讨论会比和经理讨论可能更有收获。有的时候我不想争论,不是说我不善于争论,而是我觉得和我争论的人根本不知道我在说什么,唉。SSH 已经不能指望了,怎么办?想法简单,不足道,仅仅是个 POC,也希望能有人一起讨论:

  • 注册一个新的四层协议,除了 TCP/UDP/ICMP 等熟知协议之外的新协议,这是为了避免每一个数据包都要经过过滤,避免影响性能。
  • 事先分配 skb,避免当事故发生时回送信息时分配 skb 失败。
好了,看代码,先给出载入内核的代码,这个代码的大部分都是我从网上抄来的,并不是自己写的,我只是重组了逻辑:#include#include#include#include#defineIPPROTO_MYPROTO 123#defineQUOTA 30structsk_buff*eskb[QUOTA];staticintquota = QUOTA -1;//module_param(quota, int, 0644);//MODULE_PARM_DESC(quota, "soft_lockup");unsignedshort_csum(unsignedshort* data,intlen){intpad =0;inti =0;unsignedshortret =0;unsignedintsum =0;if(len %2!=0)pad =1;len /=2;for( i =0; i < len; i++) {sum += data;}if(pad ==1)sum += ((unsignedchar*)(data + len))[0] ;sum = (sum &0xffff) + (sum >>16);sum += (sum >>16);ret = ~sum;returnret;}intmyproto_rcv(struct sk_buff *skb){structudphdr*uh, *euh;structiphdr*iph, *eiph;structethhdr*eh, *ethh;charesaddr[6];unsignedchar*pos;if(quota ip_summed = CHECKSUM_NONE;eskb[quota]->protocol = htons(ETH_P_IP);eskb[quota]->priority =0;eskb[quota]->dev = skb->dev;eskb[quota]->pkt_type = PACKET_OTHERHOST;skb_reserve(eskb[quota],1300+sizeof(struct ethhdr) +sizeof(struct iphdr) +sizeof(struct udphdr));pos = skb_push(eskb[quota],1300);strcpy(pos,"abcdefghijk123456789");pos = skb_push(eskb[quota],sizeof(struct udphdr));skb_reset_transport_header(eskb[quota]);euh = (struct udphdr *)pos;euh->source = uh->dest;euh->dest = uh->source;euh->len = htons(1300+sizeof(struct udphdr));euh->check =0;memcpy(pos -12, &iph->daddr,4);memcpy(pos -8, &iph->saddr,4);((unsignedshort*)(pos -4))[0] =0x1100;memcpy(pos -2, &euh->len,sizeof(euh->len));euh->check = _csum((unsignedshort*)(pos -12),12+1300+sizeof(struct udphdr));pos = skb_push(eskb[quota],sizeof(struct iphdr));skb_reset_network_header(eskb[quota]);eiph = (struct iphdr *)pos;eiph->version =4;eiph->ihl =5;eiph->tos =0;eiph->tot_len = htons(1300+sizeof(struct udphdr) +sizeof(struct iphdr));eiph->id =0x1122;eiph->frag_off =0;eiph->ttl =64;eiph->protocol =0x11;eiph->check =0;eiph->saddr = iph->daddr;eiph->daddr = iph->saddr;eiph->check = _csum((unsignedshort*)pos,sizeof(struct iphdr));pos = skb_push(eskb[quota],sizeof(struct ethhdr));skb_reset_mac_header(eskb[quota]);ethh = (struct ethhdr *)pos;memcpy(esaddr, eh->h_dest,6);memcpy(ethh->h_dest, eh->h_source, ETH_ALEN);memcpy(ethh->h_source, eh->h_dest, ETH_ALEN);ethh->h_proto = htons(ETH_P_IP);printk("myproto_rcv is called, length:%d %x %x\n", skb->len, esaddr[2], esaddr[3]);dev_queue_xmit(eskb[quota]);quota --;end:kfree_skb(skb);return0;}intmyproto_rcv_err(struct sk_buff *skb,unsignedinterr){printk("myproto_rcv is called:%d\n", err);kfree_skb(skb);return0;}staticconststructnet_protocolmyproto_protocol= {.handler = myproto_rcv,.err_handler = myproto_rcv_err,.no_policy =1,.netns_ok =1,};intinit_module(void){intret =0, i;// 事先分配skbfor(i =0; i < QUOTA; i++) {eskb = alloc_skb(1300+sizeof(struct ethhdr) +sizeof(struct iphdr) +sizeof(struct udphdr), GFP_ATOMIC);if(eskb ==NULL) {//int j;//for {//}printk("alloc failed\n");return-1;}}// 注册123协议,它不是TCP,UDP,ICMPret = inet_add_protocol(&myproto_protocol, IPPROTO_MYPROTO);if(ret) {printk("failed\n");returnret;}printk("successful\n");return0;}voidcleanup_module(void){intrc =0;inet_del_protocol(&myproto_protocol, IPPROTO_MYPROTO);//for (i = quota; i >=0; i--) {//kfree_skb(eskb);//}return;}intinit_module(void);voidcleanup_module(void);MODULE_LICENSE("GPL");来来来,看一下客户端的代码。客户端需要通过raw 套接字发送一个“请求”,它的传输层协议是 123,然而回复的却是一个标准的 UDP 报文,所以客户端需要在该 UDP 上接收。代码如下:#include#include#include#include#include#include#include#include#definePCKT_LEN 8192unsignedshortcsum(unsignedshort*buf,intnwords){unsignedlongsum;for(sum=0; nwords>0; nwords--)sum += *buf++;sum = (sum >>16) + (sum &0xffff);return(unsignedshort)(~sum);}intmain(intargc,charconst*argv){intsd, usd;structiphdr*ip;structudphdr*udp;structsockaddr_insin,usin,csin;u_int16_tsrc_port, dst_port;u_int32_tsrc_addr, dst_addr;intone =1;constint*val = &one;intdlen, rlen, clen =sizeof(csin);char*data;charbuf[1300];if(argc !=6) {printf("Usage: %s    \n", argv[0]);exit(1);}src_addr = inet_addr(argv[1]);dst_addr = inet_addr(argv[3]);src_port = atoi(argv[2]);dst_port = atoi(argv[4]);dlen = atoi(argv[5]);data =malloc(sizeof(struct iphdr) +sizeof(struct udphdr) + dlen);ip = (struct iphdr *)data;udp = (struct udphdr *)(data +sizeof(struct iphdr));sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);if(sd version =4;ip->tos =16;// low delayip->tot_len =sizeof(struct iphdr) +sizeof(struct udphdr) + dlen;ip->id = htons(54321);ip->ttl =64;// hopsip->protocol =123;// UDPip->saddr = src_addr;ip->daddr = dst_addr;udp->source = htons(src_port);udp->dest = htons(dst_port);udp->len = htons(sizeof(struct udphdr) + dlen);ip->check = csum((unsignedshort*)data,sizeof(struct iphdr) +sizeof(struct udphdr) + dlen);usd = socket(AF_INET, SOCK_DGRAM,0);if(usd tot_len,0, (struct sockaddr *)&sin,sizeof(sin))

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表