Simon Horman says:

====================
please consider these IPVS fixes for v4.5 or
if it is too late please consider them for v4.6.

* Arnd Bergman has corrected an error whereby the SIP persistence engine
  may incorrectly access protocol fields
* Julian Anastasov has corrected a problem reported by Jiri Bohac with the
  connection rescheduling mechanism added in 3.10 when new SYNs in
  connection to dead real server can be redirected to another real server.
* Marco Angaroni resolved a problem in the SIP persistence engine
  whereby the Call-ID could not be found if it was at the beginning of a
  SIP message.
====================

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Pablo Neira Ayuso 2016-03-11 11:35:06 +01:00
commit d387eaf51f
4 changed files with 52 additions and 12 deletions

View File

@ -1588,6 +1588,23 @@ static inline void ip_vs_conn_drop_conntrack(struct ip_vs_conn *cp)
} }
#endif /* CONFIG_IP_VS_NFCT */ #endif /* CONFIG_IP_VS_NFCT */
/* Really using conntrack? */
static inline bool ip_vs_conn_uses_conntrack(struct ip_vs_conn *cp,
struct sk_buff *skb)
{
#ifdef CONFIG_IP_VS_NFCT
enum ip_conntrack_info ctinfo;
struct nf_conn *ct;
if (!(cp->flags & IP_VS_CONN_F_NFCT))
return false;
ct = nf_ct_get(skb, &ctinfo);
if (ct && !nf_ct_is_untracked(ct))
return true;
#endif
return false;
}
static inline int static inline int
ip_vs_dest_conn_overhead(struct ip_vs_dest *dest) ip_vs_dest_conn_overhead(struct ip_vs_dest *dest)
{ {

View File

@ -1089,6 +1089,7 @@ static inline bool is_new_conn_expected(const struct ip_vs_conn *cp,
switch (cp->protocol) { switch (cp->protocol) {
case IPPROTO_TCP: case IPPROTO_TCP:
return (cp->state == IP_VS_TCP_S_TIME_WAIT) || return (cp->state == IP_VS_TCP_S_TIME_WAIT) ||
(cp->state == IP_VS_TCP_S_CLOSE) ||
((conn_reuse_mode & 2) && ((conn_reuse_mode & 2) &&
(cp->state == IP_VS_TCP_S_FIN_WAIT) && (cp->state == IP_VS_TCP_S_FIN_WAIT) &&
(cp->flags & IP_VS_CONN_F_NOOUTPUT)); (cp->flags & IP_VS_CONN_F_NOOUTPUT));
@ -1757,15 +1758,34 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int
cp = pp->conn_in_get(ipvs, af, skb, &iph); cp = pp->conn_in_get(ipvs, af, skb, &iph);
conn_reuse_mode = sysctl_conn_reuse_mode(ipvs); conn_reuse_mode = sysctl_conn_reuse_mode(ipvs);
if (conn_reuse_mode && !iph.fragoffs && if (conn_reuse_mode && !iph.fragoffs && is_new_conn(skb, &iph) && cp) {
is_new_conn(skb, &iph) && cp && bool uses_ct = false, resched = false;
((unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest &&
unlikely(!atomic_read(&cp->dest->weight))) || if (unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest &&
unlikely(is_new_conn_expected(cp, conn_reuse_mode)))) { unlikely(!atomic_read(&cp->dest->weight))) {
if (!atomic_read(&cp->n_control)) resched = true;
ip_vs_conn_expire_now(cp); uses_ct = ip_vs_conn_uses_conntrack(cp, skb);
__ip_vs_conn_put(cp); } else if (is_new_conn_expected(cp, conn_reuse_mode)) {
cp = NULL; uses_ct = ip_vs_conn_uses_conntrack(cp, skb);
if (!atomic_read(&cp->n_control)) {
resched = true;
} else {
/* Do not reschedule controlling connection
* that uses conntrack while it is still
* referenced by controlled connection(s).
*/
resched = !uses_ct;
}
}
if (resched) {
if (!atomic_read(&cp->n_control))
ip_vs_conn_expire_now(cp);
__ip_vs_conn_put(cp);
if (uses_ct)
return NF_DROP;
cp = NULL;
}
} }
if (unlikely(!cp)) { if (unlikely(!cp)) {

View File

@ -70,10 +70,10 @@ ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
const char *dptr; const char *dptr;
int retc; int retc;
ip_vs_fill_iph_skb(p->af, skb, false, &iph); retc = ip_vs_fill_iph_skb(p->af, skb, false, &iph);
/* Only useful with UDP */ /* Only useful with UDP */
if (iph.protocol != IPPROTO_UDP) if (!retc || iph.protocol != IPPROTO_UDP)
return -EINVAL; return -EINVAL;
/* todo: IPv6 fragments: /* todo: IPv6 fragments:
* I think this only should be done for the first fragment. /HS * I think this only should be done for the first fragment. /HS
@ -88,7 +88,7 @@ ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
dptr = skb->data + dataoff; dptr = skb->data + dataoff;
datalen = skb->len - dataoff; datalen = skb->len - dataoff;
if (get_callid(dptr, dataoff, datalen, &matchoff, &matchlen)) if (get_callid(dptr, 0, datalen, &matchoff, &matchlen))
return -EINVAL; return -EINVAL;
/* N.B: pe_data is only set on success, /* N.B: pe_data is only set on success,

View File

@ -242,6 +242,9 @@ nfacct_filter_alloc(const struct nlattr * const attr)
if (err < 0) if (err < 0)
return ERR_PTR(err); return ERR_PTR(err);
if (!tb[NFACCT_FILTER_MASK] || !tb[NFACCT_FILTER_VALUE])
return ERR_PTR(-EINVAL);
filter = kzalloc(sizeof(struct nfacct_filter), GFP_KERNEL); filter = kzalloc(sizeof(struct nfacct_filter), GFP_KERNEL);
if (!filter) if (!filter)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);