diff options
author | Michael Santos <[email protected]> | 2011-05-24 08:02:25 -0400 |
---|---|---|
committer | Henrik Nord <[email protected]> | 2011-05-24 14:17:03 +0200 |
commit | 169080db01101a4db6b1c265d04d972f3c39488a (patch) | |
tree | 4937485210d9c6397deec37540109a9eea11c00f /lib/kernel | |
parent | 7ae73012553fc54e84ad00fc00f7940cabf1edbb (diff) | |
download | otp-169080db01101a4db6b1c265d04d972f3c39488a.tar.gz otp-169080db01101a4db6b1c265d04d972f3c39488a.tar.bz2 otp-169080db01101a4db6b1c265d04d972f3c39488a.zip |
inet: error if fd does not match socket domain
If an IPv4 fd is opened as an IPv6 socket, unexpected behaviour can
occur. For example, if an IPv4 UDP socket is opened and passed into
Erlang as an IPv6 socket, the first 3 bytes (corresponding to 1 byte
representing the protocol family, 2 bytes set to the port) are stripped
from the payload. The cause of the UDP payload truncation happens in
inet_drv.c:packet_inet_input when a call to inet_get_address fails
silently because the family is set to PF_INET6 but the buffer len is
the size of an IPv4 struct sockaddr_in.
Prevent this behaviour by checking that the protocol family of the file
descriptor matches the family of the requested Erlang socket.
{ok, S1} = gen_udp:open(0, [binary, inet]),
{ok, FD} = inet:getfd(S1),
{ok, Port} = inet:port(S1),
{ok, S} = gen_udp:open(Port, [binary, {fd, FD}, inet6]),
{ok, C} = gen_udp:open(0, [binary]),
Msg = <<1,2,3,4,5>>,
gen_udp:send(C, "127.0.0.1", Port, Msg),
receive
{udp, S, _, _, Msg} -> ok;
{udp, S, _, _, NewMsg} -> {error, Msg, NewMsg}
end.
This test results in: {error,<<1,2,3,4,5>>,<<4,5>>}
Thanks to Andrew Tunnell-Jones for finding the bug and the test case!
Diffstat (limited to 'lib/kernel')
-rw-r--r-- | lib/kernel/test/gen_udp_SUITE.erl | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index d8a5519195..b734d7fd98 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -400,6 +400,7 @@ open_fd(Config) when is_list(Config) -> {ok,S1} = gen_udp:open(0), {ok,P2} = inet:port(S1), {ok,FD} = prim_inet:getfd(S1), + {error,einval} = gen_udp:open(P2, [inet6, {fd,FD}]), {ok,S2} = gen_udp:open(P2, [{fd,FD}]), {ok,S3} = gen_udp:open(0), {ok,P3} = inet:port(S3), |