[erlang-questions] unix domain sockets with abstract namespace: can't use all 108 bytes

Raimo Niskanen raimo+erlang-questions@REDACTED
Tue Mar 28 12:05:09 CEST 2017

On Mon, Mar 27, 2017 at 04:03:40PM +0000, Bekes, Andras G wrote:
> Hi All,
> I need to communicate with unix domain sockets using the abstract namespace and the server (which is not under my control) opens the port with all 108 bytes of the path used.
> If I understand it correctly, the server/client can decide to indicate the number of actual bytes used in the 3rd parameter to the bind/connect syscalls (this what Erlang does), but it is also possible to use all 108 bytes and fill the unused part with 0 bytes (this is what my server does).
> http://man7.org/linux/man-pages/man7/unix.7.html

That is correct.  The third argument shall always be the size of the
address structure.

> Apparently, I can fill the path with 0 bytes up to 107 only. If I try to pass a 108-byte address to gen_tcp:connect, I get a badarg exception:

Yes.  Since it is so unspecified whether the sun_path should be zero
terminated or not, inet_drv tries to do something sensible.  It first
zeros the whole sun_path, which on linux is 108 bytes, and then copies the
whole given address binary into it.  But if the binary is longer than 107
bytes it is rejected since that might overwrite the last zero, which might
be dangerous if the kernel was expecting a zero terminated address.  And
the length is set to the length of the binary (without zero termination)
since that seems to be expected for file names.

I see no good way to know for all platforms if the address is supposed to
be zero terminated or not.  Linux utilizes the special case that if the
first byte is zero then it is not zero terminated.  I do not know if that
is a safe indicator on all platforms.

An fix that sounds safe and would work in this case is to check if the
last byte is zero then allow it to fill sun_path and use its actual length.

A riskier fix would be to allow it to fill sun_path and use its acual
length if the first byte is zero since that is what Linux says.
Riskier since *BSD says it should be zero terminated and the calculated
length to use should not count the zero termination.

/ Raimo Niskanen, Erlang/OTP

> > Sun_path_length=108.
> 108
> > UDS_path = <<"whatever">>.
> <<"whatever">>
> > Fill_length = 8*(Sun_path_length-byte_size(UDS_path)-1).
> 792
> > Address = {local,<<0, UDS_path/binary,0:Fill_length>>}.
> {local,<<0,119,104,97,116,101,118,101,114,0,0,0,0,0,0,0,
>          0,0,0,0,0,0,0,0,0,0,0,...>>}
> > Port = 0.
> 0
> > gen_tcp:connect(Address,Port,[local],infinity).
> (<0.236.0>) call gen_tcp:connect({local,<<0,119,104,97,116,101,118,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
>          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
>          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
>          0,0,0,0,0,0,0,0,0,0,0,0,0>>},0,[local],infinity)
> (<0.236.0>) call gen_tcp:connect1({local,<<0,119,104,97,116,101,118,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
>          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
>          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
>          0,0,0,0,0,0,0,0,0,0,0,0,0>>},0,[local],false)
> (<0.236.0>) call gen_tcp:try_connect([{local,<<0,119,104,97,116,101,118,101,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
>           0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
>           0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
>           0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>}],0,[],false,local_tcp,{error,einval})
> (<0.236.0>) returned from gen_tcp:try_connect/6 -> {error,einval}
> ** exception exit: badarg
>      in function  gen_tcp:connect/4 (gen_tcp.erl, line 149)
> (<0.236.0>) returned from gen_tcp:connect1/4 -> {error,einval}
> (<0.236.0>) exception_from {gen_tcp,connect,4} {exit,badarg}
> If I reduce the path to 107 bytes, it works. With strace, I can see the connect syscall:
> connect(19, {sa_family=AF_FILE, path=@"whatever"...}, 109) = -1 ECONNREFUSED (Connection refused)
> When I strace the official client of this server, the 3rd parameter to the connect syscall is 110 (108 + 2), regardless of the actual length of the path.
> Apparently, with Erlang it is not possible to use all 108 bytes. I should only get a badarg error at 109 bytes, not 108.
> Seems to me that this is a bug in the Erlang implementation. What do you think?
> Thank you very much,
> Andras G. Bekes
> _______________________________________________
> erlang-questions mailing list
> erlang-questions@REDACTED
> http://erlang.org/mailman/listinfo/erlang-questions


/ Raimo Niskanen, Erlang/OTP, Ericsson AB

More information about the erlang-questions mailing list