Skip to content

Commit 52d1aa8

Browse files
danobiummakynes
authored andcommitted
netfilter: conntrack: Fix data-races around ct mark
nf_conn:mark can be read from and written to in parallel. Use READ_ONCE()/WRITE_ONCE() for reads and writes to prevent unwanted compiler optimizations. Fixes: 1da177e ("Linux-2.6.12-rc2") Signed-off-by: Daniel Xu <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 40b9d1a commit 52d1aa8

File tree

11 files changed

+45
-39
lines changed

11 files changed

+45
-39
lines changed

net/core/flow_dissector.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ skb_flow_dissect_ct(const struct sk_buff *skb,
296296
key->ct_zone = ct->zone.id;
297297
#endif
298298
#if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)
299-
key->ct_mark = ct->mark;
299+
key->ct_mark = READ_ONCE(ct->mark);
300300
#endif
301301

302302
cl = nf_ct_labels_find(ct);

net/ipv4/netfilter/ipt_CLUSTERIP.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ clusterip_tg(struct sk_buff *skb, const struct xt_action_param *par)
435435

436436
switch (ctinfo) {
437437
case IP_CT_NEW:
438-
ct->mark = hash;
438+
WRITE_ONCE(ct->mark, hash);
439439
break;
440440
case IP_CT_RELATED:
441441
case IP_CT_RELATED_REPLY:
@@ -452,7 +452,7 @@ clusterip_tg(struct sk_buff *skb, const struct xt_action_param *par)
452452
#ifdef DEBUG
453453
nf_ct_dump_tuple_ip(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
454454
#endif
455-
pr_debug("hash=%u ct_hash=%u ", hash, ct->mark);
455+
pr_debug("hash=%u ct_hash=%u ", hash, READ_ONCE(ct->mark));
456456
if (!clusterip_responsible(cipinfo->config, hash)) {
457457
pr_debug("not responsible\n");
458458
return NF_DROP;

net/netfilter/nf_conntrack_core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1781,7 +1781,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
17811781
}
17821782

17831783
#ifdef CONFIG_NF_CONNTRACK_MARK
1784-
ct->mark = exp->master->mark;
1784+
ct->mark = READ_ONCE(exp->master->mark);
17851785
#endif
17861786
#ifdef CONFIG_NF_CONNTRACK_SECMARK
17871787
ct->secmark = exp->master->secmark;

net/netfilter/nf_conntrack_netlink.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -328,9 +328,9 @@ ctnetlink_dump_timestamp(struct sk_buff *skb, const struct nf_conn *ct)
328328
}
329329

330330
#ifdef CONFIG_NF_CONNTRACK_MARK
331-
static int ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct)
331+
static int ctnetlink_dump_mark(struct sk_buff *skb, u32 mark)
332332
{
333-
if (nla_put_be32(skb, CTA_MARK, htonl(ct->mark)))
333+
if (nla_put_be32(skb, CTA_MARK, htonl(mark)))
334334
goto nla_put_failure;
335335
return 0;
336336

@@ -543,7 +543,7 @@ static int ctnetlink_dump_extinfo(struct sk_buff *skb,
543543
static int ctnetlink_dump_info(struct sk_buff *skb, struct nf_conn *ct)
544544
{
545545
if (ctnetlink_dump_status(skb, ct) < 0 ||
546-
ctnetlink_dump_mark(skb, ct) < 0 ||
546+
ctnetlink_dump_mark(skb, READ_ONCE(ct->mark)) < 0 ||
547547
ctnetlink_dump_secctx(skb, ct) < 0 ||
548548
ctnetlink_dump_id(skb, ct) < 0 ||
549549
ctnetlink_dump_use(skb, ct) < 0 ||
@@ -722,6 +722,7 @@ ctnetlink_conntrack_event(unsigned int events, const struct nf_ct_event *item)
722722
struct sk_buff *skb;
723723
unsigned int type;
724724
unsigned int flags = 0, group;
725+
u32 mark;
725726
int err;
726727

727728
if (events & (1 << IPCT_DESTROY)) {
@@ -826,8 +827,9 @@ ctnetlink_conntrack_event(unsigned int events, const struct nf_ct_event *item)
826827
}
827828

828829
#ifdef CONFIG_NF_CONNTRACK_MARK
829-
if ((events & (1 << IPCT_MARK) || ct->mark)
830-
&& ctnetlink_dump_mark(skb, ct) < 0)
830+
mark = READ_ONCE(ct->mark);
831+
if ((events & (1 << IPCT_MARK) || mark) &&
832+
ctnetlink_dump_mark(skb, mark) < 0)
831833
goto nla_put_failure;
832834
#endif
833835
nlmsg_end(skb, nlh);
@@ -1154,7 +1156,7 @@ static int ctnetlink_filter_match(struct nf_conn *ct, void *data)
11541156
}
11551157

11561158
#ifdef CONFIG_NF_CONNTRACK_MARK
1157-
if ((ct->mark & filter->mark.mask) != filter->mark.val)
1159+
if ((READ_ONCE(ct->mark) & filter->mark.mask) != filter->mark.val)
11581160
goto ignore_entry;
11591161
#endif
11601162
status = (u32)READ_ONCE(ct->status);
@@ -2002,9 +2004,9 @@ static void ctnetlink_change_mark(struct nf_conn *ct,
20022004
mask = ~ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
20032005

20042006
mark = ntohl(nla_get_be32(cda[CTA_MARK]));
2005-
newmark = (ct->mark & mask) ^ mark;
2006-
if (newmark != ct->mark)
2007-
ct->mark = newmark;
2007+
newmark = (READ_ONCE(ct->mark) & mask) ^ mark;
2008+
if (newmark != READ_ONCE(ct->mark))
2009+
WRITE_ONCE(ct->mark, newmark);
20082010
}
20092011
#endif
20102012

@@ -2669,6 +2671,7 @@ static int __ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct)
26692671
{
26702672
const struct nf_conntrack_zone *zone;
26712673
struct nlattr *nest_parms;
2674+
u32 mark;
26722675

26732676
zone = nf_ct_zone(ct);
26742677

@@ -2730,7 +2733,8 @@ static int __ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct)
27302733
goto nla_put_failure;
27312734

27322735
#ifdef CONFIG_NF_CONNTRACK_MARK
2733-
if (ct->mark && ctnetlink_dump_mark(skb, ct) < 0)
2736+
mark = READ_ONCE(ct->mark);
2737+
if (mark && ctnetlink_dump_mark(skb, mark) < 0)
27342738
goto nla_put_failure;
27352739
#endif
27362740
if (ctnetlink_dump_labels(skb, ct) < 0)

net/netfilter/nf_conntrack_standalone.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ static int ct_seq_show(struct seq_file *s, void *v)
366366
goto release;
367367

368368
#if defined(CONFIG_NF_CONNTRACK_MARK)
369-
seq_printf(s, "mark=%u ", ct->mark);
369+
seq_printf(s, "mark=%u ", READ_ONCE(ct->mark));
370370
#endif
371371

372372
ct_show_secctx(s, ct);

net/netfilter/nft_ct.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
9898
return;
9999
#ifdef CONFIG_NF_CONNTRACK_MARK
100100
case NFT_CT_MARK:
101-
*dest = ct->mark;
101+
*dest = READ_ONCE(ct->mark);
102102
return;
103103
#endif
104104
#ifdef CONFIG_NF_CONNTRACK_SECMARK
@@ -297,8 +297,8 @@ static void nft_ct_set_eval(const struct nft_expr *expr,
297297
switch (priv->key) {
298298
#ifdef CONFIG_NF_CONNTRACK_MARK
299299
case NFT_CT_MARK:
300-
if (ct->mark != value) {
301-
ct->mark = value;
300+
if (READ_ONCE(ct->mark) != value) {
301+
WRITE_ONCE(ct->mark, value);
302302
nf_conntrack_event_cache(IPCT_MARK, ct);
303303
}
304304
break;

net/netfilter/xt_connmark.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,23 @@ connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info)
3030
u_int32_t new_targetmark;
3131
struct nf_conn *ct;
3232
u_int32_t newmark;
33+
u_int32_t oldmark;
3334

3435
ct = nf_ct_get(skb, &ctinfo);
3536
if (ct == NULL)
3637
return XT_CONTINUE;
3738

3839
switch (info->mode) {
3940
case XT_CONNMARK_SET:
40-
newmark = (ct->mark & ~info->ctmask) ^ info->ctmark;
41+
oldmark = READ_ONCE(ct->mark);
42+
newmark = (oldmark & ~info->ctmask) ^ info->ctmark;
4143
if (info->shift_dir == D_SHIFT_RIGHT)
4244
newmark >>= info->shift_bits;
4345
else
4446
newmark <<= info->shift_bits;
4547

46-
if (ct->mark != newmark) {
47-
ct->mark = newmark;
48+
if (READ_ONCE(ct->mark) != newmark) {
49+
WRITE_ONCE(ct->mark, newmark);
4850
nf_conntrack_event_cache(IPCT_MARK, ct);
4951
}
5052
break;
@@ -55,15 +57,15 @@ connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info)
5557
else
5658
new_targetmark <<= info->shift_bits;
5759

58-
newmark = (ct->mark & ~info->ctmask) ^
60+
newmark = (READ_ONCE(ct->mark) & ~info->ctmask) ^
5961
new_targetmark;
60-
if (ct->mark != newmark) {
61-
ct->mark = newmark;
62+
if (READ_ONCE(ct->mark) != newmark) {
63+
WRITE_ONCE(ct->mark, newmark);
6264
nf_conntrack_event_cache(IPCT_MARK, ct);
6365
}
6466
break;
6567
case XT_CONNMARK_RESTORE:
66-
new_targetmark = (ct->mark & info->ctmask);
68+
new_targetmark = (READ_ONCE(ct->mark) & info->ctmask);
6769
if (info->shift_dir == D_SHIFT_RIGHT)
6870
new_targetmark >>= info->shift_bits;
6971
else
@@ -126,7 +128,7 @@ connmark_mt(const struct sk_buff *skb, struct xt_action_param *par)
126128
if (ct == NULL)
127129
return false;
128130

129-
return ((ct->mark & info->mask) == info->mark) ^ info->invert;
131+
return ((READ_ONCE(ct->mark) & info->mask) == info->mark) ^ info->invert;
130132
}
131133

132134
static int connmark_mt_check(const struct xt_mtchk_param *par)

net/openvswitch/conntrack.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ static u8 ovs_ct_get_state(enum ip_conntrack_info ctinfo)
152152
static u32 ovs_ct_get_mark(const struct nf_conn *ct)
153153
{
154154
#if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)
155-
return ct ? ct->mark : 0;
155+
return ct ? READ_ONCE(ct->mark) : 0;
156156
#else
157157
return 0;
158158
#endif
@@ -340,9 +340,9 @@ static int ovs_ct_set_mark(struct nf_conn *ct, struct sw_flow_key *key,
340340
#if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)
341341
u32 new_mark;
342342

343-
new_mark = ct_mark | (ct->mark & ~(mask));
344-
if (ct->mark != new_mark) {
345-
ct->mark = new_mark;
343+
new_mark = ct_mark | (READ_ONCE(ct->mark) & ~(mask));
344+
if (READ_ONCE(ct->mark) != new_mark) {
345+
WRITE_ONCE(ct->mark, new_mark);
346346
if (nf_ct_is_confirmed(ct))
347347
nf_conntrack_event_cache(IPCT_MARK, ct);
348348
key->ct.mark = new_mark;

net/sched/act_connmark.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ static int tcf_connmark_act(struct sk_buff *skb, const struct tc_action *a,
6161

6262
c = nf_ct_get(skb, &ctinfo);
6363
if (c) {
64-
skb->mark = c->mark;
64+
skb->mark = READ_ONCE(c->mark);
6565
/* using overlimits stats to count how many packets marked */
6666
ca->tcf_qstats.overlimits++;
6767
goto out;
@@ -81,7 +81,7 @@ static int tcf_connmark_act(struct sk_buff *skb, const struct tc_action *a,
8181
c = nf_ct_tuplehash_to_ctrack(thash);
8282
/* using overlimits stats to count how many packets marked */
8383
ca->tcf_qstats.overlimits++;
84-
skb->mark = c->mark;
84+
skb->mark = READ_ONCE(c->mark);
8585
nf_ct_put(c);
8686

8787
out:

net/sched/act_ct.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ static void tcf_ct_flow_table_add_action_meta(struct nf_conn *ct,
178178
entry = tcf_ct_flow_table_flow_action_get_next(action);
179179
entry->id = FLOW_ACTION_CT_METADATA;
180180
#if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)
181-
entry->ct_metadata.mark = ct->mark;
181+
entry->ct_metadata.mark = READ_ONCE(ct->mark);
182182
#endif
183183
ctinfo = dir == IP_CT_DIR_ORIGINAL ? IP_CT_ESTABLISHED :
184184
IP_CT_ESTABLISHED_REPLY;
@@ -936,9 +936,9 @@ static void tcf_ct_act_set_mark(struct nf_conn *ct, u32 mark, u32 mask)
936936
if (!mask)
937937
return;
938938

939-
new_mark = mark | (ct->mark & ~(mask));
940-
if (ct->mark != new_mark) {
941-
ct->mark = new_mark;
939+
new_mark = mark | (READ_ONCE(ct->mark) & ~(mask));
940+
if (READ_ONCE(ct->mark) != new_mark) {
941+
WRITE_ONCE(ct->mark, new_mark);
942942
if (nf_ct_is_confirmed(ct))
943943
nf_conntrack_event_cache(IPCT_MARK, ct);
944944
}

net/sched/act_ctinfo.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ static void tcf_ctinfo_dscp_set(struct nf_conn *ct, struct tcf_ctinfo *ca,
3232
{
3333
u8 dscp, newdscp;
3434

35-
newdscp = (((ct->mark & cp->dscpmask) >> cp->dscpmaskshift) << 2) &
35+
newdscp = (((READ_ONCE(ct->mark) & cp->dscpmask) >> cp->dscpmaskshift) << 2) &
3636
~INET_ECN_MASK;
3737

3838
switch (proto) {
@@ -72,7 +72,7 @@ static void tcf_ctinfo_cpmark_set(struct nf_conn *ct, struct tcf_ctinfo *ca,
7272
struct sk_buff *skb)
7373
{
7474
ca->stats_cpmark_set++;
75-
skb->mark = ct->mark & cp->cpmarkmask;
75+
skb->mark = READ_ONCE(ct->mark) & cp->cpmarkmask;
7676
}
7777

7878
static int tcf_ctinfo_act(struct sk_buff *skb, const struct tc_action *a,
@@ -130,7 +130,7 @@ static int tcf_ctinfo_act(struct sk_buff *skb, const struct tc_action *a,
130130
}
131131

132132
if (cp->mode & CTINFO_MODE_DSCP)
133-
if (!cp->dscpstatemask || (ct->mark & cp->dscpstatemask))
133+
if (!cp->dscpstatemask || (READ_ONCE(ct->mark) & cp->dscpstatemask))
134134
tcf_ctinfo_dscp_set(ct, ca, cp, skb, wlen, proto);
135135

136136
if (cp->mode & CTINFO_MODE_CPMARK)

0 commit comments

Comments
 (0)