Skip to content

Commit b54ab92

Browse files
ereshetovaummakynes
authored andcommitted
netfilter: refcounter conversions
refcount_t type and corresponding API (see include/linux/refcount.h) 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 <[email protected]> Signed-off-by: Hans Liljestrand <[email protected]> Signed-off-by: Kees Cook <[email protected]> Signed-off-by: David Windsor <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 3c679cb commit b54ab92

21 files changed

+85
-75
lines changed

include/net/ip_vs.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include <linux/list.h> /* for struct list_head */
1313
#include <linux/spinlock.h> /* for struct rwlock_t */
1414
#include <linux/atomic.h> /* for struct atomic_t */
15+
#include <linux/refcount.h> /* for struct refcount_t */
16+
1517
#include <linux/compiler.h>
1618
#include <linux/timer.h>
1719
#include <linux/bug.h>
@@ -525,7 +527,7 @@ struct ip_vs_conn {
525527
struct netns_ipvs *ipvs;
526528

527529
/* counter and timer */
528-
atomic_t refcnt; /* reference count */
530+
refcount_t refcnt; /* reference count */
529531
struct timer_list timer; /* Expiration timer */
530532
volatile unsigned long timeout; /* timeout */
531533

@@ -667,7 +669,7 @@ struct ip_vs_dest {
667669
atomic_t conn_flags; /* flags to copy to conn */
668670
atomic_t weight; /* server weight */
669671

670-
atomic_t refcnt; /* reference counter */
672+
refcount_t refcnt; /* reference counter */
671673
struct ip_vs_stats stats; /* statistics */
672674
unsigned long idle_start; /* start time, jiffies */
673675

@@ -1211,14 +1213,14 @@ struct ip_vs_conn * ip_vs_conn_out_get_proto(struct netns_ipvs *ipvs, int af,
12111213
*/
12121214
static inline bool __ip_vs_conn_get(struct ip_vs_conn *cp)
12131215
{
1214-
return atomic_inc_not_zero(&cp->refcnt);
1216+
return refcount_inc_not_zero(&cp->refcnt);
12151217
}
12161218

12171219
/* put back the conn without restarting its timer */
12181220
static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
12191221
{
12201222
smp_mb__before_atomic();
1221-
atomic_dec(&cp->refcnt);
1223+
refcount_dec(&cp->refcnt);
12221224
}
12231225
void ip_vs_conn_put(struct ip_vs_conn *cp);
12241226
void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
@@ -1410,18 +1412,18 @@ void ip_vs_try_bind_dest(struct ip_vs_conn *cp);
14101412

14111413
static inline void ip_vs_dest_hold(struct ip_vs_dest *dest)
14121414
{
1413-
atomic_inc(&dest->refcnt);
1415+
refcount_inc(&dest->refcnt);
14141416
}
14151417

14161418
static inline void ip_vs_dest_put(struct ip_vs_dest *dest)
14171419
{
14181420
smp_mb__before_atomic();
1419-
atomic_dec(&dest->refcnt);
1421+
refcount_dec(&dest->refcnt);
14201422
}
14211423

14221424
static inline void ip_vs_dest_put_and_free(struct ip_vs_dest *dest)
14231425
{
1424-
if (atomic_dec_and_test(&dest->refcnt))
1426+
if (refcount_dec_and_test(&dest->refcnt))
14251427
kfree(dest);
14261428
}
14271429

include/net/netfilter/nf_conntrack_expect.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#ifndef _NF_CONNTRACK_EXPECT_H
66
#define _NF_CONNTRACK_EXPECT_H
77

8+
#include <linux/refcount.h>
9+
810
#include <net/netfilter/nf_conntrack.h>
911
#include <net/netfilter/nf_conntrack_zones.h>
1012

@@ -37,7 +39,7 @@ struct nf_conntrack_expect {
3739
struct timer_list timeout;
3840

3941
/* Usage count. */
40-
atomic_t use;
42+
refcount_t use;
4143

4244
/* Flags */
4345
unsigned int flags;

include/net/netfilter/nf_conntrack_timeout.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <net/net_namespace.h>
55
#include <linux/netfilter/nf_conntrack_common.h>
66
#include <linux/netfilter/nf_conntrack_tuple_common.h>
7+
#include <linux/refcount.h>
78
#include <net/netfilter/nf_conntrack.h>
89
#include <net/netfilter/nf_conntrack_extend.h>
910

@@ -12,7 +13,7 @@
1213
struct ctnl_timeout {
1314
struct list_head head;
1415
struct rcu_head rcu_head;
15-
atomic_t refcnt;
16+
refcount_t refcnt;
1617
char name[CTNL_TIMEOUT_NAME_MAX];
1718
__u16 l3num;
1819
struct nf_conntrack_l4proto *l4proto;

net/ipv4/netfilter/ipt_CLUSTERIP.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <linux/icmp.h>
2323
#include <linux/if_arp.h>
2424
#include <linux/seq_file.h>
25+
#include <linux/refcount.h>
2526
#include <linux/netfilter_arp.h>
2627
#include <linux/netfilter/x_tables.h>
2728
#include <linux/netfilter_ipv4/ip_tables.h>
@@ -40,8 +41,8 @@ MODULE_DESCRIPTION("Xtables: CLUSTERIP target");
4041

4142
struct clusterip_config {
4243
struct list_head list; /* list of all configs */
43-
atomic_t refcount; /* reference count */
44-
atomic_t entries; /* number of entries/rules
44+
refcount_t refcount; /* reference count */
45+
refcount_t entries; /* number of entries/rules
4546
* referencing us */
4647

4748
__be32 clusterip; /* the IP address */
@@ -77,7 +78,7 @@ struct clusterip_net {
7778
static inline void
7879
clusterip_config_get(struct clusterip_config *c)
7980
{
80-
atomic_inc(&c->refcount);
81+
refcount_inc(&c->refcount);
8182
}
8283

8384

@@ -89,7 +90,7 @@ static void clusterip_config_rcu_free(struct rcu_head *head)
8990
static inline void
9091
clusterip_config_put(struct clusterip_config *c)
9192
{
92-
if (atomic_dec_and_test(&c->refcount))
93+
if (refcount_dec_and_test(&c->refcount))
9394
call_rcu_bh(&c->rcu, clusterip_config_rcu_free);
9495
}
9596

@@ -103,7 +104,7 @@ clusterip_config_entry_put(struct clusterip_config *c)
103104
struct clusterip_net *cn = net_generic(net, clusterip_net_id);
104105

105106
local_bh_disable();
106-
if (atomic_dec_and_lock(&c->entries, &cn->lock)) {
107+
if (refcount_dec_and_lock(&c->entries, &cn->lock)) {
107108
list_del_rcu(&c->list);
108109
spin_unlock(&cn->lock);
109110
local_bh_enable();
@@ -149,10 +150,10 @@ clusterip_config_find_get(struct net *net, __be32 clusterip, int entry)
149150
c = NULL;
150151
else
151152
#endif
152-
if (unlikely(!atomic_inc_not_zero(&c->refcount)))
153+
if (unlikely(!refcount_inc_not_zero(&c->refcount)))
153154
c = NULL;
154155
else if (entry)
155-
atomic_inc(&c->entries);
156+
refcount_inc(&c->entries);
156157
}
157158
rcu_read_unlock_bh();
158159

@@ -188,8 +189,8 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip,
188189
clusterip_config_init_nodelist(c, i);
189190
c->hash_mode = i->hash_mode;
190191
c->hash_initval = i->hash_initval;
191-
atomic_set(&c->refcount, 1);
192-
atomic_set(&c->entries, 1);
192+
refcount_set(&c->refcount, 1);
193+
refcount_set(&c->entries, 1);
193194

194195
spin_lock_bh(&cn->lock);
195196
if (__clusterip_config_find(net, ip)) {

net/netfilter/ipvs/ip_vs_conn.c

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ static inline int ip_vs_conn_hash(struct ip_vs_conn *cp)
181181

182182
if (!(cp->flags & IP_VS_CONN_F_HASHED)) {
183183
cp->flags |= IP_VS_CONN_F_HASHED;
184-
atomic_inc(&cp->refcnt);
184+
refcount_inc(&cp->refcnt);
185185
hlist_add_head_rcu(&cp->c_list, &ip_vs_conn_tab[hash]);
186186
ret = 1;
187187
} else {
@@ -215,7 +215,7 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
215215
if (cp->flags & IP_VS_CONN_F_HASHED) {
216216
hlist_del_rcu(&cp->c_list);
217217
cp->flags &= ~IP_VS_CONN_F_HASHED;
218-
atomic_dec(&cp->refcnt);
218+
refcount_dec(&cp->refcnt);
219219
ret = 1;
220220
} else
221221
ret = 0;
@@ -242,13 +242,13 @@ static inline bool ip_vs_conn_unlink(struct ip_vs_conn *cp)
242242
if (cp->flags & IP_VS_CONN_F_HASHED) {
243243
ret = false;
244244
/* Decrease refcnt and unlink conn only if we are last user */
245-
if (atomic_cmpxchg(&cp->refcnt, 1, 0) == 1) {
245+
if (refcount_dec_if_one(&cp->refcnt)) {
246246
hlist_del_rcu(&cp->c_list);
247247
cp->flags &= ~IP_VS_CONN_F_HASHED;
248248
ret = true;
249249
}
250250
} else
251-
ret = atomic_read(&cp->refcnt) ? false : true;
251+
ret = refcount_read(&cp->refcnt) ? false : true;
252252

253253
spin_unlock(&cp->lock);
254254
ct_write_unlock_bh(hash);
@@ -475,7 +475,7 @@ static void __ip_vs_conn_put_timer(struct ip_vs_conn *cp)
475475
void ip_vs_conn_put(struct ip_vs_conn *cp)
476476
{
477477
if ((cp->flags & IP_VS_CONN_F_ONE_PACKET) &&
478-
(atomic_read(&cp->refcnt) == 1) &&
478+
(refcount_read(&cp->refcnt) == 1) &&
479479
!timer_pending(&cp->timer))
480480
/* expire connection immediately */
481481
__ip_vs_conn_put_notimer(cp);
@@ -617,8 +617,8 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
617617
IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
618618
IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport),
619619
ip_vs_fwd_tag(cp), cp->state,
620-
cp->flags, atomic_read(&cp->refcnt),
621-
atomic_read(&dest->refcnt));
620+
cp->flags, refcount_read(&cp->refcnt),
621+
refcount_read(&dest->refcnt));
622622

623623
/* Update the connection counters */
624624
if (!(flags & IP_VS_CONN_F_TEMPLATE)) {
@@ -714,8 +714,8 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
714714
IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
715715
IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport),
716716
ip_vs_fwd_tag(cp), cp->state,
717-
cp->flags, atomic_read(&cp->refcnt),
718-
atomic_read(&dest->refcnt));
717+
cp->flags, refcount_read(&cp->refcnt),
718+
refcount_read(&dest->refcnt));
719719

720720
/* Update the connection counters */
721721
if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) {
@@ -863,10 +863,10 @@ static void ip_vs_conn_expire(unsigned long data)
863863

864864
expire_later:
865865
IP_VS_DBG(7, "delayed: conn->refcnt=%d conn->n_control=%d\n",
866-
atomic_read(&cp->refcnt),
866+
refcount_read(&cp->refcnt),
867867
atomic_read(&cp->n_control));
868868

869-
atomic_inc(&cp->refcnt);
869+
refcount_inc(&cp->refcnt);
870870
cp->timeout = 60*HZ;
871871

872872
if (ipvs->sync_state & IP_VS_STATE_MASTER)
@@ -941,7 +941,7 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p, int dest_af,
941941
* it in the table, so that other thread run ip_vs_random_dropentry
942942
* but cannot drop this entry.
943943
*/
944-
atomic_set(&cp->refcnt, 1);
944+
refcount_set(&cp->refcnt, 1);
945945

946946
cp->control = NULL;
947947
atomic_set(&cp->n_control, 0);

net/netfilter/ipvs/ip_vs_core.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
542542
IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport),
543543
IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
544544
IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport),
545-
cp->flags, atomic_read(&cp->refcnt));
545+
cp->flags, refcount_read(&cp->refcnt));
546546

547547
ip_vs_conn_stats(cp, svc);
548548
return cp;
@@ -1193,7 +1193,7 @@ struct ip_vs_conn *ip_vs_new_conn_out(struct ip_vs_service *svc,
11931193
IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport),
11941194
IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport),
11951195
IP_VS_DBG_ADDR(cp->af, &cp->daddr), ntohs(cp->dport),
1196-
cp->flags, atomic_read(&cp->refcnt));
1196+
cp->flags, refcount_read(&cp->refcnt));
11971197
LeaveFunction(12);
11981198
return cp;
11991199
}

net/netfilter/ipvs/ip_vs_ctl.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, int dest_af,
699699
dest->vfwmark,
700700
IP_VS_DBG_ADDR(dest->af, &dest->addr),
701701
ntohs(dest->port),
702-
atomic_read(&dest->refcnt));
702+
refcount_read(&dest->refcnt));
703703
if (dest->af == dest_af &&
704704
ip_vs_addr_equal(dest_af, &dest->addr, daddr) &&
705705
dest->port == dport &&
@@ -934,7 +934,7 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
934934
atomic_set(&dest->activeconns, 0);
935935
atomic_set(&dest->inactconns, 0);
936936
atomic_set(&dest->persistconns, 0);
937-
atomic_set(&dest->refcnt, 1);
937+
refcount_set(&dest->refcnt, 1);
938938

939939
INIT_HLIST_NODE(&dest->d_list);
940940
spin_lock_init(&dest->dst_lock);
@@ -998,7 +998,7 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest)
998998
IP_VS_DBG_BUF(3, "Get destination %s:%u from trash, "
999999
"dest->refcnt=%d, service %u/%s:%u\n",
10001000
IP_VS_DBG_ADDR(udest->af, &daddr), ntohs(dport),
1001-
atomic_read(&dest->refcnt),
1001+
refcount_read(&dest->refcnt),
10021002
dest->vfwmark,
10031003
IP_VS_DBG_ADDR(svc->af, &dest->vaddr),
10041004
ntohs(dest->vport));
@@ -1074,7 +1074,7 @@ static void __ip_vs_del_dest(struct netns_ipvs *ipvs, struct ip_vs_dest *dest,
10741074
spin_lock_bh(&ipvs->dest_trash_lock);
10751075
IP_VS_DBG_BUF(3, "Moving dest %s:%u into trash, dest->refcnt=%d\n",
10761076
IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port),
1077-
atomic_read(&dest->refcnt));
1077+
refcount_read(&dest->refcnt));
10781078
if (list_empty(&ipvs->dest_trash) && !cleanup)
10791079
mod_timer(&ipvs->dest_trash_timer,
10801080
jiffies + (IP_VS_DEST_TRASH_PERIOD >> 1));
@@ -1157,7 +1157,7 @@ static void ip_vs_dest_trash_expire(unsigned long data)
11571157

11581158
spin_lock(&ipvs->dest_trash_lock);
11591159
list_for_each_entry_safe(dest, next, &ipvs->dest_trash, t_list) {
1160-
if (atomic_read(&dest->refcnt) > 1)
1160+
if (refcount_read(&dest->refcnt) > 1)
11611161
continue;
11621162
if (dest->idle_start) {
11631163
if (time_before(now, dest->idle_start +
@@ -1545,7 +1545,7 @@ ip_vs_forget_dev(struct ip_vs_dest *dest, struct net_device *dev)
15451545
dev->name,
15461546
IP_VS_DBG_ADDR(dest->af, &dest->addr),
15471547
ntohs(dest->port),
1548-
atomic_read(&dest->refcnt));
1548+
refcount_read(&dest->refcnt));
15491549
__ip_vs_dst_cache_reset(dest);
15501550
}
15511551
spin_unlock_bh(&dest->dst_lock);

net/netfilter/ipvs/ip_vs_lblc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ __ip_vs_lblc_schedule(struct ip_vs_service *svc)
448448
IP_VS_DBG_ADDR(least->af, &least->addr),
449449
ntohs(least->port),
450450
atomic_read(&least->activeconns),
451-
atomic_read(&least->refcnt),
451+
refcount_read(&least->refcnt),
452452
atomic_read(&least->weight), loh);
453453

454454
return least;

net/netfilter/ipvs/ip_vs_lblcr.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
204204
IP_VS_DBG_ADDR(least->af, &least->addr),
205205
ntohs(least->port),
206206
atomic_read(&least->activeconns),
207-
atomic_read(&least->refcnt),
207+
refcount_read(&least->refcnt),
208208
atomic_read(&least->weight), loh);
209209
return least;
210210
}
@@ -249,7 +249,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
249249
__func__,
250250
IP_VS_DBG_ADDR(most->af, &most->addr), ntohs(most->port),
251251
atomic_read(&most->activeconns),
252-
atomic_read(&most->refcnt),
252+
refcount_read(&most->refcnt),
253253
atomic_read(&most->weight), moh);
254254
return most;
255255
}
@@ -612,7 +612,7 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc)
612612
IP_VS_DBG_ADDR(least->af, &least->addr),
613613
ntohs(least->port),
614614
atomic_read(&least->activeconns),
615-
atomic_read(&least->refcnt),
615+
refcount_read(&least->refcnt),
616616
atomic_read(&least->weight), loh);
617617

618618
return least;

net/netfilter/ipvs/ip_vs_nq.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
110110
IP_VS_DBG_ADDR(least->af, &least->addr),
111111
ntohs(least->port),
112112
atomic_read(&least->activeconns),
113-
atomic_read(&least->refcnt),
113+
refcount_read(&least->refcnt),
114114
atomic_read(&least->weight), loh);
115115

116116
return least;

net/netfilter/ipvs/ip_vs_proto_sctp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,
447447
ntohs(cp->cport),
448448
sctp_state_name(cp->state),
449449
sctp_state_name(next_state),
450-
atomic_read(&cp->refcnt));
450+
refcount_read(&cp->refcnt));
451451
if (dest) {
452452
if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&
453453
(next_state != IP_VS_SCTP_S_ESTABLISHED)) {

net/netfilter/ipvs/ip_vs_proto_tcp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ set_tcp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,
557557
ntohs(cp->cport),
558558
tcp_state_name(cp->state),
559559
tcp_state_name(new_state),
560-
atomic_read(&cp->refcnt));
560+
refcount_read(&cp->refcnt));
561561

562562
if (dest) {
563563
if (!(cp->flags & IP_VS_CONN_F_INACTIVE) &&

0 commit comments

Comments
 (0)