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 <mpeterson@caldera.com> 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 majordomo@vger.kernel.org Please read the FAQ at http://www.tux.org/lkml/
This archive was generated by hypermail 2b29 : Mon Oct 23 2000 - 21:00:13 EST