Commit 1155a228 authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next

Pablo Neira Ayuso says:

====================
Netfilter/IPVS updates for net-next

The following patchset contains Netfilter updates for net-next:

1) Add safeguard to check for NULL tupe in objects updates via
   NFT_MSG_NEWOBJ, this should not ever happen. From Alok Tiwari.

2) Incorrect pointer check in the new destroy rule command,
   from Yang Yingliang.

3) Incorrect status bitcheck in nf_conntrack_udp_packet(),
   from Florian Westphal.

4) Simplify seq_print_acct(), from Ilia Gavrilov.

5) Use 2-arg optimal variant of kfree_rcu() in IPVS,
   from Julian Anastasov.

6) TCP connection enters CLOSE state in conntrack for locally
   originated TCP reset packet from the reject target,
   from Florian Westphal.

The fixes #2 and #3 in this series address issues from the previous pull
nf-next request in this net-next cycle.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 129ff4de 2954fe60
...@@ -437,11 +437,13 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family) ...@@ -437,11 +437,13 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
#include <linux/netfilter/nf_conntrack_zones_common.h> #include <linux/netfilter/nf_conntrack_zones_common.h>
void nf_ct_attach(struct sk_buff *, const struct sk_buff *); void nf_ct_attach(struct sk_buff *, const struct sk_buff *);
void nf_ct_set_closing(struct nf_conntrack *nfct);
struct nf_conntrack_tuple; struct nf_conntrack_tuple;
bool nf_ct_get_tuple_skb(struct nf_conntrack_tuple *dst_tuple, bool nf_ct_get_tuple_skb(struct nf_conntrack_tuple *dst_tuple,
const struct sk_buff *skb); const struct sk_buff *skb);
#else #else
static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
static inline void nf_ct_set_closing(struct nf_conntrack *nfct) {}
struct nf_conntrack_tuple; struct nf_conntrack_tuple;
static inline bool nf_ct_get_tuple_skb(struct nf_conntrack_tuple *dst_tuple, static inline bool nf_ct_get_tuple_skb(struct nf_conntrack_tuple *dst_tuple,
const struct sk_buff *skb) const struct sk_buff *skb)
...@@ -459,6 +461,7 @@ struct nf_ct_hook { ...@@ -459,6 +461,7 @@ struct nf_ct_hook {
bool (*get_tuple_skb)(struct nf_conntrack_tuple *, bool (*get_tuple_skb)(struct nf_conntrack_tuple *,
const struct sk_buff *); const struct sk_buff *);
void (*attach)(struct sk_buff *nskb, const struct sk_buff *skb); void (*attach)(struct sk_buff *nskb, const struct sk_buff *skb);
void (*set_closing)(struct nf_conntrack *nfct);
}; };
extern const struct nf_ct_hook __rcu *nf_ct_hook; extern const struct nf_ct_hook __rcu *nf_ct_hook;
......
...@@ -461,6 +461,7 @@ void ip_vs_stats_free(struct ip_vs_stats *stats); ...@@ -461,6 +461,7 @@ void ip_vs_stats_free(struct ip_vs_stats *stats);
/* Multiple chains processed in same tick */ /* Multiple chains processed in same tick */
struct ip_vs_est_tick_data { struct ip_vs_est_tick_data {
struct rcu_head rcu_head;
struct hlist_head chains[IPVS_EST_TICK_CHAINS]; struct hlist_head chains[IPVS_EST_TICK_CHAINS];
DECLARE_BITMAP(present, IPVS_EST_TICK_CHAINS); DECLARE_BITMAP(present, IPVS_EST_TICK_CHAINS);
DECLARE_BITMAP(full, IPVS_EST_TICK_CHAINS); DECLARE_BITMAP(full, IPVS_EST_TICK_CHAINS);
......
...@@ -125,6 +125,12 @@ struct nf_conn { ...@@ -125,6 +125,12 @@ struct nf_conn {
union nf_conntrack_proto proto; union nf_conntrack_proto proto;
}; };
static inline struct nf_conn *
nf_ct_to_nf_conn(const struct nf_conntrack *nfct)
{
return container_of(nfct, struct nf_conn, ct_general);
}
static inline struct nf_conn * static inline struct nf_conn *
nf_ct_tuplehash_to_ctrack(const struct nf_conntrack_tuple_hash *hash) nf_ct_tuplehash_to_ctrack(const struct nf_conntrack_tuple_hash *hash)
{ {
...@@ -175,6 +181,8 @@ nf_ct_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo) ...@@ -175,6 +181,8 @@ nf_ct_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo)
void nf_ct_destroy(struct nf_conntrack *nfct); void nf_ct_destroy(struct nf_conntrack *nfct);
void nf_conntrack_tcp_set_closing(struct nf_conn *ct);
/* decrement reference count on a conntrack */ /* decrement reference count on a conntrack */
static inline void nf_ct_put(struct nf_conn *ct) static inline void nf_ct_put(struct nf_conn *ct)
{ {
......
...@@ -280,6 +280,7 @@ void nf_send_reset(struct net *net, struct sock *sk, struct sk_buff *oldskb, ...@@ -280,6 +280,7 @@ void nf_send_reset(struct net *net, struct sock *sk, struct sk_buff *oldskb,
goto free_nskb; goto free_nskb;
nf_ct_attach(nskb, oldskb); nf_ct_attach(nskb, oldskb);
nf_ct_set_closing(skb_nfct(oldskb));
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
/* If we use ip_local_out for bridged traffic, the MAC source on /* If we use ip_local_out for bridged traffic, the MAC source on
......
...@@ -345,6 +345,7 @@ void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb, ...@@ -345,6 +345,7 @@ void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb,
nf_reject_ip6_tcphdr_put(nskb, oldskb, otcph, otcplen); nf_reject_ip6_tcphdr_put(nskb, oldskb, otcph, otcplen);
nf_ct_attach(nskb, oldskb); nf_ct_attach(nskb, oldskb);
nf_ct_set_closing(skb_nfct(oldskb));
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
/* If we use ip6_local_out for bridged traffic, the MAC source on /* If we use ip6_local_out for bridged traffic, the MAC source on
......
...@@ -702,6 +702,22 @@ void nf_conntrack_destroy(struct nf_conntrack *nfct) ...@@ -702,6 +702,22 @@ void nf_conntrack_destroy(struct nf_conntrack *nfct)
} }
EXPORT_SYMBOL(nf_conntrack_destroy); EXPORT_SYMBOL(nf_conntrack_destroy);
void nf_ct_set_closing(struct nf_conntrack *nfct)
{
const struct nf_ct_hook *ct_hook;
if (!nfct)
return;
rcu_read_lock();
ct_hook = rcu_dereference(nf_ct_hook);
if (ct_hook)
ct_hook->set_closing(nfct);
rcu_read_unlock();
}
EXPORT_SYMBOL_GPL(nf_ct_set_closing);
bool nf_ct_get_tuple_skb(struct nf_conntrack_tuple *dst_tuple, bool nf_ct_get_tuple_skb(struct nf_conntrack_tuple *dst_tuple,
const struct sk_buff *skb) const struct sk_buff *skb)
{ {
......
...@@ -549,7 +549,7 @@ void ip_vs_stop_estimator(struct netns_ipvs *ipvs, struct ip_vs_stats *stats) ...@@ -549,7 +549,7 @@ void ip_vs_stop_estimator(struct netns_ipvs *ipvs, struct ip_vs_stats *stats)
__set_bit(row, kd->avail); __set_bit(row, kd->avail);
if (!kd->tick_len[row]) { if (!kd->tick_len[row]) {
RCU_INIT_POINTER(kd->ticks[row], NULL); RCU_INIT_POINTER(kd->ticks[row], NULL);
kfree_rcu(td); kfree_rcu(td, rcu_head);
} }
kd->est_count--; kd->est_count--;
if (kd->est_count) { if (kd->est_count) {
......
...@@ -2748,11 +2748,23 @@ int nf_conntrack_init_start(void) ...@@ -2748,11 +2748,23 @@ int nf_conntrack_init_start(void)
return ret; return ret;
} }
static void nf_conntrack_set_closing(struct nf_conntrack *nfct)
{
struct nf_conn *ct = nf_ct_to_nf_conn(nfct);
switch (nf_ct_protonum(ct)) {
case IPPROTO_TCP:
nf_conntrack_tcp_set_closing(ct);
break;
}
}
static const struct nf_ct_hook nf_conntrack_hook = { static const struct nf_ct_hook nf_conntrack_hook = {
.update = nf_conntrack_update, .update = nf_conntrack_update,
.destroy = nf_ct_destroy, .destroy = nf_ct_destroy,
.get_tuple_skb = nf_conntrack_get_tuple_skb, .get_tuple_skb = nf_conntrack_get_tuple_skb,
.attach = nf_conntrack_attach, .attach = nf_conntrack_attach,
.set_closing = nf_conntrack_set_closing,
}; };
void nf_conntrack_init_end(void) void nf_conntrack_init_end(void)
......
...@@ -911,6 +911,41 @@ static bool tcp_can_early_drop(const struct nf_conn *ct) ...@@ -911,6 +911,41 @@ static bool tcp_can_early_drop(const struct nf_conn *ct)
return false; return false;
} }
void nf_conntrack_tcp_set_closing(struct nf_conn *ct)
{
enum tcp_conntrack old_state;
const unsigned int *timeouts;
u32 timeout;
if (!nf_ct_is_confirmed(ct))
return;
spin_lock_bh(&ct->lock);
old_state = ct->proto.tcp.state;
ct->proto.tcp.state = TCP_CONNTRACK_CLOSE;
if (old_state == TCP_CONNTRACK_CLOSE ||
test_bit(IPS_FIXED_TIMEOUT_BIT, &ct->status)) {
spin_unlock_bh(&ct->lock);
return;
}
timeouts = nf_ct_timeout_lookup(ct);
if (!timeouts) {
const struct nf_tcp_net *tn;
tn = nf_tcp_pernet(nf_ct_net(ct));
timeouts = tn->timeouts;
}
timeout = timeouts[TCP_CONNTRACK_CLOSE];
WRITE_ONCE(ct->timeout, timeout + nfct_time_stamp);
spin_unlock_bh(&ct->lock);
nf_conntrack_event_cache(IPCT_PROTOINFO, ct);
}
static void nf_ct_tcp_state_reset(struct ip_ct_tcp_state *state) static void nf_ct_tcp_state_reset(struct ip_ct_tcp_state *state)
{ {
state->td_end = 0; state->td_end = 0;
......
...@@ -104,7 +104,7 @@ int nf_conntrack_udp_packet(struct nf_conn *ct, ...@@ -104,7 +104,7 @@ int nf_conntrack_udp_packet(struct nf_conn *ct,
/* If we've seen traffic both ways, this is some kind of UDP /* If we've seen traffic both ways, this is some kind of UDP
* stream. Set Assured. * stream. Set Assured.
*/ */
if (status & IPS_SEEN_REPLY_BIT) { if (status & IPS_SEEN_REPLY) {
unsigned long extra = timeouts[UDP_CT_UNREPLIED]; unsigned long extra = timeouts[UDP_CT_UNREPLIED];
bool stream = false; bool stream = false;
......
...@@ -275,7 +275,7 @@ static const char* l4proto_name(u16 proto) ...@@ -275,7 +275,7 @@ static const char* l4proto_name(u16 proto)
return "unknown"; return "unknown";
} }
static unsigned int static void
seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir) seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir)
{ {
struct nf_conn_acct *acct; struct nf_conn_acct *acct;
...@@ -283,14 +283,12 @@ seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir) ...@@ -283,14 +283,12 @@ seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir)
acct = nf_conn_acct_find(ct); acct = nf_conn_acct_find(ct);
if (!acct) if (!acct)
return 0; return;
counter = acct->counter; counter = acct->counter;
seq_printf(s, "packets=%llu bytes=%llu ", seq_printf(s, "packets=%llu bytes=%llu ",
(unsigned long long)atomic64_read(&counter[dir].packets), (unsigned long long)atomic64_read(&counter[dir].packets),
(unsigned long long)atomic64_read(&counter[dir].bytes)); (unsigned long long)atomic64_read(&counter[dir].bytes));
return 0;
} }
/* return 0 on success, 1 in case of error */ /* return 0 on success, 1 in case of error */
...@@ -342,8 +340,7 @@ static int ct_seq_show(struct seq_file *s, void *v) ...@@ -342,8 +340,7 @@ static int ct_seq_show(struct seq_file *s, void *v)
if (seq_has_overflowed(s)) if (seq_has_overflowed(s))
goto release; goto release;
if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL)) seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL);
goto release;
if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status))) if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status)))
seq_puts(s, "[UNREPLIED] "); seq_puts(s, "[UNREPLIED] ");
...@@ -352,8 +349,7 @@ static int ct_seq_show(struct seq_file *s, void *v) ...@@ -352,8 +349,7 @@ static int ct_seq_show(struct seq_file *s, void *v)
ct_show_zone(s, ct, NF_CT_ZONE_DIR_REPL); ct_show_zone(s, ct, NF_CT_ZONE_DIR_REPL);
if (seq_print_acct(s, ct, IP_CT_DIR_REPLY)) seq_print_acct(s, ct, IP_CT_DIR_REPLY);
goto release;
if (test_bit(IPS_HW_OFFLOAD_BIT, &ct->status)) if (test_bit(IPS_HW_OFFLOAD_BIT, &ct->status))
seq_puts(s, "[HW_OFFLOAD] "); seq_puts(s, "[HW_OFFLOAD] ");
......
...@@ -3724,7 +3724,7 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info, ...@@ -3724,7 +3724,7 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
chain = nft_chain_lookup(net, table, nla[NFTA_RULE_CHAIN], chain = nft_chain_lookup(net, table, nla[NFTA_RULE_CHAIN],
genmask); genmask);
if (IS_ERR(chain)) { if (IS_ERR(chain)) {
if (PTR_ERR(rule) == -ENOENT && if (PTR_ERR(chain) == -ENOENT &&
NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYRULE) NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_DESTROYRULE)
return 0; return 0;
...@@ -7023,6 +7023,9 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info, ...@@ -7023,6 +7023,9 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info,
return -EOPNOTSUPP; return -EOPNOTSUPP;
type = __nft_obj_type_get(objtype); type = __nft_obj_type_get(objtype);
if (WARN_ON_ONCE(!type))
return -ENOENT;
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla); nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
return nf_tables_updobj(&ctx, type, nla[NFTA_OBJ_DATA], obj); return nf_tables_updobj(&ctx, type, nla[NFTA_OBJ_DATA], obj);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment