[PATCH] (5/11) netrom - lock sockets during usage

From: Stephen Hemminger (zxgz.ptxccrqh@iph.ufrgs.br)
Date: Thu Aug 14 2003 - 02:03:00 EEST

  • Next message: Arnaldo Carvalho de Melo: "Re: [PATCH] (3/11) netrom - drop buffers in write queue on close"

    From: Jeroen Vreeken <nshuipl@rele.tunk.net>

    Lock sockets while doing protocol processing.

    diff -Nru a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
    --- a/net/netrom/af_netrom.c Wed Aug 13 12:22:36 2003
    +++ b/net/netrom/af_netrom.c Wed Aug 13 12:22:36 2003
    @@ -147,8 +147,10 @@
             spin_lock_bh(&nr_list_lock);
             sk_for_each(s, node, &nr_list)
                     if (!ax25cmp(&nr_sk(s)->source_addr, addr) &&
    - s->sk_state == TCP_LISTEN)
    + s->sk_state == TCP_LISTEN) {
    + bh_lock_sock(s);
                             goto found;
    + }
             s = NULL;
     found:
             spin_unlock_bh(&nr_list_lock);
    @@ -167,8 +169,10 @@
             sk_for_each(s, node, &nr_list) {
                     nr_cb *nr = nr_sk(s);
                     
    - if (nr->my_index == index && nr->my_id == id)
    + if (nr->my_index == index && nr->my_id == id) {
    + bh_lock_sock(s);
                             goto found;
    + }
             }
             s = NULL;
     found:
    @@ -190,8 +194,10 @@
                     nr_cb *nr = nr_sk(s);
                     
                     if (nr->your_index == index && nr->your_id == id &&
    - !ax25cmp(&nr->dest_addr, dest))
    + !ax25cmp(&nr->dest_addr, dest)) {
    + bh_lock_sock(s);
                             goto found;
    + }
             }
             s = NULL;
     found:
    @@ -206,14 +212,17 @@
     {
             unsigned short id = circuit;
             unsigned char i, j;
    + struct sock *sk;
     
             for (;;) {
                     i = id / 256;
                     j = id % 256;
     
    - if (i != 0 && j != 0)
    - if (nr_find_socket(i, j) == NULL)
    + if (i != 0 && j != 0) {
    + if ((sk=nr_find_socket(i, j)) == NULL)
                                     break;
    + bh_unlock_sock(sk);
    + }
     
                     id++;
             }
    @@ -231,7 +240,12 @@
      */
     static void nr_destroy_timer(unsigned long data)
     {
    - nr_destroy_socket((struct sock *)data);
    + struct sock *sk=(struct sock *)data;
    + bh_lock_sock(sk);
    + sock_hold(sk);
    + nr_destroy_socket(sk);
    + bh_unlock_sock(sk);
    + sock_put(sk);
     }
     
     /*
    @@ -277,7 +291,7 @@
                     sk->sk_timer.data = (unsigned long)sk;
                     add_timer(&sk->sk_timer);
             } else
    - sk_free(sk);
    + sock_put(sk);
     }
     
     /*
    @@ -391,12 +405,15 @@
     {
             struct sock *sk = sock->sk;
     
    + lock_sock(sk);
             if (sk->sk_state != TCP_LISTEN) {
                     memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN);
                     sk->sk_max_ack_backlog = backlog;
                     sk->sk_state = TCP_LISTEN;
    + release_sock(sk);
                     return 0;
             }
    + release_sock(sk);
     
             return -EOPNOTSUPP;
     }
    @@ -498,6 +515,7 @@
     
             if (sk == NULL) return 0;
     
    + lock_sock(sk);
             nr = nr_sk(sk);
     
             switch (nr->state) {
    @@ -531,6 +549,7 @@
             }
     
             sock->sk = NULL;
    + release_sock(sk);
     
             return 0;
     }
    @@ -543,21 +562,26 @@
             struct net_device *dev;
             ax25_address *user, *source;
     
    - if (!sk->sk_zapped)
    + lock_sock(sk);
    + if (!sk->sk_zapped) {
    + release_sock(sk);
                     return -EINVAL;
    -
    - if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct
    -full_sockaddr_ax25))
    + }
    + if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct full_sockaddr_ax25)) {
    + release_sock(sk);
                     return -EINVAL;
    -
    - if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25)))
    + }
    + if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25))) {
    + release_sock(sk);
                     return -EINVAL;
    -
    - if (addr->fsa_ax25.sax25_family != AF_NETROM)
    + }
    + if (addr->fsa_ax25.sax25_family != AF_NETROM) {
    + release_sock(sk);
                     return -EINVAL;
    -
    + }
             if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) {
                     SOCK_DEBUG(sk, "NET/ROM: bind failed: invalid node callsign\n");
    + release_sock(sk);
                     return -EADDRNOTAVAIL;
             }
     
    @@ -565,16 +589,22 @@
              * Only the super user can set an arbitrary user callsign.
              */
             if (addr->fsa_ax25.sax25_ndigis == 1) {
    - if (!capable(CAP_NET_BIND_SERVICE))
    + if (!capable(CAP_NET_BIND_SERVICE)) {
    + dev_put(dev);
    + release_sock(sk);
                             return -EACCES;
    + }
                     nr->user_addr = addr->fsa_digipeater[0];
                     nr->source_addr = addr->fsa_ax25.sax25_call;
             } else {
                     source = &addr->fsa_ax25.sax25_call;
     
                     if ((user = ax25_findbyuid(current->euid)) == NULL) {
    - if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE))
    + if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
    + release_sock(sk);
    + dev_put(dev);
                                     return -EPERM;
    + }
                             user = source;
                     }
     
    @@ -586,6 +616,8 @@
             nr_insert_socket(sk);
     
             sk->sk_zapped = 0;
    + dev_put(dev);
    + release_sock(sk);
             SOCK_DEBUG(sk, "NET/ROM: socket is bound\n");
             return 0;
     }
    @@ -599,39 +631,50 @@
             ax25_address *user, *source = NULL;
             struct net_device *dev;
     
    + lock_sock(sk);
             if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {
                     sock->state = SS_CONNECTED;
    + release_sock(sk);
                     return 0; /* Connect completed during a ERESTARTSYS event */
             }
     
             if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) {
                     sock->state = SS_UNCONNECTED;
    + release_sock(sk);
                     return -ECONNREFUSED;
             }
     
    - if (sk->sk_state == TCP_ESTABLISHED)
    + if (sk->sk_state == TCP_ESTABLISHED) {
    + release_sock(sk);
                     return -EISCONN; /* No reconnect on a seqpacket socket */
    + }
     
             sk->sk_state = TCP_CLOSE;
             sock->state = SS_UNCONNECTED;
     
    - if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25))
    + if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) {
    + release_sock(sk);
                     return -EINVAL;
    -
    - if (addr->sax25_family != AF_NETROM)
    + }
    + if (addr->sax25_family != AF_NETROM) {
    + release_sock(sk);
                     return -EINVAL;
    -
    + }
             if (sk->sk_zapped) { /* Must bind first - autobinding in this may or may not work */
                     sk->sk_zapped = 0;
     
    - if ((dev = nr_dev_first()) == NULL)
    + if ((dev = nr_dev_first()) == NULL) {
    + release_sock(sk);
                             return -ENETUNREACH;
    -
    + }
                     source = (ax25_address *)dev->dev_addr;
     
                     if ((user = ax25_findbyuid(current->euid)) == NULL) {
    - if (ax25_uid_policy && !capable(CAP_NET_ADMIN))
    + if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) {
    + dev_put(dev);
    + release_sock(sk);
                                     return -EPERM;
    + }
                             user = source;
                     }
     
    @@ -639,12 +682,15 @@
                     nr->source_addr = *source;
                     nr->device = dev;
     
    + dev_put(dev);
                     nr_insert_socket(sk); /* Finish the bind */
             }
     
             nr->dest_addr = addr->sax25_call;
     
    + release_sock(sk);
             circuit = nr_find_next_circuit();
    + lock_sock(sk);
     
             nr->my_index = circuit / 256;
             nr->my_id = circuit % 256;
    @@ -662,8 +708,10 @@
             nr_start_heartbeat(sk);
     
             /* Now the loop */
    - if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
    + if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
    + release_sock(sk);
                     return -EINPROGRESS;
    + }
                     
             /*
              * A Connect Ack with Choke or timeout or failed routing will go to
    @@ -678,8 +726,10 @@
                             set_current_state(TASK_INTERRUPTIBLE);
                             if (sk->sk_state != TCP_SYN_SENT)
                                     break;
    + release_sock(sk);
                             if (!signal_pending(tsk)) {
                                     schedule();
    + lock_sock(sk);
                                     continue;
                             }
                             return -ERESTARTSYS;
    @@ -690,10 +740,12 @@
     
             if (sk->sk_state != TCP_ESTABLISHED) {
                     sock->state = SS_UNCONNECTED;
    + release_sock(sk);
                     return sock_error(sk); /* Always set at this point */
             }
     
             sock->state = SS_CONNECTED;
    + release_sock(sk);
     
             return 0;
     }
    @@ -756,6 +808,7 @@
             newsock->sk = newsk;
     
     out:
    + release_sock(sk);
             return err;
     }
     
    @@ -766,9 +819,12 @@
             struct sock *sk = sock->sk;
             nr_cb *nr = nr_sk(sk);
     
    + lock_sock(sk);
             if (peer != 0) {
    - if (sk->sk_state != TCP_ESTABLISHED)
    + if (sk->sk_state != TCP_ESTABLISHED) {
    + release_sock(sk);
                             return -ENOTCONN;
    + }
                     sax->fsa_ax25.sax25_family = AF_NETROM;
                     sax->fsa_ax25.sax25_ndigis = 1;
                     sax->fsa_ax25.sax25_call = nr->user_addr;
    @@ -780,6 +836,7 @@
                     sax->fsa_ax25.sax25_call = nr->source_addr;
                     *uaddr_len = sizeof(struct sockaddr_ax25);
             }
    + release_sock(sk);
     
             return 0;
     }
    @@ -793,6 +850,7 @@
             unsigned short circuit_index, circuit_id;
             unsigned short peer_circuit_index, peer_circuit_id;
             unsigned short frametype, flags, window, timeout;
    + int ret;
     
             skb->sk = NULL; /* Initially we don't know who it's for */
     
    @@ -850,7 +908,9 @@
                     else
                             nr_sk(sk)->bpqext = 0;
     
    - return nr_process_rx_frame(sk, skb);
    + ret = nr_process_rx_frame(sk, skb);
    + bh_unlock_sock(sk);
    + return ret;
             }
     
             /*
    @@ -880,6 +940,8 @@
             if (!sk || sk->sk_ack_backlog == sk->sk_max_ack_backlog ||
                 (make = nr_make_new(sk)) == NULL) {
                     nr_transmit_refusal(skb, 0);
    + if (sk)
    + bh_unlock_sock(sk);
                     return 0;
             }
     
    @@ -897,7 +959,9 @@
             nr_make->your_index = circuit_index;
             nr_make->your_id = circuit_id;
     
    + bh_unlock_sock(sk);
             circuit = nr_find_next_circuit();
    + bh_lock_sock(sk);
     
             nr_make->my_index = circuit / 256;
             nr_make->my_id = circuit % 256;
    @@ -939,6 +1003,7 @@
             if (!sock_flag(sk, SOCK_DEAD))
                     sk->sk_data_ready(sk, skb->len);
     
    + bh_unlock_sock(sk);
             return 1;
     }
     
    @@ -957,28 +1022,42 @@
             if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR))
                     return -EINVAL;
     
    - if (sk->sk_zapped)
    - return -EADDRNOTAVAIL;
    + lock_sock(sk);
    + if (sk->sk_zapped) {
    + err = -EADDRNOTAVAIL;
    + goto out;
    + }
     
             if (sk->sk_shutdown & SEND_SHUTDOWN) {
                     send_sig(SIGPIPE, current, 0);
    - return -EPIPE;
    + err = -EPIPE;
    + goto out;
             }
     
    - if (nr->device == NULL)
    - return -ENETUNREACH;
    + if (nr->device == NULL) {
    + err = -ENETUNREACH;
    + goto out;
    + }
     
             if (usax) {
    - if (msg->msg_namelen < sizeof(sax))
    - return -EINVAL;
    + if (msg->msg_namelen < sizeof(sax)) {
    + err = -EINVAL;
    + goto out;
    + }
                     sax = *usax;
    - if (ax25cmp(&nr->dest_addr, &sax.sax25_call) != 0)
    - return -EISCONN;
    - if (sax.sax25_family != AF_NETROM)
    - return -EINVAL;
    + if (ax25cmp(&nr->dest_addr, &sax.sax25_call) != 0) {
    + err = -EISCONN;
    + goto out;
    + }
    + if (sax.sax25_family != AF_NETROM) {
    + err = -EINVAL;
    + goto out;
    + }
             } else {
    - if (sk->sk_state != TCP_ESTABLISHED)
    - return -ENOTCONN;
    + if (sk->sk_state != TCP_ESTABLISHED) {
    + err = -ENOTCONN;
    + goto out;
    + }
                     sax.sax25_family = AF_NETROM;
                     sax.sax25_call = nr->dest_addr;
             }
    @@ -987,10 +1066,10 @@
     
             /* Build a packet */
             SOCK_DEBUG(sk, "NET/ROM: sendto: building packet.\n");
    - size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
    + size = len + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
     
             if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
    - return err;
    + goto out;
     
             skb_reserve(skb, size - len);
     
    @@ -1025,12 +1104,16 @@
     
             if (sk->sk_state != TCP_ESTABLISHED) {
                     kfree_skb(skb);
    - return -ENOTCONN;
    + err = -ENOTCONN;
    + goto out;
             }
     
             nr_output(sk, skb); /* Shove it onto the queue */
     
    - return len;
    + err = len;
    +out:
    + release_sock(sk);
    + return err;
     }
     
     static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
    @@ -1047,12 +1130,17 @@
              * us! We do one quick check first though
              */
     
    - if (sk->sk_state != TCP_ESTABLISHED)
    + lock_sock(sk);
    + if (sk->sk_state != TCP_ESTABLISHED) {
    + release_sock(sk);
                     return -ENOTCONN;
    + }
     
             /* Now we can treat all alike */
    - if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL)
    + if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL) {
    + release_sock(sk);
                     return er;
    + }
     
             skb->h.raw = skb->data;
             copied = skb->len;
    @@ -1073,6 +1161,7 @@
     
             skb_free_datagram(sk, skb);
     
    + release_sock(sk);
             return copied;
     }
     
    @@ -1080,13 +1169,16 @@
     static int nr_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
     {
             struct sock *sk = sock->sk;
    + int ret;
     
    + lock_sock(sk);
             switch (cmd) {
             case TIOCOUTQ: {
                     long amount;
                     amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
                     if (amount < 0)
                             amount = 0;
    + release_sock(sk);
                     return put_user(amount, (int *)arg);
             }
     
    @@ -1096,15 +1188,21 @@
                     /* These two are safe on a single CPU system as only user tasks fiddle here */
                     if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL)
                             amount = skb->len;
    + release_sock(sk);
                     return put_user(amount, (int *)arg);
             }
     
             case SIOCGSTAMP:
                     if (sk != NULL) {
    - if (!sk->sk_stamp.tv_sec)
    + if (!sk->sk_stamp.tv_sec) {
    + release_sock(sk);
                                     return -ENOENT;
    - return copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0;
    + }
    + ret = copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0;
    + release_sock(sk);
    + return ret;
                     }
    + release_sock(sk);
                     return -EINVAL;
     
             case SIOCGIFADDR:
    @@ -1117,17 +1215,21 @@
             case SIOCSIFNETMASK:
             case SIOCGIFMETRIC:
             case SIOCSIFMETRIC:
    + release_sock(sk);
                     return -EINVAL;
     
             case SIOCADDRT:
             case SIOCDELRT:
             case SIOCNRDECOBS:
    + release_sock(sk);
                     if (!capable(CAP_NET_ADMIN)) return -EPERM;
                     return nr_rt_ioctl(cmd, (void *)arg);
     
             default:
    + release_sock(sk);
                     return dev_ioctl(cmd, (void *)arg);
             }
    + release_sock(sk);
     
             return 0;
     }
    @@ -1147,7 +1249,9 @@
             len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 t4 idle n2 wnd Snd-Q Rcv-Q inode\n");
     
             sk_for_each(s, node, &nr_list) {
    - nr_cb *nr = nr_sk(s);
    + nr_cb *nr;
    + bh_lock_sock(s);
    + nr = nr_sk(s);
     
                     if ((dev = nr->device) == NULL)
                             devname = "???";
    @@ -1190,7 +1294,7 @@
                             len = 0;
                             begin = pos;
                     }
    -
    + bh_unlock_sock(s);
                     if (pos > offset + length)
                             break;
             }
    diff -Nru a/net/netrom/nr_in.c b/net/netrom/nr_in.c
    --- a/net/netrom/nr_in.c Wed Aug 13 12:22:36 2003
    +++ b/net/netrom/nr_in.c Wed Aug 13 12:22:36 2003
    @@ -74,6 +74,7 @@
     static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
             int frametype)
     {
    + bh_lock_sock(sk);
             switch (frametype) {
             case NR_CONNACK: {
                     nr_cb *nr = nr_sk(sk);
    @@ -102,6 +103,7 @@
             default:
                     break;
             }
    + bh_unlock_sock(sk);
     
             return 0;
     }
    @@ -114,6 +116,7 @@
     static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
             int frametype)
     {
    + bh_lock_sock(sk);
             switch (frametype) {
             case NR_CONNACK | NR_CHOKE_FLAG:
                     nr_disconnect(sk, ECONNRESET);
    @@ -129,6 +132,7 @@
             default:
                     break;
             }
    + bh_unlock_sock(sk);
     
             return 0;
     }
    @@ -150,6 +154,7 @@
             nr = skb->data[18];
             ns = skb->data[17];
     
    + bh_lock_sock(sk);
             switch (frametype) {
             case NR_CONNREQ:
                     nr_write_internal(sk, NR_CONNACK);
    @@ -260,6 +265,7 @@
             default:
                     break;
             }
    + bh_unlock_sock(sk);
     
             return queued;
     }
    diff -Nru a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c
    --- a/net/netrom/nr_timer.c Wed Aug 13 12:22:36 2003
    +++ b/net/netrom/nr_timer.c Wed Aug 13 12:22:36 2003
    @@ -143,7 +143,10 @@
                        is accepted() it isn't 'dead' so doesn't get removed. */
                     if (sock_flag(sk, SOCK_DESTROY) ||
                         (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) {
    + sock_hold(sk);
                             nr_destroy_socket(sk);
    + bh_unlock_sock(sk);
    + sock_put(sk);
                             return;
                     }
                     break;
    @@ -227,6 +230,7 @@
             case NR_STATE_1:
                     if (nr->n2count == nr->n2) {
                             nr_disconnect(sk, ETIMEDOUT);
    + bh_unlock_sock(sk);
                             return;
                     } else {
                             nr->n2count++;
    @@ -237,6 +241,7 @@
             case NR_STATE_2:
                     if (nr->n2count == nr->n2) {
                             nr_disconnect(sk, ETIMEDOUT);
    + bh_unlock_sock(sk);
                             return;
                     } else {
                             nr->n2count++;
    @@ -247,6 +252,7 @@
             case NR_STATE_3:
                     if (nr->n2count == nr->n2) {
                             nr_disconnect(sk, ETIMEDOUT);
    + bh_unlock_sock(sk);
                             return;
                     } else {
                             nr->n2count++;
    -
    To unsubscribe from this list: send the line "unsubscribe linux-hams" in
    the body of a message to bmxj.wvwz@trinity-health.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html



    This archive was generated by hypermail 2b30 : Thu Aug 14 2003 - 02:04:06 EEST