diff options
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/xfrm_input.c | 41 | ||||
-rw-r--r-- | net/xfrm/xfrm_output.c | 6 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 63 |
3 files changed, 87 insertions, 23 deletions
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 8624cbdb2a1e..493243fc5fe5 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c | |||
@@ -119,8 +119,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | |||
119 | struct sec_path *sp; | 119 | struct sec_path *sp; |
120 | 120 | ||
121 | sp = secpath_dup(skb->sp); | 121 | sp = secpath_dup(skb->sp); |
122 | if (!sp) | 122 | if (!sp) { |
123 | XFRM_INC_STATS(LINUX_MIB_XFRMINERROR); | ||
123 | goto drop; | 124 | goto drop; |
125 | } | ||
124 | if (skb->sp) | 126 | if (skb->sp) |
125 | secpath_put(skb->sp); | 127 | secpath_put(skb->sp); |
126 | skb->sp = sp; | 128 | skb->sp = sp; |
@@ -131,31 +133,45 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) | |||
131 | family = XFRM_SPI_SKB_CB(skb)->family; | 133 | family = XFRM_SPI_SKB_CB(skb)->family; |
132 | 134 | ||
133 | seq = 0; | 135 | seq = 0; |
134 | if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) | 136 | if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) { |
137 | XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR); | ||
135 | goto drop; | 138 | goto drop; |
139 | } | ||
136 | 140 | ||
137 | do { | 141 | do { |
138 | if (skb->sp->len == XFRM_MAX_DEPTH) | 142 | if (skb->sp->len == XFRM_MAX_DEPTH) { |
143 | XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR); | ||
139 | goto drop; | 144 | goto drop; |
145 | } | ||
140 | 146 | ||
141 | x = xfrm_state_lookup(daddr, spi, nexthdr, family); | 147 | x = xfrm_state_lookup(daddr, spi, nexthdr, family); |
142 | if (x == NULL) | 148 | if (x == NULL) { |
149 | XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES); | ||
143 | goto drop; | 150 | goto drop; |
151 | } | ||
144 | 152 | ||
145 | skb->sp->xvec[skb->sp->len++] = x; | 153 | skb->sp->xvec[skb->sp->len++] = x; |
146 | 154 | ||
147 | spin_lock(&x->lock); | 155 | spin_lock(&x->lock); |
148 | if (unlikely(x->km.state != XFRM_STATE_VALID)) | 156 | if (unlikely(x->km.state != XFRM_STATE_VALID)) { |
157 | XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEINVALID); | ||
149 | goto drop_unlock; | 158 | goto drop_unlock; |
159 | } | ||
150 | 160 | ||
151 | if ((x->encap ? x->encap->encap_type : 0) != encap_type) | 161 | if ((x->encap ? x->encap->encap_type : 0) != encap_type) { |
162 | XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEINVALID); | ||
152 | goto drop_unlock; | 163 | goto drop_unlock; |
164 | } | ||
153 | 165 | ||
154 | if (x->props.replay_window && xfrm_replay_check(x, seq)) | 166 | if (x->props.replay_window && xfrm_replay_check(x, seq)) { |
167 | XFRM_INC_STATS(LINUX_MIB_XFRMINSEQOUTOFWINDOW); | ||
155 | goto drop_unlock; | 168 | goto drop_unlock; |
169 | } | ||
156 | 170 | ||
157 | if (xfrm_state_check_expire(x)) | 171 | if (xfrm_state_check_expire(x)) { |
172 | XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEEXPIRED); | ||
158 | goto drop_unlock; | 173 | goto drop_unlock; |
174 | } | ||
159 | 175 | ||
160 | spin_unlock(&x->lock); | 176 | spin_unlock(&x->lock); |
161 | 177 | ||
@@ -171,6 +187,7 @@ resume: | |||
171 | if (nexthdr <= 0) { | 187 | if (nexthdr <= 0) { |
172 | if (nexthdr == -EBADMSG) | 188 | if (nexthdr == -EBADMSG) |
173 | x->stats.integrity_failed++; | 189 | x->stats.integrity_failed++; |
190 | XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEPROTOERROR); | ||
174 | goto drop_unlock; | 191 | goto drop_unlock; |
175 | } | 192 | } |
176 | 193 | ||
@@ -187,8 +204,10 @@ resume: | |||
187 | 204 | ||
188 | XFRM_MODE_SKB_CB(skb)->protocol = nexthdr; | 205 | XFRM_MODE_SKB_CB(skb)->protocol = nexthdr; |
189 | 206 | ||
190 | if (x->inner_mode->input(x, skb)) | 207 | if (x->inner_mode->input(x, skb)) { |
208 | XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMODEERROR); | ||
191 | goto drop; | 209 | goto drop; |
210 | } | ||
192 | 211 | ||
193 | if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { | 212 | if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { |
194 | decaps = 1; | 213 | decaps = 1; |
@@ -203,8 +222,10 @@ resume: | |||
203 | family = x->outer_mode->afinfo->family; | 222 | family = x->outer_mode->afinfo->family; |
204 | 223 | ||
205 | err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); | 224 | err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); |
206 | if (err < 0) | 225 | if (err < 0) { |
226 | XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR); | ||
207 | goto drop; | 227 | goto drop; |
228 | } | ||
208 | } while (!err); | 229 | } while (!err); |
209 | 230 | ||
210 | nf_reset(skb); | 231 | nf_reset(skb); |
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index 26fa0cb78c94..867484a046af 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c | |||
@@ -69,10 +69,13 @@ static int xfrm_output_one(struct sk_buff *skb, int err) | |||
69 | err = x->type->output(x, skb); | 69 | err = x->type->output(x, skb); |
70 | 70 | ||
71 | resume: | 71 | resume: |
72 | if (err) | 72 | if (err) { |
73 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATEPROTOERROR); | ||
73 | goto error_nolock; | 74 | goto error_nolock; |
75 | } | ||
74 | 76 | ||
75 | if (!(skb->dst = dst_pop(dst))) { | 77 | if (!(skb->dst = dst_pop(dst))) { |
78 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTERROR); | ||
76 | err = -EHOSTUNREACH; | 79 | err = -EHOSTUNREACH; |
77 | goto error_nolock; | 80 | goto error_nolock; |
78 | } | 81 | } |
@@ -167,6 +170,7 @@ int xfrm_output(struct sk_buff *skb) | |||
167 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 170 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
168 | err = skb_checksum_help(skb); | 171 | err = skb_checksum_help(skb); |
169 | if (err) { | 172 | if (err) { |
173 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTERROR); | ||
170 | kfree_skb(skb); | 174 | kfree_skb(skb); |
171 | return err; | 175 | return err; |
172 | } | 176 | } |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 32ddb7b12e7f..74807a7d3d69 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -1494,8 +1494,10 @@ restart: | |||
1494 | if (sk && sk->sk_policy[XFRM_POLICY_OUT]) { | 1494 | if (sk && sk->sk_policy[XFRM_POLICY_OUT]) { |
1495 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); | 1495 | policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); |
1496 | err = PTR_ERR(policy); | 1496 | err = PTR_ERR(policy); |
1497 | if (IS_ERR(policy)) | 1497 | if (IS_ERR(policy)) { |
1498 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLERROR); | ||
1498 | goto dropdst; | 1499 | goto dropdst; |
1500 | } | ||
1499 | } | 1501 | } |
1500 | 1502 | ||
1501 | if (!policy) { | 1503 | if (!policy) { |
@@ -1529,6 +1531,7 @@ restart: | |||
1529 | default: | 1531 | default: |
1530 | case XFRM_POLICY_BLOCK: | 1532 | case XFRM_POLICY_BLOCK: |
1531 | /* Prohibit the flow */ | 1533 | /* Prohibit the flow */ |
1534 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLBLOCK); | ||
1532 | err = -EPERM; | 1535 | err = -EPERM; |
1533 | goto error; | 1536 | goto error; |
1534 | 1537 | ||
@@ -1548,6 +1551,7 @@ restart: | |||
1548 | */ | 1551 | */ |
1549 | dst = xfrm_find_bundle(fl, policy, family); | 1552 | dst = xfrm_find_bundle(fl, policy, family); |
1550 | if (IS_ERR(dst)) { | 1553 | if (IS_ERR(dst)) { |
1554 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR); | ||
1551 | err = PTR_ERR(dst); | 1555 | err = PTR_ERR(dst); |
1552 | goto error; | 1556 | goto error; |
1553 | } | 1557 | } |
@@ -1562,10 +1566,12 @@ restart: | |||
1562 | XFRM_POLICY_OUT); | 1566 | XFRM_POLICY_OUT); |
1563 | if (pols[1]) { | 1567 | if (pols[1]) { |
1564 | if (IS_ERR(pols[1])) { | 1568 | if (IS_ERR(pols[1])) { |
1569 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLERROR); | ||
1565 | err = PTR_ERR(pols[1]); | 1570 | err = PTR_ERR(pols[1]); |
1566 | goto error; | 1571 | goto error; |
1567 | } | 1572 | } |
1568 | if (pols[1]->action == XFRM_POLICY_BLOCK) { | 1573 | if (pols[1]->action == XFRM_POLICY_BLOCK) { |
1574 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLBLOCK); | ||
1569 | err = -EPERM; | 1575 | err = -EPERM; |
1570 | goto error; | 1576 | goto error; |
1571 | } | 1577 | } |
@@ -1611,6 +1617,7 @@ restart: | |||
1611 | nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); | 1617 | nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); |
1612 | 1618 | ||
1613 | if (nx == -EAGAIN && signal_pending(current)) { | 1619 | if (nx == -EAGAIN && signal_pending(current)) { |
1620 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTNOSTATES); | ||
1614 | err = -ERESTART; | 1621 | err = -ERESTART; |
1615 | goto error; | 1622 | goto error; |
1616 | } | 1623 | } |
@@ -1621,8 +1628,10 @@ restart: | |||
1621 | } | 1628 | } |
1622 | err = nx; | 1629 | err = nx; |
1623 | } | 1630 | } |
1624 | if (err < 0) | 1631 | if (err < 0) { |
1632 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTNOSTATES); | ||
1625 | goto error; | 1633 | goto error; |
1634 | } | ||
1626 | } | 1635 | } |
1627 | if (nx == 0) { | 1636 | if (nx == 0) { |
1628 | /* Flow passes not transformed. */ | 1637 | /* Flow passes not transformed. */ |
@@ -1632,8 +1641,10 @@ restart: | |||
1632 | 1641 | ||
1633 | dst = xfrm_bundle_create(policy, xfrm, nx, fl, dst_orig); | 1642 | dst = xfrm_bundle_create(policy, xfrm, nx, fl, dst_orig); |
1634 | err = PTR_ERR(dst); | 1643 | err = PTR_ERR(dst); |
1635 | if (IS_ERR(dst)) | 1644 | if (IS_ERR(dst)) { |
1645 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLEGENERROR); | ||
1636 | goto error; | 1646 | goto error; |
1647 | } | ||
1637 | 1648 | ||
1638 | for (pi = 0; pi < npols; pi++) { | 1649 | for (pi = 0; pi < npols; pi++) { |
1639 | read_lock_bh(&pols[pi]->lock); | 1650 | read_lock_bh(&pols[pi]->lock); |
@@ -1652,6 +1663,10 @@ restart: | |||
1652 | if (dst) | 1663 | if (dst) |
1653 | dst_free(dst); | 1664 | dst_free(dst); |
1654 | 1665 | ||
1666 | if (pol_dead) | ||
1667 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLDEAD); | ||
1668 | else | ||
1669 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR); | ||
1655 | err = -EHOSTUNREACH; | 1670 | err = -EHOSTUNREACH; |
1656 | goto error; | 1671 | goto error; |
1657 | } | 1672 | } |
@@ -1664,6 +1679,7 @@ restart: | |||
1664 | write_unlock_bh(&policy->lock); | 1679 | write_unlock_bh(&policy->lock); |
1665 | if (dst) | 1680 | if (dst) |
1666 | dst_free(dst); | 1681 | dst_free(dst); |
1682 | XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR); | ||
1667 | goto error; | 1683 | goto error; |
1668 | } | 1684 | } |
1669 | 1685 | ||
@@ -1817,8 +1833,11 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1817 | dir &= XFRM_POLICY_MASK; | 1833 | dir &= XFRM_POLICY_MASK; |
1818 | fl_dir = policy_to_flow_dir(dir); | 1834 | fl_dir = policy_to_flow_dir(dir); |
1819 | 1835 | ||
1820 | if (__xfrm_decode_session(skb, &fl, family, reverse) < 0) | 1836 | if (__xfrm_decode_session(skb, &fl, family, reverse) < 0) { |
1837 | XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR); | ||
1821 | return 0; | 1838 | return 0; |
1839 | } | ||
1840 | |||
1822 | nf_nat_decode_session(skb, &fl, family); | 1841 | nf_nat_decode_session(skb, &fl, family); |
1823 | 1842 | ||
1824 | /* First, check used SA against their selectors. */ | 1843 | /* First, check used SA against their selectors. */ |
@@ -1827,28 +1846,35 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1827 | 1846 | ||
1828 | for (i=skb->sp->len-1; i>=0; i--) { | 1847 | for (i=skb->sp->len-1; i>=0; i--) { |
1829 | struct xfrm_state *x = skb->sp->xvec[i]; | 1848 | struct xfrm_state *x = skb->sp->xvec[i]; |
1830 | if (!xfrm_selector_match(&x->sel, &fl, family)) | 1849 | if (!xfrm_selector_match(&x->sel, &fl, family)) { |
1850 | XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMISMATCH); | ||
1831 | return 0; | 1851 | return 0; |
1852 | } | ||
1832 | } | 1853 | } |
1833 | } | 1854 | } |
1834 | 1855 | ||
1835 | pol = NULL; | 1856 | pol = NULL; |
1836 | if (sk && sk->sk_policy[dir]) { | 1857 | if (sk && sk->sk_policy[dir]) { |
1837 | pol = xfrm_sk_policy_lookup(sk, dir, &fl); | 1858 | pol = xfrm_sk_policy_lookup(sk, dir, &fl); |
1838 | if (IS_ERR(pol)) | 1859 | if (IS_ERR(pol)) { |
1860 | XFRM_INC_STATS(LINUX_MIB_XFRMINPOLERROR); | ||
1839 | return 0; | 1861 | return 0; |
1862 | } | ||
1840 | } | 1863 | } |
1841 | 1864 | ||
1842 | if (!pol) | 1865 | if (!pol) |
1843 | pol = flow_cache_lookup(&fl, family, fl_dir, | 1866 | pol = flow_cache_lookup(&fl, family, fl_dir, |
1844 | xfrm_policy_lookup); | 1867 | xfrm_policy_lookup); |
1845 | 1868 | ||
1846 | if (IS_ERR(pol)) | 1869 | if (IS_ERR(pol)) { |
1870 | XFRM_INC_STATS(LINUX_MIB_XFRMINPOLERROR); | ||
1847 | return 0; | 1871 | return 0; |
1872 | } | ||
1848 | 1873 | ||
1849 | if (!pol) { | 1874 | if (!pol) { |
1850 | if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) { | 1875 | if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) { |
1851 | xfrm_secpath_reject(xerr_idx, skb, &fl); | 1876 | xfrm_secpath_reject(xerr_idx, skb, &fl); |
1877 | XFRM_INC_STATS(LINUX_MIB_XFRMINNOPOLS); | ||
1852 | return 0; | 1878 | return 0; |
1853 | } | 1879 | } |
1854 | return 1; | 1880 | return 1; |
@@ -1864,8 +1890,10 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1864 | &fl, family, | 1890 | &fl, family, |
1865 | XFRM_POLICY_IN); | 1891 | XFRM_POLICY_IN); |
1866 | if (pols[1]) { | 1892 | if (pols[1]) { |
1867 | if (IS_ERR(pols[1])) | 1893 | if (IS_ERR(pols[1])) { |
1894 | XFRM_INC_STATS(LINUX_MIB_XFRMINPOLERROR); | ||
1868 | return 0; | 1895 | return 0; |
1896 | } | ||
1869 | pols[1]->curlft.use_time = get_seconds(); | 1897 | pols[1]->curlft.use_time = get_seconds(); |
1870 | npols ++; | 1898 | npols ++; |
1871 | } | 1899 | } |
@@ -1886,10 +1914,14 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1886 | 1914 | ||
1887 | for (pi = 0; pi < npols; pi++) { | 1915 | for (pi = 0; pi < npols; pi++) { |
1888 | if (pols[pi] != pol && | 1916 | if (pols[pi] != pol && |
1889 | pols[pi]->action != XFRM_POLICY_ALLOW) | 1917 | pols[pi]->action != XFRM_POLICY_ALLOW) { |
1918 | XFRM_INC_STATS(LINUX_MIB_XFRMINPOLBLOCK); | ||
1890 | goto reject; | 1919 | goto reject; |
1891 | if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) | 1920 | } |
1921 | if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) { | ||
1922 | XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR); | ||
1892 | goto reject_error; | 1923 | goto reject_error; |
1924 | } | ||
1893 | for (i = 0; i < pols[pi]->xfrm_nr; i++) | 1925 | for (i = 0; i < pols[pi]->xfrm_nr; i++) |
1894 | tpp[ti++] = &pols[pi]->xfrm_vec[i]; | 1926 | tpp[ti++] = &pols[pi]->xfrm_vec[i]; |
1895 | } | 1927 | } |
@@ -1911,16 +1943,20 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, | |||
1911 | if (k < -1) | 1943 | if (k < -1) |
1912 | /* "-2 - errored_index" returned */ | 1944 | /* "-2 - errored_index" returned */ |
1913 | xerr_idx = -(2+k); | 1945 | xerr_idx = -(2+k); |
1946 | XFRM_INC_STATS(LINUX_MIB_XFRMINTMPLMISMATCH); | ||
1914 | goto reject; | 1947 | goto reject; |
1915 | } | 1948 | } |
1916 | } | 1949 | } |
1917 | 1950 | ||
1918 | if (secpath_has_nontransport(sp, k, &xerr_idx)) | 1951 | if (secpath_has_nontransport(sp, k, &xerr_idx)) { |
1952 | XFRM_INC_STATS(LINUX_MIB_XFRMINTMPLMISMATCH); | ||
1919 | goto reject; | 1953 | goto reject; |
1954 | } | ||
1920 | 1955 | ||
1921 | xfrm_pols_put(pols, npols); | 1956 | xfrm_pols_put(pols, npols); |
1922 | return 1; | 1957 | return 1; |
1923 | } | 1958 | } |
1959 | XFRM_INC_STATS(LINUX_MIB_XFRMINPOLBLOCK); | ||
1924 | 1960 | ||
1925 | reject: | 1961 | reject: |
1926 | xfrm_secpath_reject(xerr_idx, skb, &fl); | 1962 | xfrm_secpath_reject(xerr_idx, skb, &fl); |
@@ -1934,8 +1970,11 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) | |||
1934 | { | 1970 | { |
1935 | struct flowi fl; | 1971 | struct flowi fl; |
1936 | 1972 | ||
1937 | if (xfrm_decode_session(skb, &fl, family) < 0) | 1973 | if (xfrm_decode_session(skb, &fl, family) < 0) { |
1974 | /* XXX: we should have something like FWDHDRERROR here. */ | ||
1975 | XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR); | ||
1938 | return 0; | 1976 | return 0; |
1977 | } | ||
1939 | 1978 | ||
1940 | return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0; | 1979 | return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0; |
1941 | } | 1980 | } |