Commit eaf6ab76 authored by Elena Reshetova's avatar Elena Reshetova Committed by David S. Miller

drivers, net, ethernet: convert clip_entry.refcnt from atomic_t to refcount_t

atomic_t variables are currently used to implement reference
counters with the following properties:
 - counter is initialized to 1 using atomic_set()
 - a resource is freed upon counter reaching zero
 - once counter reaches zero, its further
   increments aren't allowed
 - counter schema uses basic atomic operations
   (set, inc, inc_not_zero, dec_and_test, etc.)

Such atomic variables should be converted to a newly provided
refcount_t type and API that prevents accidental counter overflows
and underflows. This is important since overflows and underflows
can lead to use-after-free situation and be exploitable.

The variable clip_entry.refcnt is used as pure reference counter.
Convert it to refcount_t and fix up the operations.
Suggested-by: default avatarKees Cook <keescook@chromium.org>
Reviewed-by: default avatarDavid Windsor <dwindsor@gmail.com>
Reviewed-by: default avatarHans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: default avatarElena Reshetova <elena.reshetova@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 86f540c1
...@@ -96,7 +96,8 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6) ...@@ -96,7 +96,8 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
if (!ret) { if (!ret) {
ce = cte; ce = cte;
read_unlock_bh(&ctbl->lock); read_unlock_bh(&ctbl->lock);
goto found; refcount_inc(&ce->refcnt);
return 0;
} }
} }
read_unlock_bh(&ctbl->lock); read_unlock_bh(&ctbl->lock);
...@@ -108,7 +109,7 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6) ...@@ -108,7 +109,7 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
list_del(&ce->list); list_del(&ce->list);
INIT_LIST_HEAD(&ce->list); INIT_LIST_HEAD(&ce->list);
spin_lock_init(&ce->lock); spin_lock_init(&ce->lock);
atomic_set(&ce->refcnt, 0); refcount_set(&ce->refcnt, 0);
atomic_dec(&ctbl->nfree); atomic_dec(&ctbl->nfree);
list_add_tail(&ce->list, &ctbl->hash_list[hash]); list_add_tail(&ce->list, &ctbl->hash_list[hash]);
if (v6) { if (v6) {
...@@ -138,9 +139,7 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6) ...@@ -138,9 +139,7 @@ int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
return -ENOMEM; return -ENOMEM;
} }
write_unlock_bh(&ctbl->lock); write_unlock_bh(&ctbl->lock);
found: refcount_set(&ce->refcnt, 1);
atomic_inc(&ce->refcnt);
return 0; return 0;
} }
EXPORT_SYMBOL(cxgb4_clip_get); EXPORT_SYMBOL(cxgb4_clip_get);
...@@ -179,7 +178,7 @@ void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6) ...@@ -179,7 +178,7 @@ void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6)
found: found:
write_lock_bh(&ctbl->lock); write_lock_bh(&ctbl->lock);
spin_lock_bh(&ce->lock); spin_lock_bh(&ce->lock);
if (atomic_dec_and_test(&ce->refcnt)) { if (refcount_dec_and_test(&ce->refcnt)) {
list_del(&ce->list); list_del(&ce->list);
INIT_LIST_HEAD(&ce->list); INIT_LIST_HEAD(&ce->list);
list_add_tail(&ce->list, &ctbl->ce_free_head); list_add_tail(&ce->list, &ctbl->ce_free_head);
...@@ -266,7 +265,7 @@ int clip_tbl_show(struct seq_file *seq, void *v) ...@@ -266,7 +265,7 @@ int clip_tbl_show(struct seq_file *seq, void *v)
ip[0] = '\0'; ip[0] = '\0';
sprintf(ip, "%pISc", &ce->addr); sprintf(ip, "%pISc", &ce->addr);
seq_printf(seq, "%-25s %u\n", ip, seq_printf(seq, "%-25s %u\n", ip,
atomic_read(&ce->refcnt)); refcount_read(&ce->refcnt));
} }
} }
seq_printf(seq, "Free clip entries : %d\n", atomic_read(&ctbl->nfree)); seq_printf(seq, "Free clip entries : %d\n", atomic_read(&ctbl->nfree));
......
...@@ -10,9 +10,11 @@ ...@@ -10,9 +10,11 @@
* release for licensing terms and conditions. * release for licensing terms and conditions.
*/ */
#include <linux/refcount.h>
struct clip_entry { struct clip_entry {
spinlock_t lock; /* Hold while modifying clip reference */ spinlock_t lock; /* Hold while modifying clip reference */
atomic_t refcnt; refcount_t refcnt;
struct list_head list; struct list_head list;
union { union {
struct sockaddr_in addr; struct sockaddr_in addr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment