Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf
Browse files Browse the repository at this point in the history
Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter fixes for net:

1) Don't flag SCTP heartbeat as invalid for re-used connections,
   from Florian Westphal.

2) Bogus overlap report due to rbtree tree rotations, from Stefano Brivio.

3) Detect partial overlap with start end point match, also from Stefano.

4) Skip netlink dump of NFTA_SET_USERDATA is unset.

5) Incorrect nft_list_attributes enumeration definition.

6) Missing zeroing before memcpy to destination register, also
   from Florian.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Aug 24, 2020
2 parents 7ef1fc5 + 1e105e6 commit a26aea2
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 17 deletions.
2 changes: 2 additions & 0 deletions include/linux/netfilter/nf_conntrack_sctp.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ struct ip_ct_sctp {
enum sctp_conntrack state;

__be32 vtag[IP_CT_DIR_MAX];
u8 last_dir;
u8 flags;
};

#endif /* _NF_CONNTRACK_SCTP_H */
2 changes: 2 additions & 0 deletions include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ static inline u64 nft_reg_load64(const u32 *sreg)
static inline void nft_data_copy(u32 *dst, const struct nft_data *src,
unsigned int len)
{
if (len % NFT_REG32_SIZE)
dst[len / NFT_REG32_SIZE] = 0;
memcpy(dst, src, len);
}

Expand Down
2 changes: 1 addition & 1 deletion include/uapi/linux/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ enum nf_tables_msg_types {
* @NFTA_LIST_ELEM: list element (NLA_NESTED)
*/
enum nft_list_attributes {
NFTA_LIST_UNPEC,
NFTA_LIST_UNSPEC,
NFTA_LIST_ELEM,
__NFTA_LIST_MAX
};
Expand Down
39 changes: 35 additions & 4 deletions net/netfilter/nf_conntrack_proto_sctp.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ static const unsigned int sctp_timeouts[SCTP_CONNTRACK_MAX] = {
[SCTP_CONNTRACK_HEARTBEAT_ACKED] = 210 SECS,
};

#define SCTP_FLAG_HEARTBEAT_VTAG_FAILED 1

#define sNO SCTP_CONNTRACK_NONE
#define sCL SCTP_CONNTRACK_CLOSED
#define sCW SCTP_CONNTRACK_COOKIE_WAIT
Expand Down Expand Up @@ -369,6 +371,7 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
u_int32_t offset, count;
unsigned int *timeouts;
unsigned long map[256 / sizeof(unsigned long)] = { 0 };
bool ignore = false;

if (sctp_error(skb, dataoff, state))
return -NF_ACCEPT;
Expand Down Expand Up @@ -427,15 +430,39 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
/* Sec 8.5.1 (D) */
if (sh->vtag != ct->proto.sctp.vtag[dir])
goto out_unlock;
} else if (sch->type == SCTP_CID_HEARTBEAT ||
sch->type == SCTP_CID_HEARTBEAT_ACK) {
} else if (sch->type == SCTP_CID_HEARTBEAT) {
if (ct->proto.sctp.vtag[dir] == 0) {
pr_debug("Setting %d vtag %x for dir %d\n", sch->type, sh->vtag, dir);
ct->proto.sctp.vtag[dir] = sh->vtag;
} else if (sh->vtag != ct->proto.sctp.vtag[dir]) {
if (test_bit(SCTP_CID_DATA, map) || ignore)
goto out_unlock;

ct->proto.sctp.flags |= SCTP_FLAG_HEARTBEAT_VTAG_FAILED;
ct->proto.sctp.last_dir = dir;
ignore = true;
continue;
} else if (ct->proto.sctp.flags & SCTP_FLAG_HEARTBEAT_VTAG_FAILED) {
ct->proto.sctp.flags &= ~SCTP_FLAG_HEARTBEAT_VTAG_FAILED;
}
} else if (sch->type == SCTP_CID_HEARTBEAT_ACK) {
if (ct->proto.sctp.vtag[dir] == 0) {
pr_debug("Setting vtag %x for dir %d\n",
sh->vtag, dir);
ct->proto.sctp.vtag[dir] = sh->vtag;
} else if (sh->vtag != ct->proto.sctp.vtag[dir]) {
pr_debug("Verification tag check failed\n");
goto out_unlock;
if (test_bit(SCTP_CID_DATA, map) || ignore)
goto out_unlock;

if ((ct->proto.sctp.flags & SCTP_FLAG_HEARTBEAT_VTAG_FAILED) == 0 ||
ct->proto.sctp.last_dir == dir)
goto out_unlock;

ct->proto.sctp.flags &= ~SCTP_FLAG_HEARTBEAT_VTAG_FAILED;
ct->proto.sctp.vtag[dir] = sh->vtag;
ct->proto.sctp.vtag[!dir] = 0;
} else if (ct->proto.sctp.flags & SCTP_FLAG_HEARTBEAT_VTAG_FAILED) {
ct->proto.sctp.flags &= ~SCTP_FLAG_HEARTBEAT_VTAG_FAILED;
}
}

Expand Down Expand Up @@ -470,6 +497,10 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,
}
spin_unlock_bh(&ct->lock);

/* allow but do not refresh timeout */
if (ignore)
return NF_ACCEPT;

timeouts = nf_ct_timeout_lookup(ct);
if (!timeouts)
timeouts = nf_sctp_pernet(nf_ct_net(ct))->timeouts;
Expand Down
3 changes: 2 additions & 1 deletion net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -3770,7 +3770,8 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
goto nla_put_failure;
}

if (nla_put(skb, NFTA_SET_USERDATA, set->udlen, set->udata))
if (set->udata &&
nla_put(skb, NFTA_SET_USERDATA, set->udlen, set->udata))
goto nla_put_failure;

nest = nla_nest_start_noflag(skb, NFTA_SET_DESC);
Expand Down
4 changes: 3 additions & 1 deletion net/netfilter/nft_payload.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ void nft_payload_eval(const struct nft_expr *expr,
u32 *dest = &regs->data[priv->dreg];
int offset;

dest[priv->len / NFT_REG32_SIZE] = 0;
if (priv->len % NFT_REG32_SIZE)
dest[priv->len / NFT_REG32_SIZE] = 0;

switch (priv->base) {
case NFT_PAYLOAD_LL_HEADER:
if (!skb_mac_header_was_set(skb))
Expand Down
57 changes: 47 additions & 10 deletions net/netfilter/nft_set_rbtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,11 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
struct nft_rbtree_elem *new,
struct nft_set_ext **ext)
{
bool overlap = false, dup_end_left = false, dup_end_right = false;
struct nft_rbtree *priv = nft_set_priv(set);
u8 genmask = nft_genmask_next(net);
struct nft_rbtree_elem *rbe;
struct rb_node *parent, **p;
bool overlap = false;
int d;

/* Detect overlaps as we descend the tree. Set the flag in these cases:
Expand All @@ -238,24 +238,44 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
*
* b1. _ _ __>| !_ _ __| (insert end before existing start)
* b2. _ _ ___| !_ _ _>| (insert end after existing start)
* b3. _ _ ___! >|_ _ __| (insert start after existing end)
* b3. _ _ ___! >|_ _ __| (insert start after existing end, as a leaf)
* '--' no nodes falling in this range
* b4. >|_ _ ! (insert start before existing start)
*
* Case a3. resolves to b3.:
* - if the inserted start element is the leftmost, because the '0'
* element in the tree serves as end element
* - otherwise, if an existing end is found. Note that end elements are
* always inserted after corresponding start elements.
* - otherwise, if an existing end is found immediately to the left. If
* there are existing nodes in between, we need to further descend the
* tree before we can conclude the new start isn't causing an overlap
*
* or to b4., which, preceded by a3., means we already traversed one or
* more existing intervals entirely, from the right.
*
* For a new, rightmost pair of elements, we'll hit cases b3. and b2.,
* in that order.
*
* The flag is also cleared in two special cases:
*
* b4. |__ _ _!|<_ _ _ (insert start right before existing end)
* b5. |__ _ >|!__ _ _ (insert end right after existing start)
* b5. |__ _ _!|<_ _ _ (insert start right before existing end)
* b6. |__ _ >|!__ _ _ (insert end right after existing start)
*
* which always happen as last step and imply that no further
* overlapping is possible.
*
* Another special case comes from the fact that start elements matching
* an already existing start element are allowed: insertion is not
* performed but we return -EEXIST in that case, and the error will be
* cleared by the caller if NLM_F_EXCL is not present in the request.
* This way, request for insertion of an exact overlap isn't reported as
* error to userspace if not desired.
*
* However, if the existing start matches a pre-existing start, but the
* end element doesn't match the corresponding pre-existing end element,
* we need to report a partial overlap. This is a local condition that
* can be noticed without need for a tracking flag, by checking for a
* local duplicated end for a corresponding start, from left and right,
* separately.
*/

parent = NULL;
Expand All @@ -272,26 +292,41 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
if (nft_rbtree_interval_start(new)) {
if (nft_rbtree_interval_end(rbe) &&
nft_set_elem_active(&rbe->ext, genmask) &&
!nft_set_elem_expired(&rbe->ext))
!nft_set_elem_expired(&rbe->ext) && !*p)
overlap = false;
} else {
if (dup_end_left && !*p)
return -ENOTEMPTY;

overlap = nft_rbtree_interval_end(rbe) &&
nft_set_elem_active(&rbe->ext,
genmask) &&
!nft_set_elem_expired(&rbe->ext);

if (overlap) {
dup_end_right = true;
continue;
}
}
} else if (d > 0) {
p = &parent->rb_right;

if (nft_rbtree_interval_end(new)) {
if (dup_end_right && !*p)
return -ENOTEMPTY;

overlap = nft_rbtree_interval_end(rbe) &&
nft_set_elem_active(&rbe->ext,
genmask) &&
!nft_set_elem_expired(&rbe->ext);
} else if (nft_rbtree_interval_end(rbe) &&
nft_set_elem_active(&rbe->ext, genmask) &&

if (overlap) {
dup_end_left = true;
continue;
}
} else if (nft_set_elem_active(&rbe->ext, genmask) &&
!nft_set_elem_expired(&rbe->ext)) {
overlap = true;
overlap = nft_rbtree_interval_end(rbe);
}
} else {
if (nft_rbtree_interval_end(rbe) &&
Expand All @@ -316,6 +351,8 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
p = &parent->rb_left;
}
}

dup_end_left = dup_end_right = false;
}

if (overlap)
Expand Down

0 comments on commit a26aea2

Please sign in to comment.