aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorMichael Santos <[email protected]>2011-05-24 08:02:25 -0400
committerHenrik Nord <[email protected]>2011-05-24 14:17:03 +0200
commit169080db01101a4db6b1c265d04d972f3c39488a (patch)
tree4937485210d9c6397deec37540109a9eea11c00f /lib
parent7ae73012553fc54e84ad00fc00f7940cabf1edbb (diff)
downloadotp-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')
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl1
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),