Commit e4595576 authored by David S. Miller's avatar David S. Miller
Browse files


Pablo Neira Ayuso says:

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

The following patchset contains Netfilter fixes for net:

1) refcount_inc_not_zero() is not semantically equivalent to
   atomic_int_not_zero(), from Florian Westphal. My understanding was
   that refcount_*() API provides a wrapper to easier debugging of
   reference count leaks, however, there are semantic differences
   between these two APIs, where refcount_inc_not_zero() needs a barrier.
   Reason for this subtle difference to me is unknown.

2) packet logging is not correct for ARP and IP packets, from the
   ARP family and netdev/egress respectively. Use skb_network_offset()
   to reach the headers accordingly.

3) set element extension length have been growing over time, replace
   a BUG_ON by EINVAL which might be triggerable from userspace.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3c079a22 c39ba4de
Loading
Loading
Loading
Loading
+9 −5
Original line number Diff line number Diff line
@@ -657,18 +657,22 @@ static inline void nft_set_ext_prepare(struct nft_set_ext_tmpl *tmpl)
	tmpl->len = sizeof(struct nft_set_ext);
}

static inline void nft_set_ext_add_length(struct nft_set_ext_tmpl *tmpl, u8 id,
static inline int nft_set_ext_add_length(struct nft_set_ext_tmpl *tmpl, u8 id,
					 unsigned int len)
{
	tmpl->len	 = ALIGN(tmpl->len, nft_set_ext_types[id].align);
	BUG_ON(tmpl->len > U8_MAX);
	if (tmpl->len > U8_MAX)
		return -EINVAL;

	tmpl->offset[id] = tmpl->len;
	tmpl->len	+= nft_set_ext_types[id].len + len;

	return 0;
}

static inline void nft_set_ext_add(struct nft_set_ext_tmpl *tmpl, u8 id)
static inline int nft_set_ext_add(struct nft_set_ext_tmpl *tmpl, u8 id)
{
	nft_set_ext_add_length(tmpl, id, 0);
	return nft_set_ext_add_length(tmpl, id, 0);
}

static inline void nft_set_ext_init(struct nft_set_ext *ext,
+22 −0
Original line number Diff line number Diff line
@@ -729,6 +729,9 @@ static void nf_ct_gc_expired(struct nf_conn *ct)
	if (!refcount_inc_not_zero(&ct->ct_general.use))
		return;

	/* load ->status after refcount increase */
	smp_acquire__after_ctrl_dep();

	if (nf_ct_should_gc(ct))
		nf_ct_kill(ct);

@@ -795,6 +798,9 @@ __nf_conntrack_find_get(struct net *net, const struct nf_conntrack_zone *zone,
		 */
		ct = nf_ct_tuplehash_to_ctrack(h);
		if (likely(refcount_inc_not_zero(&ct->ct_general.use))) {
			/* re-check key after refcount */
			smp_acquire__after_ctrl_dep();

			if (likely(nf_ct_key_equal(h, tuple, zone, net)))
				goto found;

@@ -1387,6 +1393,9 @@ static unsigned int early_drop_list(struct net *net,
		if (!refcount_inc_not_zero(&tmp->ct_general.use))
			continue;

		/* load ->ct_net and ->status after refcount increase */
		smp_acquire__after_ctrl_dep();

		/* kill only if still in same netns -- might have moved due to
		 * SLAB_TYPESAFE_BY_RCU rules.
		 *
@@ -1536,6 +1545,9 @@ static void gc_worker(struct work_struct *work)
			if (!refcount_inc_not_zero(&tmp->ct_general.use))
				continue;

			/* load ->status after refcount increase */
			smp_acquire__after_ctrl_dep();

			if (gc_worker_skip_ct(tmp)) {
				nf_ct_put(tmp);
				continue;
@@ -1775,6 +1787,16 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
	if (!exp)
		__nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC);

	/* Other CPU might have obtained a pointer to this object before it was
	 * released.  Because refcount is 0, refcount_inc_not_zero() will fail.
	 *
	 * After refcount_set(1) it will succeed; ensure that zeroing of
	 * ct->status and the correct ct->net pointer are visible; else other
	 * core might observe CONFIRMED bit which means the entry is valid and
	 * in the hash table, but its not (anymore).
	 */
	smp_wmb();

	/* Now it is going to be associated with an sk_buff, set refcount to 1. */
	refcount_set(&ct->ct_general.use, 1);

+1 −0
Original line number Diff line number Diff line
@@ -1203,6 +1203,7 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
					   hnnode) {
			ct = nf_ct_tuplehash_to_ctrack(h);
			if (nf_ct_is_expired(ct)) {
				/* need to defer nf_ct_kill() until lock is released */
				if (i < ARRAY_SIZE(nf_ct_evict) &&
				    refcount_inc_not_zero(&ct->ct_general.use))
					nf_ct_evict[i++] = ct;
+3 −0
Original line number Diff line number Diff line
@@ -306,6 +306,9 @@ static int ct_seq_show(struct seq_file *s, void *v)
	if (unlikely(!refcount_inc_not_zero(&ct->ct_general.use)))
		return 0;

	/* load ->status after refcount increase */
	smp_acquire__after_ctrl_dep();

	if (nf_ct_should_gc(ct)) {
		nf_ct_kill(ct);
		goto release;
+4 −4
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ dump_arp_packet(struct nf_log_buf *m,
	unsigned int logflags;
	struct arphdr _arph;

	ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
	ah = skb_header_pointer(skb, nhoff, sizeof(_arph), &_arph);
	if (!ah) {
		nf_log_buf_add(m, "TRUNCATED");
		return;
@@ -96,7 +96,7 @@ dump_arp_packet(struct nf_log_buf *m,
	    ah->ar_pln != sizeof(__be32))
		return;

	ap = skb_header_pointer(skb, sizeof(_arph), sizeof(_arpp), &_arpp);
	ap = skb_header_pointer(skb, nhoff + sizeof(_arph), sizeof(_arpp), &_arpp);
	if (!ap) {
		nf_log_buf_add(m, " INCOMPLETE [%zu bytes]",
			       skb->len - sizeof(_arph));
@@ -149,7 +149,7 @@ static void nf_log_arp_packet(struct net *net, u_int8_t pf,

	nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, loginfo,
				  prefix);
	dump_arp_packet(m, loginfo, skb, 0);
	dump_arp_packet(m, loginfo, skb, skb_network_offset(skb));

	nf_log_buf_close(m);
}
@@ -850,7 +850,7 @@ static void nf_log_ip_packet(struct net *net, u_int8_t pf,
	if (in)
		dump_mac_header(m, loginfo, skb);

	dump_ipv4_packet(net, m, loginfo, skb, 0);
	dump_ipv4_packet(net, m, loginfo, skb, skb_network_offset(skb));

	nf_log_buf_close(m);
}
Loading