xfrm4: Fix header checks in _decode_session4. [Linux 3.16.72]

This Linux kernel change "xfrm4: Fix header checks in _decode_session4" is included in the Linux 3.16.72 release. This change is authored by Steffen Klassert <steffen.klassert [at] secunet.com> on Fri Oct 23 07:31:23 2015 +0200. The commit for this change in Linux stable tree is e31193e (patch) which is from upstream commit 1a14f1e. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 1a14f1e.

xfrm4: Fix header checks in _decode_session4.

commit 1a14f1e5550a341f76e5c8f596e9b5f8a886dfbc upstream.

We skip the header informations if the data pointer points
already behind the header in question for some protocols.
This is because we call pskb_may_pull with a negative value
converted to unsigened int from pskb_may_pull in this case.
Skipping the header informations can lead to incorrect policy
lookups, so fix it by a check of the data pointer position
before we call pskb_may_pull.

Signed-off-by: Steffen Klassert <[email protected]>
Signed-off-by: Ben Hutchings <[email protected]>

There are 15 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 net/ipv4/xfrm4_policy.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 3a4c1f9..ff96243 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -131,7 +131,8 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
            break;

        case IPPROTO_ICMP:
-           if (pskb_may_pull(skb, xprth + 2 - skb->data)) {
+           if (xprth + 2 < skb->data ||
+               pskb_may_pull(skb, xprth + 2 - skb->data)) {
                u8 *icmp = xprth;

                fl4->fl4_icmp_type = icmp[0];
@@ -140,7 +141,8 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
            break;

        case IPPROTO_ESP:
-           if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
+           if (xprth + 4 < skb->data ||
+               pskb_may_pull(skb, xprth + 4 - skb->data)) {
                __be32 *ehdr = (__be32 *)xprth;

                fl4->fl4_ipsec_spi = ehdr[0];
@@ -148,7 +150,8 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
            break;

        case IPPROTO_AH:
-           if (pskb_may_pull(skb, xprth + 8 - skb->data)) {
+           if (xprth + 8 < skb->data ||
+               pskb_may_pull(skb, xprth + 8 - skb->data)) {
                __be32 *ah_hdr = (__be32 *)xprth;

                fl4->fl4_ipsec_spi = ah_hdr[1];
@@ -156,7 +159,8 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
            break;

        case IPPROTO_COMP:
-           if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
+           if (xprth + 4 < skb->data ||
+               pskb_may_pull(skb, xprth + 4 - skb->data)) {
                __be16 *ipcomp_hdr = (__be16 *)xprth;

                fl4->fl4_ipsec_spi = htonl(ntohs(ipcomp_hdr[1]));
@@ -164,7 +168,8 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
            break;

        case IPPROTO_GRE:
-           if (pskb_may_pull(skb, xprth + 12 - skb->data)) {
+           if (xprth + 12 < skb->data ||
+               pskb_may_pull(skb, xprth + 12 - skb->data)) {
                __be16 *greflags = (__be16 *)xprth;
                __be32 *gre_hdr = (__be32 *)xprth;

Leave a Reply

Your email address will not be published. Required fields are marked *