]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
sctp: implement memory accounting on rx path
authorXin Long <lucien.xin@gmail.com>
Thu, 18 Apr 2019 07:50:00 +0000 (09:50 +0200)
committerKleber Sacilotto de Souza <kleber.souza@canonical.com>
Tue, 23 Apr 2019 15:42:01 +0000 (17:42 +0200)
sk_forward_alloc's updating is also done on rx path, but to be consistent
we change to use sk_mem_charge() in sctp_skb_set_owner_r().

In sctp_eat_data(), it's not enough to check sctp_memory_pressure only,
which doesn't work for mem_cgroup_sockets_enabled, so we change to use
sk_under_memory_pressure().

When it's under memory pressure, sk_mem_reclaim() and sk_rmem_schedule()
should be called on both RENEGE or CHUNK DELIVERY path exit the memory
pressure status as soon as possible.

Note that sk_rmem_schedule() is using datalen to make things easy there.

Reported-by: Matteo Croce <mcroce@redhat.com>
Tested-by: Matteo Croce <mcroce@redhat.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
CVE-2019-3874

(cherry picked from commit 9dde27de3e5efa0d032f3c891a0ca833a0d31911 linux-next)
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
include/net/sctp/sctp.h
net/sctp/sm_statefuns.c
net/sctp/ulpevent.c
net/sctp/ulpqueue.c

index 9a6787e425a7f93fdb6db20fefa4c6cf305a8230..ada9f9f22ff26f2231ec108fd5708a9888e54517 100644 (file)
@@ -428,7 +428,7 @@ static inline void sctp_skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
        /*
         * This mimics the behavior of skb_set_owner_r
         */
-       sk->sk_forward_alloc -= event->rmem_len;
+       sk_mem_charge(sk, event->rmem_len);
 }
 
 /* Tests if the list has one and only one entry. */
index 01b078172306a59e66e28883327942548c1baaf9..018dd3b7b4b580eb1ffb1dcb7f35414bd52ead0c 100644 (file)
@@ -6351,13 +6351,15 @@ static int sctp_eat_data(const struct sctp_association *asoc,
         * in sctp_ulpevent_make_rcvmsg will drop the frame if we grow our
         * memory usage too much
         */
-       if (*sk->sk_prot_creator->memory_pressure) {
+       if (sk_under_memory_pressure(sk)) {
                if (sctp_tsnmap_has_gap(map) &&
                    (sctp_tsnmap_get_ctsn(map) + 1) == tsn) {
                        pr_debug("%s: under pressure, reneging for tsn:%u\n",
                                 __func__, tsn);
                        deliver = SCTP_CMD_RENEGE;
-                }
+               } else {
+                       sk_mem_reclaim(sk);
+               }
        }
 
        /*
index 8538c96c96c113efabe52aceeabc3e7e3adc8900..7b03578640cf8a538f9da156e47eb9489dcf9764 100644 (file)
@@ -634,8 +634,9 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
                                                gfp_t gfp)
 {
        struct sctp_ulpevent *event = NULL;
-       struct sk_buff *skb;
-       size_t padding, len;
+       struct sk_buff *skb = chunk->skb;
+       struct sock *sk = asoc->base.sk;
+       size_t padding, datalen;
        int rx_count;
 
        /*
@@ -646,15 +647,12 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
        if (asoc->ep->rcvbuf_policy)
                rx_count = atomic_read(&asoc->rmem_alloc);
        else
-               rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc);
+               rx_count = atomic_read(&sk->sk_rmem_alloc);
 
-       if (rx_count >= asoc->base.sk->sk_rcvbuf) {
+       datalen = ntohs(chunk->chunk_hdr->length);
 
-               if ((asoc->base.sk->sk_userlocks & SOCK_RCVBUF_LOCK) ||
-                   (!sk_rmem_schedule(asoc->base.sk, chunk->skb,
-                                      chunk->skb->truesize)))
-                       goto fail;
-       }
+       if (rx_count >= sk->sk_rcvbuf || !sk_rmem_schedule(sk, skb, datalen))
+               goto fail;
 
        /* Clone the original skb, sharing the data.  */
        skb = skb_clone(chunk->skb, gfp);
@@ -681,8 +679,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
         * The sender should never pad with more than 3 bytes.  The receiver
         * MUST ignore the padding bytes.
         */
-       len = ntohs(chunk->chunk_hdr->length);
-       padding = SCTP_PAD4(len) - len;
+       padding = SCTP_PAD4(datalen) - datalen;
 
        /* Fixup cloned skb with just this chunks data.  */
        skb_trim(skb, chunk->chunk_end - padding - skb->data);
index e36ec5dd64c6ff969fc30aae893d1d5ca8c221bf..93192d9bd44e49bdf727280395343d06b904823f 100644 (file)
@@ -1097,7 +1097,8 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
                        freed += sctp_ulpq_renege_frags(ulpq, needed - freed);
        }
        /* If able to free enough room, accept this chunk. */
-       if (freed >= needed) {
+       if (sk_rmem_schedule(asoc->base.sk, chunk->skb, needed) &&
+           freed >= needed) {
                int retval = sctp_ulpq_tail_data(ulpq, chunk, gfp);
                /*
                 * Enter partial delivery if chunk has not been