From 0a296cd0b186401d20de2ffbbc2c5c20f95ae645 Mon Sep 17 00:00:00 2001 From: "Reshetova, Elena" Date: Fri, 30 Jun 2017 13:08:10 +0300 Subject: [PATCH] net: convert packet_fanout.sk_ref from atomic_t to refcount_t refcount_t type and corresponding API should be used instead of atomic_t when the variable is used as a reference counter. This allows to avoid accidental refcounter overflows that might lead to use-after-free situations. Signed-off-by: Elena Reshetova Signed-off-by: Hans Liljestrand Signed-off-by: Kees Cook Signed-off-by: David Windsor Signed-off-by: David S. Miller (cherry picked from commit fb5c2c17a556d9b00798d6a6b9e624281ee2eb28) Orabug: 27050772 CVE: CVE-2017-15649 Signed-off-by: Kirtikar Kashyap Reviewed-by: Jack Vogel Conflicts: net/packet/af_packet.c --- net/packet/af_packet.c | 8 ++++---- net/packet/internal.h | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 0cdea22910d3..367534a07282 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1480,7 +1480,7 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) atomic_set(&match->rr_cur, 0); INIT_LIST_HEAD(&match->list); spin_lock_init(&match->lock); - atomic_set(&match->sk_ref, 0); + refcount_set(&match->sk_ref, 0); match->prot_hook.type = po->prot_hook.type; match->prot_hook.dev = po->prot_hook.dev; match->prot_hook.func = packet_rcv_fanout; @@ -1494,10 +1494,10 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags) match->prot_hook.type == po->prot_hook.type && match->prot_hook.dev == po->prot_hook.dev) { err = -ENOSPC; - if (atomic_read(&match->sk_ref) < PACKET_FANOUT_MAX) { + if (refcount_read(&match->sk_ref) < PACKET_FANOUT_MAX) { __dev_remove_pack(&po->prot_hook); po->fanout = match; - atomic_inc(&match->sk_ref); + refcount_set(&match->sk_ref, refcount_read(&match->sk_ref) + 1); __fanout_link(sk, po); err = 0; } @@ -1517,7 +1517,7 @@ static void fanout_release(struct sock *sk) if (f) { po->fanout = NULL; - if (atomic_dec_and_test(&f->sk_ref)) { + if (refcount_dec_and_test(&f->sk_ref)) { list_del(&f->list); dev_remove_pack(&f->prot_hook); kfree(f); diff --git a/net/packet/internal.h b/net/packet/internal.h index fe6e20caea1d..ba4a0524088d 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -1,6 +1,8 @@ #ifndef __PACKET_INTERNAL_H__ #define __PACKET_INTERNAL_H__ +#include + struct packet_mclist { struct packet_mclist *next; int ifindex; @@ -84,7 +86,7 @@ struct packet_fanout { struct sock *arr[PACKET_FANOUT_MAX]; int next[PACKET_FANOUT_MAX]; spinlock_t lock; - atomic_t sk_ref; + refcount_t sk_ref; struct packet_type prot_hook ____cacheline_aligned_in_smp; }; -- 2.50.1