Using linux-2.4.0-test9, bind() incorrectly allows a bind to a non-local
address.  The correct behavior should be a return code of -1 with errno
set to EADDRNOTAVAIL.  (Simple snippet to reproduce/debug the problem is
available on request)

There appears to be significant differences between the
net/ipv4/af_inet.c:inet_bind() in the 2.2 and 2.4 sources.  The
inet_bind() in the 2.2 sources contains a check to ensure that the value
returned by inet_addr_type() is RTN_LOCAL as well as a #ifdef'ed check
to allow the bind in certain cases if the kernel was compiled with
transparent proxy is enabled.  In inet_bind() of the 2.4 tree all of
these checks are conspicuously absent.

The following patch fixes the problem for me, but I am still concerned
possibly breaking transparent proxy.  Basically the patch is nothing
more than the addition of a simple check for RTN_LOCAL. (Moving call to
inet_addr_type() is a *very* nit-picky "optimization" that eliminates
wasted time in the call in the event that subsequent port and capability
check fails).


*** af_inet.c   Wed Oct 18 11:06:15 2000
--- af_inet.c.orig      Mon Sep 18 16:04:13 2000
***************
*** 459,471 ****
        if (addr_len < sizeof(struct sockaddr_in))
                return -EINVAL;

        snum = ntohs(addr->sin_port);
        if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
                return -EACCES;

!       chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);
!
         /*      We keep a pair of addresses. rcv_saddr is the one
         *      used by hash lookups, and saddr is used for transmit.
         *
         *      In the BSD API these are the same except where it
--- 459,471 ----
        if (addr_len < sizeof(struct sockaddr_in))
                return -EINVAL;

+       chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);
+
        snum = ntohs(addr->sin_port);
        if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
                return -EACCES;

        /*      We keep a pair of addresses. rcv_saddr is the one
         *      used by hash lookups, and saddr is used for transmit.
         *
         *      In the BSD API these are the same except where it
***************
*** 483,493 ****
        sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr;
        if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret ==
RTN_BROADCAST)
                sk->saddr = 0;  /* Use device */
!         else if(chk_addr_ret != RTN_LOCAL){
!               err = -EADDERNOTAVAIL;
!               goto out;
!       }
!
        /* Make sure we are allowed to bind here. */
        if (sk->prot->get_port(sk, snum) != 0) {
                sk->saddr = sk->rcv_saddr = 0;
--- 483,489 ----
        sk->rcv_saddr = sk->saddr = addr->sin_addr.s_addr;
        if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret ==
RTN_BROADCAST)
                sk->saddr = 0;  /* Use device */
!
        /* Make sure we are allowed to bind here. */
        if (sk->prot->get_port(sk, snum) != 0) {
                sk->saddr = sk->rcv_saddr = 0; 




Discussion?  Please personally CC me <[EMAIL PROTECTED]> as I am not
currently subscribed to the linux-kernel list.

Thanks.

--
Matthew Peterson
Software Engineer
Caldera Systems, Inc
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
Please read the FAQ at http://www.tux.org/lkml/

Reply via email to