* [PATCH 01/17] net: convert inet_peer.refcnt from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
@ 2017-06-30 10:07 ` Elena Reshetova
2017-06-30 10:07 ` [PATCH 02/17] net: convert neighbour.refcnt " Elena Reshetova
` (16 subsequent siblings)
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:07 UTC (permalink / raw)
To: netdev
Cc: keescook, peterz, bridge, linux-kernel, jmorris,
Hans Liljestrand, kuznet, kaber, Elena Reshetova, David Windsor
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.
This conversion requires overall +1 on the whole
refcounting scheme.
Signed-off-by: Elena Reshetova <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/net/inetpeer.h | 4 ++--
net/ipv4/inetpeer.c | 18 +++++++++---------
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index 235c781..f2a215f 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -46,7 +46,7 @@ struct inet_peer {
struct rcu_head gc_rcu;
};
/*
- * Once inet_peer is queued for deletion (refcnt == -1), following field
+ * Once inet_peer is queued for deletion (refcnt == 0), following field
* is not available: rid
* We can share memory with rcu_head to help keep inet_peer small.
*/
@@ -60,7 +60,7 @@ struct inet_peer {
/* following fields might be frequently dirtied */
__u32 dtime; /* the time of last use of not referenced entries */
- atomic_t refcnt;
+ refcount_t refcnt;
};
struct inet_peer_base {
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index 86fa458..c5a117c 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -115,7 +115,7 @@ static void inetpeer_gc_worker(struct work_struct *work)
n = list_entry(p->gc_list.next, struct inet_peer, gc_list);
- if (!atomic_read(&p->refcnt)) {
+ if (refcount_read(&p->refcnt) == 1) {
list_del(&p->gc_list);
kmem_cache_free(peer_cachep, p);
}
@@ -202,10 +202,11 @@ static struct inet_peer *lookup_rcu(const struct inetpeer_addr *daddr,
int cmp = inetpeer_addr_cmp(daddr, &u->daddr);
if (cmp == 0) {
/* Before taking a reference, check if this entry was
- * deleted (refcnt=-1)
+ * deleted (refcnt=0)
*/
- if (!atomic_add_unless(&u->refcnt, 1, -1))
+ if (!refcount_inc_not_zero(&u->refcnt)) {
u = NULL;
+ }
return u;
}
if (cmp == -1)
@@ -382,11 +383,10 @@ static int inet_peer_gc(struct inet_peer_base *base,
while (stackptr > stack) {
stackptr--;
p = rcu_deref_locked(**stackptr, base);
- if (atomic_read(&p->refcnt) == 0) {
+ if (refcount_read(&p->refcnt) == 1) {
smp_rmb();
delta = (__u32)jiffies - p->dtime;
- if (delta >= ttl &&
- atomic_cmpxchg(&p->refcnt, 0, -1) == 0) {
+ if (delta >= ttl && refcount_dec_if_one(&p->refcnt)) {
p->gc_next = gchead;
gchead = p;
}
@@ -432,7 +432,7 @@ struct inet_peer *inet_getpeer(struct inet_peer_base *base,
relookup:
p = lookup(daddr, stack, base);
if (p != peer_avl_empty) {
- atomic_inc(&p->refcnt);
+ refcount_inc(&p->refcnt);
write_sequnlock_bh(&base->lock);
return p;
}
@@ -444,7 +444,7 @@ struct inet_peer *inet_getpeer(struct inet_peer_base *base,
p = create ? kmem_cache_alloc(peer_cachep, GFP_ATOMIC) : NULL;
if (p) {
p->daddr = *daddr;
- atomic_set(&p->refcnt, 1);
+ refcount_set(&p->refcnt, 2);
atomic_set(&p->rid, 0);
p->metrics[RTAX_LOCK-1] = INETPEER_METRICS_NEW;
p->rate_tokens = 0;
@@ -468,7 +468,7 @@ void inet_putpeer(struct inet_peer *p)
{
p->dtime = (__u32)jiffies;
smp_mb__before_atomic();
- atomic_dec(&p->refcnt);
+ refcount_dec(&p->refcnt);
}
EXPORT_SYMBOL_GPL(inet_putpeer);
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 02/17] net: convert neighbour.refcnt from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
2017-06-30 10:07 ` [PATCH 01/17] net: convert inet_peer.refcnt from atomic_t to refcount_t Elena Reshetova
@ 2017-06-30 10:07 ` Elena Reshetova
2017-06-30 10:07 ` [PATCH 03/17] net: convert neigh_params.refcnt " Elena Reshetova
` (15 subsequent siblings)
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:07 UTC (permalink / raw)
To: netdev
Cc: keescook, peterz, bridge, linux-kernel, jmorris,
Hans Liljestrand, kuznet, kaber, Elena Reshetova, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/net/arp.h | 2 +-
include/net/ndisc.h | 2 +-
include/net/neighbour.h | 9 +++++----
net/atm/clip.c | 6 +++---
net/core/neighbour.c | 14 +++++++-------
net/decnet/dn_neigh.c | 2 +-
6 files changed, 18 insertions(+), 17 deletions(-)
diff --git a/include/net/arp.h b/include/net/arp.h
index 65619a2..17d90e4 100644
--- a/include/net/arp.h
+++ b/include/net/arp.h
@@ -28,7 +28,7 @@ static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32
rcu_read_lock_bh();
n = __ipv4_neigh_lookup_noref(dev, key);
- if (n && !atomic_inc_not_zero(&n->refcnt))
+ if (n && !refcount_inc_not_zero(&n->refcnt))
n = NULL;
rcu_read_unlock_bh();
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index 1036c90..31b1bb1 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -384,7 +384,7 @@ static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, cons
rcu_read_lock_bh();
n = __ipv6_neigh_lookup_noref(dev, pkey);
- if (n && !atomic_inc_not_zero(&n->refcnt))
+ if (n && !refcount_inc_not_zero(&n->refcnt))
n = NULL;
rcu_read_unlock_bh();
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 639b675..e5ee739 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -17,6 +17,7 @@
*/
#include <linux/atomic.h>
+#include <linux/refcount.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/rcupdate.h>
@@ -137,7 +138,7 @@ struct neighbour {
unsigned long confirmed;
unsigned long updated;
rwlock_t lock;
- atomic_t refcnt;
+ refcount_t refcnt;
struct sk_buff_head arp_queue;
unsigned int arp_queue_len_bytes;
struct timer_list timer;
@@ -410,18 +411,18 @@ static inline struct neigh_parms *neigh_parms_clone(struct neigh_parms *parms)
static inline void neigh_release(struct neighbour *neigh)
{
- if (atomic_dec_and_test(&neigh->refcnt))
+ if (refcount_dec_and_test(&neigh->refcnt))
neigh_destroy(neigh);
}
static inline struct neighbour * neigh_clone(struct neighbour *neigh)
{
if (neigh)
- atomic_inc(&neigh->refcnt);
+ refcount_inc(&neigh->refcnt);
return neigh;
}
-#define neigh_hold(n) atomic_inc(&(n)->refcnt)
+#define neigh_hold(n) refcount_inc(&(n)->refcnt)
static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
{
diff --git a/net/atm/clip.c b/net/atm/clip.c
index a7e4018..47c36f4 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -137,11 +137,11 @@ static int neigh_check_cb(struct neighbour *n)
if (entry->vccs || time_before(jiffies, entry->expires))
return 0;
- if (atomic_read(&n->refcnt) > 1) {
+ if (refcount_read(&n->refcnt) > 1) {
struct sk_buff *skb;
pr_debug("destruction postponed with ref %d\n",
- atomic_read(&n->refcnt));
+ refcount_read(&n->refcnt));
while ((skb = skb_dequeue(&n->arp_queue)) != NULL)
dev_kfree_skb(skb);
@@ -767,7 +767,7 @@ static void atmarp_info(struct seq_file *seq, struct neighbour *n,
seq_printf(seq, "(resolving)\n");
else
seq_printf(seq, "(expired, ref %d)\n",
- atomic_read(&entry->neigh->refcnt));
+ refcount_read(&entry->neigh->refcnt));
} else if (!svc) {
seq_printf(seq, "%d.%d.%d\n",
clip_vcc->vcc->dev->number,
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index dadb5ee..0c78c8e 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -124,7 +124,7 @@ static bool neigh_del(struct neighbour *n, __u8 state,
bool retval = false;
write_lock(&n->lock);
- if (atomic_read(&n->refcnt) == 1 && !(n->nud_state & state)) {
+ if (refcount_read(&n->refcnt) == 1 && !(n->nud_state & state)) {
struct neighbour *neigh;
neigh = rcu_dereference_protected(n->next,
@@ -254,7 +254,7 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
neigh_del_timer(n);
n->dead = 1;
- if (atomic_read(&n->refcnt) != 1) {
+ if (refcount_read(&n->refcnt) != 1) {
/* The most unpleasant situation.
We must destroy neighbour entry,
but someone still uses it.
@@ -335,7 +335,7 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device
NEIGH_CACHE_STAT_INC(tbl, allocs);
n->tbl = tbl;
- atomic_set(&n->refcnt, 1);
+ refcount_set(&n->refcnt, 1);
n->dead = 1;
out:
return n;
@@ -444,7 +444,7 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
rcu_read_lock_bh();
n = __neigh_lookup_noref(tbl, pkey, dev);
if (n) {
- if (!atomic_inc_not_zero(&n->refcnt))
+ if (!refcount_inc_not_zero(&n->refcnt))
n = NULL;
NEIGH_CACHE_STAT_INC(tbl, hits);
}
@@ -473,7 +473,7 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
n = rcu_dereference_bh(n->next)) {
if (!memcmp(n->primary_key, pkey, key_len) &&
net_eq(dev_net(n->dev), net)) {
- if (!atomic_inc_not_zero(&n->refcnt))
+ if (!refcount_inc_not_zero(&n->refcnt))
n = NULL;
NEIGH_CACHE_STAT_INC(tbl, hits);
break;
@@ -821,7 +821,7 @@ static void neigh_periodic_work(struct work_struct *work)
if (time_before(n->used, n->confirmed))
n->used = n->confirmed;
- if (atomic_read(&n->refcnt) == 1 &&
+ if (refcount_read(&n->refcnt) == 1 &&
(state == NUD_FAILED ||
time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) {
*np = n->next;
@@ -2234,7 +2234,7 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh,
ci.ndm_used = jiffies_to_clock_t(now - neigh->used);
ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed);
ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated);
- ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1;
+ ci.ndm_refcnt = refcount_read(&neigh->refcnt) - 1;
read_unlock_bh(&neigh->lock);
if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) ||
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
index eeb5fc5..21dedf6 100644
--- a/net/decnet/dn_neigh.c
+++ b/net/decnet/dn_neigh.c
@@ -559,7 +559,7 @@ static inline void dn_neigh_format_entry(struct seq_file *seq,
(dn->flags&DN_NDFLAG_R2) ? "2" : "-",
(dn->flags&DN_NDFLAG_P3) ? "3" : "-",
dn->n.nud_state,
- atomic_read(&dn->n.refcnt),
+ refcount_read(&dn->n.refcnt),
dn->blksize,
(dn->n.dev) ? dn->n.dev->name : "?");
read_unlock(&n->lock);
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 03/17] net: convert neigh_params.refcnt from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
2017-06-30 10:07 ` [PATCH 01/17] net: convert inet_peer.refcnt from atomic_t to refcount_t Elena Reshetova
2017-06-30 10:07 ` [PATCH 02/17] net: convert neighbour.refcnt " Elena Reshetova
@ 2017-06-30 10:07 ` Elena Reshetova
2017-06-30 10:07 ` [PATCH 04/17] net: convert nf_bridge_info.use " Elena Reshetova
` (14 subsequent siblings)
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:07 UTC (permalink / raw)
To: netdev
Cc: keescook, peterz, bridge, linux-kernel, jmorris,
Hans Liljestrand, kuznet, kaber, Elena Reshetova, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/net/neighbour.h | 6 +++---
net/core/neighbour.c | 8 ++++----
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index e5ee739..afc39e3 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -77,7 +77,7 @@ struct neigh_parms {
void *sysctl_table;
int dead;
- atomic_t refcnt;
+ refcount_t refcnt;
struct rcu_head rcu_head;
int reachable_time;
@@ -396,12 +396,12 @@ void neigh_sysctl_unregister(struct neigh_parms *p);
static inline void __neigh_parms_put(struct neigh_parms *parms)
{
- atomic_dec(&parms->refcnt);
+ refcount_dec(&parms->refcnt);
}
static inline struct neigh_parms *neigh_parms_clone(struct neigh_parms *parms)
{
- atomic_inc(&parms->refcnt);
+ refcount_inc(&parms->refcnt);
return parms;
}
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 0c78c8e..e31fc11 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -709,7 +709,7 @@ static void neigh_parms_destroy(struct neigh_parms *parms);
static inline void neigh_parms_put(struct neigh_parms *parms)
{
- if (atomic_dec_and_test(&parms->refcnt))
+ if (refcount_dec_and_test(&parms->refcnt))
neigh_parms_destroy(parms);
}
@@ -1479,7 +1479,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
if (p) {
p->tbl = tbl;
- atomic_set(&p->refcnt, 1);
+ refcount_set(&p->refcnt, 1);
p->reachable_time =
neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
dev_hold(dev);
@@ -1542,7 +1542,7 @@ void neigh_table_init(int index, struct neigh_table *tbl)
INIT_LIST_HEAD(&tbl->parms_list);
list_add(&tbl->parms.list, &tbl->parms_list);
write_pnet(&tbl->parms.net, &init_net);
- atomic_set(&tbl->parms.refcnt, 1);
+ refcount_set(&tbl->parms.refcnt, 1);
tbl->parms.reachable_time =
neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME));
@@ -1796,7 +1796,7 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms)
if ((parms->dev &&
nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) ||
- nla_put_u32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)) ||
+ nla_put_u32(skb, NDTPA_REFCNT, refcount_read(&parms->refcnt)) ||
nla_put_u32(skb, NDTPA_QUEUE_LENBYTES,
NEIGH_VAR(parms, QUEUE_LEN_BYTES)) ||
/* approximative value for deprecated QUEUE_LEN (in packets) */
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 04/17] net: convert nf_bridge_info.use from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (2 preceding siblings ...)
2017-06-30 10:07 ` [PATCH 03/17] net: convert neigh_params.refcnt " Elena Reshetova
@ 2017-06-30 10:07 ` Elena Reshetova
2017-06-30 10:07 ` [PATCH 05/17] net: convert sk_buff.users " Elena Reshetova
` (13 subsequent siblings)
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:07 UTC (permalink / raw)
To: netdev
Cc: bridge, linux-kernel, kuznet, jmorris, kaber, stephen, peterz,
keescook, Elena Reshetova, Hans Liljestrand, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/linux/skbuff.h | 6 +++---
include/net/netfilter/br_netfilter.h | 2 +-
net/bridge/br_netfilter_hooks.c | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index a17e235..005793e 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -252,7 +252,7 @@ struct nf_conntrack {
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
struct nf_bridge_info {
- atomic_t use;
+ refcount_t use;
enum {
BRNF_PROTO_UNCHANGED,
BRNF_PROTO_8021Q,
@@ -3589,13 +3589,13 @@ static inline void nf_conntrack_get(struct nf_conntrack *nfct)
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge)
{
- if (nf_bridge && atomic_dec_and_test(&nf_bridge->use))
+ if (nf_bridge && refcount_dec_and_test(&nf_bridge->use))
kfree(nf_bridge);
}
static inline void nf_bridge_get(struct nf_bridge_info *nf_bridge)
{
if (nf_bridge)
- atomic_inc(&nf_bridge->use);
+ refcount_inc(&nf_bridge->use);
}
#endif /* CONFIG_BRIDGE_NETFILTER */
static inline void nf_reset(struct sk_buff *skb)
diff --git a/include/net/netfilter/br_netfilter.h b/include/net/netfilter/br_netfilter.h
index 0b0c35c..925524e 100644
--- a/include/net/netfilter/br_netfilter.h
+++ b/include/net/netfilter/br_netfilter.h
@@ -8,7 +8,7 @@ static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
skb->nf_bridge = kzalloc(sizeof(struct nf_bridge_info), GFP_ATOMIC);
if (likely(skb->nf_bridge))
- atomic_set(&(skb->nf_bridge->use), 1);
+ refcount_set(&(skb->nf_bridge->use), 1);
return skb->nf_bridge;
}
diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c
index 067cf03..2261e51 100644
--- a/net/bridge/br_netfilter_hooks.c
+++ b/net/bridge/br_netfilter_hooks.c
@@ -149,12 +149,12 @@ static inline struct nf_bridge_info *nf_bridge_unshare(struct sk_buff *skb)
{
struct nf_bridge_info *nf_bridge = skb->nf_bridge;
- if (atomic_read(&nf_bridge->use) > 1) {
+ if (refcount_read(&nf_bridge->use) > 1) {
struct nf_bridge_info *tmp = nf_bridge_alloc(skb);
if (tmp) {
memcpy(tmp, nf_bridge, sizeof(struct nf_bridge_info));
- atomic_set(&tmp->use, 1);
+ refcount_set(&tmp->use, 1);
}
nf_bridge_put(nf_bridge);
nf_bridge = tmp;
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 05/17] net: convert sk_buff.users from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (3 preceding siblings ...)
2017-06-30 10:07 ` [PATCH 04/17] net: convert nf_bridge_info.use " Elena Reshetova
@ 2017-06-30 10:07 ` Elena Reshetova
2017-06-30 10:07 ` [PATCH 06/17] net: convert sk_buff_fclones.fclone_ref " Elena Reshetova
` (12 subsequent siblings)
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:07 UTC (permalink / raw)
To: netdev
Cc: keescook, peterz, bridge, linux-kernel, jmorris,
Hans Liljestrand, kuznet, kaber, Elena Reshetova, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
drivers/infiniband/hw/nes/nes_cm.c | 4 ++--
drivers/isdn/mISDN/socket.c | 2 +-
drivers/net/rionet.c | 2 +-
drivers/s390/net/ctcm_main.c | 26 +++++++++++++-------------
drivers/s390/net/netiucv.c | 10 +++++-----
drivers/s390/net/qeth_core_main.c | 4 ++--
include/linux/skbuff.h | 10 +++++-----
net/core/datagram.c | 4 ++--
net/core/dev.c | 10 +++++-----
net/core/netpoll.c | 4 ++--
net/core/pktgen.c | 16 ++++++++--------
net/core/rtnetlink.c | 2 +-
net/core/skbuff.c | 8 ++++----
net/dccp/ipv6.c | 2 +-
net/ipv6/syncookies.c | 2 +-
net/ipv6/tcp_ipv6.c | 2 +-
net/key/af_key.c | 4 ++--
net/netlink/af_netlink.c | 6 +++---
net/rxrpc/skbuff.c | 12 ++++++------
net/sctp/outqueue.c | 2 +-
net/sctp/socket.c | 2 +-
21 files changed, 67 insertions(+), 67 deletions(-)
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 30b256a..de4025d 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -742,7 +742,7 @@ int schedule_nes_timer(struct nes_cm_node *cm_node, struct sk_buff *skb,
if (type == NES_TIMER_TYPE_SEND) {
new_send->seq_num = ntohl(tcp_hdr(skb)->seq);
- atomic_inc(&new_send->skb->users);
+ refcount_inc(&new_send->skb->users);
spin_lock_irqsave(&cm_node->retrans_list_lock, flags);
cm_node->send_entry = new_send;
add_ref_cm_node(cm_node);
@@ -924,7 +924,7 @@ static void nes_cm_timer_tick(unsigned long pass)
flags);
break;
}
- atomic_inc(&send_entry->skb->users);
+ refcount_inc(&send_entry->skb->users);
cm_packets_retrans++;
nes_debug(NES_DBG_CM, "Retransmitting send_entry %p "
"for node %p, jiffies = %lu, time to send = "
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index 99e5f97..c5603d1 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -155,7 +155,7 @@ mISDN_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
copied = skb->len + MISDN_HEADER_LEN;
if (len < copied) {
if (flags & MSG_PEEK)
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
else
skb_queue_head(&sk->sk_receive_queue, skb);
return -ENOSPC;
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index 300bb14..e9f101c 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -201,7 +201,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
rionet_queue_tx_msg(skb, ndev,
nets[rnet->mport->id].active[i]);
if (count)
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
count++;
}
} else if (RIONET_MAC_MATCH(eth->h_dest)) {
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index 9912135..e8782a8 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -483,7 +483,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
spin_unlock_irqrestore(&ch->collect_lock, saveflags);
return -EBUSY;
} else {
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
header.length = l;
header.type = be16_to_cpu(skb->protocol);
header.unused = 0;
@@ -500,7 +500,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
* Protect skb against beeing free'd by upper
* layers.
*/
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
ch->prof.txlen += skb->len;
header.length = skb->len + LL_HEADER_LENGTH;
header.type = be16_to_cpu(skb->protocol);
@@ -517,14 +517,14 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
if (hi) {
nskb = alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
if (!nskb) {
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
skb_pull(skb, LL_HEADER_LENGTH + 2);
ctcm_clear_busy(ch->netdev);
return -ENOMEM;
} else {
skb_put_data(nskb, skb->data, skb->len);
- atomic_inc(&nskb->users);
- atomic_dec(&skb->users);
+ refcount_inc(&nskb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
skb = nskb;
}
@@ -542,7 +542,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
* Remove our header. It gets added
* again on retransmit.
*/
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
skb_pull(skb, LL_HEADER_LENGTH + 2);
ctcm_clear_busy(ch->netdev);
return -ENOMEM;
@@ -553,7 +553,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
ch->ccw[1].count = skb->len;
skb_copy_from_linear_data(skb,
skb_put(ch->trans_skb, skb->len), skb->len);
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
ccw_idx = 0;
} else {
@@ -679,7 +679,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
if ((fsm_getstate(ch->fsm) != CTC_STATE_TXIDLE) || grp->in_sweep) {
spin_lock_irqsave(&ch->collect_lock, saveflags);
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
p_header = kmalloc(PDU_HEADER_LENGTH, gfp_type());
if (!p_header) {
@@ -716,7 +716,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
* Protect skb against beeing free'd by upper
* layers.
*/
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
/*
* IDAL support in CTCM is broken, so we have to
@@ -729,8 +729,8 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
goto nomem_exit;
} else {
skb_put_data(nskb, skb->data, skb->len);
- atomic_inc(&nskb->users);
- atomic_dec(&skb->users);
+ refcount_inc(&nskb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
skb = nskb;
}
@@ -810,7 +810,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
ch->trans_skb->len = 0;
ch->ccw[1].count = skb->len;
skb_put_data(ch->trans_skb, skb->data, skb->len);
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_irq(skb);
ccw_idx = 0;
CTCM_PR_DBGDATA("%s(%s): trans_skb len: %04x\n"
@@ -855,7 +855,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
"%s(%s): MEMORY allocation ERROR\n",
CTCM_FUNTAIL, ch->id);
rc = -ENOMEM;
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_any(skb);
fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev);
done:
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 7db427c..1579695 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -743,7 +743,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
conn->prof.tx_pending--;
if (single_flag) {
if ((skb = skb_dequeue(&conn->commit_queue))) {
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
if (privptr) {
privptr->stats.tx_packets++;
privptr->stats.tx_bytes +=
@@ -766,7 +766,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
txbytes += skb->len;
txpackets++;
stat_maxcq++;
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_any(skb);
}
if (conn->collect_len > conn->prof.maxmulti)
@@ -958,7 +958,7 @@ static void netiucv_purge_skb_queue(struct sk_buff_head *q)
struct sk_buff *skb;
while ((skb = skb_dequeue(q))) {
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_any(skb);
}
}
@@ -1176,7 +1176,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
IUCV_DBF_TEXT(data, 2,
"EBUSY from netiucv_transmit_skb\n");
} else {
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
skb_queue_tail(&conn->collect_queue, skb);
conn->collect_len += l;
rc = 0;
@@ -1245,7 +1245,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
} else {
if (copied)
dev_kfree_skb(skb);
- atomic_inc(&nskb->users);
+ refcount_inc(&nskb->users);
skb_queue_tail(&conn->commit_queue, nskb);
}
}
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 3b657d5..aec06e1 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -1242,7 +1242,7 @@ static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf)
iucv->sk_txnotify(skb, TX_NOTIFY_GENERALERROR);
}
}
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
dev_kfree_skb_any(skb);
skb = skb_dequeue(&buf->skb_list);
}
@@ -3975,7 +3975,7 @@ static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
int flush_cnt = 0, hdr_len, large_send = 0;
buffer = buf->buffer;
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
skb_queue_tail(&buf->skb_list, skb);
/*check first on TSO ....*/
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 005793e..90cbd86 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -761,7 +761,7 @@ struct sk_buff {
unsigned char *head,
*data;
unsigned int truesize;
- atomic_t users;
+ refcount_t users;
};
#ifdef __KERNEL__
@@ -872,9 +872,9 @@ static inline bool skb_unref(struct sk_buff *skb)
{
if (unlikely(!skb))
return false;
- if (likely(atomic_read(&skb->users) == 1))
+ if (likely(refcount_read(&skb->users) == 1))
smp_rmb();
- else if (likely(!atomic_dec_and_test(&skb->users)))
+ else if (likely(!refcount_dec_and_test(&skb->users)))
return false;
return true;
@@ -1283,7 +1283,7 @@ static inline struct sk_buff *skb_queue_prev(const struct sk_buff_head *list,
*/
static inline struct sk_buff *skb_get(struct sk_buff *skb)
{
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
return skb;
}
@@ -1384,7 +1384,7 @@ static inline void __skb_header_release(struct sk_buff *skb)
*/
static inline int skb_shared(const struct sk_buff *skb)
{
- return atomic_read(&skb->users) != 1;
+ return refcount_read(&skb->users) != 1;
}
/**
diff --git a/net/core/datagram.c b/net/core/datagram.c
index e5311a7..95d4354 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -188,7 +188,7 @@ struct sk_buff *__skb_try_recv_from_queue(struct sock *sk,
}
}
*peeked = 1;
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
} else {
__skb_unlink(skb, queue);
if (destructor)
@@ -358,7 +358,7 @@ int __sk_queue_drop_skb(struct sock *sk, struct sk_buff_head *sk_queue,
spin_lock_bh(&sk_queue->lock);
if (skb == skb_peek(sk_queue)) {
__skb_unlink(skb, sk_queue);
- atomic_dec(&skb->users);
+ refcount_dec(&skb->users);
if (destructor)
destructor(sk, skb);
err = 0;
diff --git a/net/core/dev.c b/net/core/dev.c
index a91572a..fcc0b75 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1862,7 +1862,7 @@ static inline int deliver_skb(struct sk_buff *skb,
{
if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC)))
return -ENOMEM;
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
}
@@ -2484,10 +2484,10 @@ void __dev_kfree_skb_irq(struct sk_buff *skb, enum skb_free_reason reason)
if (unlikely(!skb))
return;
- if (likely(atomic_read(&skb->users) == 1)) {
+ if (likely(refcount_read(&skb->users) == 1)) {
smp_rmb();
- atomic_set(&skb->users, 0);
- } else if (likely(!atomic_dec_and_test(&skb->users))) {
+ refcount_set(&skb->users, 0);
+ } else if (likely(!refcount_dec_and_test(&skb->users))) {
return;
}
get_kfree_skb_cb(skb)->reason = reason;
@@ -3955,7 +3955,7 @@ static __latent_entropy void net_tx_action(struct softirq_action *h)
clist = clist->next;
- WARN_ON(atomic_read(&skb->users));
+ WARN_ON(refcount_read(&skb->users));
if (likely(get_kfree_skb_cb(skb)->reason == SKB_REASON_CONSUMED))
trace_consume_skb(skb);
else
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 37c1e34..a835155 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -277,7 +277,7 @@ static void zap_completion_queue(void)
struct sk_buff *skb = clist;
clist = clist->next;
if (!skb_irq_freeable(skb)) {
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
dev_kfree_skb_any(skb); /* put this one back */
} else {
__kfree_skb(skb);
@@ -309,7 +309,7 @@ static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
return NULL;
}
- atomic_set(&skb->users, 1);
+ refcount_set(&skb->users, 1);
skb_reserve(skb, reserve);
return skb;
}
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 2dd42c5..6e1e10f 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -3363,7 +3363,7 @@ static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev)
{
ktime_t idle_start = ktime_get();
- while (atomic_read(&(pkt_dev->skb->users)) != 1) {
+ while (refcount_read(&(pkt_dev->skb->users)) != 1) {
if (signal_pending(current))
break;
@@ -3420,7 +3420,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
if (pkt_dev->xmit_mode == M_NETIF_RECEIVE) {
skb = pkt_dev->skb;
skb->protocol = eth_type_trans(skb, skb->dev);
- atomic_add(burst, &skb->users);
+ refcount_add(burst, &skb->users);
local_bh_disable();
do {
ret = netif_receive_skb(skb);
@@ -3428,11 +3428,11 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
pkt_dev->errors++;
pkt_dev->sofar++;
pkt_dev->seq_num++;
- if (atomic_read(&skb->users) != burst) {
+ if (refcount_read(&skb->users) != burst) {
/* skb was queued by rps/rfs or taps,
* so cannot reuse this skb
*/
- atomic_sub(burst - 1, &skb->users);
+ WARN_ON(refcount_sub_and_test(burst - 1, &skb->users));
/* get out of the loop and wait
* until skb is consumed
*/
@@ -3446,7 +3446,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
goto out; /* Skips xmit_mode M_START_XMIT */
} else if (pkt_dev->xmit_mode == M_QUEUE_XMIT) {
local_bh_disable();
- atomic_inc(&pkt_dev->skb->users);
+ refcount_inc(&pkt_dev->skb->users);
ret = dev_queue_xmit(pkt_dev->skb);
switch (ret) {
@@ -3487,7 +3487,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
pkt_dev->last_ok = 0;
goto unlock;
}
- atomic_add(burst, &pkt_dev->skb->users);
+ refcount_add(burst, &pkt_dev->skb->users);
xmit_more:
ret = netdev_start_xmit(pkt_dev->skb, odev, txq, --burst > 0);
@@ -3513,11 +3513,11 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
/* fallthru */
case NETDEV_TX_BUSY:
/* Retry it next time */
- atomic_dec(&(pkt_dev->skb->users));
+ refcount_dec(&(pkt_dev->skb->users));
pkt_dev->last_ok = 0;
}
if (unlikely(burst))
- atomic_sub(burst, &pkt_dev->skb->users);
+ WARN_ON(refcount_sub_and_test(burst, &pkt_dev->skb->users));
unlock:
HARD_TX_UNLOCK(odev, txq);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index ed51de5..d1ba909 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -649,7 +649,7 @@ int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned int g
NETLINK_CB(skb).dst_group = group;
if (echo)
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
netlink_broadcast(rtnl, skb, pid, group, GFP_KERNEL);
if (echo)
err = netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index f75897a..45dc662 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -176,7 +176,7 @@ struct sk_buff *__alloc_skb_head(gfp_t gfp_mask, int node)
memset(skb, 0, offsetof(struct sk_buff, tail));
skb->head = NULL;
skb->truesize = sizeof(struct sk_buff);
- atomic_set(&skb->users, 1);
+ refcount_set(&skb->users, 1);
skb->mac_header = (typeof(skb->mac_header))~0U;
out:
@@ -247,7 +247,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
/* Account for allocated memory : skb + skb->head */
skb->truesize = SKB_TRUESIZE(size);
skb->pfmemalloc = pfmemalloc;
- atomic_set(&skb->users, 1);
+ refcount_set(&skb->users, 1);
skb->head = data;
skb->data = data;
skb_reset_tail_pointer(skb);
@@ -314,7 +314,7 @@ struct sk_buff *__build_skb(void *data, unsigned int frag_size)
memset(skb, 0, offsetof(struct sk_buff, tail));
skb->truesize = SKB_TRUESIZE(size);
- atomic_set(&skb->users, 1);
+ refcount_set(&skb->users, 1);
skb->head = data;
skb->data = data;
skb_reset_tail_pointer(skb);
@@ -915,7 +915,7 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
C(head_frag);
C(data);
C(truesize);
- atomic_set(&n->users, 1);
+ refcount_set(&n->users, 1);
atomic_inc(&(skb_shinfo(skb)->dataref));
skb->cloned = 1;
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 4fccc0c..c376af5 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -353,7 +353,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
if (ipv6_opt_accepted(sk, skb, IP6CB(skb)) ||
np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
ireq->pktopts = skb;
}
ireq->ir_iif = sk->sk_bound_dev_if;
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 2f7e99a..7b75b06 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -194,7 +194,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
if (ipv6_opt_accepted(sk, skb, &TCP_SKB_CB(skb)->header.h6) ||
np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo ||
np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) {
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
ireq->pktopts = skb;
}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index f85cbfc..f1a4881 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -734,7 +734,7 @@ static void tcp_v6_init_req(struct request_sock *req,
np->rxopt.bits.rxinfo ||
np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim ||
np->rxopt.bits.rxohlim || np->repflow)) {
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
ireq->pktopts = skb;
}
}
diff --git a/net/key/af_key.c b/net/key/af_key.c
index ce9b856..0fe7ff3 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -203,11 +203,11 @@ static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2,
sock_hold(sk);
if (*skb2 == NULL) {
- if (atomic_read(&skb->users) != 1) {
+ if (refcount_read(&skb->users) != 1) {
*skb2 = skb_clone(skb, allocation);
} else {
*skb2 = skb;
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
}
}
if (*skb2 != NULL) {
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index a88745e..05030ad 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1848,7 +1848,7 @@ static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
}
if (dst_group) {
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
netlink_broadcast(sk, skb, dst_portid, dst_group, GFP_KERNEL);
}
err = netlink_unicast(sk, skb, dst_portid, msg->msg_flags&MSG_DONTWAIT);
@@ -2226,7 +2226,7 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
struct netlink_sock *nlk;
int ret;
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).portid);
if (sk == NULL) {
@@ -2431,7 +2431,7 @@ int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 portid,
int exclude_portid = 0;
if (report) {
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
exclude_portid = portid;
}
diff --git a/net/rxrpc/skbuff.c b/net/rxrpc/skbuff.c
index 67b02c4..b8985d0 100644
--- a/net/rxrpc/skbuff.c
+++ b/net/rxrpc/skbuff.c
@@ -27,7 +27,7 @@ void rxrpc_new_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
{
const void *here = __builtin_return_address(0);
int n = atomic_inc_return(select_skb_count(op));
- trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here);
+ trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, here);
}
/*
@@ -38,7 +38,7 @@ void rxrpc_see_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
const void *here = __builtin_return_address(0);
if (skb) {
int n = atomic_read(select_skb_count(op));
- trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here);
+ trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, here);
}
}
@@ -49,7 +49,7 @@ void rxrpc_get_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
{
const void *here = __builtin_return_address(0);
int n = atomic_inc_return(select_skb_count(op));
- trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here);
+ trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, here);
skb_get(skb);
}
@@ -63,7 +63,7 @@ void rxrpc_free_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
int n;
CHECK_SLAB_OKAY(&skb->users);
n = atomic_dec_return(select_skb_count(op));
- trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here);
+ trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, here);
kfree_skb(skb);
}
}
@@ -78,7 +78,7 @@ void rxrpc_lose_skb(struct sk_buff *skb, enum rxrpc_skb_trace op)
int n;
CHECK_SLAB_OKAY(&skb->users);
n = atomic_dec_return(select_skb_count(op));
- trace_rxrpc_skb(skb, op, atomic_read(&skb->users), n, here);
+ trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, here);
kfree_skb(skb);
}
}
@@ -93,7 +93,7 @@ void rxrpc_purge_queue(struct sk_buff_head *list)
while ((skb = skb_dequeue((list))) != NULL) {
int n = atomic_dec_return(select_skb_count(rxrpc_skb_rx_purged));
trace_rxrpc_skb(skb, rxrpc_skb_rx_purged,
- atomic_read(&skb->users), n, here);
+ refcount_read(&skb->users), n, here);
kfree_skb(skb);
}
}
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 20299df..e876270 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -1102,7 +1102,7 @@ static void sctp_outq_flush(struct sctp_outq *q, int rtx_timeout, gfp_t gfp)
sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) :
"illegal chunk", ntohl(chunk->subh.data_hdr->tsn),
chunk->skb ? chunk->skb->head : NULL, chunk->skb ?
- atomic_read(&chunk->skb->users) : -1);
+ refcount_read(&chunk->skb->users) : -1);
/* Add the chunk to the packet. */
status = sctp_packet_transmit_chunk(packet, chunk, 0, gfp);
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 7b6e20e..b497ee8 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -7563,7 +7563,7 @@ struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
if (flags & MSG_PEEK) {
skb = skb_peek(&sk->sk_receive_queue);
if (skb)
- atomic_inc(&skb->users);
+ refcount_inc(&skb->users);
} else {
skb = __skb_dequeue(&sk->sk_receive_queue);
}
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 06/17] net: convert sk_buff_fclones.fclone_ref from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (4 preceding siblings ...)
2017-06-30 10:07 ` [PATCH 05/17] net: convert sk_buff.users " Elena Reshetova
@ 2017-06-30 10:07 ` Elena Reshetova
2017-06-30 10:08 ` [PATCH 07/17] net: convert sock.sk_wmem_alloc " Elena Reshetova
` (11 subsequent siblings)
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:07 UTC (permalink / raw)
To: netdev
Cc: keescook, peterz, bridge, linux-kernel, jmorris,
Hans Liljestrand, kuznet, kaber, Elena Reshetova, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/linux/skbuff.h | 4 ++--
net/core/skbuff.c | 10 +++++-----
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 90cbd86..d0b9f38 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -915,7 +915,7 @@ struct sk_buff_fclones {
struct sk_buff skb2;
- atomic_t fclone_ref;
+ refcount_t fclone_ref;
};
/**
@@ -935,7 +935,7 @@ static inline bool skb_fclone_busy(const struct sock *sk,
fclones = container_of(skb, struct sk_buff_fclones, skb1);
return skb->fclone == SKB_FCLONE_ORIG &&
- atomic_read(&fclones->fclone_ref) > 1 &&
+ refcount_read(&fclones->fclone_ref) > 1 &&
fclones->skb2.sk == sk;
}
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 45dc662..659dfc0 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -268,7 +268,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
kmemcheck_annotate_bitfield(&fclones->skb2, flags1);
skb->fclone = SKB_FCLONE_ORIG;
- atomic_set(&fclones->fclone_ref, 1);
+ refcount_set(&fclones->fclone_ref, 1);
fclones->skb2.fclone = SKB_FCLONE_CLONE;
}
@@ -629,7 +629,7 @@ static void kfree_skbmem(struct sk_buff *skb)
* This test would have no chance to be true for the clone,
* while here, branch prediction will be good.
*/
- if (atomic_read(&fclones->fclone_ref) == 1)
+ if (refcount_read(&fclones->fclone_ref) == 1)
goto fastpath;
break;
@@ -637,7 +637,7 @@ static void kfree_skbmem(struct sk_buff *skb)
fclones = container_of(skb, struct sk_buff_fclones, skb2);
break;
}
- if (!atomic_dec_and_test(&fclones->fclone_ref))
+ if (!refcount_dec_and_test(&fclones->fclone_ref))
return;
fastpath:
kmem_cache_free(skbuff_fclone_cache, fclones);
@@ -1027,9 +1027,9 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
return NULL;
if (skb->fclone == SKB_FCLONE_ORIG &&
- atomic_read(&fclones->fclone_ref) == 1) {
+ refcount_read(&fclones->fclone_ref) == 1) {
n = &fclones->skb2;
- atomic_set(&fclones->fclone_ref, 2);
+ refcount_set(&fclones->fclone_ref, 2);
} else {
if (skb_pfmemalloc(skb))
gfp_mask |= __GFP_MEMALLOC;
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 07/17] net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (5 preceding siblings ...)
2017-06-30 10:07 ` [PATCH 06/17] net: convert sk_buff_fclones.fclone_ref " Elena Reshetova
@ 2017-06-30 10:08 ` Elena Reshetova
2018-06-15 12:29 ` David Woodhouse
2017-06-30 10:08 ` [PATCH 08/17] net: convert sock.sk_refcnt " Elena Reshetova
` (10 subsequent siblings)
17 siblings, 1 reply; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:08 UTC (permalink / raw)
To: netdev
Cc: bridge, linux-kernel, kuznet, jmorris, kaber, stephen, peterz,
keescook, Elena Reshetova, Hans Liljestrand, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
drivers/atm/fore200e.c | 12 +-----------
drivers/atm/he.c | 2 +-
drivers/atm/idt77252.c | 4 ++--
include/linux/atmdev.h | 2 +-
include/net/sock.h | 8 ++++----
net/atm/br2684.c | 2 +-
net/atm/clip.c | 2 +-
net/atm/common.c | 10 +++++-----
net/atm/lec.c | 4 ++--
net/atm/mpc.c | 4 ++--
net/atm/pppoatm.c | 2 +-
net/atm/raw.c | 2 +-
net/atm/signaling.c | 2 +-
net/caif/caif_socket.c | 2 +-
net/core/datagram.c | 2 +-
net/core/skbuff.c | 2 +-
net/core/sock.c | 26 +++++++++++++-------------
net/ipv4/af_inet.c | 2 +-
net/ipv4/esp4.c | 2 +-
net/ipv4/ip_output.c | 6 +++---
net/ipv4/tcp.c | 4 ++--
net/ipv4/tcp_offload.c | 2 +-
net/ipv4/tcp_output.c | 15 +++++++--------
net/ipv6/esp6.c | 2 +-
net/ipv6/ip6_output.c | 4 ++--
net/kcm/kcmproc.c | 2 +-
net/key/af_key.c | 2 +-
net/netlink/af_netlink.c | 2 +-
net/packet/af_packet.c | 4 ++--
net/phonet/socket.c | 2 +-
net/rds/tcp_send.c | 2 +-
net/rxrpc/af_rxrpc.c | 4 ++--
net/sched/sch_atm.c | 2 +-
net/sctp/output.c | 2 +-
net/sctp/proc.c | 2 +-
net/sctp/socket.c | 4 ++--
net/unix/af_unix.c | 6 +++---
37 files changed, 74 insertions(+), 85 deletions(-)
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 7584ae1..f0433ad 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -924,12 +924,7 @@ fore200e_tx_irq(struct fore200e* fore200e)
else {
dev_kfree_skb_any(entry->skb);
}
-#if 1
- /* race fixed by the above incarnation mechanism, but... */
- if (atomic_read(&sk_atm(vcc)->sk_wmem_alloc) < 0) {
- atomic_set(&sk_atm(vcc)->sk_wmem_alloc, 0);
- }
-#endif
+
/* check error condition */
if (*entry->status & STATUS_ERROR)
atomic_inc(&vcc->stats->tx_err);
@@ -1130,13 +1125,9 @@ fore200e_push_rpd(struct fore200e* fore200e, struct atm_vcc* vcc, struct rpd* rp
return -ENOMEM;
}
- ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);
-
vcc->push(vcc, skb);
atomic_inc(&vcc->stats->rx);
- ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);
-
return 0;
}
@@ -1572,7 +1563,6 @@ fore200e_send(struct atm_vcc *vcc, struct sk_buff *skb)
unsigned long flags;
ASSERT(vcc);
- ASSERT(atomic_read(&sk_atm(vcc)->sk_wmem_alloc) >= 0);
ASSERT(fore200e);
ASSERT(fore200e_vcc);
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index 461da2b..37ee21c 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -2395,7 +2395,7 @@ he_close(struct atm_vcc *vcc)
* TBRQ, the host issues the close command to the adapter.
*/
- while (((tx_inuse = atomic_read(&sk_atm(vcc)->sk_wmem_alloc)) > 1) &&
+ while (((tx_inuse = refcount_read(&sk_atm(vcc)->sk_wmem_alloc)) > 1) &&
(retry < MAX_RETRY)) {
msleep(sleep);
if (sleep < 250)
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index 4e64de3..60bacba 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -724,7 +724,7 @@ push_on_scq(struct idt77252_dev *card, struct vc_map *vc, struct sk_buff *skb)
struct sock *sk = sk_atm(vcc);
vc->estimator->cells += (skb->len + 47) / 48;
- if (atomic_read(&sk->sk_wmem_alloc) >
+ if (refcount_read(&sk->sk_wmem_alloc) >
(sk->sk_sndbuf >> 1)) {
u32 cps = vc->estimator->maxcps;
@@ -2009,7 +2009,7 @@ idt77252_send_oam(struct atm_vcc *vcc, void *cell, int flags)
atomic_inc(&vcc->stats->tx_err);
return -ENOMEM;
}
- atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
+ refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
skb_put_data(skb, cell, 52);
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
index c1da539..4d97a89 100644
--- a/include/linux/atmdev.h
+++ b/include/linux/atmdev.h
@@ -254,7 +254,7 @@ static inline void atm_return(struct atm_vcc *vcc,int truesize)
static inline int atm_may_send(struct atm_vcc *vcc,unsigned int size)
{
- return (size + atomic_read(&sk_atm(vcc)->sk_wmem_alloc)) <
+ return (size + refcount_read(&sk_atm(vcc)->sk_wmem_alloc)) <
sk_atm(vcc)->sk_sndbuf;
}
diff --git a/include/net/sock.h b/include/net/sock.h
index 00d0914..5284e50 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -390,7 +390,7 @@ struct sock {
/* ===== cache line for TX ===== */
int sk_wmem_queued;
- atomic_t sk_wmem_alloc;
+ refcount_t sk_wmem_alloc;
unsigned long sk_tsq_flags;
struct sk_buff *sk_send_head;
struct sk_buff_head sk_write_queue;
@@ -1911,7 +1911,7 @@ static inline int skb_copy_to_page_nocache(struct sock *sk, struct iov_iter *fro
*/
static inline int sk_wmem_alloc_get(const struct sock *sk)
{
- return atomic_read(&sk->sk_wmem_alloc) - 1;
+ return refcount_read(&sk->sk_wmem_alloc) - 1;
}
/**
@@ -2055,7 +2055,7 @@ static inline unsigned long sock_wspace(struct sock *sk)
int amt = 0;
if (!(sk->sk_shutdown & SEND_SHUTDOWN)) {
- amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);
+ amt = sk->sk_sndbuf - refcount_read(&sk->sk_wmem_alloc);
if (amt < 0)
amt = 0;
}
@@ -2136,7 +2136,7 @@ bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag);
*/
static inline bool sock_writeable(const struct sock *sk)
{
- return atomic_read(&sk->sk_wmem_alloc) < (sk->sk_sndbuf >> 1);
+ return refcount_read(&sk->sk_wmem_alloc) < (sk->sk_sndbuf >> 1);
}
static inline gfp_t gfp_any(void)
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index fca84e1..4e11119 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -252,7 +252,7 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev,
ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev);
- atomic_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);
+ refcount_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);
ATM_SKB(skb)->atm_options = atmvcc->atm_options;
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 47c36f4..f271a7b 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -381,7 +381,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
memcpy(here, llc_oui, sizeof(llc_oui));
((__be16 *) here)[3] = skb->protocol;
}
- atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
+ refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
ATM_SKB(skb)->atm_options = vcc->atm_options;
entry->vccs->last_use = jiffies;
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev);
diff --git a/net/atm/common.c b/net/atm/common.c
index f06422f..8a4f991 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -80,9 +80,9 @@ static void vcc_sock_destruct(struct sock *sk)
printk(KERN_DEBUG "%s: rmem leakage (%d bytes) detected.\n",
__func__, atomic_read(&sk->sk_rmem_alloc));
- if (atomic_read(&sk->sk_wmem_alloc))
+ if (refcount_read(&sk->sk_wmem_alloc))
printk(KERN_DEBUG "%s: wmem leakage (%d bytes) detected.\n",
- __func__, atomic_read(&sk->sk_wmem_alloc));
+ __func__, refcount_read(&sk->sk_wmem_alloc));
}
static void vcc_def_wakeup(struct sock *sk)
@@ -101,7 +101,7 @@ static inline int vcc_writable(struct sock *sk)
struct atm_vcc *vcc = atm_sk(sk);
return (vcc->qos.txtp.max_sdu +
- atomic_read(&sk->sk_wmem_alloc)) <= sk->sk_sndbuf;
+ refcount_read(&sk->sk_wmem_alloc)) <= sk->sk_sndbuf;
}
static void vcc_write_space(struct sock *sk)
@@ -156,7 +156,7 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family, i
memset(&vcc->local, 0, sizeof(struct sockaddr_atmsvc));
memset(&vcc->remote, 0, sizeof(struct sockaddr_atmsvc));
vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */
- atomic_set(&sk->sk_wmem_alloc, 1);
+ refcount_set(&sk->sk_wmem_alloc, 1);
atomic_set(&sk->sk_rmem_alloc, 0);
vcc->push = NULL;
vcc->pop = NULL;
@@ -630,7 +630,7 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size)
goto out;
}
pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize);
- atomic_add(skb->truesize, &sk->sk_wmem_alloc);
+ refcount_add(skb->truesize, &sk->sk_wmem_alloc);
skb->dev = NULL; /* for paths shared with net_device interfaces */
ATM_SKB(skb)->atm_options = vcc->atm_options;
diff --git a/net/atm/lec.c b/net/atm/lec.c
index 09cfe87..7554571 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -181,7 +181,7 @@ lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
ATM_SKB(skb)->vcc = vcc;
ATM_SKB(skb)->atm_options = vcc->atm_options;
- atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
+ refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
if (vcc->send(vcc, skb) < 0) {
dev->stats.tx_dropped++;
return;
@@ -345,7 +345,7 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
int i;
char *tmp; /* FIXME */
- atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
+ WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc));
mesg = (struct atmlec_msg *)skb->data;
tmp = skb->data;
tmp += sizeof(struct atmlec_msg);
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
index a190800..680a4b9 100644
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -555,7 +555,7 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc)
sizeof(struct llc_snap_hdr));
}
- atomic_add(skb->truesize, &sk_atm(entry->shortcut)->sk_wmem_alloc);
+ refcount_add(skb->truesize, &sk_atm(entry->shortcut)->sk_wmem_alloc);
ATM_SKB(skb)->atm_options = entry->shortcut->atm_options;
entry->shortcut->send(entry->shortcut, skb);
entry->packets_fwded++;
@@ -911,7 +911,7 @@ static int msg_from_mpoad(struct atm_vcc *vcc, struct sk_buff *skb)
struct mpoa_client *mpc = find_mpc_by_vcc(vcc);
struct k_message *mesg = (struct k_message *)skb->data;
- atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
+ WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc));
if (mpc == NULL) {
pr_info("no mpc found\n");
diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c
index c4e0984..21d9d34 100644
--- a/net/atm/pppoatm.c
+++ b/net/atm/pppoatm.c
@@ -350,7 +350,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
return 1;
}
- atomic_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc);
+ refcount_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc);
ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n",
skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev);
diff --git a/net/atm/raw.c b/net/atm/raw.c
index 2e17e97..821c079 100644
--- a/net/atm/raw.c
+++ b/net/atm/raw.c
@@ -35,7 +35,7 @@ static void atm_pop_raw(struct atm_vcc *vcc, struct sk_buff *skb)
pr_debug("(%d) %d -= %d\n",
vcc->vci, sk_wmem_alloc_get(sk), skb->truesize);
- atomic_sub(skb->truesize, &sk->sk_wmem_alloc);
+ WARN_ON(refcount_sub_and_test(skb->truesize, &sk->sk_wmem_alloc));
dev_kfree_skb_any(skb);
sk->sk_write_space(sk);
}
diff --git a/net/atm/signaling.c b/net/atm/signaling.c
index f640a99..983c3a2 100644
--- a/net/atm/signaling.c
+++ b/net/atm/signaling.c
@@ -67,7 +67,7 @@ static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb)
struct sock *sk;
msg = (struct atmsvc_msg *) skb->data;
- atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
+ WARN_ON(refcount_sub_and_test(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc));
vcc = *(struct atm_vcc **) &msg->vcc;
pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc);
sk = sk_atm(vcc);
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 7506b85..632d5a4 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -1013,7 +1013,7 @@ static const struct proto_ops caif_stream_ops = {
static void caif_sock_destructor(struct sock *sk)
{
struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
- caif_assert(!atomic_read(&sk->sk_wmem_alloc));
+ caif_assert(!refcount_read(&sk->sk_wmem_alloc));
caif_assert(sk_unhashed(sk));
caif_assert(!sk->sk_socket);
if (!sock_flag(sk, SOCK_DEAD)) {
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 95d4354..454ec89 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -614,7 +614,7 @@ int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from)
skb->data_len += copied;
skb->len += copied;
skb->truesize += truesize;
- atomic_add(truesize, &skb->sk->sk_wmem_alloc);
+ refcount_add(truesize, &skb->sk->sk_wmem_alloc);
while (copied) {
int size = min_t(int, copied, PAGE_SIZE - start);
skb_fill_page_desc(skb, frag++, pages[n], start, size);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 659dfc0..c267713 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3024,7 +3024,7 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,
get_page(pfrag->page);
skb->truesize += copy;
- atomic_add(copy, &sk->sk_wmem_alloc);
+ refcount_add(copy, &sk->sk_wmem_alloc);
skb->len += copy;
skb->data_len += copy;
offset += copy;
diff --git a/net/core/sock.c b/net/core/sock.c
index 6f4b090..0866d59 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1528,7 +1528,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
if (likely(sk->sk_net_refcnt))
get_net(net);
sock_net_set(sk, net);
- atomic_set(&sk->sk_wmem_alloc, 1);
+ refcount_set(&sk->sk_wmem_alloc, 1);
mem_cgroup_sk_alloc(sk);
cgroup_sk_alloc(&sk->sk_cgrp_data);
@@ -1552,7 +1552,7 @@ static void __sk_destruct(struct rcu_head *head)
sk->sk_destruct(sk);
filter = rcu_dereference_check(sk->sk_filter,
- atomic_read(&sk->sk_wmem_alloc) == 0);
+ refcount_read(&sk->sk_wmem_alloc) == 0);
if (filter) {
sk_filter_uncharge(sk, filter);
RCU_INIT_POINTER(sk->sk_filter, NULL);
@@ -1602,7 +1602,7 @@ void sk_free(struct sock *sk)
* some packets are still in some tx queue.
* If not null, sock_wfree() will call __sk_free(sk) later
*/
- if (atomic_dec_and_test(&sk->sk_wmem_alloc))
+ if (refcount_dec_and_test(&sk->sk_wmem_alloc))
__sk_free(sk);
}
EXPORT_SYMBOL(sk_free);
@@ -1659,7 +1659,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
/*
* sk_wmem_alloc set to one (see sk_free() and sock_wfree())
*/
- atomic_set(&newsk->sk_wmem_alloc, 1);
+ refcount_set(&newsk->sk_wmem_alloc, 1);
atomic_set(&newsk->sk_omem_alloc, 0);
sk_init_common(newsk);
@@ -1787,7 +1787,7 @@ void sock_wfree(struct sk_buff *skb)
* Keep a reference on sk_wmem_alloc, this will be released
* after sk_write_space() call
*/
- atomic_sub(len - 1, &sk->sk_wmem_alloc);
+ WARN_ON(refcount_sub_and_test(len - 1, &sk->sk_wmem_alloc));
sk->sk_write_space(sk);
len = 1;
}
@@ -1795,7 +1795,7 @@ void sock_wfree(struct sk_buff *skb)
* if sk_wmem_alloc reaches 0, we must finish what sk_free()
* could not do because of in-flight packets
*/
- if (atomic_sub_and_test(len, &sk->sk_wmem_alloc))
+ if (refcount_sub_and_test(len, &sk->sk_wmem_alloc))
__sk_free(sk);
}
EXPORT_SYMBOL(sock_wfree);
@@ -1807,7 +1807,7 @@ void __sock_wfree(struct sk_buff *skb)
{
struct sock *sk = skb->sk;
- if (atomic_sub_and_test(skb->truesize, &sk->sk_wmem_alloc))
+ if (refcount_sub_and_test(skb->truesize, &sk->sk_wmem_alloc))
__sk_free(sk);
}
@@ -1829,7 +1829,7 @@ void skb_set_owner_w(struct sk_buff *skb, struct sock *sk)
* is enough to guarantee sk_free() wont free this sock until
* all in-flight packets are completed
*/
- atomic_add(skb->truesize, &sk->sk_wmem_alloc);
+ refcount_add(skb->truesize, &sk->sk_wmem_alloc);
}
EXPORT_SYMBOL(skb_set_owner_w);
@@ -1852,7 +1852,7 @@ void skb_orphan_partial(struct sk_buff *skb)
struct sock *sk = skb->sk;
if (atomic_inc_not_zero(&sk->sk_refcnt)) {
- atomic_sub(skb->truesize, &sk->sk_wmem_alloc);
+ WARN_ON(refcount_sub_and_test(skb->truesize, &sk->sk_wmem_alloc));
skb->destructor = sock_efree;
}
} else {
@@ -1912,7 +1912,7 @@ EXPORT_SYMBOL(sock_i_ino);
struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force,
gfp_t priority)
{
- if (force || atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) {
+ if (force || refcount_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) {
struct sk_buff *skb = alloc_skb(size, priority);
if (skb) {
skb_set_owner_w(skb, sk);
@@ -1987,7 +1987,7 @@ static long sock_wait_for_wmem(struct sock *sk, long timeo)
break;
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
- if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf)
+ if (refcount_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf)
break;
if (sk->sk_shutdown & SEND_SHUTDOWN)
break;
@@ -2310,7 +2310,7 @@ int __sk_mem_raise_allocated(struct sock *sk, int size, int amt, int kind)
if (sk->sk_type == SOCK_STREAM) {
if (sk->sk_wmem_queued < prot->sysctl_wmem[0])
return 1;
- } else if (atomic_read(&sk->sk_wmem_alloc) <
+ } else if (refcount_read(&sk->sk_wmem_alloc) <
prot->sysctl_wmem[0])
return 1;
}
@@ -2577,7 +2577,7 @@ static void sock_def_write_space(struct sock *sk)
/* Do not wake up a writer until he can make "significant"
* progress. --DaveM
*/
- if ((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) {
+ if ((refcount_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) {
wq = rcu_dereference(sk->sk_wq);
if (skwq_has_sleeper(wq))
wake_up_interruptible_sync_poll(&wq->wait, POLLOUT |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 58925b6..76c2077c 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -150,7 +150,7 @@ void inet_sock_destruct(struct sock *sk)
}
WARN_ON(atomic_read(&sk->sk_rmem_alloc));
- WARN_ON(atomic_read(&sk->sk_wmem_alloc));
+ WARN_ON(refcount_read(&sk->sk_wmem_alloc));
WARN_ON(sk->sk_wmem_queued);
WARN_ON(sk->sk_forward_alloc);
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 1f18b46..0cbee0a 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -307,7 +307,7 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *
skb->data_len += tailen;
skb->truesize += tailen;
if (sk)
- atomic_add(tailen, &sk->sk_wmem_alloc);
+ refcount_add(tailen, &sk->sk_wmem_alloc);
goto out;
}
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 7a3fd25..c3ddfbb 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1036,7 +1036,7 @@ static int __ip_append_data(struct sock *sk,
(flags & MSG_DONTWAIT), &err);
} else {
skb = NULL;
- if (atomic_read(&sk->sk_wmem_alloc) <=
+ if (refcount_read(&sk->sk_wmem_alloc) <=
2 * sk->sk_sndbuf)
skb = sock_wmalloc(sk,
alloclen + hh_len + 15, 1,
@@ -1144,7 +1144,7 @@ static int __ip_append_data(struct sock *sk,
skb->len += copy;
skb->data_len += copy;
skb->truesize += copy;
- atomic_add(copy, &sk->sk_wmem_alloc);
+ refcount_add(copy, &sk->sk_wmem_alloc);
}
offset += copy;
length -= copy;
@@ -1368,7 +1368,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page,
skb->len += len;
skb->data_len += len;
skb->truesize += len;
- atomic_add(len, &sk->sk_wmem_alloc);
+ refcount_add(len, &sk->sk_wmem_alloc);
offset += len;
size -= len;
}
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 4c88d20..f2b47e8 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -664,7 +664,7 @@ static bool tcp_should_autocork(struct sock *sk, struct sk_buff *skb,
return skb->len < size_goal &&
sysctl_tcp_autocorking &&
skb != tcp_write_queue_head(sk) &&
- atomic_read(&sk->sk_wmem_alloc) > skb->truesize;
+ refcount_read(&sk->sk_wmem_alloc) > skb->truesize;
}
static void tcp_push(struct sock *sk, int flags, int mss_now,
@@ -692,7 +692,7 @@ static void tcp_push(struct sock *sk, int flags, int mss_now,
/* It is possible TX completion already happened
* before we set TSQ_THROTTLED.
*/
- if (atomic_read(&sk->sk_wmem_alloc) > skb->truesize)
+ if (refcount_read(&sk->sk_wmem_alloc) > skb->truesize)
return;
}
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c
index bc68da3..11f69bb 100644
--- a/net/ipv4/tcp_offload.c
+++ b/net/ipv4/tcp_offload.c
@@ -152,7 +152,7 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
swap(gso_skb->sk, skb->sk);
swap(gso_skb->destructor, skb->destructor);
sum_truesize += skb->truesize;
- atomic_add(sum_truesize - gso_skb->truesize,
+ refcount_add(sum_truesize - gso_skb->truesize,
&skb->sk->sk_wmem_alloc);
}
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 9a9c395..1d79137 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -861,12 +861,11 @@ void tcp_wfree(struct sk_buff *skb)
struct sock *sk = skb->sk;
struct tcp_sock *tp = tcp_sk(sk);
unsigned long flags, nval, oval;
- int wmem;
/* Keep one reference on sk_wmem_alloc.
* Will be released by sk_free() from here or tcp_tasklet_func()
*/
- wmem = atomic_sub_return(skb->truesize - 1, &sk->sk_wmem_alloc);
+ WARN_ON(refcount_sub_and_test(skb->truesize - 1, &sk->sk_wmem_alloc));
/* If this softirq is serviced by ksoftirqd, we are likely under stress.
* Wait until our queues (qdisc + devices) are drained.
@@ -875,7 +874,7 @@ void tcp_wfree(struct sk_buff *skb)
* - chance for incoming ACK (processed by another cpu maybe)
* to migrate this flow (skb->ooo_okay will be eventually set)
*/
- if (wmem >= SKB_TRUESIZE(1) && this_cpu_ksoftirqd() == current)
+ if (refcount_read(&sk->sk_wmem_alloc) >= SKB_TRUESIZE(1) && this_cpu_ksoftirqd() == current)
goto out;
for (oval = READ_ONCE(sk->sk_tsq_flags);; oval = nval) {
@@ -925,7 +924,7 @@ enum hrtimer_restart tcp_pace_kick(struct hrtimer *timer)
if (nval != oval)
continue;
- if (!atomic_inc_not_zero(&sk->sk_wmem_alloc))
+ if (!refcount_inc_not_zero(&sk->sk_wmem_alloc))
break;
/* queue this socket to tasklet queue */
tsq = this_cpu_ptr(&tsq_tasklet);
@@ -1045,7 +1044,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
skb->sk = sk;
skb->destructor = skb_is_tcp_pure_ack(skb) ? __sock_wfree : tcp_wfree;
skb_set_hash_from_sk(skb, sk);
- atomic_add(skb->truesize, &sk->sk_wmem_alloc);
+ refcount_add(skb->truesize, &sk->sk_wmem_alloc);
skb_set_dst_pending_confirm(skb, sk->sk_dst_pending_confirm);
@@ -2176,7 +2175,7 @@ static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb,
limit = min_t(u32, limit, sysctl_tcp_limit_output_bytes);
limit <<= factor;
- if (atomic_read(&sk->sk_wmem_alloc) > limit) {
+ if (refcount_read(&sk->sk_wmem_alloc) > limit) {
/* Always send the 1st or 2nd skb in write queue.
* No need to wait for TX completion to call us back,
* after softirq/tasklet schedule.
@@ -2192,7 +2191,7 @@ static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb,
* test again the condition.
*/
smp_mb__after_atomic();
- if (atomic_read(&sk->sk_wmem_alloc) > limit)
+ if (refcount_read(&sk->sk_wmem_alloc) > limit)
return true;
}
return false;
@@ -2812,7 +2811,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs)
/* Do not sent more than we queued. 1/4 is reserved for possible
* copying overhead: fragmentation, tunneling, mangling etc.
*/
- if (atomic_read(&sk->sk_wmem_alloc) >
+ if (refcount_read(&sk->sk_wmem_alloc) >
min_t(u32, sk->sk_wmem_queued + (sk->sk_wmem_queued >> 2),
sk->sk_sndbuf))
return -EAGAIN;
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 71faffd..9ed3547 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -275,7 +275,7 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info
skb->data_len += tailen;
skb->truesize += tailen;
if (sk)
- atomic_add(tailen, &sk->sk_wmem_alloc);
+ refcount_add(tailen, &sk->sk_wmem_alloc);
goto out;
}
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 5baa6fa..28ee907 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1472,7 +1472,7 @@ static int __ip6_append_data(struct sock *sk,
(flags & MSG_DONTWAIT), &err);
} else {
skb = NULL;
- if (atomic_read(&sk->sk_wmem_alloc) <=
+ if (refcount_read(&sk->sk_wmem_alloc) <=
2 * sk->sk_sndbuf)
skb = sock_wmalloc(sk,
alloclen + hh_len, 1,
@@ -1581,7 +1581,7 @@ static int __ip6_append_data(struct sock *sk,
skb->len += copy;
skb->data_len += copy;
skb->truesize += copy;
- atomic_add(copy, &sk->sk_wmem_alloc);
+ refcount_add(copy, &sk->sk_wmem_alloc);
}
offset += copy;
length -= copy;
diff --git a/net/kcm/kcmproc.c b/net/kcm/kcmproc.c
index bf75c92..c343ac6 100644
--- a/net/kcm/kcmproc.c
+++ b/net/kcm/kcmproc.c
@@ -162,7 +162,7 @@ static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq,
psock->sk->sk_receive_queue.qlen,
atomic_read(&psock->sk->sk_rmem_alloc),
psock->sk->sk_write_queue.qlen,
- atomic_read(&psock->sk->sk_wmem_alloc));
+ refcount_read(&psock->sk->sk_wmem_alloc));
if (psock->done)
seq_puts(seq, "Done ");
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 0fe7ff3..3dac3cd 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -109,7 +109,7 @@ static void pfkey_sock_destruct(struct sock *sk)
}
WARN_ON(atomic_read(&sk->sk_rmem_alloc));
- WARN_ON(atomic_read(&sk->sk_wmem_alloc));
+ WARN_ON(refcount_read(&sk->sk_wmem_alloc));
atomic_dec(&net_pfkey->socks_nr);
}
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 05030ad..8ced52e 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -372,7 +372,7 @@ static void netlink_sock_destruct(struct sock *sk)
}
WARN_ON(atomic_read(&sk->sk_rmem_alloc));
- WARN_ON(atomic_read(&sk->sk_wmem_alloc));
+ WARN_ON(refcount_read(&sk->sk_wmem_alloc));
WARN_ON(nlk_sk(sk)->groups);
}
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index f9349a4..90fd38d 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1317,7 +1317,7 @@ static void packet_sock_destruct(struct sock *sk)
skb_queue_purge(&sk->sk_error_queue);
WARN_ON(atomic_read(&sk->sk_rmem_alloc));
- WARN_ON(atomic_read(&sk->sk_wmem_alloc));
+ WARN_ON(refcount_read(&sk->sk_wmem_alloc));
if (!sock_flag(sk, SOCK_DEAD)) {
pr_err("Attempt to release alive packet socket: %p\n", sk);
@@ -2523,7 +2523,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
skb->data_len = to_write;
skb->len += to_write;
skb->truesize += to_write;
- atomic_add(to_write, &po->sk.sk_wmem_alloc);
+ refcount_add(to_write, &po->sk.sk_wmem_alloc);
while (likely(to_write)) {
nr_frags = skb_shinfo(skb)->nr_frags;
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 64634e3..29c7f75 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -360,7 +360,7 @@ static unsigned int pn_socket_poll(struct file *file, struct socket *sock,
return POLLHUP;
if (sk->sk_state == TCP_ESTABLISHED &&
- atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf &&
+ refcount_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf &&
atomic_read(&pn->tx_credits))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
diff --git a/net/rds/tcp_send.c b/net/rds/tcp_send.c
index 52d11d7..0d8616a 100644
--- a/net/rds/tcp_send.c
+++ b/net/rds/tcp_send.c
@@ -202,7 +202,7 @@ void rds_tcp_write_space(struct sock *sk)
tc->t_last_seen_una = rds_tcp_snd_una(tc);
rds_send_path_drop_acked(cp, rds_tcp_snd_una(tc), rds_tcp_is_acked);
- if ((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf)
+ if ((refcount_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf)
queue_delayed_work(rds_wq, &cp->cp_send_w, 0);
out:
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 58ae0db..f1299f5 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -53,7 +53,7 @@ static void rxrpc_sock_destructor(struct sock *);
*/
static inline int rxrpc_writable(struct sock *sk)
{
- return atomic_read(&sk->sk_wmem_alloc) < (size_t) sk->sk_sndbuf;
+ return refcount_read(&sk->sk_wmem_alloc) < (size_t) sk->sk_sndbuf;
}
/*
@@ -730,7 +730,7 @@ static void rxrpc_sock_destructor(struct sock *sk)
rxrpc_purge_queue(&sk->sk_receive_queue);
- WARN_ON(atomic_read(&sk->sk_wmem_alloc));
+ WARN_ON(refcount_read(&sk->sk_wmem_alloc));
WARN_ON(!sk_unhashed(sk));
WARN_ON(sk->sk_socket);
diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c
index de16259..572fe25 100644
--- a/net/sched/sch_atm.c
+++ b/net/sched/sch_atm.c
@@ -498,7 +498,7 @@ static void sch_atm_dequeue(unsigned long data)
ATM_SKB(skb)->vcc = flow->vcc;
memcpy(skb_push(skb, flow->hdr_len), flow->hdr,
flow->hdr_len);
- atomic_add(skb->truesize,
+ refcount_add(skb->truesize,
&sk_atm(flow->vcc)->sk_wmem_alloc);
/* atm.atm_options are already set by atm_tc_enqueue */
flow->vcc->send(flow->vcc, skb);
diff --git a/net/sctp/output.c b/net/sctp/output.c
index 89cee14..9bf9d84 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -402,7 +402,7 @@ static void sctp_packet_set_owner_w(struct sk_buff *skb, struct sock *sk)
* therefore only reserve a single byte to keep socket around until
* the packet has been transmitted.
*/
- atomic_inc(&sk->sk_wmem_alloc);
+ refcount_inc(&sk->sk_wmem_alloc);
}
static int sctp_packet_pack(struct sctp_packet *packet,
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index 8e34db5..26b4be6 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -363,7 +363,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
assoc->stream.outcnt, assoc->max_retrans,
assoc->init_retries, assoc->shutdown_retries,
assoc->rtx_data_chunks,
- atomic_read(&sk->sk_wmem_alloc),
+ refcount_read(&sk->sk_wmem_alloc),
sk->sk_wmem_queued,
sk->sk_sndbuf,
sk->sk_rcvbuf);
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index b497ee8..15401d0 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -164,7 +164,7 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
sizeof(struct sk_buff) +
sizeof(struct sctp_chunk);
- atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
+ refcount_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
sk->sk_wmem_queued += chunk->skb->truesize;
sk_mem_charge(sk, chunk->skb->truesize);
}
@@ -7684,7 +7684,7 @@ static void sctp_wfree(struct sk_buff *skb)
sizeof(struct sk_buff) +
sizeof(struct sctp_chunk);
- atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
+ WARN_ON(refcount_sub_and_test(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc));
/*
* This undoes what is done via sctp_set_owner_w and sk_mem_charge
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 1a0c961..7c2e21e 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -442,7 +442,7 @@ static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other)
static int unix_writable(const struct sock *sk)
{
return sk->sk_state != TCP_LISTEN &&
- (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf;
+ (refcount_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf;
}
static void unix_write_space(struct sock *sk)
@@ -487,7 +487,7 @@ static void unix_sock_destructor(struct sock *sk)
skb_queue_purge(&sk->sk_receive_queue);
- WARN_ON(atomic_read(&sk->sk_wmem_alloc));
+ WARN_ON(refcount_read(&sk->sk_wmem_alloc));
WARN_ON(!sk_unhashed(sk));
WARN_ON(sk->sk_socket);
if (!sock_flag(sk, SOCK_DEAD)) {
@@ -2033,7 +2033,7 @@ static ssize_t unix_stream_sendpage(struct socket *socket, struct page *page,
skb->len += size;
skb->data_len += size;
skb->truesize += size;
- atomic_add(size, &sk->sk_wmem_alloc);
+ refcount_add(size, &sk->sk_wmem_alloc);
if (newskb) {
err = unix_scm_to_skb(&scm, skb, false);
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH 07/17] net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
2017-06-30 10:08 ` [PATCH 07/17] net: convert sock.sk_wmem_alloc " Elena Reshetova
@ 2018-06-15 12:29 ` David Woodhouse
2018-06-15 13:27 ` Eric Dumazet
0 siblings, 1 reply; 34+ messages in thread
From: David Woodhouse @ 2018-06-15 12:29 UTC (permalink / raw)
To: Elena Reshetova, netdev
Cc: Krzysztof Mazur, Kevin Darbyshire-Bryant, chas, Mathias Kresin
[-- Attachment #1: Type: text/plain, Size: 2083 bytes --]
On Fri, 2017-06-30 at 13:08 +0300, Elena Reshetova wrote:
> diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
> index c1da539..4d97a89 100644
> --- a/include/linux/atmdev.h
> +++ b/include/linux/atmdev.h
> @@ -254,7 +254,7 @@ static inline void atm_return(struct atm_vcc *vcc,int truesize)
>
> static inline int atm_may_send(struct atm_vcc *vcc,unsigned int size)
> {
> - return (size + atomic_read(&sk_atm(vcc)->sk_wmem_alloc)) <
> + return (size + refcount_read(&sk_atm(vcc)->sk_wmem_alloc)) <
> sk_atm(vcc)->sk_sndbuf;
> }
Hm, this (commit 14afee4b6092fd) may have broken PPPoATM. I did spend a
while staring hard at my own commit 9d02daf754238 which introduced
pppoatm_may_send(), but it's actually atm_may_send() which is never
allowing packets to be pushed.
Debugging (which is ongoing) has so far shown that we are accounting
for a packet in pppoatm_send() which has skb->truesize==0x1c0, and
later end up in pppoatm_pop()→atm_raw_pop() with skb->truesize==0x2c0.
This was always harmless before, but now it's a refcount_t it appears
to underflow and go into its "screw you" mode and never let any more
packets get sent.
I'm staring hard at the special case in pskb_expand_head() to *not*
change skb->truesize under certain circumstances, and wondering if that
(is, should be) covering the case of ATM skbs:
/* It is not generally safe to change skb->truesize.
* For the moment, we really care of rx path, or
* when skb is orphaned (not attached to a socket).
*/
if (!skb->sk || skb->destructor == sock_edemux)
skb->truesize += size - osize;
Failing that, maybe we should copy the accounted value of skb->truesize
into the struct skb_atm_data in skb->cb at the time we add it to
sk_wmem_alloc — and then subtract *that* value from sk_wmem_alloc in
atm_raw_pop() instead of the then current value of skb->truesize.
Suggestions?
[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 5213 bytes --]
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 07/17] net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
2018-06-15 12:29 ` David Woodhouse
@ 2018-06-15 13:27 ` Eric Dumazet
2018-06-15 13:39 ` Eric Dumazet
0 siblings, 1 reply; 34+ messages in thread
From: Eric Dumazet @ 2018-06-15 13:27 UTC (permalink / raw)
To: David Woodhouse, Elena Reshetova, netdev
Cc: Krzysztof Mazur, Kevin Darbyshire-Bryant, chas, Mathias Kresin
On 06/15/2018 05:29 AM, David Woodhouse wrote:
> On Fri, 2017-06-30 at 13:08 +0300, Elena Reshetova wrote:
>> diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
>> index c1da539..4d97a89 100644
>> --- a/include/linux/atmdev.h
>> +++ b/include/linux/atmdev.h
>> @@ -254,7 +254,7 @@ static inline void atm_return(struct atm_vcc *vcc,int truesize)
>>
>> static inline int atm_may_send(struct atm_vcc *vcc,unsigned int size)
>> {
>> - return (size + atomic_read(&sk_atm(vcc)->sk_wmem_alloc)) <
>> + return (size + refcount_read(&sk_atm(vcc)->sk_wmem_alloc)) <
>> sk_atm(vcc)->sk_sndbuf;
>> }
>
>
> Hm, this (commit 14afee4b6092fd) may have broken PPPoATM. I did spend a
> while staring hard at my own commit 9d02daf754238 which introduced
> pppoatm_may_send(), but it's actually atm_may_send() which is never
> allowing packets to be pushed.
>
> Debugging (which is ongoing) has so far shown that we are accounting
> for a packet in pppoatm_send() which has skb->truesize==0x1c0, and
> later end up in pppoatm_pop()→atm_raw_pop() with skb->truesize==0x2c0.
>
> This was always harmless before, but now it's a refcount_t it appears
> to underflow and go into its "screw you" mode and never let any more
> packets get sent.
>
> I'm staring hard at the special case in pskb_expand_head() to *not*
> change skb->truesize under certain circumstances, and wondering if that
> (is, should be) covering the case of ATM skbs:
>
> /* It is not generally safe to change skb->truesize.
> * For the moment, we really care of rx path, or
> * when skb is orphaned (not attached to a socket).
> */
> if (!skb->sk || skb->destructor == sock_edemux)
> skb->truesize += size - osize;
>
> Failing that, maybe we should copy the accounted value of skb->truesize
> into the struct skb_atm_data in skb->cb at the time we add it to
> sk_wmem_alloc — and then subtract *that* value from sk_wmem_alloc in
> atm_raw_pop() instead of the then current value of skb->truesize.
>
> Suggestions?
>
Maybe ATM should make sure skb->sk is set ?
something like the following :
diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c
index 21d9d341a6199255a017437954e4b688f1ba5bfd..4863d02939a26ce0a5816da86779336255d550bd 100644
--- a/net/atm/pppoatm.c
+++ b/net/atm/pppoatm.c
@@ -350,7 +350,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
return 1;
}
- refcount_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc);
+ skb_set_owner_w(skb, &sk_atm(ATM_SKB(skb)->vcc));
ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n",
skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev);
Or something more sophisticated, but this might need more thinking
diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c
index 21d9d341a6199255a017437954e4b688f1ba5bfd..80902a0b56a1d15d2851a07f067490d99136d214 100644
--- a/net/atm/pppoatm.c
+++ b/net/atm/pppoatm.c
@@ -350,7 +350,10 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
return 1;
}
- refcount_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc);
+ if (!skb->sk)
+ skb_set_owner_w(skb, &sk_atm(ATM_SKB(skb)->vcc));
+- else
+ refcount_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc);
ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n",
skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev);
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH 07/17] net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
2018-06-15 13:27 ` Eric Dumazet
@ 2018-06-15 13:39 ` Eric Dumazet
2018-06-15 13:44 ` David Woodhouse
0 siblings, 1 reply; 34+ messages in thread
From: Eric Dumazet @ 2018-06-15 13:39 UTC (permalink / raw)
To: Eric Dumazet, David Woodhouse, Elena Reshetova, netdev
Cc: Krzysztof Mazur, Kevin Darbyshire-Bryant, chas, Mathias Kresin
On 06/15/2018 06:27 AM, Eric Dumazet wrote:
>
>
> On 06/15/2018 05:29 AM, David Woodhouse wrote:
>> On Fri, 2017-06-30 at 13:08 +0300, Elena Reshetova wrote:
>>> diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
>>> index c1da539..4d97a89 100644
>>> --- a/include/linux/atmdev.h
>>> +++ b/include/linux/atmdev.h
>>> @@ -254,7 +254,7 @@ static inline void atm_return(struct atm_vcc *vcc,int truesize)
>>>
>>> static inline int atm_may_send(struct atm_vcc *vcc,unsigned int size)
>>> {
>>> - return (size + atomic_read(&sk_atm(vcc)->sk_wmem_alloc)) <
>>> + return (size + refcount_read(&sk_atm(vcc)->sk_wmem_alloc)) <
>>> sk_atm(vcc)->sk_sndbuf;
>>> }
>>
>>
>> Hm, this (commit 14afee4b6092fd) may have broken PPPoATM. I did spend a
>> while staring hard at my own commit 9d02daf754238 which introduced
>> pppoatm_may_send(), but it's actually atm_may_send() which is never
>> allowing packets to be pushed.
>>
>> Debugging (which is ongoing) has so far shown that we are accounting
>> for a packet in pppoatm_send() which has skb->truesize==0x1c0, and
>> later end up in pppoatm_pop()→atm_raw_pop() with skb->truesize==0x2c0.
>>
>> This was always harmless before, but now it's a refcount_t it appears
>> to underflow and go into its "screw you" mode and never let any more
>> packets get sent.
>>
>> I'm staring hard at the special case in pskb_expand_head() to *not*
>> change skb->truesize under certain circumstances, and wondering if that
>> (is, should be) covering the case of ATM skbs:
>>
>> /* It is not generally safe to change skb->truesize.
>> * For the moment, we really care of rx path, or
>> * when skb is orphaned (not attached to a socket).
>> */
>> if (!skb->sk || skb->destructor == sock_edemux)
>> skb->truesize += size - osize;
>>
>> Failing that, maybe we should copy the accounted value of skb->truesize
>> into the struct skb_atm_data in skb->cb at the time we add it to
>> sk_wmem_alloc — and then subtract *that* value from sk_wmem_alloc in
>> atm_raw_pop() instead of the then current value of skb->truesize.
>>
>> Suggestions?
>>
>
> Maybe ATM should make sure skb->sk is set ?
>
> something like the following :
>
Or simply use a new field in ATM_SKB(skb) to remember a stable truesize used in both sides (add/sub)
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 07/17] net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
2018-06-15 13:39 ` Eric Dumazet
@ 2018-06-15 13:44 ` David Woodhouse
2018-06-15 20:00 ` David Woodhouse
0 siblings, 1 reply; 34+ messages in thread
From: David Woodhouse @ 2018-06-15 13:44 UTC (permalink / raw)
To: Eric Dumazet, Elena Reshetova, netdev
Cc: Krzysztof Mazur, Kevin Darbyshire-Bryant, 3chas3, Mathias Kresin
[-- Attachment #1: Type: text/plain, Size: 3273 bytes --]
On Fri, 2018-06-15 at 06:39 -0700, Eric Dumazet wrote:
>
> On 06/15/2018 06:27 AM, Eric Dumazet wrote:
> >
> >
> >
> > On 06/15/2018 05:29 AM, David Woodhouse wrote:
> > >
> > > On Fri, 2017-06-30 at 13:08 +0300, Elena Reshetova wrote:
> > > >
> > > > diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
> > > > index c1da539..4d97a89 100644
> > > > --- a/include/linux/atmdev.h
> > > > +++ b/include/linux/atmdev.h
> > > > @@ -254,7 +254,7 @@ static inline void atm_return(struct atm_vcc *vcc,int truesize)
> > > >
> > > > static inline int atm_may_send(struct atm_vcc *vcc,unsigned int size)
> > > > {
> > > > - return (size + atomic_read(&sk_atm(vcc)->sk_wmem_alloc)) <
> > > > + return (size + refcount_read(&sk_atm(vcc)->sk_wmem_alloc)) <
> > > > sk_atm(vcc)->sk_sndbuf;
> > > > }
> > >
> > > Hm, this (commit 14afee4b6092fd) may have broken PPPoATM. I did spend a
> > > while staring hard at my own commit 9d02daf754238 which introduced
> > > pppoatm_may_send(), but it's actually atm_may_send() which is never
> > > allowing packets to be pushed.
> > >
> > > Debugging (which is ongoing) has so far shown that we are accounting
> > > for a packet in pppoatm_send() which has skb->truesize==0x1c0, and
> > > later end up in pppoatm_pop()→atm_raw_pop() with skb->truesize==0x2c0.
> > >
> > > This was always harmless before, but now it's a refcount_t it appears
> > > to underflow and go into its "screw you" mode and never let any more
> > > packets get sent.
> > >
> > > I'm staring hard at the special case in pskb_expand_head() to *not*
> > > change skb->truesize under certain circumstances, and wondering if that
> > > (is, should be) covering the case of ATM skbs:
> > >
> > > /* It is not generally safe to change skb->truesize.
> > > * For the moment, we really care of rx path, or
> > > * when skb is orphaned (not attached to a socket).
> > > */
> > > if (!skb->sk || skb->destructor == sock_edemux)
> > > skb->truesize += size - osize;
> > >
> > > Failing that, maybe we should copy the accounted value of skb->truesize
> > > into the struct skb_atm_data in skb->cb at the time we add it to
> > > sk_wmem_alloc — and then subtract *that* value from sk_wmem_alloc in
> > > atm_raw_pop() instead of the then current value of skb->truesize.
> > >
> > > Suggestions?
> > >
> > Maybe ATM should make sure skb->sk is set ?
Yeah... I don't think we want sock_wfree() as a destructor, unless we
also fix up atm_pop_raw() not to do the same refcount_sub() and cope
with some other details, but it could probably be workable with
sufficient caffeine.
> > something like the following :
> >
> Or simply use a new field in ATM_SKB(skb) to remember a stable
> truesize used in both sides (add/sub)
Right, that was my second suggestion ("copy the accounted value...").
It's a bit of a hack, and I think that actually *using* sock_wfree()
instead of what's currently in atm_pop_raw() would be the better
solution. Does anyone remember why we didn't do that in the first
place?
[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 5213 bytes --]
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 07/17] net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
2018-06-15 13:44 ` David Woodhouse
@ 2018-06-15 20:00 ` David Woodhouse
2018-06-15 20:49 ` Kevin Darbyshire-Bryant
0 siblings, 1 reply; 34+ messages in thread
From: David Woodhouse @ 2018-06-15 20:00 UTC (permalink / raw)
To: Eric Dumazet, Elena Reshetova, netdev
Cc: Krzysztof Mazur, Kevin Darbyshire-Bryant, 3chas3, Mathias Kresin
On Fri, 2018-06-15 at 14:44 +0100, David Woodhouse wrote:
>
> > Or simply use a new field in ATM_SKB(skb) to remember a stable
> > truesize used in both sides (add/sub)
>
> Right, that was my second suggestion ("copy the accounted value...").
>
> It's a bit of a hack, and I think that actually *using* sock_wfree()
> instead of what's currently in atm_pop_raw() would be the better
> solution. Does anyone remember why we didn't do that in the first
> place?
That does end up being quite hairy. I don't think it's worth doing.
This should probably suffice to fix it...
Kevin this is going to conflict with the ifx_atm_alloc_skb() hack in
the tree you're working on, but that needs to be killed with fire
anyway. It's utterly pointless as discussed.
>From 3368eaeb0a2f09138894dde0f26f879e5228005a Mon Sep 17 00:00:00 2001
From: David Woodhouse <dwmw2@infradead.org>
Date: Fri, 15 Jun 2018 20:49:20 +0100
Subject: [PATCH] atm: Preserve value of skb->truesize when accounting to vcc
There's a hack in pskb_expand_head() to avoid adjusting skb->truesize
for certain skbs. Ideally it would cover ATM too. It doesn't. Just
stashing the accounted value and using it in atm_raw_pop() is probably
the easiest way to cope.
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
---
include/linux/atmdev.h | 15 +++++++++++++++
net/atm/br2684.c | 3 +--
net/atm/clip.c | 3 +--
net/atm/common.c | 3 +--
net/atm/lec.c | 3 +--
net/atm/mpc.c | 3 +--
net/atm/pppoatm.c | 3 +--
net/atm/raw.c | 4 ++--
8 files changed, 23 insertions(+), 14 deletions(-)
diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
index 0c27515d2cf6..8124815eb121 100644
--- a/include/linux/atmdev.h
+++ b/include/linux/atmdev.h
@@ -214,6 +214,7 @@ struct atmphy_ops {
struct atm_skb_data {
struct atm_vcc *vcc; /* ATM VCC */
unsigned long atm_options; /* ATM layer options */
+ unsigned int acct_truesize; /* truesize accounted to vcc */
};
#define VCC_HTABLE_SIZE 32
@@ -241,6 +242,20 @@ void vcc_insert_socket(struct sock *sk);
void atm_dev_release_vccs(struct atm_dev *dev);
+static inline void atm_account_tx(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+ /*
+ * Because ATM skbs may not belong to a sock (and we don't
+ * necessarily want to), skb->truesize may be adjusted,
+ * escaping the hack in pskb_expand_head() which avoids
+ * doing so for some cases. So stash the value of truesize
+ * at the time we accounted it, and atm_pop_raw() can use
+ * that value later, in case it changes.
+ */
+ refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
+ ATM_SKB(skb)->acct_truesize = skb->truesize;
+ ATM_SKB(skb)->atm_options = vcc->atm_options;
+}
static inline void atm_force_charge(struct atm_vcc *vcc,int truesize)
{
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 4e111196f902..bc21f8e8daf2 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -252,8 +252,7 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev,
ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev);
- refcount_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);
- ATM_SKB(skb)->atm_options = atmvcc->atm_options;
+ atm_account_tx(atmvcc, skb);
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 65f706e4344c..60920a42f640 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -381,8 +381,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
memcpy(here, llc_oui, sizeof(llc_oui));
((__be16 *) here)[3] = skb->protocol;
}
- refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
- ATM_SKB(skb)->atm_options = vcc->atm_options;
+ atm_account_tx(vcc, skb);
entry->vccs->last_use = jiffies;
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev);
old = xchg(&entry->vccs->xoff, 1); /* assume XOFF ... */
diff --git a/net/atm/common.c b/net/atm/common.c
index 8a4f99114cd2..9e812c782a37 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -630,10 +630,9 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size)
goto out;
}
pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize);
- refcount_add(skb->truesize, &sk->sk_wmem_alloc);
+ atm_account_tx(vcc, skb);
skb->dev = NULL; /* for paths shared with net_device interfaces */
- ATM_SKB(skb)->atm_options = vcc->atm_options;
if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) {
kfree_skb(skb);
error = -EFAULT;
diff --git a/net/atm/lec.c b/net/atm/lec.c
index a3d93a1bb133..d7cc165e24e0 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -179,9 +179,8 @@ lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
struct net_device *dev = skb->dev;
ATM_SKB(skb)->vcc = vcc;
- ATM_SKB(skb)->atm_options = vcc->atm_options;
+ atm_account_tx(vcc, skb);
- refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
if (vcc->send(vcc, skb) < 0) {
dev->stats.tx_dropped++;
return;
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
index 5677147209e8..db9a1838687c 100644
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -555,8 +555,7 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc)
sizeof(struct llc_snap_hdr));
}
- refcount_add(skb->truesize, &sk_atm(entry->shortcut)->sk_wmem_alloc);
- ATM_SKB(skb)->atm_options = entry->shortcut->atm_options;
+ atm_account_tx(entry->shortcut, skb);
entry->shortcut->send(entry->shortcut, skb);
entry->packets_fwded++;
mpc->in_ops->put(entry);
diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c
index 21d9d341a619..af8c4b38b746 100644
--- a/net/atm/pppoatm.c
+++ b/net/atm/pppoatm.c
@@ -350,8 +350,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
return 1;
}
- refcount_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc);
- ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
+ atm_account_tx(vcc, skb);
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n",
skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev);
ret = ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb)
diff --git a/net/atm/raw.c b/net/atm/raw.c
index ee10e8d46185..b3ba44aab0ee 100644
--- a/net/atm/raw.c
+++ b/net/atm/raw.c
@@ -35,8 +35,8 @@ static void atm_pop_raw(struct atm_vcc *vcc, struct sk_buff *skb)
struct sock *sk = sk_atm(vcc);
pr_debug("(%d) %d -= %d\n",
- vcc->vci, sk_wmem_alloc_get(sk), skb->truesize);
- WARN_ON(refcount_sub_and_test(skb->truesize, &sk->sk_wmem_alloc));
+ vcc->vci, sk_wmem_alloc_get(sk), ATM_SKB(skb)->acct_truesize);
+ WARN_ON(refcount_sub_and_test(ATM_SKB(skb)->acct_truesize, &sk->sk_wmem_alloc));
dev_kfree_skb_any(skb);
sk->sk_write_space(sk);
}
--
2.17.0
--
dwmw2
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH 07/17] net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
2018-06-15 20:00 ` David Woodhouse
@ 2018-06-15 20:49 ` Kevin Darbyshire-Bryant
2018-06-15 20:57 ` David Woodhouse
0 siblings, 1 reply; 34+ messages in thread
From: Kevin Darbyshire-Bryant @ 2018-06-15 20:49 UTC (permalink / raw)
To: David Woodhouse
Cc: Eric Dumazet, Elena Reshetova, netdev, Krzysztof Mazur, 3chas3,
Mathias Kresin
[-- Attachment #1: Type: text/plain, Size: 7853 bytes --]
> On 15 Jun 2018, at 21:00, David Woodhouse <dwmw2@infradead.org> wrote:
>
> On Fri, 2018-06-15 at 14:44 +0100, David Woodhouse wrote:
>>
>>> Or simply use a new field in ATM_SKB(skb) to remember a stable
>>> truesize used in both sides (add/sub)
>>
>> Right, that was my second suggestion ("copy the accounted value...").
>>
>> It's a bit of a hack, and I think that actually *using* sock_wfree()
>> instead of what's currently in atm_pop_raw() would be the better
>> solution. Does anyone remember why we didn't do that in the first
>> place?
>
> That does end up being quite hairy. I don't think it's worth doing.
>
> This should probably suffice to fix it...
>
> Kevin this is going to conflict with the ifx_atm_alloc_skb() hack in
> the tree you're working on, but that needs to be killed with fire
> anyway. It's utterly pointless as discussed.
I had already done so as part of the last pastebin debug info round :-)
As regards your patch… MAGIC! Works an absolute treat. Will get that submitted along with the ‘nuke ifx_atm_alloc_skb’ patch to OpenWrt tomorrow. For now, maybe my brain will let me sleep :-)
Thank you soooooo much for your help & patience.
Tested-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
>
>
> From 3368eaeb0a2f09138894dde0f26f879e5228005a Mon Sep 17 00:00:00 2001
> From: David Woodhouse <dwmw2@infradead.org>
> Date: Fri, 15 Jun 2018 20:49:20 +0100
> Subject: [PATCH] atm: Preserve value of skb->truesize when accounting to vcc
>
> There's a hack in pskb_expand_head() to avoid adjusting skb->truesize
> for certain skbs. Ideally it would cover ATM too. It doesn't. Just
> stashing the accounted value and using it in atm_raw_pop() is probably
> the easiest way to cope.
>
> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
> ---
> include/linux/atmdev.h | 15 +++++++++++++++
> net/atm/br2684.c | 3 +--
> net/atm/clip.c | 3 +--
> net/atm/common.c | 3 +--
> net/atm/lec.c | 3 +--
> net/atm/mpc.c | 3 +--
> net/atm/pppoatm.c | 3 +--
> net/atm/raw.c | 4 ++--
> 8 files changed, 23 insertions(+), 14 deletions(-)
>
> diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h
> index 0c27515d2cf6..8124815eb121 100644
> --- a/include/linux/atmdev.h
> +++ b/include/linux/atmdev.h
> @@ -214,6 +214,7 @@ struct atmphy_ops {
> struct atm_skb_data {
> struct atm_vcc *vcc; /* ATM VCC */
> unsigned long atm_options; /* ATM layer options */
> + unsigned int acct_truesize; /* truesize accounted to vcc */
> };
>
> #define VCC_HTABLE_SIZE 32
> @@ -241,6 +242,20 @@ void vcc_insert_socket(struct sock *sk);
>
> void atm_dev_release_vccs(struct atm_dev *dev);
>
> +static inline void atm_account_tx(struct atm_vcc *vcc, struct sk_buff *skb)
> +{
> + /*
> + * Because ATM skbs may not belong to a sock (and we don't
> + * necessarily want to), skb->truesize may be adjusted,
> + * escaping the hack in pskb_expand_head() which avoids
> + * doing so for some cases. So stash the value of truesize
> + * at the time we accounted it, and atm_pop_raw() can use
> + * that value later, in case it changes.
> + */
> + refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
> + ATM_SKB(skb)->acct_truesize = skb->truesize;
> + ATM_SKB(skb)->atm_options = vcc->atm_options;
> +}
>
> static inline void atm_force_charge(struct atm_vcc *vcc,int truesize)
> {
> diff --git a/net/atm/br2684.c b/net/atm/br2684.c
> index 4e111196f902..bc21f8e8daf2 100644
> --- a/net/atm/br2684.c
> +++ b/net/atm/br2684.c
> @@ -252,8 +252,7 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev,
>
> ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
> pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev);
> - refcount_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);
> - ATM_SKB(skb)->atm_options = atmvcc->atm_options;
> + atm_account_tx(atmvcc, skb);
> dev->stats.tx_packets++;
> dev->stats.tx_bytes += skb->len;
>
> diff --git a/net/atm/clip.c b/net/atm/clip.c
> index 65f706e4344c..60920a42f640 100644
> --- a/net/atm/clip.c
> +++ b/net/atm/clip.c
> @@ -381,8 +381,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
> memcpy(here, llc_oui, sizeof(llc_oui));
> ((__be16 *) here)[3] = skb->protocol;
> }
> - refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
> - ATM_SKB(skb)->atm_options = vcc->atm_options;
> + atm_account_tx(vcc, skb);
> entry->vccs->last_use = jiffies;
> pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev);
> old = xchg(&entry->vccs->xoff, 1); /* assume XOFF ... */
> diff --git a/net/atm/common.c b/net/atm/common.c
> index 8a4f99114cd2..9e812c782a37 100644
> --- a/net/atm/common.c
> +++ b/net/atm/common.c
> @@ -630,10 +630,9 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size)
> goto out;
> }
> pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize);
> - refcount_add(skb->truesize, &sk->sk_wmem_alloc);
> + atm_account_tx(vcc, skb);
>
> skb->dev = NULL; /* for paths shared with net_device interfaces */
> - ATM_SKB(skb)->atm_options = vcc->atm_options;
> if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) {
> kfree_skb(skb);
> error = -EFAULT;
> diff --git a/net/atm/lec.c b/net/atm/lec.c
> index a3d93a1bb133..d7cc165e24e0 100644
> --- a/net/atm/lec.c
> +++ b/net/atm/lec.c
> @@ -179,9 +179,8 @@ lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
> struct net_device *dev = skb->dev;
>
> ATM_SKB(skb)->vcc = vcc;
> - ATM_SKB(skb)->atm_options = vcc->atm_options;
> + atm_account_tx(vcc, skb);
>
> - refcount_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
> if (vcc->send(vcc, skb) < 0) {
> dev->stats.tx_dropped++;
> return;
> diff --git a/net/atm/mpc.c b/net/atm/mpc.c
> index 5677147209e8..db9a1838687c 100644
> --- a/net/atm/mpc.c
> +++ b/net/atm/mpc.c
> @@ -555,8 +555,7 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc)
> sizeof(struct llc_snap_hdr));
> }
>
> - refcount_add(skb->truesize, &sk_atm(entry->shortcut)->sk_wmem_alloc);
> - ATM_SKB(skb)->atm_options = entry->shortcut->atm_options;
> + atm_account_tx(entry->shortcut, skb);
> entry->shortcut->send(entry->shortcut, skb);
> entry->packets_fwded++;
> mpc->in_ops->put(entry);
> diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c
> index 21d9d341a619..af8c4b38b746 100644
> --- a/net/atm/pppoatm.c
> +++ b/net/atm/pppoatm.c
> @@ -350,8 +350,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
> return 1;
> }
>
> - refcount_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc);
> - ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
> + atm_account_tx(vcc, skb);
> pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n",
> skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev);
> ret = ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb)
> diff --git a/net/atm/raw.c b/net/atm/raw.c
> index ee10e8d46185..b3ba44aab0ee 100644
> --- a/net/atm/raw.c
> +++ b/net/atm/raw.c
> @@ -35,8 +35,8 @@ static void atm_pop_raw(struct atm_vcc *vcc, struct sk_buff *skb)
> struct sock *sk = sk_atm(vcc);
>
> pr_debug("(%d) %d -= %d\n",
> - vcc->vci, sk_wmem_alloc_get(sk), skb->truesize);
> - WARN_ON(refcount_sub_and_test(skb->truesize, &sk->sk_wmem_alloc));
> + vcc->vci, sk_wmem_alloc_get(sk), ATM_SKB(skb)->acct_truesize);
> + WARN_ON(refcount_sub_and_test(ATM_SKB(skb)->acct_truesize, &sk->sk_wmem_alloc));
> dev_kfree_skb_any(skb);
> sk->sk_write_space(sk);
> }
> --
> 2.17.0
>
> --
> dwmw2
Tested-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
Cheers,
Kevin D-B
012C ACB2 28C6 C53E 9775 9123 B3A2 389B 9DE2 334A
[-- Attachment #2: Message signed with OpenPGP --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 07/17] net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
2018-06-15 20:49 ` Kevin Darbyshire-Bryant
@ 2018-06-15 20:57 ` David Woodhouse
2018-06-16 3:44 ` Kevin Darbyshire-Bryant
0 siblings, 1 reply; 34+ messages in thread
From: David Woodhouse @ 2018-06-15 20:57 UTC (permalink / raw)
To: Kevin Darbyshire-Bryant
Cc: Eric Dumazet, Elena Reshetova, netdev, Krzysztof Mazur, 3chas3,
Mathias Kresin
[-- Attachment #1: Type: text/plain, Size: 994 bytes --]
On Fri, 2018-06-15 at 20:49 +0000, Kevin Darbyshire-Bryant wrote:
>
> > That does end up being quite hairy. I don't think it's worth doing.
> >
> > This should probably suffice to fix it...
> >
> > Kevin this is going to conflict with the ifx_atm_alloc_skb() hack in
> > the tree you're working on, but that needs to be killed with fire
> > anyway. It's utterly pointless as discussed.
>
> I had already done so as part of the last pastebin debug info round :-)
>
> As regards your patch… MAGIC! Works an absolute treat. Will get
> that submitted along with the ‘nuke ifx_atm_alloc_skb’ patch to
> OpenWrt tomorrow. For now, maybe my brain will let me sleep :-)
>
> Thank you soooooo much for your help & patience.
>
> Tested-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
Thanks. In the morning please could I trouble you to test the other
variants that you can manage — PPPoA with llc-encap, as well as br2684
and PPPoE over that?
[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 5213 bytes --]
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 07/17] net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
2018-06-15 20:57 ` David Woodhouse
@ 2018-06-16 3:44 ` Kevin Darbyshire-Bryant
2018-06-16 11:30 ` David Woodhouse
0 siblings, 1 reply; 34+ messages in thread
From: Kevin Darbyshire-Bryant @ 2018-06-16 3:44 UTC (permalink / raw)
To: David Woodhouse
Cc: Eric Dumazet, Elena Reshetova, netdev, Krzysztof Mazur, 3chas3,
Mathias Kresin
[-- Attachment #1: Type: text/plain, Size: 1407 bytes --]
> On 15 Jun 2018, at 21:57, David Woodhouse <dwmw2@infradead.org> wrote:
>
>
>
> On Fri, 2018-06-15 at 20:49 +0000, Kevin Darbyshire-Bryant wrote:
>>
>>> That does end up being quite hairy. I don't think it's worth doing.
>>>
>>> This should probably suffice to fix it...
>>>
>>> Kevin this is going to conflict with the ifx_atm_alloc_skb() hack in
>>> the tree you're working on, but that needs to be killed with fire
>>> anyway. It's utterly pointless as discussed.
>>
>> I had already done so as part of the last pastebin debug info round :-)
>>
>> As regards your patch… MAGIC! Works an absolute treat. Will get
>> that submitted along with the ‘nuke ifx_atm_alloc_skb’ patch to
>> OpenWrt tomorrow. For now, maybe my brain will let me sleep :-)
>>
>> Thank you soooooo much for your help & patience.
>>
>> Tested-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
>
> Thanks. In the morning please could I trouble you to test the other
> variants that you can manage — PPPoA with llc-encap, as well as br2684
> and PPPoE over that?
I can confirm that PPPoA with both vc & llc encapsulations work. BR2684 with PPPoE and both vc & llc encapsulations also work. No nasty messages noted in dmesg. I’m actually gobsmacked at how tolerant TalkTalk/BT are of what I’ve thrown at them, they clearly just look for PPP frames :-)
Kevin
[-- Attachment #2: Message signed with OpenPGP --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 07/17] net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
2018-06-16 3:44 ` Kevin Darbyshire-Bryant
@ 2018-06-16 11:30 ` David Woodhouse
0 siblings, 0 replies; 34+ messages in thread
From: David Woodhouse @ 2018-06-16 11:30 UTC (permalink / raw)
To: Kevin Darbyshire-Bryant
Cc: Eric Dumazet, Elena Reshetova, netdev, Krzysztof Mazur, 3chas3,
Mathias Kresin
[-- Attachment #1: Type: text/plain, Size: 621 bytes --]
On Sat, 2018-06-16 at 03:44 +0000, Kevin Darbyshire-Bryant wrote:
>
> I can confirm that PPPoA with both vc & llc encapsulations work.
> BR2684 with PPPoE and both vc & llc encapsulations also work. No
> nasty messages noted in dmesg.
Thanks.
> I’m actually gobsmacked at how tolerant TalkTalk/BT are of what
> I’ve thrown at them, they clearly just look for PPP frames :-)
We weren't saying that in the days when they stupidly assumed all PPP
data frames contained Legacy IP, and then dropped any short frames
which, if they *had* been Legacy IP, would have had zeroes in the
'length' field.
[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 5213 bytes --]
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH 08/17] net: convert sock.sk_refcnt from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (6 preceding siblings ...)
2017-06-30 10:08 ` [PATCH 07/17] net: convert sock.sk_wmem_alloc " Elena Reshetova
@ 2017-06-30 10:08 ` Elena Reshetova
2017-06-30 10:08 ` [PATCH 09/17] net: convert ip_mc_list.refcnt " Elena Reshetova
` (9 subsequent siblings)
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:08 UTC (permalink / raw)
To: netdev
Cc: bridge, linux-kernel, kuznet, jmorris, kaber, stephen, peterz,
keescook, Elena Reshetova, Hans Liljestrand, David Windsor
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.
This patch uses refcount_inc_not_zero() instead of
atomic_inc_not_zero_hint() due to absense of a _hint()
version of refcount API. If the hint() version must
be used, we might need to revisit API.
Signed-off-by: Elena Reshetova <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
crypto/algif_aead.c | 2 +-
include/net/inet_hashtables.h | 4 ++--
include/net/request_sock.h | 9 +++++----
include/net/sock.h | 17 +++++++++--------
net/atm/proc.c | 2 +-
net/bluetooth/af_bluetooth.c | 2 +-
net/bluetooth/rfcomm/sock.c | 2 +-
net/core/skbuff.c | 6 +++---
net/core/sock.c | 6 +++---
net/ipv4/inet_connection_sock.c | 2 +-
net/ipv4/inet_hashtables.c | 4 ++--
net/ipv4/inet_timewait_sock.c | 8 ++++----
net/ipv4/ping.c | 4 ++--
net/ipv4/raw.c | 2 +-
net/ipv4/syncookies.c | 2 +-
net/ipv4/tcp_fastopen.c | 2 +-
net/ipv4/tcp_ipv4.c | 4 ++--
net/ipv4/udp.c | 6 +++---
net/ipv4/udp_diag.c | 4 ++--
net/ipv6/datagram.c | 2 +-
net/ipv6/inet6_hashtables.c | 4 ++--
net/ipv6/tcp_ipv6.c | 4 ++--
net/ipv6/udp.c | 4 ++--
net/key/af_key.c | 2 +-
net/l2tp/l2tp_debugfs.c | 3 +--
net/llc/llc_conn.c | 8 ++++----
net/llc/llc_sap.c | 2 +-
net/netfilter/xt_TPROXY.c | 4 ++--
net/netlink/af_netlink.c | 6 +++---
net/packet/af_packet.c | 2 +-
net/phonet/socket.c | 2 +-
net/rxrpc/af_rxrpc.c | 2 +-
net/sched/em_meta.c | 2 +-
net/tipc/socket.c | 2 +-
net/unix/af_unix.c | 2 +-
35 files changed, 70 insertions(+), 69 deletions(-)
diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
index 8af664f..be11749 100644
--- a/crypto/algif_aead.c
+++ b/crypto/algif_aead.c
@@ -877,7 +877,7 @@ static void aead_sock_destruct(struct sock *sk)
unsigned int ivlen = crypto_aead_ivsize(
crypto_aead_reqtfm(&ctx->aead_req));
- WARN_ON(atomic_read(&sk->sk_refcnt) != 0);
+ WARN_ON(refcount_read(&sk->sk_refcnt) != 0);
aead_put_sgl(sk);
sock_kzfree_s(sk, ctx->iv, ivlen);
sock_kfree_s(sk, ctx, ctx->len);
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index 1178931..b9e6e0e 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -32,7 +32,7 @@
#include <net/tcp_states.h>
#include <net/netns/hash.h>
-#include <linux/atomic.h>
+#include <linux/refcount.h>
#include <asm/byteorder.h>
/* This is for all connections with a full identity, no wildcards.
@@ -334,7 +334,7 @@ static inline struct sock *inet_lookup(struct net *net,
sk = __inet_lookup(net, hashinfo, skb, doff, saddr, sport, daddr,
dport, dif, &refcounted);
- if (sk && !refcounted && !atomic_inc_not_zero(&sk->sk_refcnt))
+ if (sk && !refcounted && !refcount_inc_not_zero(&sk->sk_refcnt))
sk = NULL;
return sk;
}
diff --git a/include/net/request_sock.h b/include/net/request_sock.h
index 53ced67..23e2205 100644
--- a/include/net/request_sock.h
+++ b/include/net/request_sock.h
@@ -19,6 +19,7 @@
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/bug.h>
+#include <linux/refcount.h>
#include <net/sock.h>
@@ -89,7 +90,7 @@ reqsk_alloc(const struct request_sock_ops *ops, struct sock *sk_listener,
return NULL;
req->rsk_listener = NULL;
if (attach_listener) {
- if (unlikely(!atomic_inc_not_zero(&sk_listener->sk_refcnt))) {
+ if (unlikely(!refcount_inc_not_zero(&sk_listener->sk_refcnt))) {
kmem_cache_free(ops->slab, req);
return NULL;
}
@@ -100,7 +101,7 @@ reqsk_alloc(const struct request_sock_ops *ops, struct sock *sk_listener,
sk_node_init(&req_to_sk(req)->sk_node);
sk_tx_queue_clear(req_to_sk(req));
req->saved_syn = NULL;
- atomic_set(&req->rsk_refcnt, 0);
+ refcount_set(&req->rsk_refcnt, 0);
return req;
}
@@ -108,7 +109,7 @@ reqsk_alloc(const struct request_sock_ops *ops, struct sock *sk_listener,
static inline void reqsk_free(struct request_sock *req)
{
/* temporary debugging */
- WARN_ON_ONCE(atomic_read(&req->rsk_refcnt) != 0);
+ WARN_ON_ONCE(refcount_read(&req->rsk_refcnt) != 0);
req->rsk_ops->destructor(req);
if (req->rsk_listener)
@@ -119,7 +120,7 @@ static inline void reqsk_free(struct request_sock *req)
static inline void reqsk_put(struct request_sock *req)
{
- if (atomic_dec_and_test(&req->rsk_refcnt))
+ if (refcount_dec_and_test(&req->rsk_refcnt))
reqsk_free(req);
}
diff --git a/include/net/sock.h b/include/net/sock.h
index 5284e50..60200f4 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -66,6 +66,7 @@
#include <linux/poll.h>
#include <linux/atomic.h>
+#include <linux/refcount.h>
#include <net/dst.h>
#include <net/checksum.h>
#include <net/tcp_states.h>
@@ -219,7 +220,7 @@ struct sock_common {
u32 skc_tw_rcv_nxt; /* struct tcp_timewait_sock */
};
- atomic_t skc_refcnt;
+ refcount_t skc_refcnt;
/* private: */
int skc_dontcopy_end[0];
union {
@@ -611,7 +612,7 @@ static inline bool __sk_del_node_init(struct sock *sk)
static __always_inline void sock_hold(struct sock *sk)
{
- atomic_inc(&sk->sk_refcnt);
+ refcount_inc(&sk->sk_refcnt);
}
/* Ungrab socket in the context, which assumes that socket refcnt
@@ -619,7 +620,7 @@ static __always_inline void sock_hold(struct sock *sk)
*/
static __always_inline void __sock_put(struct sock *sk)
{
- atomic_dec(&sk->sk_refcnt);
+ refcount_dec(&sk->sk_refcnt);
}
static inline bool sk_del_node_init(struct sock *sk)
@@ -628,7 +629,7 @@ static inline bool sk_del_node_init(struct sock *sk)
if (rc) {
/* paranoid for a while -acme */
- WARN_ON(atomic_read(&sk->sk_refcnt) == 1);
+ WARN_ON(refcount_read(&sk->sk_refcnt) == 1);
__sock_put(sk);
}
return rc;
@@ -650,7 +651,7 @@ static inline bool sk_nulls_del_node_init_rcu(struct sock *sk)
if (rc) {
/* paranoid for a while -acme */
- WARN_ON(atomic_read(&sk->sk_refcnt) == 1);
+ WARN_ON(refcount_read(&sk->sk_refcnt) == 1);
__sock_put(sk);
}
return rc;
@@ -1144,9 +1145,9 @@ static inline void sk_refcnt_debug_dec(struct sock *sk)
static inline void sk_refcnt_debug_release(const struct sock *sk)
{
- if (atomic_read(&sk->sk_refcnt) != 1)
+ if (refcount_read(&sk->sk_refcnt) != 1)
printk(KERN_DEBUG "Destruction of the %s socket %p delayed, refcnt=%d\n",
- sk->sk_prot->name, sk, atomic_read(&sk->sk_refcnt));
+ sk->sk_prot->name, sk, refcount_read(&sk->sk_refcnt));
}
#else /* SOCK_REFCNT_DEBUG */
#define sk_refcnt_debug_inc(sk) do { } while (0)
@@ -1636,7 +1637,7 @@ void sock_init_data(struct socket *sock, struct sock *sk);
/* Ungrab socket and destroy it, if it was the last reference. */
static inline void sock_put(struct sock *sk)
{
- if (atomic_dec_and_test(&sk->sk_refcnt))
+ if (refcount_dec_and_test(&sk->sk_refcnt))
sk_free(sk);
}
/* Generic version of sock_put(), dealing with all sockets
diff --git a/net/atm/proc.c b/net/atm/proc.c
index bbb6461..27c9c01 100644
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -211,7 +211,7 @@ static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc)
vcc->flags, sk->sk_err,
sk_wmem_alloc_get(sk), sk->sk_sndbuf,
sk_rmem_alloc_get(sk), sk->sk_rcvbuf,
- atomic_read(&sk->sk_refcnt));
+ refcount_read(&sk->sk_refcnt));
}
static void svc_info(struct seq_file *seq, struct atm_vcc *vcc)
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 8a8f77a..91e3ba2 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -657,7 +657,7 @@ static int bt_seq_show(struct seq_file *seq, void *v)
seq_printf(seq,
"%pK %-6d %-6u %-6u %-6u %-6lu %-6lu",
sk,
- atomic_read(&sk->sk_refcnt),
+ refcount_read(&sk->sk_refcnt),
sk_rmem_alloc_get(sk),
sk_wmem_alloc_get(sk),
from_kuid(seq_user_ns(seq), sock_i_uid(sk)),
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index ac3c650..2172ae5 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -197,7 +197,7 @@ static void rfcomm_sock_kill(struct sock *sk)
if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
return;
- BT_DBG("sk %p state %d refcnt %d", sk, sk->sk_state, atomic_read(&sk->sk_refcnt));
+ BT_DBG("sk %p state %d refcnt %d", sk, sk->sk_state, refcount_read(&sk->sk_refcnt));
/* Kill poor orphan */
bt_sock_unlink(&rfcomm_sk_list, sk);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index c267713..8b11341 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3844,7 +3844,7 @@ struct sk_buff *skb_clone_sk(struct sk_buff *skb)
struct sock *sk = skb->sk;
struct sk_buff *clone;
- if (!sk || !atomic_inc_not_zero(&sk->sk_refcnt))
+ if (!sk || !refcount_inc_not_zero(&sk->sk_refcnt))
return NULL;
clone = skb_clone(skb, GFP_ATOMIC);
@@ -3915,7 +3915,7 @@ void skb_complete_tx_timestamp(struct sk_buff *skb,
/* Take a reference to prevent skb_orphan() from freeing the socket,
* but only if the socket refcount is not zero.
*/
- if (likely(atomic_inc_not_zero(&sk->sk_refcnt))) {
+ if (likely(refcount_inc_not_zero(&sk->sk_refcnt))) {
*skb_hwtstamps(skb) = *hwtstamps;
__skb_complete_tx_timestamp(skb, sk, SCM_TSTAMP_SND, false);
sock_put(sk);
@@ -3997,7 +3997,7 @@ void skb_complete_wifi_ack(struct sk_buff *skb, bool acked)
/* Take a reference to prevent skb_orphan() from freeing the socket,
* but only if the socket refcount is not zero.
*/
- if (likely(atomic_inc_not_zero(&sk->sk_refcnt))) {
+ if (likely(refcount_inc_not_zero(&sk->sk_refcnt))) {
err = sock_queue_err_skb(sk, skb);
sock_put(sk);
}
diff --git a/net/core/sock.c b/net/core/sock.c
index 0866d59..ba0ef6a 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1708,7 +1708,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
* (Documentation/RCU/rculist_nulls.txt for details)
*/
smp_wmb();
- atomic_set(&newsk->sk_refcnt, 2);
+ refcount_set(&newsk->sk_refcnt, 2);
/*
* Increment the counter in the same struct proto as the master
@@ -1851,7 +1851,7 @@ void skb_orphan_partial(struct sk_buff *skb)
) {
struct sock *sk = skb->sk;
- if (atomic_inc_not_zero(&sk->sk_refcnt)) {
+ if (refcount_inc_not_zero(&sk->sk_refcnt)) {
WARN_ON(refcount_sub_and_test(skb->truesize, &sk->sk_wmem_alloc));
skb->destructor = sock_efree;
}
@@ -2687,7 +2687,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)
* (Documentation/RCU/rculist_nulls.txt for details)
*/
smp_wmb();
- atomic_set(&sk->sk_refcnt, 1);
+ refcount_set(&sk->sk_refcnt, 1);
atomic_set(&sk->sk_drops, 0);
}
EXPORT_SYMBOL(sock_init_data);
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index a3fa1a5..4089c01 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -756,7 +756,7 @@ static void reqsk_queue_hash_req(struct request_sock *req,
* are committed to memory and refcnt initialized.
*/
smp_wmb();
- atomic_set(&req->rsk_refcnt, 2 + 1);
+ refcount_set(&req->rsk_refcnt, 2 + 1);
}
void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req,
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index e9a59d2..a4be2c1 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -246,7 +246,7 @@ EXPORT_SYMBOL_GPL(__inet_lookup_listener);
/* All sockets share common refcount, but have different destructors */
void sock_gen_put(struct sock *sk)
{
- if (!atomic_dec_and_test(&sk->sk_refcnt))
+ if (!refcount_dec_and_test(&sk->sk_refcnt))
return;
if (sk->sk_state == TCP_TIME_WAIT)
@@ -287,7 +287,7 @@ struct sock *__inet_lookup_established(struct net *net,
continue;
if (likely(INET_MATCH(sk, net, acookie,
saddr, daddr, ports, dif))) {
- if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt)))
+ if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
goto out;
if (unlikely(!INET_MATCH(sk, net, acookie,
saddr, daddr, ports, dif))) {
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index f8aff2c..5b03915 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -76,7 +76,7 @@ void inet_twsk_free(struct inet_timewait_sock *tw)
void inet_twsk_put(struct inet_timewait_sock *tw)
{
- if (atomic_dec_and_test(&tw->tw_refcnt))
+ if (refcount_dec_and_test(&tw->tw_refcnt))
inet_twsk_free(tw);
}
EXPORT_SYMBOL_GPL(inet_twsk_put);
@@ -131,7 +131,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk,
* We can use atomic_set() because prior spin_lock()/spin_unlock()
* committed into memory all tw fields.
*/
- atomic_set(&tw->tw_refcnt, 4);
+ refcount_set(&tw->tw_refcnt, 4);
inet_twsk_add_node_rcu(tw, &ehead->chain);
/* Step 3: Remove SK from hash chain */
@@ -195,7 +195,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk,
* to a non null value before everything is setup for this
* timewait socket.
*/
- atomic_set(&tw->tw_refcnt, 0);
+ refcount_set(&tw->tw_refcnt, 0);
__module_get(tw->tw_prot->owner);
}
@@ -278,7 +278,7 @@ void inet_twsk_purge(struct inet_hashinfo *hashinfo, int family)
atomic_read(&twsk_net(tw)->count))
continue;
- if (unlikely(!atomic_inc_not_zero(&tw->tw_refcnt)))
+ if (unlikely(!refcount_inc_not_zero(&tw->tw_refcnt)))
continue;
if (unlikely((tw->tw_family != family) ||
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index ccfbce1..b8f0db5 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -290,7 +290,7 @@ void ping_close(struct sock *sk, long timeout)
{
pr_debug("ping_close(sk=%p,sk->num=%u)\n",
inet_sk(sk), inet_sk(sk)->inet_num);
- pr_debug("isk->refcnt = %d\n", sk->sk_refcnt.counter);
+ pr_debug("isk->refcnt = %d\n", refcount_read(&sk->sk_refcnt));
sk_common_release(sk);
}
@@ -1127,7 +1127,7 @@ static void ping_v4_format_sock(struct sock *sp, struct seq_file *f,
0, 0L, 0,
from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
0, sock_i_ino(sp),
- atomic_read(&sp->sk_refcnt), sp,
+ refcount_read(&sp->sk_refcnt), sp,
atomic_read(&sp->sk_drops));
}
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index bdffad8..b0bb5d0 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -1063,7 +1063,7 @@ static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
0, 0L, 0,
from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)),
0, sock_i_ino(sp),
- atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
+ refcount_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));
}
static int raw_seq_show(struct seq_file *seq, void *v)
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 7835bb4..0905cf0 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -213,7 +213,7 @@ struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb,
child = icsk->icsk_af_ops->syn_recv_sock(sk, skb, req, dst,
NULL, &own_req);
if (child) {
- atomic_set(&req->rsk_refcnt, 1);
+ refcount_set(&req->rsk_refcnt, 1);
tcp_sk(child)->tsoffset = tsoff;
sock_rps_save_rxhash(child, skb);
inet_csk_reqsk_queue_add(sk, req, child);
diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c
index 4af82b9..8b1539e 100644
--- a/net/ipv4/tcp_fastopen.c
+++ b/net/ipv4/tcp_fastopen.c
@@ -214,7 +214,7 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk,
inet_csk_reset_xmit_timer(child, ICSK_TIME_RETRANS,
TCP_TIMEOUT_INIT, TCP_RTO_MAX);
- atomic_set(&req->rsk_refcnt, 2);
+ refcount_set(&req->rsk_refcnt, 2);
/* Now finish processing the fastopen child socket. */
inet_csk(child)->icsk_af_ops->rebuild_header(child);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index d774bcd..6ec6900 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2323,7 +2323,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
from_kuid_munged(seq_user_ns(f), sock_i_uid(sk)),
icsk->icsk_probes_out,
sock_i_ino(sk),
- atomic_read(&sk->sk_refcnt), sk,
+ refcount_read(&sk->sk_refcnt), sk,
jiffies_to_clock_t(icsk->icsk_rto),
jiffies_to_clock_t(icsk->icsk_ack.ato),
(icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
@@ -2349,7 +2349,7 @@ static void get_timewait4_sock(const struct inet_timewait_sock *tw,
" %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK",
i, src, srcp, dest, destp, tw->tw_substate, 0, 0,
3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0,
- atomic_read(&tw->tw_refcnt), tw);
+ refcount_read(&tw->tw_refcnt), tw);
}
#define TMPSZ 150
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 86fad2a..25294d4 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -577,7 +577,7 @@ struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
sk = __udp4_lib_lookup(net, saddr, sport, daddr, dport,
dif, &udp_table, NULL);
- if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
+ if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
sk = NULL;
return sk;
}
@@ -2242,7 +2242,7 @@ void udp_v4_early_demux(struct sk_buff *skb)
uh->source, iph->saddr, dif);
}
- if (!sk || !atomic_inc_not_zero_hint(&sk->sk_refcnt, 2))
+ if (!sk || !refcount_inc_not_zero(&sk->sk_refcnt))
return;
skb->sk = sk;
@@ -2691,7 +2691,7 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
0, 0L, 0,
from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)),
0, sock_i_ino(sp),
- atomic_read(&sp->sk_refcnt), sp,
+ refcount_read(&sp->sk_refcnt), sp,
atomic_read(&sp->sk_drops));
}
diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c
index 9a89c10..4515836 100644
--- a/net/ipv4/udp_diag.c
+++ b/net/ipv4/udp_diag.c
@@ -55,7 +55,7 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
req->id.idiag_dport,
req->id.idiag_if, tbl, NULL);
#endif
- if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
+ if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
sk = NULL;
rcu_read_unlock();
err = -ENOENT;
@@ -206,7 +206,7 @@ static int __udp_diag_destroy(struct sk_buff *in_skb,
return -EINVAL;
}
- if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
+ if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
sk = NULL;
rcu_read_unlock();
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index e011122..697223e 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -1035,6 +1035,6 @@ void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp,
from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)),
0,
sock_i_ino(sp),
- atomic_read(&sp->sk_refcnt), sp,
+ refcount_read(&sp->sk_refcnt), sp,
atomic_read(&sp->sk_drops));
}
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index d090091..b13b8f9 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -75,7 +75,7 @@ struct sock *__inet6_lookup_established(struct net *net,
continue;
if (!INET6_MATCH(sk, net, saddr, daddr, ports, dif))
continue;
- if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt)))
+ if (unlikely(!refcount_inc_not_zero(&sk->sk_refcnt)))
goto out;
if (unlikely(!INET6_MATCH(sk, net, saddr, daddr, ports, dif))) {
@@ -172,7 +172,7 @@ struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
sk = __inet6_lookup(net, hashinfo, skb, doff, saddr, sport, daddr,
ntohs(dport), dif, &refcounted);
- if (sk && !refcounted && !atomic_inc_not_zero(&sk->sk_refcnt))
+ if (sk && !refcounted && !refcount_inc_not_zero(&sk->sk_refcnt))
sk = NULL;
return sk;
}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index f1a4881..2521690 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1809,7 +1809,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)),
icsk->icsk_probes_out,
sock_i_ino(sp),
- atomic_read(&sp->sk_refcnt), sp,
+ refcount_read(&sp->sk_refcnt), sp,
jiffies_to_clock_t(icsk->icsk_rto),
jiffies_to_clock_t(icsk->icsk_ack.ato),
(icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
@@ -1842,7 +1842,7 @@ static void get_timewait6_sock(struct seq_file *seq,
dest->s6_addr32[2], dest->s6_addr32[3], destp,
tw->tw_substate, 0, 0,
3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0,
- atomic_read(&tw->tw_refcnt), tw);
+ refcount_read(&tw->tw_refcnt), tw);
}
static int tcp6_seq_show(struct seq_file *seq, void *v)
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 450829d..cde4ae3 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -325,7 +325,7 @@ struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be
sk = __udp6_lib_lookup(net, saddr, sport, daddr, dport,
dif, &udp_table, NULL);
- if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
+ if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
sk = NULL;
return sk;
}
@@ -915,7 +915,7 @@ static void udp_v6_early_demux(struct sk_buff *skb)
else
return;
- if (!sk || !atomic_inc_not_zero_hint(&sk->sk_refcnt, 2))
+ if (!sk || !refcount_inc_not_zero(&sk->sk_refcnt))
return;
skb->sk = sk;
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 3dac3cd..48e769f 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3728,7 +3728,7 @@ static int pfkey_seq_show(struct seq_file *f, void *v)
else
seq_printf(f, "%pK %-6d %-6u %-6u %-6u %-6lu\n",
s,
- atomic_read(&s->sk_refcnt),
+ refcount_read(&s->sk_refcnt),
sk_rmem_alloc_get(s),
sk_wmem_alloc_get(s),
from_kuid_munged(seq_user_ns(f), sock_i_uid(s)),
diff --git a/net/l2tp/l2tp_debugfs.c b/net/l2tp/l2tp_debugfs.c
index d100aed..98a005d 100644
--- a/net/l2tp/l2tp_debugfs.c
+++ b/net/l2tp/l2tp_debugfs.c
@@ -144,9 +144,8 @@ static void l2tp_dfs_seq_tunnel_show(struct seq_file *m, void *v)
tunnel->encap == L2TP_ENCAPTYPE_IP ? "IP" :
"");
seq_printf(m, " %d sessions, refcnt %d/%d\n", session_count,
- tunnel->sock ? atomic_read(&tunnel->sock->sk_refcnt) : 0,
+ tunnel->sock ? refcount_read(&tunnel->sock->sk_refcnt) : 0,
atomic_read(&tunnel->ref_count));
-
seq_printf(m, " %08x rx %ld/%ld/%ld rx %ld/%ld/%ld\n",
tunnel->debug,
atomic_long_read(&tunnel->stats.tx_packets),
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index 9b02c13..5e91b47 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -507,7 +507,7 @@ static struct sock *__llc_lookup_established(struct llc_sap *sap,
sk_nulls_for_each_rcu(rc, node, laddr_hb) {
if (llc_estab_match(sap, daddr, laddr, rc)) {
/* Extra checks required by SLAB_TYPESAFE_BY_RCU */
- if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
+ if (unlikely(!refcount_inc_not_zero(&rc->sk_refcnt)))
goto again;
if (unlikely(llc_sk(rc)->sap != sap ||
!llc_estab_match(sap, daddr, laddr, rc))) {
@@ -566,7 +566,7 @@ static struct sock *__llc_lookup_listener(struct llc_sap *sap,
sk_nulls_for_each_rcu(rc, node, laddr_hb) {
if (llc_listener_match(sap, laddr, rc)) {
/* Extra checks required by SLAB_TYPESAFE_BY_RCU */
- if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
+ if (unlikely(!refcount_inc_not_zero(&rc->sk_refcnt)))
goto again;
if (unlikely(llc_sk(rc)->sap != sap ||
!llc_listener_match(sap, laddr, rc))) {
@@ -973,9 +973,9 @@ void llc_sk_free(struct sock *sk)
skb_queue_purge(&sk->sk_write_queue);
skb_queue_purge(&llc->pdu_unack_q);
#ifdef LLC_REFCNT_DEBUG
- if (atomic_read(&sk->sk_refcnt) != 1) {
+ if (refcount_read(&sk->sk_refcnt) != 1) {
printk(KERN_DEBUG "Destruction of LLC sock %p delayed in %s, cnt=%d\n",
- sk, __func__, atomic_read(&sk->sk_refcnt));
+ sk, __func__, refcount_read(&sk->sk_refcnt));
printk(KERN_DEBUG "%d LLC sockets are still alive\n",
atomic_read(&llc_sock_nr));
} else {
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index 63b6ab0..d90928f 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -329,7 +329,7 @@ static struct sock *llc_lookup_dgram(struct llc_sap *sap,
sk_nulls_for_each_rcu(rc, node, laddr_hb) {
if (llc_dgram_match(sap, laddr, rc)) {
/* Extra checks required by SLAB_TYPESAFE_BY_RCU */
- if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
+ if (unlikely(!refcount_inc_not_zero(&rc->sk_refcnt)))
goto again;
if (unlikely(llc_sk(rc)->sap != sap ||
!llc_dgram_match(sap, laddr, rc))) {
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index df7f1df..d767e35 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -127,7 +127,7 @@ nf_tproxy_get_sock_v4(struct net *net, struct sk_buff *skb, void *hp,
daddr, dport,
in->ifindex);
- if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
+ if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
sk = NULL;
/* NOTE: we return listeners even if bound to
* 0.0.0.0, those are filtered out in
@@ -197,7 +197,7 @@ nf_tproxy_get_sock_v6(struct net *net, struct sk_buff *skb, int thoff, void *hp,
daddr, ntohs(dport),
in->ifindex);
- if (sk && !atomic_inc_not_zero(&sk->sk_refcnt))
+ if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
sk = NULL;
/* NOTE: we return listeners even if bound to
* 0.0.0.0, those are filtered out in
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 8ced52e..5acee49 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -575,7 +575,7 @@ static void netlink_remove(struct sock *sk)
table = &nl_table[sk->sk_protocol];
if (!rhashtable_remove_fast(&table->hash, &nlk_sk(sk)->node,
netlink_rhashtable_params)) {
- WARN_ON(atomic_read(&sk->sk_refcnt) == 1);
+ WARN_ON(refcount_read(&sk->sk_refcnt) == 1);
__sock_put(sk);
}
@@ -691,7 +691,7 @@ static void deferred_put_nlk_sk(struct rcu_head *head)
struct netlink_sock *nlk = container_of(head, struct netlink_sock, rcu);
struct sock *sk = &nlk->sk;
- if (!atomic_dec_and_test(&sk->sk_refcnt))
+ if (!refcount_dec_and_test(&sk->sk_refcnt))
return;
if (nlk->cb_running && nlk->cb.done) {
@@ -2568,7 +2568,7 @@ static int netlink_seq_show(struct seq_file *seq, void *v)
sk_rmem_alloc_get(s),
sk_wmem_alloc_get(s),
nlk->cb_running,
- atomic_read(&s->sk_refcnt),
+ refcount_read(&s->sk_refcnt),
atomic_read(&s->sk_drops),
sock_i_ino(s)
);
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 90fd38d..643302b 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -4495,7 +4495,7 @@ static int packet_seq_show(struct seq_file *seq, void *v)
seq_printf(seq,
"%pK %-6d %-4d %04x %-5d %1d %-6u %-6u %-6lu\n",
s,
- atomic_read(&s->sk_refcnt),
+ refcount_read(&s->sk_refcnt),
s->sk_type,
ntohs(po->num),
po->ifindex,
diff --git a/net/phonet/socket.c b/net/phonet/socket.c
index 29c7f75..1b050dd 100644
--- a/net/phonet/socket.c
+++ b/net/phonet/socket.c
@@ -614,7 +614,7 @@ static int pn_sock_seq_show(struct seq_file *seq, void *v)
sk_wmem_alloc_get(sk), sk_rmem_alloc_get(sk),
from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)),
sock_i_ino(sk),
- atomic_read(&sk->sk_refcnt), sk,
+ refcount_read(&sk->sk_refcnt), sk,
atomic_read(&sk->sk_drops));
}
seq_pad(seq, '\n');
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index f1299f5..a2ad448 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -747,7 +747,7 @@ static int rxrpc_release_sock(struct sock *sk)
{
struct rxrpc_sock *rx = rxrpc_sk(sk);
- _enter("%p{%d,%d}", sk, sk->sk_state, atomic_read(&sk->sk_refcnt));
+ _enter("%p{%d,%d}", sk, sk->sk_state, refcount_read(&sk->sk_refcnt));
/* declare the socket closed for business */
sock_orphan(sk);
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
index eb0e9ba..d6e9711 100644
--- a/net/sched/em_meta.c
+++ b/net/sched/em_meta.c
@@ -340,7 +340,7 @@ META_COLLECTOR(int_sk_refcnt)
*err = -1;
return;
}
- dst->value = atomic_read(&skb->sk->sk_refcnt);
+ dst->value = refcount_read(&skb->sk->sk_refcnt);
}
META_COLLECTOR(int_sk_rcvbuf)
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 1b92b72..101e359 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -2313,7 +2313,7 @@ static void tipc_sk_remove(struct tipc_sock *tsk)
struct tipc_net *tn = net_generic(sock_net(sk), tipc_net_id);
if (!rhashtable_remove_fast(&tn->sk_rht, &tsk->node, tsk_rht_params)) {
- WARN_ON(atomic_read(&sk->sk_refcnt) == 1);
+ WARN_ON(refcount_read(&sk->sk_refcnt) == 1);
__sock_put(sk);
}
}
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 7c2e21e..c885254 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -2847,7 +2847,7 @@ static int unix_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "%pK: %08X %08X %08X %04X %02X %5lu",
s,
- atomic_read(&s->sk_refcnt),
+ refcount_read(&s->sk_refcnt),
0,
s->sk_state == TCP_LISTEN ? __SO_ACCEPTCON : 0,
s->sk_type,
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 09/17] net: convert ip_mc_list.refcnt from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (7 preceding siblings ...)
2017-06-30 10:08 ` [PATCH 08/17] net: convert sock.sk_refcnt " Elena Reshetova
@ 2017-06-30 10:08 ` Elena Reshetova
2017-06-30 10:08 ` [PATCH 10/17] net: convert in_device.refcnt " Elena Reshetova
` (8 subsequent siblings)
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:08 UTC (permalink / raw)
To: netdev
Cc: keescook, peterz, bridge, linux-kernel, jmorris,
Hans Liljestrand, kuznet, kaber, Elena Reshetova, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/linux/igmp.h | 3 ++-
net/ipv4/igmp.c | 10 +++++-----
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 12f6fba..97caf18 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -18,6 +18,7 @@
#include <linux/skbuff.h>
#include <linux/timer.h>
#include <linux/in.h>
+#include <linux/refcount.h>
#include <uapi/linux/igmp.h>
static inline struct igmphdr *igmp_hdr(const struct sk_buff *skb)
@@ -84,7 +85,7 @@ struct ip_mc_list {
struct ip_mc_list __rcu *next_hash;
struct timer_list timer;
int users;
- atomic_t refcnt;
+ refcount_t refcnt;
spinlock_t lock;
char tm_running;
char reporter;
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index c403230..28f14af 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -173,7 +173,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
static void ip_ma_put(struct ip_mc_list *im)
{
- if (atomic_dec_and_test(&im->refcnt)) {
+ if (refcount_dec_and_test(&im->refcnt)) {
in_dev_put(im->interface);
kfree_rcu(im, rcu);
}
@@ -199,7 +199,7 @@ static void igmp_stop_timer(struct ip_mc_list *im)
{
spin_lock_bh(&im->lock);
if (del_timer(&im->timer))
- atomic_dec(&im->refcnt);
+ refcount_dec(&im->refcnt);
im->tm_running = 0;
im->reporter = 0;
im->unsolicit_count = 0;
@@ -213,7 +213,7 @@ static void igmp_start_timer(struct ip_mc_list *im, int max_delay)
im->tm_running = 1;
if (!mod_timer(&im->timer, jiffies+tv+2))
- atomic_inc(&im->refcnt);
+ refcount_inc(&im->refcnt);
}
static void igmp_gq_start_timer(struct in_device *in_dev)
@@ -249,7 +249,7 @@ static void igmp_mod_timer(struct ip_mc_list *im, int max_delay)
spin_unlock_bh(&im->lock);
return;
}
- atomic_dec(&im->refcnt);
+ refcount_dec(&im->refcnt);
}
igmp_start_timer(im, max_delay);
spin_unlock_bh(&im->lock);
@@ -1374,7 +1374,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
/* initial mode is (EX, empty) */
im->sfmode = MCAST_EXCLUDE;
im->sfcount[MCAST_EXCLUDE] = 1;
- atomic_set(&im->refcnt, 1);
+ refcount_set(&im->refcnt, 1);
spin_lock_init(&im->lock);
#ifdef CONFIG_IP_MULTICAST
setup_timer(&im->timer, igmp_timer_expire, (unsigned long)im);
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 10/17] net: convert in_device.refcnt from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (8 preceding siblings ...)
2017-06-30 10:08 ` [PATCH 09/17] net: convert ip_mc_list.refcnt " Elena Reshetova
@ 2017-06-30 10:08 ` Elena Reshetova
2017-06-30 10:08 ` [PATCH 11/17] net: convert netpoll_info.refcnt " Elena Reshetova
` (7 subsequent siblings)
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:08 UTC (permalink / raw)
To: netdev
Cc: bridge, linux-kernel, kuznet, jmorris, kaber, stephen, peterz,
keescook, Elena Reshetova, Hans Liljestrand, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/linux/inetdevice.h | 11 ++++++-----
net/ipv4/devinet.c | 2 +-
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index e7c04c4..fb3f809 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -11,6 +11,7 @@
#include <linux/timer.h>
#include <linux/sysctl.h>
#include <linux/rtnetlink.h>
+#include <linux/refcount.h>
struct ipv4_devconf {
void *sysctl;
@@ -22,7 +23,7 @@ struct ipv4_devconf {
struct in_device {
struct net_device *dev;
- atomic_t refcnt;
+ refcount_t refcnt;
int dead;
struct in_ifaddr *ifa_list; /* IP ifaddr chain */
@@ -219,7 +220,7 @@ static inline struct in_device *in_dev_get(const struct net_device *dev)
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
if (in_dev)
- atomic_inc(&in_dev->refcnt);
+ refcount_inc(&in_dev->refcnt);
rcu_read_unlock();
return in_dev;
}
@@ -240,12 +241,12 @@ void in_dev_finish_destroy(struct in_device *idev);
static inline void in_dev_put(struct in_device *idev)
{
- if (atomic_dec_and_test(&idev->refcnt))
+ if (refcount_dec_and_test(&idev->refcnt))
in_dev_finish_destroy(idev);
}
-#define __in_dev_put(idev) atomic_dec(&(idev)->refcnt)
-#define in_dev_hold(idev) atomic_inc(&(idev)->refcnt)
+#define __in_dev_put(idev) refcount_dec(&(idev)->refcnt)
+#define in_dev_hold(idev) refcount_inc(&(idev)->refcnt)
#endif /* __KERNEL__ */
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index a7dd088..38d9af9 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -252,7 +252,7 @@ static struct in_device *inetdev_init(struct net_device *dev)
/* Reference in_dev->dev */
dev_hold(dev);
/* Account for reference dev->ip_ptr (below) */
- in_dev_hold(in_dev);
+ refcount_set(&in_dev->refcnt, 1);
err = devinet_sysctl_register(in_dev);
if (err) {
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 11/17] net: convert netpoll_info.refcnt from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (9 preceding siblings ...)
2017-06-30 10:08 ` [PATCH 10/17] net: convert in_device.refcnt " Elena Reshetova
@ 2017-06-30 10:08 ` Elena Reshetova
2017-06-30 10:08 ` [PATCH 12/17] net: convert unix_address.refcnt " Elena Reshetova
` (6 subsequent siblings)
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:08 UTC (permalink / raw)
To: netdev
Cc: bridge, linux-kernel, kuznet, jmorris, kaber, stephen, peterz,
keescook, Elena Reshetova, Hans Liljestrand, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/linux/netpoll.h | 3 ++-
net/core/netpoll.c | 6 +++---
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 1828900..27c0aaa 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -11,6 +11,7 @@
#include <linux/interrupt.h>
#include <linux/rcupdate.h>
#include <linux/list.h>
+#include <linux/refcount.h>
union inet_addr {
__u32 all[4];
@@ -34,7 +35,7 @@ struct netpoll {
};
struct netpoll_info {
- atomic_t refcnt;
+ refcount_t refcnt;
struct semaphore dev_lock;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index a835155..d3408a6 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -632,7 +632,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
skb_queue_head_init(&npinfo->txq);
INIT_DELAYED_WORK(&npinfo->tx_work, queue_process);
- atomic_set(&npinfo->refcnt, 1);
+ refcount_set(&npinfo->refcnt, 1);
ops = np->dev->netdev_ops;
if (ops->ndo_netpoll_setup) {
@@ -642,7 +642,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
}
} else {
npinfo = rtnl_dereference(ndev->npinfo);
- atomic_inc(&npinfo->refcnt);
+ refcount_inc(&npinfo->refcnt);
}
npinfo->netpoll = np;
@@ -821,7 +821,7 @@ void __netpoll_cleanup(struct netpoll *np)
synchronize_srcu(&netpoll_srcu);
- if (atomic_dec_and_test(&npinfo->refcnt)) {
+ if (refcount_dec_and_test(&npinfo->refcnt)) {
const struct net_device_ops *ops;
ops = np->dev->netdev_ops;
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 12/17] net: convert unix_address.refcnt from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (10 preceding siblings ...)
2017-06-30 10:08 ` [PATCH 11/17] net: convert netpoll_info.refcnt " Elena Reshetova
@ 2017-06-30 10:08 ` Elena Reshetova
2017-06-30 10:08 ` [PATCH 13/17] net: convert fib_rule.refcnt " Elena Reshetova
` (5 subsequent siblings)
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:08 UTC (permalink / raw)
To: netdev
Cc: bridge, linux-kernel, kuznet, jmorris, kaber, stephen, peterz,
keescook, Elena Reshetova, Hans Liljestrand, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/net/af_unix.h | 3 ++-
net/unix/af_unix.c | 8 ++++----
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index fd60ecc..3a385e4 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -4,6 +4,7 @@
#include <linux/socket.h>
#include <linux/un.h>
#include <linux/mutex.h>
+#include <linux/refcount.h>
#include <net/sock.h>
void unix_inflight(struct user_struct *user, struct file *fp);
@@ -21,7 +22,7 @@ extern spinlock_t unix_table_lock;
extern struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE];
struct unix_address {
- atomic_t refcnt;
+ refcount_t refcnt;
int len;
unsigned int hash;
struct sockaddr_un name[0];
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index c885254..b9ee766 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -212,7 +212,7 @@ EXPORT_SYMBOL_GPL(unix_peer_get);
static inline void unix_release_addr(struct unix_address *addr)
{
- if (atomic_dec_and_test(&addr->refcnt))
+ if (refcount_dec_and_test(&addr->refcnt))
kfree(addr);
}
@@ -864,7 +864,7 @@ static int unix_autobind(struct socket *sock)
goto out;
addr->name->sun_family = AF_UNIX;
- atomic_set(&addr->refcnt, 1);
+ refcount_set(&addr->refcnt, 1);
retry:
addr->len = sprintf(addr->name->sun_path+1, "%05x", ordernum) + 1 + sizeof(short);
@@ -1040,7 +1040,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
memcpy(addr->name, sunaddr, addr_len);
addr->len = addr_len;
addr->hash = hash ^ sk->sk_type;
- atomic_set(&addr->refcnt, 1);
+ refcount_set(&addr->refcnt, 1);
if (sun_path[0]) {
addr->hash = UNIX_HASH_SIZE;
@@ -1335,7 +1335,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr,
/* copy address information from listening to new sock*/
if (otheru->addr) {
- atomic_inc(&otheru->addr->refcnt);
+ refcount_inc(&otheru->addr->refcnt);
newu->addr = otheru->addr;
}
if (otheru->path.dentry) {
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 13/17] net: convert fib_rule.refcnt from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (11 preceding siblings ...)
2017-06-30 10:08 ` [PATCH 12/17] net: convert unix_address.refcnt " Elena Reshetova
@ 2017-06-30 10:08 ` Elena Reshetova
2017-06-30 10:08 ` [PATCH 14/17] net: convert inet_frag_queue.refcnt " Elena Reshetova
` (4 subsequent siblings)
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:08 UTC (permalink / raw)
To: netdev
Cc: bridge, linux-kernel, kuznet, jmorris, kaber, stephen, peterz,
keescook, Elena Reshetova, Hans Liljestrand, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/net/fib_rules.h | 7 ++++---
net/core/fib_rules.c | 4 ++--
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index 76c7300..c487bfa 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -5,6 +5,7 @@
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/fib_rules.h>
+#include <linux/refcount.h>
#include <net/flow.h>
#include <net/rtnetlink.h>
@@ -29,7 +30,7 @@ struct fib_rule {
struct fib_rule __rcu *ctarget;
struct net *fr_net;
- atomic_t refcnt;
+ refcount_t refcnt;
u32 pref;
int suppress_ifgroup;
int suppress_prefixlen;
@@ -103,12 +104,12 @@ struct fib_rules_ops {
static inline void fib_rule_get(struct fib_rule *rule)
{
- atomic_inc(&rule->refcnt);
+ refcount_inc(&rule->refcnt);
}
static inline void fib_rule_put(struct fib_rule *rule)
{
- if (atomic_dec_and_test(&rule->refcnt))
+ if (refcount_dec_and_test(&rule->refcnt))
kfree_rcu(rule, rcu);
}
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 3bba291..c4ecd9f 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -46,7 +46,7 @@ int fib_default_rule_add(struct fib_rules_ops *ops,
if (r == NULL)
return -ENOMEM;
- atomic_set(&r->refcnt, 1);
+ refcount_set(&r->refcnt, 1);
r->action = FR_ACT_TO_TBL;
r->pref = pref;
r->table = table;
@@ -283,7 +283,7 @@ int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl,
if (err != -EAGAIN) {
if ((arg->flags & FIB_LOOKUP_NOREF) ||
- likely(atomic_inc_not_zero(&rule->refcnt))) {
+ likely(refcount_inc_not_zero(&rule->refcnt))) {
arg->rule = rule;
goto out;
}
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 14/17] net: convert inet_frag_queue.refcnt from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (12 preceding siblings ...)
2017-06-30 10:08 ` [PATCH 13/17] net: convert fib_rule.refcnt " Elena Reshetova
@ 2017-06-30 10:08 ` Elena Reshetova
2017-06-30 10:08 ` [PATCH 15/17] net: convert net.passive " Elena Reshetova
` (3 subsequent siblings)
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:08 UTC (permalink / raw)
To: netdev
Cc: bridge, linux-kernel, kuznet, jmorris, kaber, stephen, peterz,
keescook, Elena Reshetova, Hans Liljestrand, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/net/inet_frag.h | 4 ++--
net/ipv4/inet_fragment.c | 14 +++++++-------
net/ipv4/ip_fragment.c | 2 +-
3 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h
index 975779d..440c1e9 100644
--- a/include/net/inet_frag.h
+++ b/include/net/inet_frag.h
@@ -50,7 +50,7 @@ struct inet_frag_queue {
spinlock_t lock;
struct timer_list timer;
struct hlist_node list;
- atomic_t refcnt;
+ refcount_t refcnt;
struct sk_buff *fragments;
struct sk_buff *fragments_tail;
ktime_t stamp;
@@ -129,7 +129,7 @@ void inet_frag_maybe_warn_overflow(struct inet_frag_queue *q,
static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f)
{
- if (atomic_dec_and_test(&q->refcnt))
+ if (refcount_dec_and_test(&q->refcnt))
inet_frag_destroy(q, f);
}
diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c
index b5e9317..96e95e8 100644
--- a/net/ipv4/inet_fragment.c
+++ b/net/ipv4/inet_fragment.c
@@ -276,11 +276,11 @@ static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f)
void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f)
{
if (del_timer(&fq->timer))
- atomic_dec(&fq->refcnt);
+ refcount_dec(&fq->refcnt);
if (!(fq->flags & INET_FRAG_COMPLETE)) {
fq_unlink(fq, f);
- atomic_dec(&fq->refcnt);
+ refcount_dec(&fq->refcnt);
}
}
EXPORT_SYMBOL(inet_frag_kill);
@@ -329,7 +329,7 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
*/
hlist_for_each_entry(qp, &hb->chain, list) {
if (qp->net == nf && f->match(qp, arg)) {
- atomic_inc(&qp->refcnt);
+ refcount_inc(&qp->refcnt);
spin_unlock(&hb->chain_lock);
qp_in->flags |= INET_FRAG_COMPLETE;
inet_frag_put(qp_in, f);
@@ -339,9 +339,9 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf,
#endif
qp = qp_in;
if (!mod_timer(&qp->timer, jiffies + nf->timeout))
- atomic_inc(&qp->refcnt);
+ refcount_inc(&qp->refcnt);
- atomic_inc(&qp->refcnt);
+ refcount_inc(&qp->refcnt);
hlist_add_head(&qp->list, &hb->chain);
spin_unlock(&hb->chain_lock);
@@ -370,7 +370,7 @@ static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf,
setup_timer(&q->timer, f->frag_expire, (unsigned long)q);
spin_lock_init(&q->lock);
- atomic_set(&q->refcnt, 1);
+ refcount_set(&q->refcnt, 1);
return q;
}
@@ -405,7 +405,7 @@ struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
spin_lock(&hb->chain_lock);
hlist_for_each_entry(q, &hb->chain, list) {
if (q->net == nf && f->match(q, key)) {
- atomic_inc(&q->refcnt);
+ refcount_inc(&q->refcnt);
spin_unlock(&hb->chain_lock);
return q;
}
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index b3cdeec..9a8cfac 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -312,7 +312,7 @@ static int ip_frag_reinit(struct ipq *qp)
unsigned int sum_truesize = 0;
if (!mod_timer(&qp->q.timer, jiffies + qp->q.net->timeout)) {
- atomic_inc(&qp->q.refcnt);
+ refcount_inc(&qp->q.refcnt);
return -ETIMEDOUT;
}
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 15/17] net: convert net.passive from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (13 preceding siblings ...)
2017-06-30 10:08 ` [PATCH 14/17] net: convert inet_frag_queue.refcnt " Elena Reshetova
@ 2017-06-30 10:08 ` Elena Reshetova
2017-06-30 10:08 ` [PATCH 16/17] net: convert netlbl_lsm_cache.refcount " Elena Reshetova
` (2 subsequent siblings)
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:08 UTC (permalink / raw)
To: netdev
Cc: bridge, linux-kernel, kuznet, jmorris, kaber, stephen, peterz,
keescook, Elena Reshetova, Hans Liljestrand, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/net/net_namespace.h | 3 ++-
net/core/net-sysfs.c | 2 +-
net/core/net_namespace.c | 4 ++--
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index fe80bb4..bffe0a3 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -5,6 +5,7 @@
#define __NET_NET_NAMESPACE_H
#include <linux/atomic.h>
+#include <linux/refcount.h>
#include <linux/workqueue.h>
#include <linux/list.h>
#include <linux/sysctl.h>
@@ -46,7 +47,7 @@ struct netns_ipvs;
#define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS)
struct net {
- atomic_t passive; /* To decided when the network
+ refcount_t passive; /* To decided when the network
* namespace should be freed.
*/
atomic_t count; /* To decided when the network
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index fe7e145..b4f9922 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -1448,7 +1448,7 @@ static void *net_grab_current_ns(void)
struct net *ns = current->nsproxy->net_ns;
#ifdef CONFIG_NET_NS
if (ns)
- atomic_inc(&ns->passive);
+ refcount_inc(&ns->passive);
#endif
return ns;
}
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index 2178db8..57feb1e 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -284,7 +284,7 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns)
LIST_HEAD(net_exit_list);
atomic_set(&net->count, 1);
- atomic_set(&net->passive, 1);
+ refcount_set(&net->passive, 1);
net->dev_base_seq = 1;
net->user_ns = user_ns;
idr_init(&net->netns_ids);
@@ -380,7 +380,7 @@ static void net_free(struct net *net)
void net_drop_ns(void *p)
{
struct net *ns = p;
- if (ns && atomic_dec_and_test(&ns->passive))
+ if (ns && refcount_dec_and_test(&ns->passive))
net_free(ns);
}
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 16/17] net: convert netlbl_lsm_cache.refcount from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (14 preceding siblings ...)
2017-06-30 10:08 ` [PATCH 15/17] net: convert net.passive " Elena Reshetova
@ 2017-06-30 10:08 ` Elena Reshetova
2017-06-30 10:08 ` [PATCH 17/17] net: convert packet_fanout.sk_ref " Elena Reshetova
2017-07-03 9:28 ` [PATCH 00/17] v3 net generic subsystem refcount conversions Eric Dumazet
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:08 UTC (permalink / raw)
To: netdev
Cc: bridge, linux-kernel, kuznet, jmorris, kaber, stephen, peterz,
keescook, Elena Reshetova, Hans Liljestrand, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
include/net/netlabel.h | 8 ++++----
net/ipv4/cipso_ipv4.c | 4 ++--
net/ipv6/calipso.c | 4 ++--
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index efe9806..72d6435 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -37,7 +37,7 @@
#include <linux/in6.h>
#include <net/netlink.h>
#include <net/request_sock.h>
-#include <linux/atomic.h>
+#include <linux/refcount.h>
struct cipso_v4_doi;
struct calipso_doi;
@@ -136,7 +136,7 @@ struct netlbl_audit {
*
*/
struct netlbl_lsm_cache {
- atomic_t refcount;
+ refcount_t refcount;
void (*free) (const void *data);
void *data;
};
@@ -295,7 +295,7 @@ static inline struct netlbl_lsm_cache *netlbl_secattr_cache_alloc(gfp_t flags)
cache = kzalloc(sizeof(*cache), flags);
if (cache)
- atomic_set(&cache->refcount, 1);
+ refcount_set(&cache->refcount, 1);
return cache;
}
@@ -309,7 +309,7 @@ static inline struct netlbl_lsm_cache *netlbl_secattr_cache_alloc(gfp_t flags)
*/
static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache)
{
- if (!atomic_dec_and_test(&cache->refcount))
+ if (!refcount_dec_and_test(&cache->refcount))
return;
if (cache->free)
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index ae20616..c204477 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -265,7 +265,7 @@ static int cipso_v4_cache_check(const unsigned char *key,
entry->key_len == key_len &&
memcmp(entry->key, key, key_len) == 0) {
entry->activity += 1;
- atomic_inc(&entry->lsm_data->refcount);
+ refcount_inc(&entry->lsm_data->refcount);
secattr->cache = entry->lsm_data;
secattr->flags |= NETLBL_SECATTR_CACHE;
secattr->type = NETLBL_NLTYPE_CIPSOV4;
@@ -332,7 +332,7 @@ int cipso_v4_cache_add(const unsigned char *cipso_ptr,
}
entry->key_len = cipso_ptr_len;
entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len);
- atomic_inc(&secattr->cache->refcount);
+ refcount_inc(&secattr->cache->refcount);
entry->lsm_data = secattr->cache;
bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETS - 1);
diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c
index 8d772fe..4406752 100644
--- a/net/ipv6/calipso.c
+++ b/net/ipv6/calipso.c
@@ -227,7 +227,7 @@ static int calipso_cache_check(const unsigned char *key,
entry->key_len == key_len &&
memcmp(entry->key, key, key_len) == 0) {
entry->activity += 1;
- atomic_inc(&entry->lsm_data->refcount);
+ refcount_inc(&entry->lsm_data->refcount);
secattr->cache = entry->lsm_data;
secattr->flags |= NETLBL_SECATTR_CACHE;
secattr->type = NETLBL_NLTYPE_CALIPSO;
@@ -296,7 +296,7 @@ static int calipso_cache_add(const unsigned char *calipso_ptr,
}
entry->key_len = calipso_ptr_len;
entry->hash = calipso_map_cache_hash(calipso_ptr, calipso_ptr_len);
- atomic_inc(&secattr->cache->refcount);
+ refcount_inc(&secattr->cache->refcount);
entry->lsm_data = secattr->cache;
bkt = entry->hash & (CALIPSO_CACHE_BUCKETS - 1);
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 17/17] net: convert packet_fanout.sk_ref from atomic_t to refcount_t
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (15 preceding siblings ...)
2017-06-30 10:08 ` [PATCH 16/17] net: convert netlbl_lsm_cache.refcount " Elena Reshetova
@ 2017-06-30 10:08 ` Elena Reshetova
2017-07-03 9:28 ` [PATCH 00/17] v3 net generic subsystem refcount conversions Eric Dumazet
17 siblings, 0 replies; 34+ messages in thread
From: Elena Reshetova @ 2017-06-30 10:08 UTC (permalink / raw)
To: netdev
Cc: bridge, linux-kernel, kuznet, jmorris, kaber, stephen, peterz,
keescook, Elena Reshetova, Hans Liljestrand, David Windsor
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 <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
---
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 643302b..e3beb28 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1739,7 +1739,7 @@ static int fanout_add(struct sock *sk, u16 id, u16 type_flags)
match->flags = flags;
INIT_LIST_HEAD(&match->list);
spin_lock_init(&match->lock);
- atomic_set(&match->sk_ref, 0);
+ refcount_set(&match->sk_ref, 0);
fanout_init_data(match);
match->prot_hook.type = po->prot_hook.type;
match->prot_hook.dev = po->prot_hook.dev;
@@ -1753,10 +1753,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;
}
@@ -1785,7 +1785,7 @@ static struct packet_fanout *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);
else
f = NULL;
diff --git a/net/packet/internal.h b/net/packet/internal.h
index 9ee4631..94d1d40 100644
--- a/net/packet/internal.h
+++ b/net/packet/internal.h
@@ -1,6 +1,8 @@
#ifndef __PACKET_INTERNAL_H__
#define __PACKET_INTERNAL_H__
+#include <linux/refcount.h>
+
struct packet_mclist {
struct packet_mclist *next;
int ifindex;
@@ -86,7 +88,7 @@ struct packet_fanout {
struct list_head list;
struct sock *arr[PACKET_FANOUT_MAX];
spinlock_t lock;
- atomic_t sk_ref;
+ refcount_t sk_ref;
struct packet_type prot_hook ____cacheline_aligned_in_smp;
};
--
2.7.4
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH 00/17] v3 net generic subsystem refcount conversions
2017-06-30 10:07 [PATCH 00/17] v3 net generic subsystem refcount conversions Elena Reshetova
` (16 preceding siblings ...)
2017-06-30 10:08 ` [PATCH 17/17] net: convert packet_fanout.sk_ref " Elena Reshetova
@ 2017-07-03 9:28 ` Eric Dumazet
2017-07-03 9:54 ` [PATCH net-next] net: avoid one splat in fib_nl_delrule() Eric Dumazet
` (2 more replies)
17 siblings, 3 replies; 34+ messages in thread
From: Eric Dumazet @ 2017-07-03 9:28 UTC (permalink / raw)
To: Elena Reshetova
Cc: netdev, bridge, linux-kernel, kuznet, jmorris, kaber, stephen,
peterz, keescook
On Fri, 2017-06-30 at 13:07 +0300, Elena Reshetova wrote:
> Changes in v3:
> Rebased on top of the net-next tree.
>
> Changes in v2:
> No changes in patches apart from rebases, but now by
> default refcount_t = atomic_t (*) and uses all atomic standard operations
> unless CONFIG_REFCOUNT_FULL is enabled. This is a compromise for the
> systems that are critical on performance (such as net) and cannot accept even
> slight delay on the refcounter operations.
>
> This series, for core network subsystem components, replaces atomic_t reference
> counters with the new refcount_t type and API (see include/linux/refcount.h).
> By doing this we prevent intentional or accidental
> underflows or overflows that can led to use-after-free vulnerabilities.
> These patches contain only generic net pieces. Other changes will be sent separately.
>
> The patches are fully independent and can be cherry-picked separately.
> The big patches, such as conversions for sock structure, need a very detailed
> look from maintainers: refcount managing is quite complex in them and while
> it seems that they would benefit from the change, extra checking is needed.
> The biggest corner issue is the fact that refcount_inc() does not increment
> from zero.
>
> If there are no objections to the patches, please merge them via respective trees.
>
> * The respective change is currently merged into -next as
> "locking/refcount: Create unchecked atomic_t implementation".
>
> Elena Reshetova (17):
> net: convert inet_peer.refcnt from atomic_t to refcount_t
> net: convert neighbour.refcnt from atomic_t to refcount_t
> net: convert neigh_params.refcnt from atomic_t to refcount_t
> net: convert nf_bridge_info.use from atomic_t to refcount_t
> net: convert sk_buff.users from atomic_t to refcount_t
> net: convert sk_buff_fclones.fclone_ref from atomic_t to refcount_t
> net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
> net: convert sock.sk_refcnt from atomic_t to refcount_t
> net: convert ip_mc_list.refcnt from atomic_t to refcount_t
> net: convert in_device.refcnt from atomic_t to refcount_t
> net: convert netpoll_info.refcnt from atomic_t to refcount_t
> net: convert unix_address.refcnt from atomic_t to refcount_t
> net: convert fib_rule.refcnt from atomic_t to refcount_t
> net: convert inet_frag_queue.refcnt from atomic_t to refcount_t
> net: convert net.passive from atomic_t to refcount_t
> net: convert netlbl_lsm_cache.refcount from atomic_t to refcount_t
> net: convert packet_fanout.sk_ref from atomic_t to refcount_t
Can you take a look at this please ?
Thanks.
[ 64.601749] ------------[ cut here ]------------
[ 64.601757] WARNING: CPU: 0 PID: 6476 at lib/refcount.c:184 refcount_sub_and_test+0x75/0xa0
[ 64.601758] Modules linked in: w1_therm wire cdc_acm ehci_pci ehci_hcd mlx4_en ib_uverbs mlx4_ib ib_core mlx4_core
[ 64.601769] CPU: 0 PID: 6476 Comm: ip Tainted: G W 4.12.0-smp-DEV #274
[ 64.601770] Hardware name: Intel RML,PCH/Iota_QC_19, BIOS 2.40.0 06/22/2016
[ 64.601771] task: ffff8837bf482040 task.stack: ffff8837bdc08000
[ 64.601773] RIP: 0010:refcount_sub_and_test+0x75/0xa0
[ 64.601774] RSP: 0018:ffff8837bdc0f5c0 EFLAGS: 00010286
[ 64.601776] RAX: 0000000000000026 RBX: 0000000000000001 RCX: 0000000000000000
[ 64.601777] RDX: 0000000000000026 RSI: 0000000000000096 RDI: ffffed06f7b81eae
[ 64.601778] RBP: ffff8837bdc0f5d0 R08: 0000000000000004 R09: fffffbfff4a54c25
[ 64.601779] R10: 00000000cbc500e5 R11: ffffffffa52a6128 R12: ffff881febcf6f24
[ 64.601779] R13: ffff881fbf4eaf00 R14: ffff881febcf6f80 R15: ffff8837d7a4ed00
[ 64.601781] FS: 00007ff5a2f6b700(0000) GS:ffff881fff800000(0000) knlGS:0000000000000000
[ 64.601782] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 64.601783] CR2: 00007ffcdc70d000 CR3: 0000001f9c91e000 CR4: 00000000001406f0
[ 64.601783] Call Trace:
[ 64.601786] refcount_dec_and_test+0x11/0x20
[ 64.601790] fib_nl_delrule+0xc39/0x1630
[ 64.601793] ? is_bpf_text_address+0xe/0x20
[ 64.601795] ? fib_nl_newrule+0x25e0/0x25e0
[ 64.601798] ? depot_save_stack+0x133/0x470
[ 64.601801] ? ns_capable+0x13/0x20
[ 64.601803] ? __netlink_ns_capable+0xcc/0x100
[ 64.601806] rtnetlink_rcv_msg+0x23a/0x6a0
[ 64.601808] ? rtnl_newlink+0x1630/0x1630
[ 64.601811] ? memset+0x31/0x40
[ 64.601813] netlink_rcv_skb+0x2d7/0x440
[ 64.601815] ? rtnl_newlink+0x1630/0x1630
[ 64.601816] ? netlink_ack+0xaf0/0xaf0
[ 64.601818] ? kasan_unpoison_shadow+0x35/0x50
[ 64.601820] ? __kmalloc_node_track_caller+0x4c/0x70
[ 64.601821] rtnetlink_rcv+0x28/0x30
[ 64.601823] netlink_unicast+0x422/0x610
[ 64.601824] ? netlink_attachskb+0x650/0x650
[ 64.601826] netlink_sendmsg+0x7b7/0xb60
[ 64.601828] ? netlink_unicast+0x610/0x610
[ 64.601830] ? netlink_unicast+0x610/0x610
[ 64.601832] sock_sendmsg+0xba/0xf0
[ 64.601834] ___sys_sendmsg+0x6a9/0x8c0
[ 64.601835] ? copy_msghdr_from_user+0x520/0x520
[ 64.601837] ? __alloc_pages_nodemask+0x160/0x520
[ 64.601839] ? memcg_write_event_control+0xd60/0xd60
[ 64.601841] ? __alloc_pages_slowpath+0x1d50/0x1d50
[ 64.601843] ? kasan_slab_free+0x71/0xc0
[ 64.601845] ? mem_cgroup_commit_charge+0xb2/0x11d0
[ 64.601847] ? lru_cache_add_active_or_unevictable+0x7d/0x1a0
[ 64.601849] ? __handle_mm_fault+0x1af8/0x2810
[ 64.601851] ? may_open_dev+0xc0/0xc0
[ 64.601852] ? __pmd_alloc+0x2c0/0x2c0
[ 64.601853] ? __fdget+0x13/0x20
[ 64.601855] __sys_sendmsg+0xc6/0x150
[ 64.601856] ? __sys_sendmsg+0xc6/0x150
[ 64.601857] ? SyS_shutdown+0x170/0x170
[ 64.601859] ? handle_mm_fault+0x28a/0x650
[ 64.601861] SyS_sendmsg+0x12/0x20
[ 64.601863] entry_SYSCALL_64_fastpath+0x13/0x94
[ 64.601864] RIP: 0033:0x7ff5a29b6080
[ 64.601865] RSP: 002b:00007ffcdc707e08 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
[ 64.601867] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007ff5a29b6080
[ 64.601867] RDX: 0000000000000000 RSI: 00007ffcdc707e58 RDI: 0000000000000003
[ 64.601868] RBP: 00007ffcdc70fec0 R08: 0000000000000001 R09: 0000000000000000
[ 64.601869] R10: 00007ffcdc711eb7 R11: 0000000000000246 R12: 0000000000456000
[ 64.601870] R13: 00007ffcdc7108b0 R14: 0000000000000000 R15: 0000000000000001
[ 64.601871] Code: 16 75 33 85 d2 0f 94 c0 48 83 c4 08 5b 5d c3 80 3d 7d 5b 84 01 00 75 15 48 c7 c7 60 8e 57 a4 c6 05 6d 5b 84 01 01 e8 bb e2 99 ff <0f> ff 31 c0 48 83 c4 08 5b 5d c3 83 f8 ff 75 b3 31 c0 eb f0 48
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH net-next] net: avoid one splat in fib_nl_delrule()
2017-07-03 9:28 ` [PATCH 00/17] v3 net generic subsystem refcount conversions Eric Dumazet
@ 2017-07-03 9:54 ` Eric Dumazet
2017-07-03 10:29 ` David Miller
2017-07-03 9:57 ` [PATCH 00/17] v3 net generic subsystem refcount conversions Reshetova, Elena
2017-07-08 18:51 ` Levin, Alexander (Sasha Levin)
2 siblings, 1 reply; 34+ messages in thread
From: Eric Dumazet @ 2017-07-03 9:54 UTC (permalink / raw)
To: Elena Reshetova, David Miller; +Cc: netdev
From: Eric Dumazet <edumazet@google.com>
We need to use refcount_set() on a newly created rule to avoid
following error :
[ 64.601749] ------------[ cut here ]------------
[ 64.601757] WARNING: CPU: 0 PID: 6476 at lib/refcount.c:184 refcount_sub_and_test+0x75/0xa0
[ 64.601758] Modules linked in: w1_therm wire cdc_acm ehci_pci ehci_hcd mlx4_en ib_uverbs mlx4_ib ib_core mlx4_core
[ 64.601769] CPU: 0 PID: 6476 Comm: ip Tainted: G W 4.12.0-smp-DEV #274
[ 64.601771] task: ffff8837bf482040 task.stack: ffff8837bdc08000
[ 64.601773] RIP: 0010:refcount_sub_and_test+0x75/0xa0
[ 64.601774] RSP: 0018:ffff8837bdc0f5c0 EFLAGS: 00010286
[ 64.601776] RAX: 0000000000000026 RBX: 0000000000000001 RCX: 0000000000000000
[ 64.601777] RDX: 0000000000000026 RSI: 0000000000000096 RDI: ffffed06f7b81eae
[ 64.601778] RBP: ffff8837bdc0f5d0 R08: 0000000000000004 R09: fffffbfff4a54c25
[ 64.601779] R10: 00000000cbc500e5 R11: ffffffffa52a6128 R12: ffff881febcf6f24
[ 64.601779] R13: ffff881fbf4eaf00 R14: ffff881febcf6f80 R15: ffff8837d7a4ed00
[ 64.601781] FS: 00007ff5a2f6b700(0000) GS:ffff881fff800000(0000) knlGS:0000000000000000
[ 64.601782] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 64.601783] CR2: 00007ffcdc70d000 CR3: 0000001f9c91e000 CR4: 00000000001406f0
[ 64.601783] Call Trace:
[ 64.601786] refcount_dec_and_test+0x11/0x20
[ 64.601790] fib_nl_delrule+0xc39/0x1630
[ 64.601793] ? is_bpf_text_address+0xe/0x20
[ 64.601795] ? fib_nl_newrule+0x25e0/0x25e0
[ 64.601798] ? depot_save_stack+0x133/0x470
[ 64.601801] ? ns_capable+0x13/0x20
[ 64.601803] ? __netlink_ns_capable+0xcc/0x100
[ 64.601806] rtnetlink_rcv_msg+0x23a/0x6a0
[ 64.601808] ? rtnl_newlink+0x1630/0x1630
[ 64.601811] ? memset+0x31/0x40
[ 64.601813] netlink_rcv_skb+0x2d7/0x440
[ 64.601815] ? rtnl_newlink+0x1630/0x1630
[ 64.601816] ? netlink_ack+0xaf0/0xaf0
[ 64.601818] ? kasan_unpoison_shadow+0x35/0x50
[ 64.601820] ? __kmalloc_node_track_caller+0x4c/0x70
[ 64.601821] rtnetlink_rcv+0x28/0x30
[ 64.601823] netlink_unicast+0x422/0x610
[ 64.601824] ? netlink_attachskb+0x650/0x650
[ 64.601826] netlink_sendmsg+0x7b7/0xb60
[ 64.601828] ? netlink_unicast+0x610/0x610
[ 64.601830] ? netlink_unicast+0x610/0x610
[ 64.601832] sock_sendmsg+0xba/0xf0
[ 64.601834] ___sys_sendmsg+0x6a9/0x8c0
[ 64.601835] ? copy_msghdr_from_user+0x520/0x520
[ 64.601837] ? __alloc_pages_nodemask+0x160/0x520
[ 64.601839] ? memcg_write_event_control+0xd60/0xd60
[ 64.601841] ? __alloc_pages_slowpath+0x1d50/0x1d50
[ 64.601843] ? kasan_slab_free+0x71/0xc0
[ 64.601845] ? mem_cgroup_commit_charge+0xb2/0x11d0
[ 64.601847] ? lru_cache_add_active_or_unevictable+0x7d/0x1a0
[ 64.601849] ? __handle_mm_fault+0x1af8/0x2810
[ 64.601851] ? may_open_dev+0xc0/0xc0
[ 64.601852] ? __pmd_alloc+0x2c0/0x2c0
[ 64.601853] ? __fdget+0x13/0x20
[ 64.601855] __sys_sendmsg+0xc6/0x150
[ 64.601856] ? __sys_sendmsg+0xc6/0x150
[ 64.601857] ? SyS_shutdown+0x170/0x170
[ 64.601859] ? handle_mm_fault+0x28a/0x650
[ 64.601861] SyS_sendmsg+0x12/0x20
[ 64.601863] entry_SYSCALL_64_fastpath+0x13/0x94
Fixes: 717d1e993ad8 ("net: convert fib_rule.refcnt from atomic_t to refcount_t")
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/core/fib_rules.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index c4ecd9f75a47f1c861e11b21f55768053609b649..a0093e1b0235355db66b980580243dd6619c9aa6 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -517,7 +517,7 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,
last = r;
}
- fib_rule_get(rule);
+ refcount_set(&rule->refcnt, 1);
if (last)
list_add_rcu(&rule->list, &last->list);
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH 00/17] v3 net generic subsystem refcount conversions
2017-07-03 9:28 ` [PATCH 00/17] v3 net generic subsystem refcount conversions Eric Dumazet
2017-07-03 9:54 ` [PATCH net-next] net: avoid one splat in fib_nl_delrule() Eric Dumazet
@ 2017-07-03 9:57 ` Reshetova, Elena
2017-07-03 10:30 ` Eric Dumazet
2017-07-08 18:51 ` Levin, Alexander (Sasha Levin)
2 siblings, 1 reply; 34+ messages in thread
From: Reshetova, Elena @ 2017-07-03 9:57 UTC (permalink / raw)
To: Eric Dumazet
Cc: keescook, peterz, netdev, bridge, jmorris, linux-kernel, kuznet, kaber
> On Fri, 2017-06-30 at 13:07 +0300, Elena Reshetova wrote:
> > Changes in v3:
> > Rebased on top of the net-next tree.
> >
> > Changes in v2:
> > No changes in patches apart from rebases, but now by
> > default refcount_t = atomic_t (*) and uses all atomic standard operations
> > unless CONFIG_REFCOUNT_FULL is enabled. This is a compromise for the
> > systems that are critical on performance (such as net) and cannot accept even
> > slight delay on the refcounter operations.
> >
> > This series, for core network subsystem components, replaces atomic_t reference
> > counters with the new refcount_t type and API (see include/linux/refcount.h).
> > By doing this we prevent intentional or accidental
> > underflows or overflows that can led to use-after-free vulnerabilities.
> > These patches contain only generic net pieces. Other changes will be sent
> separately.
> >
> > The patches are fully independent and can be cherry-picked separately.
> > The big patches, such as conversions for sock structure, need a very detailed
> > look from maintainers: refcount managing is quite complex in them and while
> > it seems that they would benefit from the change, extra checking is needed.
> > The biggest corner issue is the fact that refcount_inc() does not increment
> > from zero.
> >
> > If there are no objections to the patches, please merge them via respective trees.
> >
> > * The respective change is currently merged into -next as
> > "locking/refcount: Create unchecked atomic_t implementation".
> >
> > Elena Reshetova (17):
> > net: convert inet_peer.refcnt from atomic_t to refcount_t
> > net: convert neighbour.refcnt from atomic_t to refcount_t
> > net: convert neigh_params.refcnt from atomic_t to refcount_t
> > net: convert nf_bridge_info.use from atomic_t to refcount_t
> > net: convert sk_buff.users from atomic_t to refcount_t
> > net: convert sk_buff_fclones.fclone_ref from atomic_t to refcount_t
> > net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
> > net: convert sock.sk_refcnt from atomic_t to refcount_t
> > net: convert ip_mc_list.refcnt from atomic_t to refcount_t
> > net: convert in_device.refcnt from atomic_t to refcount_t
> > net: convert netpoll_info.refcnt from atomic_t to refcount_t
> > net: convert unix_address.refcnt from atomic_t to refcount_t
> > net: convert fib_rule.refcnt from atomic_t to refcount_t
> > net: convert inet_frag_queue.refcnt from atomic_t to refcount_t
> > net: convert net.passive from atomic_t to refcount_t
> > net: convert netlbl_lsm_cache.refcount from atomic_t to refcount_t
> > net: convert packet_fanout.sk_ref from atomic_t to refcount_t
>
>
> Can you take a look at this please ?
>
> Thanks.
Thank you very much for the report! This is an underflow (dec/sub from zero) that is reported by WARNING.
I guess it is unlikely that actual code underflows, so the most probable cause is that it attempted to do refcount_inc/add() from zero, but then failed.
However in that case you should have seen another warning on refcount_inc() somewhere earlier. That one is actually the one I need to see to track the root cause.
Could you tell me how do you arrive to the below output? Boot in what config/etc.
I can try to reproduce to debug further.
Best Regards,
Elena
>
> [ 64.601749] ------------[ cut here ]------------
> [ 64.601757] WARNING: CPU: 0 PID: 6476 at lib/refcount.c:184
> refcount_sub_and_test+0x75/0xa0
> [ 64.601758] Modules linked in: w1_therm wire cdc_acm ehci_pci ehci_hcd
> mlx4_en ib_uverbs mlx4_ib ib_core mlx4_core
> [ 64.601769] CPU: 0 PID: 6476 Comm: ip Tainted: G W 4.12.0-smp-DEV #274
> [ 64.601770] Hardware name: Intel RML,PCH/Iota_QC_19, BIOS 2.40.0 06/22/2016
> [ 64.601771] task: ffff8837bf482040 task.stack: ffff8837bdc08000
> [ 64.601773] RIP: 0010:refcount_sub_and_test+0x75/0xa0
> [ 64.601774] RSP: 0018:ffff8837bdc0f5c0 EFLAGS: 00010286
> [ 64.601776] RAX: 0000000000000026 RBX: 0000000000000001 RCX:
> 0000000000000000
> [ 64.601777] RDX: 0000000000000026 RSI: 0000000000000096 RDI:
> ffffed06f7b81eae
> [ 64.601778] RBP: ffff8837bdc0f5d0 R08: 0000000000000004 R09: fffffbfff4a54c25
> [ 64.601779] R10: 00000000cbc500e5 R11: ffffffffa52a6128 R12: ffff881febcf6f24
> [ 64.601779] R13: ffff881fbf4eaf00 R14: ffff881febcf6f80 R15: ffff8837d7a4ed00
> [ 64.601781] FS: 00007ff5a2f6b700(0000) GS:ffff881fff800000(0000)
> knlGS:0000000000000000
> [ 64.601782] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [ 64.601783] CR2: 00007ffcdc70d000 CR3: 0000001f9c91e000 CR4:
> 00000000001406f0
> [ 64.601783] Call Trace:
> [ 64.601786] refcount_dec_and_test+0x11/0x20
> [ 64.601790] fib_nl_delrule+0xc39/0x1630
> [ 64.601793] ? is_bpf_text_address+0xe/0x20
> [ 64.601795] ? fib_nl_newrule+0x25e0/0x25e0
> [ 64.601798] ? depot_save_stack+0x133/0x470
> [ 64.601801] ? ns_capable+0x13/0x20
> [ 64.601803] ? __netlink_ns_capable+0xcc/0x100
> [ 64.601806] rtnetlink_rcv_msg+0x23a/0x6a0
> [ 64.601808] ? rtnl_newlink+0x1630/0x1630
> [ 64.601811] ? memset+0x31/0x40
> [ 64.601813] netlink_rcv_skb+0x2d7/0x440
> [ 64.601815] ? rtnl_newlink+0x1630/0x1630
> [ 64.601816] ? netlink_ack+0xaf0/0xaf0
> [ 64.601818] ? kasan_unpoison_shadow+0x35/0x50
> [ 64.601820] ? __kmalloc_node_track_caller+0x4c/0x70
> [ 64.601821] rtnetlink_rcv+0x28/0x30
> [ 64.601823] netlink_unicast+0x422/0x610
> [ 64.601824] ? netlink_attachskb+0x650/0x650
> [ 64.601826] netlink_sendmsg+0x7b7/0xb60
> [ 64.601828] ? netlink_unicast+0x610/0x610
> [ 64.601830] ? netlink_unicast+0x610/0x610
> [ 64.601832] sock_sendmsg+0xba/0xf0
> [ 64.601834] ___sys_sendmsg+0x6a9/0x8c0
> [ 64.601835] ? copy_msghdr_from_user+0x520/0x520
> [ 64.601837] ? __alloc_pages_nodemask+0x160/0x520
> [ 64.601839] ? memcg_write_event_control+0xd60/0xd60
> [ 64.601841] ? __alloc_pages_slowpath+0x1d50/0x1d50
> [ 64.601843] ? kasan_slab_free+0x71/0xc0
> [ 64.601845] ? mem_cgroup_commit_charge+0xb2/0x11d0
> [ 64.601847] ? lru_cache_add_active_or_unevictable+0x7d/0x1a0
> [ 64.601849] ? __handle_mm_fault+0x1af8/0x2810
> [ 64.601851] ? may_open_dev+0xc0/0xc0
> [ 64.601852] ? __pmd_alloc+0x2c0/0x2c0
> [ 64.601853] ? __fdget+0x13/0x20
> [ 64.601855] __sys_sendmsg+0xc6/0x150
> [ 64.601856] ? __sys_sendmsg+0xc6/0x150
> [ 64.601857] ? SyS_shutdown+0x170/0x170
> [ 64.601859] ? handle_mm_fault+0x28a/0x650
> [ 64.601861] SyS_sendmsg+0x12/0x20
> [ 64.601863] entry_SYSCALL_64_fastpath+0x13/0x94
> [ 64.601864] RIP: 0033:0x7ff5a29b6080
> [ 64.601865] RSP: 002b:00007ffcdc707e08 EFLAGS: 00000246 ORIG_RAX:
> 000000000000002e
> [ 64.601867] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007ff5a29b6080
> [ 64.601867] RDX: 0000000000000000 RSI: 00007ffcdc707e58 RDI:
> 0000000000000003
> [ 64.601868] RBP: 00007ffcdc70fec0 R08: 0000000000000001 R09:
> 0000000000000000
> [ 64.601869] R10: 00007ffcdc711eb7 R11: 0000000000000246 R12:
> 0000000000456000
> [ 64.601870] R13: 00007ffcdc7108b0 R14: 0000000000000000 R15:
> 0000000000000001
> [ 64.601871] Code: 16 75 33 85 d2 0f 94 c0 48 83 c4 08 5b 5d c3 80 3d 7d 5b 84 01
> 00 75 15 48 c7 c7 60 8e 57 a4 c6 05 6d 5b 84 01 01 e8 bb e2 99 ff <0f> ff 31 c0 48 83
> c4 08 5b 5d c3 83 f8 ff 75 b3 31 c0 eb f0 48
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 00/17] v3 net generic subsystem refcount conversions
2017-07-03 9:57 ` [PATCH 00/17] v3 net generic subsystem refcount conversions Reshetova, Elena
@ 2017-07-03 10:30 ` Eric Dumazet
0 siblings, 0 replies; 34+ messages in thread
From: Eric Dumazet @ 2017-07-03 10:30 UTC (permalink / raw)
To: Reshetova, Elena
Cc: netdev, bridge, linux-kernel, kuznet, jmorris, kaber, stephen,
peterz, keescook
On Mon, 2017-07-03 at 09:57 +0000, Reshetova, Elena wrote:
> Thank you very much for the report! This is an underflow (dec/sub from
> zero) that is reported by WARNING.
> I guess it is unlikely that actual code underflows, so the most
> probable cause is that it attempted to do refcount_inc/add() from
> zero, but then failed.
> However in that case you should have seen another warning on
> refcount_inc() somewhere earlier. That one is actually the one I need
> to see to track the root cause.
> Could you tell me how do you arrive to the below output? Boot in what
> config/etc.
> I can try to reproduce to debug further.
I sent this fix :
https://patchwork.ozlabs.org/patch/783389/
Thanks.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 00/17] v3 net generic subsystem refcount conversions
2017-07-03 9:28 ` [PATCH 00/17] v3 net generic subsystem refcount conversions Eric Dumazet
2017-07-03 9:54 ` [PATCH net-next] net: avoid one splat in fib_nl_delrule() Eric Dumazet
2017-07-03 9:57 ` [PATCH 00/17] v3 net generic subsystem refcount conversions Reshetova, Elena
@ 2017-07-08 18:51 ` Levin, Alexander (Sasha Levin)
2017-07-10 7:13 ` Reshetova, Elena
2 siblings, 1 reply; 34+ messages in thread
From: Levin, Alexander (Sasha Levin) @ 2017-07-08 18:51 UTC (permalink / raw)
To: Eric Dumazet
Cc: Elena Reshetova, netdev, bridge, linux-kernel, kuznet, jmorris,
kaber, stephen, peterz, keescook
On Mon, Jul 03, 2017 at 02:28:56AM -0700, Eric Dumazet wrote:
>On Fri, 2017-06-30 at 13:07 +0300, Elena Reshetova wrote:
>> Changes in v3:
>> Rebased on top of the net-next tree.
>>
>> Changes in v2:
>> No changes in patches apart from rebases, but now by
>> default refcount_t = atomic_t (*) and uses all atomic standard operations
>> unless CONFIG_REFCOUNT_FULL is enabled. This is a compromise for the
>> systems that are critical on performance (such as net) and cannot accept even
>> slight delay on the refcounter operations.
>>
>> This series, for core network subsystem components, replaces atomic_t reference
>> counters with the new refcount_t type and API (see include/linux/refcount.h).
>> By doing this we prevent intentional or accidental
>> underflows or overflows that can led to use-after-free vulnerabilities.
>> These patches contain only generic net pieces. Other changes will be sent separately.
>>
>> The patches are fully independent and can be cherry-picked separately.
>> The big patches, such as conversions for sock structure, need a very detailed
>> look from maintainers: refcount managing is quite complex in them and while
>> it seems that they would benefit from the change, extra checking is needed.
>> The biggest corner issue is the fact that refcount_inc() does not increment
>> from zero.
>>
>> If there are no objections to the patches, please merge them via respective trees.
>>
>> * The respective change is currently merged into -next as
>> "locking/refcount: Create unchecked atomic_t implementation".
>>
>> Elena Reshetova (17):
>> net: convert inet_peer.refcnt from atomic_t to refcount_t
>> net: convert neighbour.refcnt from atomic_t to refcount_t
>> net: convert neigh_params.refcnt from atomic_t to refcount_t
>> net: convert nf_bridge_info.use from atomic_t to refcount_t
>> net: convert sk_buff.users from atomic_t to refcount_t
>> net: convert sk_buff_fclones.fclone_ref from atomic_t to refcount_t
>> net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
>> net: convert sock.sk_refcnt from atomic_t to refcount_t
>> net: convert ip_mc_list.refcnt from atomic_t to refcount_t
>> net: convert in_device.refcnt from atomic_t to refcount_t
>> net: convert netpoll_info.refcnt from atomic_t to refcount_t
>> net: convert unix_address.refcnt from atomic_t to refcount_t
>> net: convert fib_rule.refcnt from atomic_t to refcount_t
>> net: convert inet_frag_queue.refcnt from atomic_t to refcount_t
>> net: convert net.passive from atomic_t to refcount_t
>> net: convert netlbl_lsm_cache.refcount from atomic_t to refcount_t
>> net: convert packet_fanout.sk_ref from atomic_t to refcount_t
>
>
>Can you take a look at this please ?
>
>[ 64.601749] ------------[ cut here ]------------
>[ 64.601757] WARNING: CPU: 0 PID: 6476 at lib/refcount.c:184 refcount_sub_and_test+0x75/0xa0
>[ 64.601758] Modules linked in: w1_therm wire cdc_acm ehci_pci ehci_hcd mlx4_en ib_uverbs mlx4_ib ib_core mlx4_core
>[ 64.601769] CPU: 0 PID: 6476 Comm: ip Tainted: G W 4.12.0-smp-DEV #274
>[ 64.601770] Hardware name: Intel RML,PCH/Iota_QC_19, BIOS 2.40.0 06/22/2016
>[ 64.601771] task: ffff8837bf482040 task.stack: ffff8837bdc08000
>[ 64.601773] RIP: 0010:refcount_sub_and_test+0x75/0xa0
>[ 64.601774] RSP: 0018:ffff8837bdc0f5c0 EFLAGS: 00010286
>[ 64.601776] RAX: 0000000000000026 RBX: 0000000000000001 RCX: 0000000000000000
>[ 64.601777] RDX: 0000000000000026 RSI: 0000000000000096 RDI: ffffed06f7b81eae
>[ 64.601778] RBP: ffff8837bdc0f5d0 R08: 0000000000000004 R09: fffffbfff4a54c25
>[ 64.601779] R10: 00000000cbc500e5 R11: ffffffffa52a6128 R12: ffff881febcf6f24
>[ 64.601779] R13: ffff881fbf4eaf00 R14: ffff881febcf6f80 R15: ffff8837d7a4ed00
>[ 64.601781] FS: 00007ff5a2f6b700(0000) GS:ffff881fff800000(0000) knlGS:0000000000000000
>[ 64.601782] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>[ 64.601783] CR2: 00007ffcdc70d000 CR3: 0000001f9c91e000 CR4: 00000000001406f0
>[ 64.601783] Call Trace:
>[ 64.601786] refcount_dec_and_test+0x11/0x20
>[ 64.601790] fib_nl_delrule+0xc39/0x1630
[snip]
I'm seeing a similar one coming from sctp:
refcount_t: underflow; use-after-free.
------------[ cut here ]------------
WARNING: CPU: 3 PID: 15570 at lib/refcount.c:186 refcount_sub_and_test.cold.13+0x18/0x21 lib/refcount.c:186
Kernel panic - not syncing: panic_on_warn set ...
CPU: 3 PID: 15570 Comm: syz-executor0 Not tainted 4.12.0-next-20170706+ #186
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.1-1ubuntu1 04/01/2014
Call Trace:
__dump_stack lib/dump_stack.c:16 [inline]
dump_stack+0x11d/0x1ef lib/dump_stack.c:52
panic+0x1bc/0x3ad kernel/panic.c:180
__warn.cold.6+0x2f/0x2f kernel/panic.c:541
report_bug+0x20d/0x2d0 lib/bug.c:183
fixup_bug+0x3f/0x90 arch/x86/kernel/traps.c:190
do_trap_no_signal arch/x86/kernel/traps.c:224 [inline]
do_trap+0x132/0x390 arch/x86/kernel/traps.c:273
do_error_trap+0x133/0x380 arch/x86/kernel/traps.c:310
do_invalid_op+0x1b/0x20 arch/x86/kernel/traps.c:323
invalid_op+0x1e/0x30 arch/x86/entry/entry_64.S:845
RIP: 0010:refcount_sub_and_test.cold.13+0x18/0x21 lib/refcount.c:186
RSP: 0018:ffff880062f7e270 EFLAGS: 00010282
RAX: 0000000000000026 RBX: ffff88006086a8cc RCX: 0000000000000000
RDX: 0000000000000000 RSI: 1ffff1000c5efc0a RDI: ffffffffac15c400
RBP: ffff880062f7e2f8 R08: 0000000000000006 R09: 0000000000000000
R10: ffff880069914040 R11: 0000000000000000 R12: 00000000ffffff01
R13: 0000000000000100 R14: 1ffff1000c5efc4e R15: 0000000000000001
sctp_wfree+0x183/0x620 net/sctp/socket.c:7745
skb_release_head_state+0x124/0x250 net/core/skbuff.c:652
skb_release_all+0x15/0x60 net/core/skbuff.c:665
__kfree_skb net/core/skbuff.c:681 [inline]
consume_skb+0x16c/0x500 net/core/skbuff.c:748
sctp_chunk_destroy net/sctp/sm_make_chunk.c:1441 [inline]
sctp_chunk_put+0x206/0x430 net/sctp/sm_make_chunk.c:1468
sctp_chunk_free+0x53/0x60 net/sctp/sm_make_chunk.c:1455
__sctp_outq_teardown+0x274/0x15b0 net/sctp/outqueue.c:228
sctp_outq_free+0x15/0x20 net/sctp/outqueue.c:284
sctp_association_free+0x2d4/0x934 net/sctp/associola.c:358
sctp_cmd_delete_tcb net/sctp/sm_sideeffect.c:917 [inline]
sctp_cmd_interpreter net/sctp/sm_sideeffect.c:1333 [inline]
sctp_side_effects net/sctp/sm_sideeffect.c:1198 [inline]
sctp_do_sm+0x4024/0x6d60 net/sctp/sm_sideeffect.c:1170
sctp_primitive_ABORT+0xa0/0xd0 net/sctp/primitive.c:119
sctp_close+0x293/0x9b0 net/sctp/socket.c:1529
inet_release+0xed/0x1c0 net/ipv4/af_inet.c:425
inet6_release+0x50/0x70 net/ipv6/af_inet6.c:432
sock_release+0x8d/0x1b0 net/socket.c:597
sock_close+0x16/0x20 net/socket.c:1112
__fput+0x327/0x920 fs/file_table.c:210
____fput+0x15/0x20 fs/file_table.c:246
llcp: llcp_sock_recvmsg: Recv datagram failed state 5 -11 0
task_work_run+0x192/0x270 kernel/task_work.c:116
exit_task_work include/linux/task_work.h:21 [inline]
do_exit+0xa42/0x1ba0 kernel/exit.c:864
do_group_exit+0x151/0x410 kernel/exit.c:966
get_signal+0x84e/0x18a0 kernel/signal.c:2330
do_signal+0x9c/0x2210 arch/x86/kernel/signal.c:808
exit_to_usermode_loop+0x187/0x220 arch/x86/entry/common.c:157
prepare_exit_to_usermode arch/x86/entry/common.c:194 [inline]
syscall_return_slowpath arch/x86/entry/common.c:263 [inline]
do_syscall_64+0x50b/0x740 arch/x86/entry/common.c:289
llcp: llcp_sock_recvmsg: Recv datagram failed state 5 -11 0
entry_SYSCALL64_slow_path+0x25/0x25
RIP: 0033:0x452309
RSP: 002b:00007f6aed443cf8 EFLAGS: 00000246 ORIG_RAX: 00000000000000ca
RAX: fffffffffffffe00 RBX: 0000000000718218 RCX: 0000000000452309
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000718218
RBP: 00000000007181f8 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 00007fffb90a5aae
R13: 00007fffb90a5aaf R14: 00007f6aed4449c0 R15: 00007f6aed444700
Dumping ftrace buffer:
(ftrace buffer empty)
Kernel Offset: 0x24000000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
Rebooting in 86400 seconds..
--
Thanks,
Sasha
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 00/17] v3 net generic subsystem refcount conversions
2017-07-08 18:51 ` Levin, Alexander (Sasha Levin)
@ 2017-07-10 7:13 ` Reshetova, Elena
0 siblings, 0 replies; 34+ messages in thread
From: Reshetova, Elena @ 2017-07-10 7:13 UTC (permalink / raw)
To: Levin, Alexander (Sasha Levin), Eric Dumazet
Cc: keescook, peterz, netdev, bridge, jmorris, linux-kernel, kuznet, kaber
> On Mon, Jul 03, 2017 at 02:28:56AM -0700, Eric Dumazet wrote:
> >On Fri, 2017-06-30 at 13:07 +0300, Elena Reshetova wrote:
> >> Changes in v3:
> >> Rebased on top of the net-next tree.
> >>
> >> Changes in v2:
> >> No changes in patches apart from rebases, but now by
> >> default refcount_t = atomic_t (*) and uses all atomic standard operations
> >> unless CONFIG_REFCOUNT_FULL is enabled. This is a compromise for the
> >> systems that are critical on performance (such as net) and cannot accept even
> >> slight delay on the refcounter operations.
> >>
> >> This series, for core network subsystem components, replaces atomic_t
> reference
> >> counters with the new refcount_t type and API (see
> include/linux/refcount.h).
> >> By doing this we prevent intentional or accidental
> >> underflows or overflows that can led to use-after-free vulnerabilities.
> >> These patches contain only generic net pieces. Other changes will be sent
> separately.
> >>
> >> The patches are fully independent and can be cherry-picked separately.
> >> The big patches, such as conversions for sock structure, need a very detailed
> >> look from maintainers: refcount managing is quite complex in them and while
> >> it seems that they would benefit from the change, extra checking is needed.
> >> The biggest corner issue is the fact that refcount_inc() does not increment
> >> from zero.
> >>
> >> If there are no objections to the patches, please merge them via respective
> trees.
> >>
> >> * The respective change is currently merged into -next as
> >> "locking/refcount: Create unchecked atomic_t implementation".
> >>
> >> Elena Reshetova (17):
> >> net: convert inet_peer.refcnt from atomic_t to refcount_t
> >> net: convert neighbour.refcnt from atomic_t to refcount_t
> >> net: convert neigh_params.refcnt from atomic_t to refcount_t
> >> net: convert nf_bridge_info.use from atomic_t to refcount_t
> >> net: convert sk_buff.users from atomic_t to refcount_t
> >> net: convert sk_buff_fclones.fclone_ref from atomic_t to refcount_t
> >> net: convert sock.sk_wmem_alloc from atomic_t to refcount_t
> >> net: convert sock.sk_refcnt from atomic_t to refcount_t
> >> net: convert ip_mc_list.refcnt from atomic_t to refcount_t
> >> net: convert in_device.refcnt from atomic_t to refcount_t
> >> net: convert netpoll_info.refcnt from atomic_t to refcount_t
> >> net: convert unix_address.refcnt from atomic_t to refcount_t
> >> net: convert fib_rule.refcnt from atomic_t to refcount_t
> >> net: convert inet_frag_queue.refcnt from atomic_t to refcount_t
> >> net: convert net.passive from atomic_t to refcount_t
> >> net: convert netlbl_lsm_cache.refcount from atomic_t to refcount_t
> >> net: convert packet_fanout.sk_ref from atomic_t to refcount_t
> >
> >
> >Can you take a look at this please ?
> >
> >[ 64.601749] ------------[ cut here ]------------
> >[ 64.601757] WARNING: CPU: 0 PID: 6476 at lib/refcount.c:184
> refcount_sub_and_test+0x75/0xa0
> >[ 64.601758] Modules linked in: w1_therm wire cdc_acm ehci_pci ehci_hcd
> mlx4_en ib_uverbs mlx4_ib ib_core mlx4_core
> >[ 64.601769] CPU: 0 PID: 6476 Comm: ip Tainted: G W 4.12.0-smp-DEV
> #274
> >[ 64.601770] Hardware name: Intel RML,PCH/Iota_QC_19, BIOS 2.40.0
> 06/22/2016
> >[ 64.601771] task: ffff8837bf482040 task.stack: ffff8837bdc08000
> >[ 64.601773] RIP: 0010:refcount_sub_and_test+0x75/0xa0
> >[ 64.601774] RSP: 0018:ffff8837bdc0f5c0 EFLAGS: 00010286
> >[ 64.601776] RAX: 0000000000000026 RBX: 0000000000000001 RCX:
> 0000000000000000
> >[ 64.601777] RDX: 0000000000000026 RSI: 0000000000000096 RDI:
> ffffed06f7b81eae
> >[ 64.601778] RBP: ffff8837bdc0f5d0 R08: 0000000000000004 R09:
> fffffbfff4a54c25
> >[ 64.601779] R10: 00000000cbc500e5 R11: ffffffffa52a6128 R12: ffff881febcf6f24
> >[ 64.601779] R13: ffff881fbf4eaf00 R14: ffff881febcf6f80 R15: ffff8837d7a4ed00
> >[ 64.601781] FS: 00007ff5a2f6b700(0000) GS:ffff881fff800000(0000)
> knlGS:0000000000000000
> >[ 64.601782] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> >[ 64.601783] CR2: 00007ffcdc70d000 CR3: 0000001f9c91e000 CR4:
> 00000000001406f0
> >[ 64.601783] Call Trace:
> >[ 64.601786] refcount_dec_and_test+0x11/0x20
> >[ 64.601790] fib_nl_delrule+0xc39/0x1630
> [snip]
>
> I'm seeing a similar one coming from sctp:
>
> refcount_t: underflow; use-after-free.
> ------------[ cut here ]------------
> WARNING: CPU: 3 PID: 15570 at lib/refcount.c:186
> refcount_sub_and_test.cold.13+0x18/0x21 lib/refcount.c:186
> Kernel panic - not syncing: panic_on_warn set ...
>
> CPU: 3 PID: 15570 Comm: syz-executor0 Not tainted 4.12.0-next-20170706+ #186
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.1-1ubuntu1
> 04/01/2014
> Call Trace:
> __dump_stack lib/dump_stack.c:16 [inline]
> dump_stack+0x11d/0x1ef lib/dump_stack.c:52
> panic+0x1bc/0x3ad kernel/panic.c:180
> __warn.cold.6+0x2f/0x2f kernel/panic.c:541
> report_bug+0x20d/0x2d0 lib/bug.c:183
> fixup_bug+0x3f/0x90 arch/x86/kernel/traps.c:190
> do_trap_no_signal arch/x86/kernel/traps.c:224 [inline]
> do_trap+0x132/0x390 arch/x86/kernel/traps.c:273
> do_error_trap+0x133/0x380 arch/x86/kernel/traps.c:310
> do_invalid_op+0x1b/0x20 arch/x86/kernel/traps.c:323
> invalid_op+0x1e/0x30 arch/x86/entry/entry_64.S:845
> RIP: 0010:refcount_sub_and_test.cold.13+0x18/0x21 lib/refcount.c:186
> RSP: 0018:ffff880062f7e270 EFLAGS: 00010282
> RAX: 0000000000000026 RBX: ffff88006086a8cc RCX: 0000000000000000
> RDX: 0000000000000000 RSI: 1ffff1000c5efc0a RDI: ffffffffac15c400
> RBP: ffff880062f7e2f8 R08: 0000000000000006 R09: 0000000000000000
> R10: ffff880069914040 R11: 0000000000000000 R12: 00000000ffffff01
> R13: 0000000000000100 R14: 1ffff1000c5efc4e R15: 0000000000000001
> sctp_wfree+0x183/0x620 net/sctp/socket.c:7745
> skb_release_head_state+0x124/0x250 net/core/skbuff.c:652
> skb_release_all+0x15/0x60 net/core/skbuff.c:665
> __kfree_skb net/core/skbuff.c:681 [inline]
> consume_skb+0x16c/0x500 net/core/skbuff.c:748
> sctp_chunk_destroy net/sctp/sm_make_chunk.c:1441 [inline]
> sctp_chunk_put+0x206/0x430 net/sctp/sm_make_chunk.c:1468
> sctp_chunk_free+0x53/0x60 net/sctp/sm_make_chunk.c:1455
> __sctp_outq_teardown+0x274/0x15b0 net/sctp/outqueue.c:228
> sctp_outq_free+0x15/0x20 net/sctp/outqueue.c:284
> sctp_association_free+0x2d4/0x934 net/sctp/associola.c:358
> sctp_cmd_delete_tcb net/sctp/sm_sideeffect.c:917 [inline]
> sctp_cmd_interpreter net/sctp/sm_sideeffect.c:1333 [inline]
> sctp_side_effects net/sctp/sm_sideeffect.c:1198 [inline]
> sctp_do_sm+0x4024/0x6d60 net/sctp/sm_sideeffect.c:1170
> sctp_primitive_ABORT+0xa0/0xd0 net/sctp/primitive.c:119
> sctp_close+0x293/0x9b0 net/sctp/socket.c:1529
> inet_release+0xed/0x1c0 net/ipv4/af_inet.c:425
> inet6_release+0x50/0x70 net/ipv6/af_inet6.c:432
> sock_release+0x8d/0x1b0 net/socket.c:597
> sock_close+0x16/0x20 net/socket.c:1112
> __fput+0x327/0x920 fs/file_table.c:210
> ____fput+0x15/0x20 fs/file_table.c:246
> llcp: llcp_sock_recvmsg: Recv datagram failed state 5 -11 0
> task_work_run+0x192/0x270 kernel/task_work.c:116
> exit_task_work include/linux/task_work.h:21 [inline]
> do_exit+0xa42/0x1ba0 kernel/exit.c:864
> do_group_exit+0x151/0x410 kernel/exit.c:966
> get_signal+0x84e/0x18a0 kernel/signal.c:2330
> do_signal+0x9c/0x2210 arch/x86/kernel/signal.c:808
> exit_to_usermode_loop+0x187/0x220 arch/x86/entry/common.c:157
> prepare_exit_to_usermode arch/x86/entry/common.c:194 [inline]
> syscall_return_slowpath arch/x86/entry/common.c:263 [inline]
> do_syscall_64+0x50b/0x740 arch/x86/entry/common.c:289
> llcp: llcp_sock_recvmsg: Recv datagram failed state 5 -11 0
> entry_SYSCALL64_slow_path+0x25/0x25
> RIP: 0033:0x452309
> RSP: 002b:00007f6aed443cf8 EFLAGS: 00000246 ORIG_RAX: 00000000000000ca
> RAX: fffffffffffffe00 RBX: 0000000000718218 RCX: 0000000000452309
> RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000718218
> RBP: 00000000007181f8 R08: 0000000000000000 R09: 0000000000000000
> R10: 0000000000000000 R11: 0000000000000246 R12: 00007fffb90a5aae
> R13: 00007fffb90a5aaf R14: 00007f6aed4449c0 R15: 00007f6aed444700
> Dumping ftrace buffer:
> (ftrace buffer empty)
> Kernel Offset: 0x24000000 from 0xffffffff81000000 (relocation range:
> 0xffffffff80000000-0xffffffffbfffffff)
> Rebooting in 86400 seconds..
>
Thank you for reporting this! However, I might need some help checking
what is going on there. Your kernel is enabled to panic on warn, which is great
since it gives us understanding that this is a different issue than previous one
(otherwise we would see a panic earlier when failing to increment from zero somewhere).
The code that causes the warning here is this:
@@ -7684,7 +7684,7 @@ static void sctp_wfree(struct sk_buff *skb)
sizeof(struct sk_buff) +
sizeof(struct sctp_chunk);
- atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
+ WARN_ON(refcount_sub_and_test(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc));
As you can see previously it would just do a atomic_sub() and not care of
end result, but now it issues a warning if result underflows.
Is it possible that it just uncovered the existing bug or was it supposed to underflow in
certain conditions?
Best Regards,
Elena.
> --
>
> Thanks,
> Sasha
^ permalink raw reply [flat|nested] 34+ messages in thread