Re: [PATCH] possible overflow of sock->sk_policy

2005-07-26 Thread David S. Miller
From: Herbert Xu <[EMAIL PROTECTED]>
Subject: Re: [PATCH] possible overflow of sock->sk_policy
Date: Tue, 26 Jul 2005 13:07:14 +1000

> Balazs Scheidler <[EMAIL PROTECTED]> wrote:
> > 
> > While reading through the xfrm code I've found a possible array overflow
> > in struct sock.
> 
> Thanks for catching this.  However, the check should be done in xfrm_user
> as we do for af_key.  The following patch does just that.
> 
> Signed-off-by: Herbert Xu <[EMAIL PROTECTED]>

Applied, thanks Herbert.
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] possible overflow of sock->sk_policy

2005-07-25 Thread Herbert Xu
Balazs Scheidler <[EMAIL PROTECTED]> wrote:
> 
> While reading through the xfrm code I've found a possible array overflow
> in struct sock.

Thanks for catching this.  However, the check should be done in xfrm_user
as we do for af_key.  The following patch does just that.

Signed-off-by: Herbert Xu <[EMAIL PROTECTED]>

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[EMAIL PROTECTED]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1350,6 +1350,9 @@ static struct xfrm_policy *xfrm_compile_
if (nr > XFRM_MAX_DEPTH)
return NULL;
 
+   if (p->dir > XFRM_POLICY_OUT)
+   return NULL;
+
xp = xfrm_policy_alloc(GFP_KERNEL);
if (xp == NULL) {
*dir = -ENOBUFS;
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [PATCH] possible overflow of sock->sk_policy

2005-07-25 Thread Balazs Scheidler
> Hi,
> 

> I'm attaching a small testprogram which tries to install an
> XFRM_POLICY_FWD, and I confirmed with a printk that the value of 2 is
> successfully propagated to xfrm_sk_policy_insert().

test program originally missed, here it is this time.

-- 
Bazsi
#include 
#include 
#include 
#include 
#include 

#include 

#define IP_XFRM_POLICY 17

int 
main()
{
  int fd;
  struct sockaddr_in s_in;
  struct xfrm_userpolicy_info xp;
  
  inet_aton("192.168.13.8", &s_in.sin_addr);
  s_in.sin_family = AF_INET;
  s_in.sin_port = htons(555);
  fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  if (fd < 0)
{
  perror("socket");
  return 1;
}
  if (connect(fd, (struct sockaddr *) &s_in, sizeof(s_in)) < 0)
{
  perror("connect");
  return 1;
}
  
  inet_aton("192.168.13.7", (struct in_addr *) &xp.sel.saddr);
  xp.sel.prefixlen_s = 32;
  inet_aton("192.168.13.8", (struct in_addr *) &xp.sel.daddr);
  xp.sel.prefixlen_d = 32;
  xp.sel.dport = 0;
  xp.sel.dport_mask = 0;
  xp.sel.sport = 0;
  xp.sel.sport_mask = 0;
  xp.sel.family = AF_INET;
  xp.sel.proto = 0;
  xp.sel.ifindex = 0;
  xp.sel.user = 0;
  xp.lft.soft_byte_limit = 1000;
  xp.lft.hard_byte_limit = 1000;
  xp.lft.soft_packet_limit = 1000;
  xp.lft.hard_packet_limit = 1000;
  xp.lft.soft_add_expires_seconds = 3600;
  xp.lft.hard_add_expires_seconds = 3600;
  xp.lft.soft_use_expires_seconds = 3600;
  xp.lft.hard_use_expires_seconds = 3600;
  xp.curlft.bytes = 0;
  xp.curlft.packets = 0;
  xp.curlft.add_time = 0;
  xp.curlft.use_time = 0;
  xp.priority = 0;
  xp.index = 0;
  xp.dir = XFRM_POLICY_FWD;
  xp.action = XFRM_POLICY_ALLOW;
  xp.flags = 0;
  xp.share = XFRM_SHARE_UNIQUE;
  
  if (setsockopt(fd, SOL_IP, IP_XFRM_POLICY, &xp, sizeof(xp)) < 0)
{
  perror("setsockopt(IP_XFRM_POLICY)");
  return 1;
}
  
  send(fd, "abrakadabra", 11, 0);
  close(fd);
}


[PATCH] possible overflow of sock->sk_policy

2005-07-25 Thread Balazs Scheidler
Hi,

While reading through the xfrm code I've found a possible array overflow
in struct sock.

When issuing a setsockopt(SOL_IP, IP_XFRM_POLICY) on a socket, a
function called xfrm_user_policy() is called to compile and install a
socket specific XFRM policy.

This function calls km->compile_policy() to compile the incoming
setsockopt data to struct xfrm_policy which validates the incoming data
and checks (among other things) that struct xfrm_userpolicy_info->dir is
valid. Valid here means that it is either XFRM_POLICY_{IN,OUT,FWD}.

xfrm_sk_policy_insert() then takes this value blindly and inserts the
new policy to struct sock->sk_policy[dir], if dir is XFRM_POLICY_FWD,
then the sk_policy array is overflown as it is declared as having two
items only and XFRM_POLICY_FWD numerically equals to 2.

I'm attaching a small testprogram which tries to install an
XFRM_POLICY_FWD, and I confirmed with a printk that the value of 2 is
successfully propagated to xfrm_sk_policy_insert().

The value after the sk_policy is an "rwlock_t sk_dst_lock;" which seems
to be used from TCP only.

The effect of this bug is probably only a deadlock, as rwlock_t contains
a single unsigned int value and no pointers.

A possible fix below can be found at the end of this mail.

Signed-off-by: Balazs Scheidler <[EMAIL PROTECTED]>

--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -571,6 +571,9 @@ int xfrm_policy_delete(struct xfrm_polic
 int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
 {
struct xfrm_policy *old_pol;
+
+   if (dir > XFRM_POLICY_OUT)
+   return -EINVAL;

write_lock_bh(&xfrm_policy_lock);
old_pol = sk->sk_policy[dir];
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -920,9 +920,8 @@ int xfrm_user_policy(struct sock *sk, in
read_unlock(&xfrm_km_lock);

if (err >= 0) {
-   xfrm_sk_policy_insert(sk, err, pol);
+   err = xfrm_sk_policy_insert(sk, err, pol);
xfrm_pol_put(pol);
-   err = 0;
}

 out:


-- 
Bazsi

-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html