]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - net/sctp/socket.c
sctp: reset owner sk for data chunks on out queues when migrating a sock
[mirror_ubuntu-artful-kernel.git] / net / sctp / socket.c
index 1db478e345203f75733044d843a763cc3a3966e1..083da13e1af47e93051e0e365b4873c35bda4937 100644 (file)
@@ -169,6 +169,36 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
        sk_mem_charge(sk, chunk->skb->truesize);
 }
 
+static void sctp_clear_owner_w(struct sctp_chunk *chunk)
+{
+       skb_orphan(chunk->skb);
+}
+
+static void sctp_for_each_tx_datachunk(struct sctp_association *asoc,
+                                      void (*cb)(struct sctp_chunk *))
+
+{
+       struct sctp_outq *q = &asoc->outqueue;
+       struct sctp_transport *t;
+       struct sctp_chunk *chunk;
+
+       list_for_each_entry(t, &asoc->peer.transport_addr_list, transports)
+               list_for_each_entry(chunk, &t->transmitted, transmitted_list)
+                       cb(chunk);
+
+       list_for_each_entry(chunk, &q->retransmit, list)
+               cb(chunk);
+
+       list_for_each_entry(chunk, &q->sacked, list)
+               cb(chunk);
+
+       list_for_each_entry(chunk, &q->abandoned, list)
+               cb(chunk);
+
+       list_for_each_entry(chunk, &q->out_chunk_list, list)
+               cb(chunk);
+}
+
 /* Verify that this is a valid address. */
 static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
                                   int len)
@@ -4538,8 +4568,7 @@ int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc,
        info->sctpi_ictrlchunks = asoc->stats.ictrlchunks;
 
        prim = asoc->peer.primary_path;
-       memcpy(&info->sctpi_p_address, &prim->ipaddr,
-              sizeof(struct sockaddr_storage));
+       memcpy(&info->sctpi_p_address, &prim->ipaddr, sizeof(prim->ipaddr));
        info->sctpi_p_state = prim->state;
        info->sctpi_p_cwnd = prim->cwnd;
        info->sctpi_p_srtt = prim->srtt;
@@ -4895,6 +4924,10 @@ int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp)
        struct socket *sock;
        int err = 0;
 
+       /* Do not peel off from one netns to another one. */
+       if (!net_eq(current->nsproxy->net_ns, sock_net(sk)))
+               return -EINVAL;
+
        if (!asoc)
                return -EINVAL;
 
@@ -8197,7 +8230,9 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
         * paths won't try to lock it and then oldsk.
         */
        lock_sock_nested(newsk, SINGLE_DEPTH_NESTING);
+       sctp_for_each_tx_datachunk(assoc, sctp_clear_owner_w);
        sctp_assoc_migrate(assoc, newsk);
+       sctp_for_each_tx_datachunk(assoc, sctp_set_owner_w);
 
        /* If the association on the newsk is already closed before accept()
         * is called, set RCV_SHUTDOWN flag.