C Linux内核中遍历sk_write_队列时的Oops

C Linux内核中遍历sk_write_队列时的Oops,c,linux,oop,tcp,kernel,C,Linux,Oop,Tcp,Kernel,我的Linux 3.8.8内核在内核中遍历tcp sk_write_队列时会出现Oops,如下所示: BUG: unable to handle kernel paging request at 00b85055 我在内核中的代码逻辑如下: 从套接字文件描述符获取结构套接字 从结构套接字获取结构套接字 锁紧袜子() 从struct sock获取sk_write_队列 遍历SKU写队列,读取链接skb缓冲区 松开_-sock() 返回用户空间 在步骤(5)中,有时会触发上述Oops,问题代码为:

我的Linux 3.8.8内核在内核中遍历tcp sk_write_队列时会出现Oops,如下所示:

BUG: unable to handle kernel paging request at 00b85055
我在内核中的代码逻辑如下:

  • 从套接字文件描述符获取结构套接字
  • 从结构套接字获取结构套接字
  • 锁紧袜子()
  • 从struct sock获取sk_write_队列
  • 遍历SKU写队列,读取链接skb缓冲区
  • 松开_-sock()
  • 返回用户空间
  • 在步骤(5)中,有时会触发上述Oops,问题代码为:

    skb_is_nonlinear(skb);
    
    这意味着skb指针现在无效或为空,锁sock不能保护遍历过程吗

    代码:

    asmlong-sys\u-tcp\u-get(int-fd,int*id)
    {
    int-err,i,j;
    结构套接字*sock;
    结构sock*sk;
    结构sk_buff_head*队列;
    结构sk_buff*skb;
    无符号字符buf[4]={0};
    sock=sockfd_查找(fd和err);
    if(sock==NULL)返回-1;
    sk=sock->sk;
    if(sk==NULL){
    误差=-1;
    转到自由_插座;
    }
    锁紧短袜(sk);
    如果((1个sk_州)和建立了TCPF_)||
    (sk->sk|U错误(sk->sk|U关闭和发送|U关闭))){
    误差=-1;
    转到释放插座;
    }
    队列=&(sk->sk_写入_队列);
    如果(tcp_发送_头(sk)==NULL){
    误差=-1;
    转到释放插座;
    }
    对于(skb=tcp\u发送头(sk);skb!=(struct sk\u buff*)(队列);skb=skb->next){
    if(skb_是非线性的(skb)){
    误差=-1;
    转到释放插座;
    }
    i=0;
    j=0;
    而(ilen){
    buf[j++]=skb->data[i++];
    如果(j==4){
    if(buf[0]==1&&buf[1]==2&&buf[2]==3){
    *id=buf[3];
    误差=0;
    转到释放插座;
    }否则{
    j=0;
    }
    }
    }
    }
    释放U形插座:
    释放袜子(sk);
    自由U形插座:
    短袜;
    返回错误;
    }
    
    您能在这里发布您的代码吗?其中的细节可能很重要。我已经列出了上面的代码,skb_是非线性函数。
    asmlinkage long sys_tcp_get(int fd, int *id)
    {
        int err, i, j;
        struct socket *sock;
        struct sock *sk;
        struct sk_buff_head *queue;
        struct sk_buff *skb;
        unsigned char buf[4] = {0};
    
        sock = sockfd_lookup(fd, &err);
        if (sock == NULL) return -1;
    
        sk = sock->sk;
        if (sk == NULL) {
                err = -1;
                goto free_socket;
        }
    
        lock_sock(sk);
    
        if (((1 << sk->sk_state) & ~TCPF_ESTABLISHED) ||
                (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))) {
                        err = -1;
                        goto release_socket;
        }
    
        queue = &(sk->sk_write_queue);
        if (tcp_send_head(sk) == NULL) {
                err = -1;
                goto release_socket;
        }
    
        for(skb = tcp_send_head(sk); skb != (struct sk_buff *)(queue); skb = skb->next) {
                if (skb_is_nonlinear(skb)) {
                        err = -1;
                        goto release_socket;
                }
    
                i = 0;
                j = 0;
                while(i < skb->len) {
                        buf[j++] = skb->data[i++];
                        if (j == 4) {
                                if (buf[0] == 1 && buf[1] == 2 && buf[2] == 3) {
                                       *id = buf[3];
                                        err = 0;
                                        goto release_socket;
                                } else {
                                        j = 0;
                                }
                        }
                }
        }
    
    release_socket:
        release_sock(sk);
    
    free_socket:
        sockfd_put(sock);
        return err;
    }