Commit d387eaf51f8c869a41d90474d3599d1e89826254

Authored by Pablo Neira Ayuso

Merge tag 'ipvs-fixes-for-v4.5' of https://git.kernel.org/pub/scm/linux/kernel/git/horms/ipvs

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>

Showing 4 changed files Side-by-side Diff

... ... @@ -1588,6 +1588,23 @@
1588 1588 }
1589 1589 #endif /* CONFIG_IP_VS_NFCT */
1590 1590  
  1591 +/* Really using conntrack? */
  1592 +static inline bool ip_vs_conn_uses_conntrack(struct ip_vs_conn *cp,
  1593 + struct sk_buff *skb)
  1594 +{
  1595 +#ifdef CONFIG_IP_VS_NFCT
  1596 + enum ip_conntrack_info ctinfo;
  1597 + struct nf_conn *ct;
  1598 +
  1599 + if (!(cp->flags & IP_VS_CONN_F_NFCT))
  1600 + return false;
  1601 + ct = nf_ct_get(skb, &ctinfo);
  1602 + if (ct && !nf_ct_is_untracked(ct))
  1603 + return true;
  1604 +#endif
  1605 + return false;
  1606 +}
  1607 +
1591 1608 static inline int
1592 1609 ip_vs_dest_conn_overhead(struct ip_vs_dest *dest)
1593 1610 {
net/netfilter/ipvs/ip_vs_core.c
... ... @@ -1089,6 +1089,7 @@
1089 1089 switch (cp->protocol) {
1090 1090 case IPPROTO_TCP:
1091 1091 return (cp->state == IP_VS_TCP_S_TIME_WAIT) ||
  1092 + (cp->state == IP_VS_TCP_S_CLOSE) ||
1092 1093 ((conn_reuse_mode & 2) &&
1093 1094 (cp->state == IP_VS_TCP_S_FIN_WAIT) &&
1094 1095 (cp->flags & IP_VS_CONN_F_NOOUTPUT));
... ... @@ -1757,15 +1758,34 @@
1757 1758 cp = pp->conn_in_get(ipvs, af, skb, &iph);
1758 1759  
1759 1760 conn_reuse_mode = sysctl_conn_reuse_mode(ipvs);
1760   - if (conn_reuse_mode && !iph.fragoffs &&
1761   - is_new_conn(skb, &iph) && cp &&
1762   - ((unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest &&
1763   - unlikely(!atomic_read(&cp->dest->weight))) ||
1764   - unlikely(is_new_conn_expected(cp, conn_reuse_mode)))) {
1765   - if (!atomic_read(&cp->n_control))
1766   - ip_vs_conn_expire_now(cp);
1767   - __ip_vs_conn_put(cp);
1768   - cp = NULL;
  1761 + if (conn_reuse_mode && !iph.fragoffs && is_new_conn(skb, &iph) && cp) {
  1762 + bool uses_ct = false, resched = false;
  1763 +
  1764 + if (unlikely(sysctl_expire_nodest_conn(ipvs)) && cp->dest &&
  1765 + unlikely(!atomic_read(&cp->dest->weight))) {
  1766 + resched = true;
  1767 + uses_ct = ip_vs_conn_uses_conntrack(cp, skb);
  1768 + } else if (is_new_conn_expected(cp, conn_reuse_mode)) {
  1769 + uses_ct = ip_vs_conn_uses_conntrack(cp, skb);
  1770 + if (!atomic_read(&cp->n_control)) {
  1771 + resched = true;
  1772 + } else {
  1773 + /* Do not reschedule controlling connection
  1774 + * that uses conntrack while it is still
  1775 + * referenced by controlled connection(s).
  1776 + */
  1777 + resched = !uses_ct;
  1778 + }
  1779 + }
  1780 +
  1781 + if (resched) {
  1782 + if (!atomic_read(&cp->n_control))
  1783 + ip_vs_conn_expire_now(cp);
  1784 + __ip_vs_conn_put(cp);
  1785 + if (uses_ct)
  1786 + return NF_DROP;
  1787 + cp = NULL;
  1788 + }
1769 1789 }
1770 1790  
1771 1791 if (unlikely(!cp)) {
net/netfilter/ipvs/ip_vs_pe_sip.c
... ... @@ -70,10 +70,10 @@
70 70 const char *dptr;
71 71 int retc;
72 72  
73   - ip_vs_fill_iph_skb(p->af, skb, false, &iph);
  73 + retc = ip_vs_fill_iph_skb(p->af, skb, false, &iph);
74 74  
75 75 /* Only useful with UDP */
76   - if (iph.protocol != IPPROTO_UDP)
  76 + if (!retc || iph.protocol != IPPROTO_UDP)
77 77 return -EINVAL;
78 78 /* todo: IPv6 fragments:
79 79 * I think this only should be done for the first fragment. /HS
... ... @@ -88,7 +88,7 @@
88 88 dptr = skb->data + dataoff;
89 89 datalen = skb->len - dataoff;
90 90  
91   - if (get_callid(dptr, dataoff, datalen, &matchoff, &matchlen))
  91 + if (get_callid(dptr, 0, datalen, &matchoff, &matchlen))
92 92 return -EINVAL;
93 93  
94 94 /* N.B: pe_data is only set on success,
net/netfilter/nfnetlink_acct.c
... ... @@ -242,6 +242,9 @@
242 242 if (err < 0)
243 243 return ERR_PTR(err);
244 244  
  245 + if (!tb[NFACCT_FILTER_MASK] || !tb[NFACCT_FILTER_VALUE])
  246 + return ERR_PTR(-EINVAL);
  247 +
245 248 filter = kzalloc(sizeof(struct nfacct_filter), GFP_KERNEL);
246 249 if (!filter)
247 250 return ERR_PTR(-ENOMEM);