Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AF_UNIX abstract on Windows do not work #4240

Open
amoldeshpande opened this issue Jun 27, 2019 · 37 comments
Open

AF_UNIX abstract on Windows do not work #4240

amoldeshpande opened this issue Jun 27, 2019 · 37 comments
Labels

Comments

@amoldeshpande
Copy link

amoldeshpande commented Jun 27, 2019

  • Your Windows build number: (Type ver at a Windows Command Prompt)
    18362.175
  • What you're doing and what's happening: (Copy&paste the full set of specific command-line steps necessary to reproduce the behavior, and their output. Include screen shots if that helps demonstrate the problem.)
    Trying to create an "abstract" namespace AF_UNIX application.
  • What's wrong / what should be happening instead:
    connect always returns EINVAL, regardless of what I try.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <afunix.h>
#include <stdio.h>

typedef SOCKET fd_t;
#define INVALID_FD INVALID_SOCKET

int socketpair(int domain, int type, int protocol, fd_t sv[2])

{
	SOCKET fd0 = INVALID_FD;
	SOCKET fd1 = INVALID_FD;
	SOCKET fdListen = INVALID_FD;
	struct sockaddr_un sa;
	int  len = 0;
	static int counter = 666;

	memset(&sa, 0, sizeof sa);
	sa.sun_family = AF_UNIX;
	_snprintf_s(sa.sun_path, ARRAYSIZE(sa.sun_path),_TRUNCATE, " ./xyx-%d-%d", GetCurrentProcessId(),counter++);
	len = sizeof(sa);
	sa.sun_path[0] = 0;

	if (domain != AF_UNIX || type != SOCK_STREAM || protocol != PF_UNSPEC)
	{
		return -1;
	}
	fdListen = socket(domain, type, protocol);// WSASocketW(domain, type, protocol, NULL, 0, 0);
	if (fdListen == INVALID_SOCKET)
	{
		goto Error;
	}
	printf("before bind address %s\n",sa.sun_path+1);
	if (bind(fdListen, (struct sockaddr *)&sa, len) == SOCKET_ERROR) {
		goto Error;
	}
	if (listen(fdListen, 5) == SOCKET_ERROR) {
		goto Error;
	}
	fd0 = socket(domain, type, protocol);
	if (fd0 == INVALID_SOCKET)
	{
		goto Error;
	}
	len = sizeof(sa);
	getsockname(fdListen, (struct sockaddr*)&sa, &len);
	printf("bound address %s\n",sa.sun_path+1);
	if (connect(fd0, (const struct sockaddr*)&sa, len) == SOCKET_ERROR)
	{
		fprintf(stderr,"connect error %d\n",WSAGetLastError());
		goto Error;
	}
	{
		int addrLen = sizeof(sa);;
		fd1 = accept(fdListen, (struct sockaddr*) & sa, &addrLen);
	}
	if (fd1 == SOCKET_ERROR)
	{
		goto Error;
	}

	sv[0] = fd0;
	sv[1] = fd1;
	closesocket(fdListen);
	printf("success\n");
	return 0;
Error:
	if (fd0 != INVALID_FD)
	{
		closesocket(fd0);
	}
	if (fd1 != INVALID_FD)
	{
		closesocket(fd1);
	}
	if (fdListen != INVALID_FD)
	{
		closesocket(fdListen);
	}
	return -1;
}
int main(int argc, char **argv) {
	
	fd_t x[2];
	WSADATA wsd;
	WSAStartup(WINSOCK_VERSION,&wsd);
	socketpair(AF_UNIX,SOCK_STREAM,0,x);
}

@therealkenc
Copy link
Collaborator

I almost posted this one myself sometime last year after having burned an evening trying to use abstract names. [The announcement blog doesn't say they aren't supported, although no socketpair() makes for a unsubtle hint.] I ended up not posting after I came to the uncomfortable conclusion the ask isn't strictly speaking WSL actionable (it is a win32 feature). Happy to hear I'm not the only one who tried tho.

Heads up we lost named AF_UNIX Windows interop in WSL2 (for now anyway). But even if we get that back 🙏, the fact that WSL2 is not in the same network namespace (nvm mount namespace) as win32 speaks to why abstract names is hard.

For time being, the way in and out of WSL (notwithstanding extreme unsupported measures) is through interop stdin/stdout/stderr and AF_INET.

@amoldeshpande
Copy link
Author

Thanks @therealkenc , but the blog post does explicitly state "The second category is the ‘abstract’ socket address where the first character in ‘sun_path’ is a null byte. Windows implementation of AF_UNIX socket can also accept abstract addresses".

I am not really interested in interop with WSL, and while I don't see why they direct support for Winsock here, I hope it reaches someone who cares.

There's some real strangeness going on in this "feature" because I can run the code from
https://gist.github.com/mattn/6b6bd66ff15e95ab0b241a578023e1ed
and it will succeed outside a debugger but not within windbg. But that's an issue for another day.

I guess AF_INET on loopback is always an option for me in my specific use-case.

@therealkenc
Copy link
Collaborator

but the blog post does explicitly state

Indeed, it does; thanks. I knew there must have been a reason I spent so long trying to make it work.

I am not really interested in interop with WSL, and while I don't see why they direct support for Winsock here, I hope it reaches someone who cares.

I actually don't know the right place to reach someone who might care. I do hope someone does. Windows SDK forum maybe? [Noting that I didn't post there at the time either, and punted AF_INET pretty quick.]

My scenario at the time was interop with WSL though. If you are pure-play win32, I guess SOP would be win32 pipes.

Closing with tag question, since WSL is not the use case. Appreciate the post though, since it's a pretty good question regardless.

@amoldeshpande
Copy link
Author

Well, the blog post explicitly points to this issue tracker as a place to provide feedback for AF_UNIX on Windows, and the forums have always been beyond useless. So, I'd like it left open for a real answer if that's possible. thanks.

@benhillis
Copy link
Member

Let's leave this open, it was our team that did the AF_UNIX work.

@benhillis benhillis reopened this Jun 27, 2019
asveikau added a commit to asveikau/pollster that referenced this issue Aug 16, 2019
What I am seeing on Win10 18362 is that a process cannot see another
process's abstract sockets, connect(2) fails and bind(2) works
uniquely across multiple processes.

After debugging this issue and concluding the above, I found this:

microsoft/WSL#4240

So it seems I am not the only one to note it.
@jabedude
Copy link

Heads up we lost named AF_UNIX Windows interop in WSL2 (for now anyway). But even if we get that back 🙏, the fact that WSL2 is not in the same network namespace (nvm mount namespace) as win32 speaks to why abstract names is hard.

@therealkenc what do you mean by that?

Also, how is WSL connecting to the 9P server to share the Linux filesystem now? I thought it was using a Unix socket in /run/WSL/_interop.

@therealkenc
Copy link
Collaborator

therealkenc commented Sep 11, 2019

what do you mean by that?

I mean, we lost named AF_UNIX Windows interop in WSL2 (for now anyway). [edit, correction: that's assuming we ever had AF_UNIX Windows interop. It looks like not; I incorrectly assumed otherwise. The OP ask is abstract sockets in Windows.]

Also, how is WSL connecting to the 9P server to share the Linux filesystem now?

Wouldn't know. Probably a hyper-v socket, but that's only a guess.

I thought it was using a Unix socket in /run/WSL/_interop.

That path is not on 9p. Quick look shows /run/WSL/*_interop is accessed by /init not a Windows process.

@amoldeshpande
Copy link
Author

can we please not bring WSL into this ? I know this is a WSL issue tracker, but I specifically filed a Windows bug. If you have similar WSL issues, please separate them. thanks.

@heaven-hq
Copy link

I also encountered this problem, AF_UNIX abstract on Windows, but connect always returns EINVAL,
Is there any solution at the moment?

@sigiesec
Copy link

I also have problems with named AF_UNIX sockets, bind & listen & select work, but when I call accept in a response to a successful read select, I mysteriously get a WSAENOTSOCK error. I was not able to find any example code for AF_UNIX sockets on Windows. Do you have some working examples (named and/or abstract)?

This doesn't look like the right place to report this, since it is unrelated to WSL, but I am also missing a better feedback channel.

@Myriachan
Copy link

I have this problem as well: non-abstract AF_UNIX sockets work fine, but connect fails with WSAEINVAL with abstract AF_UNIX sockets.

The entire reason I am doing this is so that I can implement my own socketpair so I can interrupt a select/WSAPoll loop. So if you implement socketpair in WinSock, that'd work, too.

By the way, if you do implement socketpair in Win32, please add something equivalent to Linux's SOCK_CLOEXEC to it, which would atomically set the socket as non-inheritable. (Compare WSASocket's WSA_FLAG_NO_HANDLE_INHERIT.)

@Myriachan
Copy link

This feature is simply not implemented. The AfUnixTlConnect function of afunix.sys checks whether the address is abstract, and if it is, does a trace log of [0x%08x] connect to abstract address then returns STATUS_INVALID_PARAMETER, which becomes WSAEINVAL in WinSock.

@microsoft microsoft deleted a comment from amoldeshpande Nov 6, 2019
@jabedude
Copy link

jabedude commented Nov 6, 2019

Why does this blog post from Microsoft claim that "Windows implementation of AF_UNIX socket can also accept abstract addresses" then? And why is @microsoft deleting comments?

@amoldeshpande
Copy link
Author

well, that comment was just me ranting, so it definitely deserved to be deleted :) Nothing useful was lost in that deletion.

@luisfavila
Copy link

Will this ever be worked on?

@emmenlau
Copy link

Oh and maybe someone can correct the original blog post at https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/? I've lost a day's work due to this (know) limitation :-(

@sunilmut
Copy link
Member

Windows implementation of AF_UNIX does not support abstract sockets (as already established here so far) and we have very less desire to implement it since it lacks the Windows security model (abstract unix sockets cannot be secured).

The blog post is incorrect and we take responsibility for that (we will correct it). And, we do apologize for the confusion caused here.

@emmenlau
Copy link

Thanks @sunilmut !

@Myriachan
Copy link

@sunilmut The entire reason I tried to use abstract sockets was so that I could interrupt select. The only decent way to interrupt select is to send a byte to one of the sockets it's using. But this requires a loopback socket, which without a socketpair API can only be created by binding a socket to a localhost port and connecting to it. I didn't want to create an actual TCP port, so I used AF_UNIX instead. I wanted to use abstract sockets so that there wasn't an object in the filesystem sticking around.

As for the security issue, the way I got around the problem of other processes connecting to my socket in the timing window was to use SIO_AF_UNIX_GETPEERPID to verify that I am talking to myself. So even without the ability to set ACLs on abstract sockets, it would've been secure.

All this could be avoided with a socketpair API in WinSock.

(Yes, you can queue a user-mode APC to a select thread, but there's no well-defined method to cause the select to abort and return from that APC.)

@Zingam
Copy link

Zingam commented May 19, 2020

@sunilmut So there are no abstract sockets in Windows and I wasted a couple of days and there are also no docs about AF_SOCKET here: https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-start-page-2

Very nice! Maybe the doc issues could be rectified too?

@davidebeatrici
Copy link

davidebeatrici commented Jan 12, 2022

Your solution is indeed excellent and probably the best right now.

The only thing I would do differently is use GetTempFileName() to generate the filename. The function should guarantee a unique string, the only limitation is the lack of a custom prefix (it's always .TMP).

@dlenski
Copy link

dlenski commented Jan 12, 2022

The only thing I would do differently is use GetTempFileNameA() to generate the filename. The function should guarantee a unique string, the only limitation is the lack of a custom prefix (it's always .TMP).

Thanks! That's a great addition. Will include that when I try to contribute it back upstream to https://github.com/ncm/selectable-socketpair/blob/master/socketpair.c

@davidebeatrici
Copy link

Sure, no problem!

jollaitbot pushed a commit to sailfishos-mirror/openconnect that referenced this issue Jan 13, 2022
Windows forces us to use named-path Unix sockets.  Generating a path in the
temporary directory, combining current high-res time and PID, seems like a
less-bad option.

On GitHub, a commenter
[suggested](microsoft/WSL#4240 (comment))
that it would be better to use
[GetTempFileName](https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettempfilenamea)
here. However, that function:

- Only adds 16 bits of time-based random bits,
- Will currently fail if there aren't 14 characters available for the filename,
- Might conceivably generate paths longer than UNIX_PATH_MAX, and
- Offers no other apparent offsetting advantages

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
@davidebeatrici
Copy link

Is the socket file not deleted when closesocket() is called?

@dlenski
Copy link

dlenski commented Feb 2, 2022

Is the socket file not deleted when closesocket() is called?

It is not, in the Windows 10 implementation. My temp directory is littered with size-0 files that were Unix domain sockets.

@davidebeatrici
Copy link

Solution: call DeleteFile() right after connect().

jollaitbot pushed a commit to sailfishos-mirror/openconnect that referenced this issue Feb 4, 2022
…eeded

Small follow-up improvement to
https://gitlab.com/openconnect/openconnect/-/merge_requests/320, which made
dumb_socketpair() able to use Unix-domain sockets, on those Windows versions
that support them albeit only with named paths.

This was suggested as a way to prevent the Windows dumb_socketpair()
implementation from leaving behind size-0 files, even if normally only in
temporary directories.

See original suggestion at
microsoft/WSL#4240 (comment).

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
jollaitbot pushed a commit to sailfishos-mirror/openconnect that referenced this issue Feb 11, 2022
…eeded

Small follow-up improvement to
https://gitlab.com/openconnect/openconnect/-/merge_requests/320, which made
dumb_socketpair() able to use Unix-domain sockets, on those Windows versions
that support them albeit only with named paths.

This was suggested as a way to prevent the Windows dumb_socketpair()
implementation from leaving behind size-0 files, even if normally only in
temporary directories.

See original suggestion at
microsoft/WSL#4240 (comment).

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
@GMC254
Copy link

GMC254 commented May 16, 2022

Oh and maybe someone can correct the original blog post at https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/? I've lost a day's work due to this (know) limitation :-(

That misleading blogpost! Lost 2 days.

@ioquatix
Copy link

ioquatix commented Oct 8, 2022

Please implement correct support for socketpair. The documentation and lack of support is truely frustrating and time consuming.

dlenski added a commit to dlenski/selectable-socketpair that referenced this issue Oct 4, 2023
This PR is based on the improvements we made in OpenConnect in
https://gitlab.com/openconnect/openconnect/-/merge_requests/320.

Unfortunately, and maddeningly, it's possible for the local IPv4 routes
(127.0.0.0/8) to be deleted on Windows; this will prevent dumb_socketpair()
from working in its current form. Using AF_UNIX sockets

- AF_UNIX/SOCK_STREAM became available in Windows 10:
  https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows
- There appears to be no other documentation whatsoever of Windows's support
  for AF_UNIX sockets.
- Contrary to the claims of that blog post, abstract sockets
  (filesystem-independent) are not implemented:
  microsoft/WSL#4240 (comment)

In order to deal with the above weaknesses, the approach taken here is
to first try creating an AF_UNIX socketpair, and then to fallback to
AF_INET if it fails. Furthermore, because the AF_UNIX socketpair
requires a real, writable filesystem path, it tries binding to each
of the following before giving up on AF_UNIX:

1. GetTempDir() \ (filename including PID and 64-bit time ticks)
2. GetWindowsDirectory() \ Temp \ (...)
3. C:\TEMP \                      (...)
4. . \                            (...)

Based on testing so far, this implementation appears to be robust and to
avoid the problems with deleted IPv4 localhost routes.

Also adds a stub for the <afunix.h>, which defines `UNIX_PATH_MAX` and
`struct sockaddr_un`.  MinGW lacks this header, but other FLOSS projects
show how to embed the needed definitions:

- MisterDA/ocaml@5855ce5
- https://github.com/curl/curl/blob/curl-7_74_0/lib/config-win32.h#L725-L734
@halifir
Copy link

halifir commented Dec 28, 2023

btw
The unnamed AF_UNIX socket does not work as well.

Windows implementation of AF_UNIX does not support abstract sockets
since it lacks the Windows security model (abstract unix sockets cannot be secured).

it would be nice of the unnamed AF_UNIX socket may be changed to a working state. I dont see an security problem, because the used internal name (handle) can be calculated by the members of microsoft themself. no one can do it better and more secure than a microsoft member.

To get more secured sockets for internal communication it would be great to get the unnamed AF_UNIX sockets working.
The other way to open two sockets on a arbritayr ports is always less secure.
So to "not implement" abstract or unnamed sockets to avoid security problems is not a solution, because there is no documented known secure solution available on windows, isnt it?

Source:
https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/?nsl_bypass_cache=1691bb3186187e54c37d7a6cd3e209af#comments
"Lastly, ‘unnamed’ sockets, where the socket is bound to a pathname with no name. This is also supported on Windows unix socket implementation."

But unnamed sockets with length "2" (just sun_family=AF_UNIX not path) lead into the same not available error message.

@RivenSkaye
Copy link

As we've hit 2024, the blog post was not yet rectified
image
There's a comment beneath it from someone whose name I don't see in this entire thread. Can someone please pick up the work of either fixing the blog post, or getting abstract sockets to work upstream rather than with robust workarounds?

@nathnial
Copy link

nathnial commented Jul 25, 2024

where to put this afunix.h file.

@halifir
Copy link

halifir commented Jul 25, 2024

The file afunix.h is part of visual studio / windows kits / wsdk. If not beside winsock2.h or stdio.h on your disk, you may need sdk (Software development kit) / visual studio updates.

The file afunix.h is an include file to get header definitions in your code. You should not deliver this file.

@ioquatix
Copy link

@keith-horton @CatalinFetoiu @OneBlue folks are you able to address this issue and the incorrect blog post? This is causing a lot of confusion, and it's been ~5 years since the issue was reported.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests