Bug 141440 - bind() does not properly report an error due to wrong address type.
Summary: bind() does not properly report an error due to wrong address type.
Alias: None
Product: Fedora
Classification: Fedora
Component: kernel   
(Show other bugs)
Version: 2
Hardware: All
OS: Linux
Target Milestone: ---
Assignee: David Miller
QA Contact: Brian Brock
Depends On:
TreeView+ depends on / blocked
Reported: 2004-12-01 04:40 UTC by Sam Varshavchik
Modified: 2007-11-30 22:10 UTC (History)
3 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Last Closed: 2005-02-09 00:15:58 UTC
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---

Attachments (Terms of Use)
Test program (419 bytes, text/plain)
2004-12-09 12:22 UTC, Sam Varshavchik
no flags Details

Description Sam Varshavchik 2004-12-01 04:40:05 UTC
Observe the following strace of obviously invalid syscall sequence:

[pid  7906] socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 4
[pid  7906] fcntl64(4, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
[pid  7906] setsockopt(4, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
[pid  7906] setsockopt(4, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
[pid  7906] write(1, "REBIND: ::ffff:;0\n", 29REBIND:
) = 29
[pid  7906] bind(4, {sa_family=AF_INET6, sin6_port=htons(0),
inet_pton(AF_INET6, "::ffff:", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
[pid  7906] listen(4, 128)              = 0
[pid  7906] getsockname(4, {sa_family=AF_INET, sin_port=htons(35031),
sin_addr=inet_addr("")}, [16]) = 0

I'm creating an IPv4 socket, but then I'm trying to bind an IPv6
address to it.  This should not work.  This should fail, yet bind()
returns 0!  To add insult to injury, getsockname() shows that the
socket was bound to the port, but not to any IP address!

I think that bind() should either fail and return -1, or convert the
IPv4-mapped IPv6 address to the real IPv4 address, and bind that
( is a valid IP address on this machine).

This is kernel 2.6.9-1.6_FC2

Comment 1 Jakub Jelinek 2004-12-01 07:06:54 UTC
I don't see why this was reassigned to glibc.  socket/bind/setsockopt/listen
are all simple wrappers around the syscalls (just putting arguments in the places
where kernel expects them) and glibc doesn't have information wheter a filedescriptor is socket or not and what domain it has been created in readily
available.  Only the kernel can do something about this without performance penalty.

Comment 2 David Miller 2004-12-09 06:16:38 UTC
I'm mystified as to how this can even happen.

The write() call causes inet_autobind() to automatically
bind the socket to some port.  This causes the inet_sk(sk)->num
of the socket to be set non-zero if the write() returns success.

This should cause the subsequent bind() call to return -EINVAL
due to this check:

	err = -EINVAL;
	if (sk->sk_state != TCP_CLOSE || inet->num)
		goto out_release_sock;

As stated above, inet->num should be non-zero and therefore
we will return -EINVAL.

Can you provide a simple test program to reproduce this
problem instead of just an strace?

Comment 3 Sam Varshavchik 2004-12-09 12:22:31 UTC
Created attachment 108196 [details]
Test program

The write() is to a different file descriptor, and has nothing to do with it.

The strace from this test program is the same.	Note that is a
valid IP4 IP address for this machine, which may be a factor:

bind(3, {sa_family=AF_INET6, sin6_port=htons(0), inet_pton(AF_INET6,
"::ffff:", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
getsockname(3, {sa_family=AF_INET, sin_port=htons(32809),
sin_addr=inet_addr("")}, [16]) = 0

The bind of an IPv6 address to an IPv4 socket must fail.

Comment 4 David Miller 2005-02-09 00:15:58 UTC
We can't change this behavior, it's too risky.  I did some research and
BSD, even modern BSD such as current FreeBSD CVS, does not enforce the
sa_family value to be correct when binding.

I was very suspicious about exactly something like this when I found that,
upon scanning the entire Linux networking, ipv4 and ipv6 were basically
the only two protocols not verifying the sa_family value at bind() time.
I am certain this was a conscious decision.

If BSD doesn't enforce it, and Linux never did, it is incredibly likely
that there are many applications out there not setting up the sa_family
field for bind() calls correctly to ipv4 and ipv6 sockets.

"fixing" this, therefore, would break many applications, so we just have
to live with the current behavior.

If you would like to have a further discussion on this topic, I encourage
you to start a thread on the netdev@oss.sgi.com mailing lists so that
opinions other than ours can be voiced about such a risky change.

Comment 5 David Miller 2005-02-09 00:17:37 UTC
One final comment, in the BSD sources, where the sin_family check
would go, the code looks like this:

#ifdef notdef
		 * We should check the family, but old programs
		 * incorrectly fail to initialize it.
		if (sin->sin_family != AF_INET)
			return (EAFNOSUPPORT);

Meaning the check is there, but never enabled in the sources.  This
further supports the idea that adding this check would cause more harm
than good.

Note You need to log in before you can comment on or make changes to this bug.