[erlang-patches] [PATCH] inet: error if fd does not match socket domain

Henrik Nord <>
Tue May 24 14:20:36 CEST 2011


On 05/24/2011 02:02 PM, Michael Santos wrote:
> 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!
> ---
>   erts/emulator/drivers/common/inet_drv.c |    4 +++-
>   lib/kernel/test/gen_udp_SUITE.erl       |    1 +
>   2 files changed, 4 insertions(+), 1 deletions(-)
>
> diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
> index 40c4a0d..ebc4469 100644
> --- a/erts/emulator/drivers/common/inet_drv.c
> +++ b/erts/emulator/drivers/common/inet_drv.c
> @@ -3709,6 +3709,8 @@ static int inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
>       /* check that it is a socket and that the socket is bound */
>       if (IS_SOCKET_ERROR(sock_name(s, (struct sockaddr*)&name,&sz)))
>   	return ctl_error(sock_errno(), rbuf, rsize);
> +    if (name.sa.sa_family != domain)
> +	return ctl_error(EINVAL, rbuf, rsize);
>       desc->s = s;
>       if ((desc->event = sock_create_event(desc)) == INVALID_EVENT)
>   	return ctl_error(sock_errno(), rbuf, rsize);
> @@ -9739,7 +9741,7 @@ static int packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len,
>   	    if (desc->active || (len != 8))
>   		return ctl_error(EINVAL, rbuf, rsize);
>   	    timeout = get_int32(buf);
> -	    /* The 2nd arg, Length(4), is ignored for both UDP ans SCTP protocols,
> +	    /* The 2nd arg, Length(4), is ignored for both UDP and SCTP protocols,
>   	       since they are msg-oriented. */
>
>   	    if (enq_async(desc, tbuf, PACKET_REQ_RECV)<  0)
> diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
> index d8a5519..b734d7f 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),
Hi

I have merged this into 'pu' as "ms/inet-socket-domain-error"

thank you for the contribution!

-- 
/Henrik Nord Erlang/OTP



More information about the erlang-patches mailing list