* [PATCH nf] netfilter: ctnetlink: make it safer when updating ct->status
@ 2017-04-12 15:56 Liping Zhang
2017-04-13 2:42 ` Gao Feng
2017-04-13 2:43 ` Gao Feng
0 siblings, 2 replies; 6+ messages in thread
From: Liping Zhang @ 2017-04-12 15:56 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel, cernekee, Liping Zhang
From: Liping Zhang <zlpnobody@gmail.com>
User can update the ct->status via nfnetlink, but using a non-atomic
operation "ct->status |= status;". This is unsafe, and may clear
IPS_DYING_BIT bit set by another CPU unexpectedly. For example:
CPU0 CPU1
ctnetlink_change_status __nf_conntrack_find_get
old = ct->status nf_ct_gc_expired
- nf_ct_kill
- test_and_set_bit(IPS_DYING_BIT
- -
ct->status = old | status;<-- oops, _DYING_ is cleared!
So using a series of atomic bit operation to solve the above issue.
Also note, user shouldn't set IPS_TEMPLATE, IPS_SEQ_ADJUST directly.
If we set the IPS_TEMPLATE_BIT, ct will be freed by nf_ct_tmpl_free,
but actually it is alloced by nf_conntrack_alloc.
If we set the IPS_SEQ_ADJUST_BIT, this may cause the NULL pointer
deference, as the nfct_seqadj(ct) maybe NULL.
So make these two bits be unchangable too.
Last, add some comments to describe the logic change due to the
commit a963d710f367 ("netfilter: ctnetlink: Fix regression in CTA_STATUS
processing"), which makes me feel a little confusing.
Signed-off-by: Liping Zhang <zlpnobody@gmail.com>
---
include/uapi/linux/netfilter/nf_conntrack_common.h | 13 +++++---
net/netfilter/nf_conntrack_netlink.c | 35 ++++++++++++++++------
2 files changed, 35 insertions(+), 13 deletions(-)
diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/uapi/linux/netfilter/nf_conntrack_common.h
index 6a8e33d..38fc383 100644
--- a/include/uapi/linux/netfilter/nf_conntrack_common.h
+++ b/include/uapi/linux/netfilter/nf_conntrack_common.h
@@ -82,10 +82,6 @@ enum ip_conntrack_status {
IPS_DYING_BIT = 9,
IPS_DYING = (1 << IPS_DYING_BIT),
- /* Bits that cannot be altered from userland. */
- IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK |
- IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING),
-
/* Connection has fixed timeout. */
IPS_FIXED_TIMEOUT_BIT = 10,
IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT),
@@ -101,6 +97,15 @@ enum ip_conntrack_status {
/* Conntrack got a helper explicitly attached via CT target. */
IPS_HELPER_BIT = 13,
IPS_HELPER = (1 << IPS_HELPER_BIT),
+
+ /* Be careful here, modifying these bits can make things messy,
+ * so don't let users modify them directly.
+ */
+ IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK |
+ IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING |
+ IPS_SEQ_ADJUST | IPS_TEMPLATE),
+
+ __IPS_MAX_BIT = 14,
};
/* Connection tracking event types */
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 908d858..68efe1a 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1419,6 +1419,26 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
}
#endif
+static void
+__ctnetlink_change_status(struct nf_conn *ct, unsigned long on,
+ unsigned long off)
+{
+ unsigned long mask;
+ unsigned int bit;
+
+ for (bit = 0; bit < __IPS_MAX_BIT; bit++) {
+ mask = 1 << bit;
+ /* Ignore these unchangable bits */
+ if (mask & IPS_UNCHANGEABLE_MASK)
+ continue;
+
+ if (on & mask)
+ set_bit(bit, &ct->status);
+ else if (off & mask)
+ clear_bit(bit, &ct->status);
+ }
+}
+
static int
ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[])
{
@@ -1438,10 +1458,7 @@ ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[])
/* ASSURED bit can only be set */
return -EBUSY;
- /* Be careful here, modifying NAT bits can screw up things,
- * so don't let users modify them directly if they don't pass
- * nf_nat_range. */
- ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
+ __ctnetlink_change_status(ct, status, 0);
return 0;
}
@@ -1632,7 +1649,7 @@ ctnetlink_change_seq_adj(struct nf_conn *ct,
if (ret < 0)
return ret;
- ct->status |= IPS_SEQ_ADJUST;
+ set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
}
if (cda[CTA_SEQ_ADJ_REPLY]) {
@@ -1641,7 +1658,7 @@ ctnetlink_change_seq_adj(struct nf_conn *ct,
if (ret < 0)
return ret;
- ct->status |= IPS_SEQ_ADJUST;
+ set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
}
return 0;
@@ -2295,10 +2312,10 @@ ctnetlink_update_status(struct nf_conn *ct, const struct nlattr * const cda[])
/* This check is less strict than ctnetlink_change_status()
* because callers often flip IPS_EXPECTED bits when sending
* an NFQA_CT attribute to the kernel. So ignore the
- * unchangeable bits but do not error out.
+ * unchangeable bits but do not error out. Also user programs
+ * are allowed to clear the bits that they are allowed to change.
*/
- ct->status = (status & ~IPS_UNCHANGEABLE_MASK) |
- (ct->status & IPS_UNCHANGEABLE_MASK);
+ __ctnetlink_change_status(ct, status, ~status);
return 0;
}
--
2.5.5
^ permalink raw reply related [flat|nested] 6+ messages in thread
* RE: [PATCH nf] netfilter: ctnetlink: make it safer when updating ct->status
2017-04-12 15:56 [PATCH nf] netfilter: ctnetlink: make it safer when updating ct->status Liping Zhang
@ 2017-04-13 2:42 ` Gao Feng
2017-04-13 3:15 ` Liping Zhang
2017-04-13 2:43 ` Gao Feng
1 sibling, 1 reply; 6+ messages in thread
From: Gao Feng @ 2017-04-13 2:42 UTC (permalink / raw)
To: 'Liping Zhang', pablo
Cc: netfilter-devel, cernekee, 'Liping Zhang'
Hi Liping,
> -----Original Message-----
> From: netfilter-devel-owner@vger.kernel.org
> [mailto:netfilter-devel-owner@vger.kernel.org] On Behalf Of Liping Zhang
> Sent: Wednesday, April 12, 2017 11:57 PM
> To: pablo@netfilter.org
> Cc: netfilter-devel@vger.kernel.org; cernekee@chromium.org; Liping Zhang
> <zlpnobody@gmail.com>
> Subject: [PATCH nf] netfilter: ctnetlink: make it safer when updating
ct->status
>
> From: Liping Zhang <zlpnobody@gmail.com>
>
> User can update the ct->status via nfnetlink, but using a non-atomic
operation
> "ct->status |= status;". This is unsafe, and may clear IPS_DYING_BIT bit
set by
> another CPU unexpectedly. For example:
> CPU0 CPU1
> ctnetlink_change_status __nf_conntrack_find_get
> old = ct->status nf_ct_gc_expired
> - nf_ct_kill
> - test_and_set_bit(IPS_DYING_BIT
> - -
> ct->status = old | status;<-- oops, _DYING_ is cleared!
>
> So using a series of atomic bit operation to solve the above issue.
>
> Also note, user shouldn't set IPS_TEMPLATE, IPS_SEQ_ADJUST directly.
>
> If we set the IPS_TEMPLATE_BIT, ct will be freed by nf_ct_tmpl_free, but
> actually it is alloced by nf_conntrack_alloc.
>
> If we set the IPS_SEQ_ADJUST_BIT, this may cause the NULL pointer
deference,
> as the nfct_seqadj(ct) maybe NULL.
>
> So make these two bits be unchangable too.
>
> Last, add some comments to describe the logic change due to the commit
> a963d710f367 ("netfilter: ctnetlink: Fix regression in CTA_STATUS
processing"),
> which makes me feel a little confusing.
>
> Signed-off-by: Liping Zhang <zlpnobody@gmail.com>
> ---
> include/uapi/linux/netfilter/nf_conntrack_common.h | 13 +++++---
> net/netfilter/nf_conntrack_netlink.c | 35
> ++++++++++++++++------
> 2 files changed, 35 insertions(+), 13 deletions(-)
>
> diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h
> b/include/uapi/linux/netfilter/nf_conntrack_common.h
> index 6a8e33d..38fc383 100644
> --- a/include/uapi/linux/netfilter/nf_conntrack_common.h
> +++ b/include/uapi/linux/netfilter/nf_conntrack_common.h
> @@ -82,10 +82,6 @@ enum ip_conntrack_status {
> IPS_DYING_BIT = 9,
> IPS_DYING = (1 << IPS_DYING_BIT),
>
> - /* Bits that cannot be altered from userland. */
> - IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK |
> - IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING),
> -
> /* Connection has fixed timeout. */
> IPS_FIXED_TIMEOUT_BIT = 10,
> IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT), @@ -101,6
> +97,15 @@ enum ip_conntrack_status {
> /* Conntrack got a helper explicitly attached via CT target. */
> IPS_HELPER_BIT = 13,
> IPS_HELPER = (1 << IPS_HELPER_BIT),
> +
> + /* Be careful here, modifying these bits can make things messy,
> + * so don't let users modify them directly.
> + */
> + IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK |
> + IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING |
> + IPS_SEQ_ADJUST | IPS_TEMPLATE),
> +
> + __IPS_MAX_BIT = 14,
> };
>
> /* Connection tracking event types */
> diff --git a/net/netfilter/nf_conntrack_netlink.c
> b/net/netfilter/nf_conntrack_netlink.c
> index 908d858..68efe1a 100644
> --- a/net/netfilter/nf_conntrack_netlink.c
> +++ b/net/netfilter/nf_conntrack_netlink.c
> @@ -1419,6 +1419,26 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct, }
> #endif
>
> +static void
> +__ctnetlink_change_status(struct nf_conn *ct, unsigned long on,
> + unsigned long off)
> +{
> + unsigned long mask;
> + unsigned int bit;
> +
> + for (bit = 0; bit < __IPS_MAX_BIT; bit++) {
> + mask = 1 << bit;
> + /* Ignore these unchangable bits */
> + if (mask & IPS_UNCHANGEABLE_MASK)
> + continue;
How about clear the bits of on and off with IPS_UNCHANGEABLE_MASK before
loop.
Like "on &= ~ IPS_UNCHANGEABLE_MASK";
Then the "if (mask & IPS_UNCHANGEABLE_MASK)" could be removed.
BTW, when some bits are set both of on and off, the "on" would be effective,
but "off" not.
So I think we could use BUILD_BUG_ON to avoid it during building.
BUILD_BUG_ON(on&mask);
Best Regards
Feng
> +
> + if (on & mask)
> + set_bit(bit, &ct->status);
> + else if (off & mask)
> + clear_bit(bit, &ct->status);
> + }
> +}
> +
> static int
> ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const
cda[])
> { @@ -1438,10 +1458,7 @@ ctnetlink_change_status(struct nf_conn *ct, const
> struct nlattr * const cda[])
> /* ASSURED bit can only be set */
> return -EBUSY;
>
> - /* Be careful here, modifying NAT bits can screw up things,
> - * so don't let users modify them directly if they don't pass
> - * nf_nat_range. */
> - ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
> + __ctnetlink_change_status(ct, status, 0);
> return 0;
> }
>
> @@ -1632,7 +1649,7 @@ ctnetlink_change_seq_adj(struct nf_conn *ct,
> if (ret < 0)
> return ret;
>
> - ct->status |= IPS_SEQ_ADJUST;
> + set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
> }
>
> if (cda[CTA_SEQ_ADJ_REPLY]) {
> @@ -1641,7 +1658,7 @@ ctnetlink_change_seq_adj(struct nf_conn *ct,
> if (ret < 0)
> return ret;
>
> - ct->status |= IPS_SEQ_ADJUST;
> + set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
> }
>
> return 0;
> @@ -2295,10 +2312,10 @@ ctnetlink_update_status(struct nf_conn *ct, const
> struct nlattr * const cda[])
> /* This check is less strict than ctnetlink_change_status()
> * because callers often flip IPS_EXPECTED bits when sending
> * an NFQA_CT attribute to the kernel. So ignore the
> - * unchangeable bits but do not error out.
> + * unchangeable bits but do not error out. Also user programs
> + * are allowed to clear the bits that they are allowed to change.
> */
> - ct->status = (status & ~IPS_UNCHANGEABLE_MASK) |
> - (ct->status & IPS_UNCHANGEABLE_MASK);
> + __ctnetlink_change_status(ct, status, ~status);
> return 0;
> }
>
> --
> 2.5.5
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe netfilter-devel"
in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH nf] netfilter: ctnetlink: make it safer when updating ct->status
2017-04-13 2:42 ` Gao Feng
@ 2017-04-13 3:15 ` Liping Zhang
2017-04-13 3:22 ` Gao Feng
0 siblings, 1 reply; 6+ messages in thread
From: Liping Zhang @ 2017-04-13 3:15 UTC (permalink / raw)
To: Gao Feng
Cc: Liping Zhang, Pablo Neira Ayuso, Netfilter Developer Mailing List,
cernekee
Hi Feng,
2017-04-13 10:42 GMT+08:00 Gao Feng <gfree.wind@foxmail.com>:
[...]
>> +static void
>> +__ctnetlink_change_status(struct nf_conn *ct, unsigned long on,
>> + unsigned long off)
>> +{
>> + unsigned long mask;
>> + unsigned int bit;
>> +
>> + for (bit = 0; bit < __IPS_MAX_BIT; bit++) {
>> + mask = 1 << bit;
>> + /* Ignore these unchangable bits */
>> + if (mask & IPS_UNCHANGEABLE_MASK)
>> + continue;
>
> How about clear the bits of on and off with IPS_UNCHANGEABLE_MASK before
> loop.
> Like "on &= ~ IPS_UNCHANGEABLE_MASK";
> Then the "if (mask & IPS_UNCHANGEABLE_MASK)" could be removed.
No, it's better to do this together, there are two invocations, it's not good to
copy these codes twice.
>
> BTW, when some bits are set both of on and off, the "on" would be effective,
> but "off" not.
This won't happen, see the invocation:
1. __ctnetlink_change_status(ct, status, 0);
2. __ctnetlink_change_status(ct, status, ~status);
> So I think we could use BUILD_BUG_ON to avoid it during building.
> BUILD_BUG_ON(on&mask);
Btw, this won't help, BUILD_BUG_ON is only effective on compile time,
but "on" and "off" will be modified at the running time.
^ permalink raw reply [flat|nested] 6+ messages in thread
* RE: [PATCH nf] netfilter: ctnetlink: make it safer when updating ct->status
2017-04-13 3:15 ` Liping Zhang
@ 2017-04-13 3:22 ` Gao Feng
2017-04-13 3:55 ` Liping Zhang
0 siblings, 1 reply; 6+ messages in thread
From: Gao Feng @ 2017-04-13 3:22 UTC (permalink / raw)
To: 'Liping Zhang'
Cc: 'Liping Zhang', 'Pablo Neira Ayuso',
'Netfilter Developer Mailing List', cernekee
Hi Liping,
> -----Original Message-----
> From: Liping Zhang [mailto:zlpnobody@gmail.com]
> Sent: Thursday, April 13, 2017 11:15 AM
> To: Gao Feng <gfree.wind@foxmail.com>
> Cc: Liping Zhang <zlpnobody@163.com>; Pablo Neira Ayuso
> <pablo@netfilter.org>; Netfilter Developer Mailing List
> <netfilter-devel@vger.kernel.org>; cernekee@chromium.org
> Subject: Re: [PATCH nf] netfilter: ctnetlink: make it safer when updating
> ct->status
>
> Hi Feng,
>
> 2017-04-13 10:42 GMT+08:00 Gao Feng <gfree.wind@foxmail.com>:
> [...]
> >> +static void
> >> +__ctnetlink_change_status(struct nf_conn *ct, unsigned long on,
> >> + unsigned long off) {
> >> + unsigned long mask;
> >> + unsigned int bit;
> >> +
> >> + for (bit = 0; bit < __IPS_MAX_BIT; bit++) {
> >> + mask = 1 << bit;
> >> + /* Ignore these unchangable bits */
> >> + if (mask & IPS_UNCHANGEABLE_MASK)
> >> + continue;
> >
> > How about clear the bits of on and off with IPS_UNCHANGEABLE_MASK
> > before loop.
> > Like "on &= ~ IPS_UNCHANGEABLE_MASK";
> > Then the "if (mask & IPS_UNCHANGEABLE_MASK)" could be removed.
>
> No, it's better to do this together, there are two invocations, it's not good to
> copy these codes twice.
You mean " on &= ~ IPS_UNCHANGEABLE_MASK " and " off &= ~ IPS_UNCHANGEABLE_MASK " seems duplicated?
>
> >
> > BTW, when some bits are set both of on and off, the "on" would be
> > effective, but "off" not.
>
> This won't happen, see the invocation:
> 1. __ctnetlink_change_status(ct, status, 0); 2. __ctnetlink_change_status(ct,
> status, ~status);
>
> > So I think we could use BUILD_BUG_ON to avoid it during building.
> > BUILD_BUG_ON(on&mask);
>
> Btw, this won't help, BUILD_BUG_ON is only effective on compile time, but
> "on" and "off" will be modified at the running time.
You are right.
This new function would be used frequently at running time.
Regards
Feng
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH nf] netfilter: ctnetlink: make it safer when updating ct->status
2017-04-13 3:22 ` Gao Feng
@ 2017-04-13 3:55 ` Liping Zhang
0 siblings, 0 replies; 6+ messages in thread
From: Liping Zhang @ 2017-04-13 3:55 UTC (permalink / raw)
To: Gao Feng
Cc: Liping Zhang, Pablo Neira Ayuso, Netfilter Developer Mailing List,
cernekee
Hi Feng,
2017-04-13 11:22 GMT+08:00 Gao Feng <gfree.wind@foxmail.com>:
[...]
>> No, it's better to do this together, there are two invocations, it's not good to
>> copy these codes twice.
>
> You mean " on &= ~ IPS_UNCHANGEABLE_MASK " and " off &= ~ IPS_UNCHANGEABLE_MASK " seems duplicated?
I see. I misunderstood your initial meaning. So I will send V2 :)
^ permalink raw reply [flat|nested] 6+ messages in thread
* RE: [PATCH nf] netfilter: ctnetlink: make it safer when updating ct->status
2017-04-12 15:56 [PATCH nf] netfilter: ctnetlink: make it safer when updating ct->status Liping Zhang
2017-04-13 2:42 ` Gao Feng
@ 2017-04-13 2:43 ` Gao Feng
1 sibling, 0 replies; 6+ messages in thread
From: Gao Feng @ 2017-04-13 2:43 UTC (permalink / raw)
To: 'Liping Zhang', pablo
Cc: netfilter-devel, cernekee, 'Liping Zhang'
> -----Original Message-----
> From: Gao Feng [mailto:gfree.wind@foxmail.com]
> Sent: Thursday, April 13, 2017 10:42 AM
> To: 'Liping Zhang' <zlpnobody@163.com>; 'pablo@netfilter.org'
> <pablo@netfilter.org>
> Cc: 'netfilter-devel@vger.kernel.org' <netfilter-devel@vger.kernel.org>;
> 'cernekee@chromium.org' <cernekee@chromium.org>; 'Liping Zhang'
> <zlpnobody@gmail.com>
> Subject: RE: [PATCH nf] netfilter: ctnetlink: make it safer when updating
> ct->status
>
> Hi Liping,
>
> > -----Original Message-----
> > From: netfilter-devel-owner@vger.kernel.org
> > [mailto:netfilter-devel-owner@vger.kernel.org] On Behalf Of Liping
> > Zhang
> > Sent: Wednesday, April 12, 2017 11:57 PM
> > To: pablo@netfilter.org
> > Cc: netfilter-devel@vger.kernel.org; cernekee@chromium.org; Liping
> > Zhang <zlpnobody@gmail.com>
> > Subject: [PATCH nf] netfilter: ctnetlink: make it safer when updating
> > ct->status
> >
> > From: Liping Zhang <zlpnobody@gmail.com>
> >
> > User can update the ct->status via nfnetlink, but using a non-atomic
> > operation "ct->status |= status;". This is unsafe, and may clear
> > IPS_DYING_BIT bit set by another CPU unexpectedly. For example:
> > CPU0 CPU1
> > ctnetlink_change_status __nf_conntrack_find_get
> > old = ct->status nf_ct_gc_expired
> > - nf_ct_kill
> > - test_and_set_bit(IPS_DYING_BIT
> > - -
> > ct->status = old | status;<-- oops, _DYING_ is cleared!
> >
> > So using a series of atomic bit operation to solve the above issue.
> >
> > Also note, user shouldn't set IPS_TEMPLATE, IPS_SEQ_ADJUST directly.
> >
> > If we set the IPS_TEMPLATE_BIT, ct will be freed by nf_ct_tmpl_free,
> > but actually it is alloced by nf_conntrack_alloc.
> >
> > If we set the IPS_SEQ_ADJUST_BIT, this may cause the NULL pointer
> > deference, as the nfct_seqadj(ct) maybe NULL.
> >
> > So make these two bits be unchangable too.
> >
> > Last, add some comments to describe the logic change due to the commit
> > a963d710f367 ("netfilter: ctnetlink: Fix regression in CTA_STATUS
> > processing"), which makes me feel a little confusing.
> >
> > Signed-off-by: Liping Zhang <zlpnobody@gmail.com>
> > ---
> > include/uapi/linux/netfilter/nf_conntrack_common.h | 13 +++++---
> > net/netfilter/nf_conntrack_netlink.c | 35
> > ++++++++++++++++------
> > 2 files changed, 35 insertions(+), 13 deletions(-)
> >
> > diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h
> > b/include/uapi/linux/netfilter/nf_conntrack_common.h
> > index 6a8e33d..38fc383 100644
> > --- a/include/uapi/linux/netfilter/nf_conntrack_common.h
> > +++ b/include/uapi/linux/netfilter/nf_conntrack_common.h
> > @@ -82,10 +82,6 @@ enum ip_conntrack_status {
> > IPS_DYING_BIT = 9,
> > IPS_DYING = (1 << IPS_DYING_BIT),
> >
> > - /* Bits that cannot be altered from userland. */
> > - IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK |
> > - IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING),
> > -
> > /* Connection has fixed timeout. */
> > IPS_FIXED_TIMEOUT_BIT = 10,
> > IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT), @@ -101,6
> > +97,15 @@ enum ip_conntrack_status {
> > /* Conntrack got a helper explicitly attached via CT target. */
> > IPS_HELPER_BIT = 13,
> > IPS_HELPER = (1 << IPS_HELPER_BIT),
> > +
> > + /* Be careful here, modifying these bits can make things messy,
> > + * so don't let users modify them directly.
> > + */
> > + IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK |
> > + IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING |
> > + IPS_SEQ_ADJUST | IPS_TEMPLATE),
> > +
> > + __IPS_MAX_BIT = 14,
> > };
> >
> > /* Connection tracking event types */ diff --git
> > a/net/netfilter/nf_conntrack_netlink.c
> > b/net/netfilter/nf_conntrack_netlink.c
> > index 908d858..68efe1a 100644
> > --- a/net/netfilter/nf_conntrack_netlink.c
> > +++ b/net/netfilter/nf_conntrack_netlink.c
> > @@ -1419,6 +1419,26 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
> > } #endif
> >
> > +static void
> > +__ctnetlink_change_status(struct nf_conn *ct, unsigned long on,
> > + unsigned long off)
> > +{
> > + unsigned long mask;
> > + unsigned int bit;
> > +
> > + for (bit = 0; bit < __IPS_MAX_BIT; bit++) {
> > + mask = 1 << bit;
> > + /* Ignore these unchangable bits */
> > + if (mask & IPS_UNCHANGEABLE_MASK)
> > + continue;
>
> How about clear the bits of on and off with IPS_UNCHANGEABLE_MASK before
> loop.
> Like "on &= ~ IPS_UNCHANGEABLE_MASK";
> Then the "if (mask & IPS_UNCHANGEABLE_MASK)" could be removed.
>
> BTW, when some bits are set both of on and off, the "on" would be
effective,
> but "off" not.
> So I think we could use BUILD_BUG_ON to avoid it during building.
> BUILD_BUG_ON(on&mask);
It is typo. Should be BUILD_BUG_ON(on&off).
Regards
Feng
>
> Best Regards
> Feng
>
> > +
> > + if (on & mask)
> > + set_bit(bit, &ct->status);
> > + else if (off & mask)
> > + clear_bit(bit, &ct->status);
> > + }
> > +}
> > +
> > static int
> > ctnetlink_change_status(struct nf_conn *ct, const struct nlattr *
> > const cda[]) { @@ -1438,10 +1458,7 @@ ctnetlink_change_status(struct
> > nf_conn *ct, const struct nlattr * const cda[])
> > /* ASSURED bit can only be set */
> > return -EBUSY;
> >
> > - /* Be careful here, modifying NAT bits can screw up things,
> > - * so don't let users modify them directly if they don't pass
> > - * nf_nat_range. */
> > - ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK);
> > + __ctnetlink_change_status(ct, status, 0);
> > return 0;
> > }
> >
> > @@ -1632,7 +1649,7 @@ ctnetlink_change_seq_adj(struct nf_conn *ct,
> > if (ret < 0)
> > return ret;
> >
> > - ct->status |= IPS_SEQ_ADJUST;
> > + set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
> > }
> >
> > if (cda[CTA_SEQ_ADJ_REPLY]) {
> > @@ -1641,7 +1658,7 @@ ctnetlink_change_seq_adj(struct nf_conn *ct,
> > if (ret < 0)
> > return ret;
> >
> > - ct->status |= IPS_SEQ_ADJUST;
> > + set_bit(IPS_SEQ_ADJUST_BIT, &ct->status);
> > }
> >
> > return 0;
> > @@ -2295,10 +2312,10 @@ ctnetlink_update_status(struct nf_conn *ct,
> > const struct nlattr * const cda[])
> > /* This check is less strict than ctnetlink_change_status()
> > * because callers often flip IPS_EXPECTED bits when sending
> > * an NFQA_CT attribute to the kernel. So ignore the
> > - * unchangeable bits but do not error out.
> > + * unchangeable bits but do not error out. Also user programs
> > + * are allowed to clear the bits that they are allowed to change.
> > */
> > - ct->status = (status & ~IPS_UNCHANGEABLE_MASK) |
> > - (ct->status & IPS_UNCHANGEABLE_MASK);
> > + __ctnetlink_change_status(ct, status, ~status);
> > return 0;
> > }
> >
> > --
> > 2.5.5
> >
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe
> > netfilter-devel" in the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2017-04-13 3:55 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-04-12 15:56 [PATCH nf] netfilter: ctnetlink: make it safer when updating ct->status Liping Zhang
2017-04-13 2:42 ` Gao Feng
2017-04-13 3:15 ` Liping Zhang
2017-04-13 3:22 ` Gao Feng
2017-04-13 3:55 ` Liping Zhang
2017-04-13 2:43 ` Gao Feng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).