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

How it works #3

Open
fpqc opened this issue Sep 19, 2016 · 8 comments
Open

How it works #3

fpqc opened this issue Sep 19, 2016 · 8 comments

Comments

@fpqc
Copy link

fpqc commented Sep 19, 2016

Hi rprichard, just wondering if you have a blog or something where you explain roughly how this works. Up til wslbridge, we were doing stupid tricks like using hidden windows and stuff.

Edit: Looked through the source code a bit. I guess you are running a bash.exe instance and hiding it? I wonder if you could actually directly connect to the COM socket that bash.exe connects to and tell it to start up without actually using bash.exe at all.

@rprichard
Copy link
Owner

The only way I know of for a Windows program to start a WSL program is via the WSL bash.exe adapter program. (i.e. I've never heard of a "COM socket".) WSL bash insists that its stdin/stdout be console handles. Therefore, the wslbridge frontend starts the wslbridge backend using bash.exe, in a new, hidden console. (It's similar to how winpty creates a hidden console.) The backend's stdin/stdout file descriptors refer to the hidden Windows console, which is unused (except for debugging, possibly).

After that, everything uses plain old Unix APIs. The backend sets up a pty using forkpty; the frontend and backend set up a few TCP sockets to carry the pty traffic.

The TCP sockets are secured by (1) listening only on the loopback interface and (2) through use of a randomly-generated key that the backend must provide when connecting. The key is passed from the frontend to the backend over the command-line.

@fpqc
Copy link
Author

fpqc commented Sep 20, 2016

@rprichard There is a COM interface on the LXSSManager service that bash.exe is using to communicate with and initialize the session.

@rprichard
Copy link
Owner

Interesting. How do I see the COM interface? I do see an LxssManager service in the Services window.

@fpqc
Copy link
Author

fpqc commented Sep 20, 2016

This is all undocumented, but some of this stuff has been messed around with and done by @ionescu007 in his lxss repo (also look over the talk notes from blackhat). The proof of concept that is in that repo is mainly doing the opposite of writing a bash.exe replacement, namely having a server listening back on the COM interface and then establishing a socket on the Linux side (through /dev/lxss) to send commands back into Windows.

Nobody so far has released info reversing how bash.exe initializes the session and how it sends and receives stdio from the /bin/bash instance that it launches in the LX instance.

The devs at microsoft have said that they probably will eventually document the interface, which is still under heavy development. Mr. Ionescu said on Twitter that the latest version has a built-in way to launch Windows applications (using binfmt_misc, exes will probably get executed by a device in /dev, get sent to the bus, and then will be sent to an ntcreateprocess() function that is now attached to the COM interface.

The way the real bash.exe works (not your bridge) is by doing almost exactly what your wsl bridge does, except instead of doing it over TCP, it is doing it by some kind of communication through COM, then through the kernel, through the the WSL kernel drivers, and up into the linux instance (and back the opposite way for stdout). If I had to guess, on the Linux side, the stdio of a tty looks writing to and reading from a device in /dev. Microsoft's implementation of the tty driver probably is forwarding the virtual tty's std input and output back up into the session manager's memory, which then exposes it to the bash.exe wrapper through some kind of COM session as raw UTF-8 with all escape sequences intact. Then the wrapper's stdio is obtained by a UTF-8<->Little Endian UTF-16 translation (since this is the character encoding of conhost and indeed all of WinNT since its very first release). However this translation appears to be stripping some unhandled xterm escape sequences, like, for example, the ones associated with mouseclicks (we know this because @Maximus5, the dev behind ConEMU, has a hack of conhost that will output these mouse escape sequences, which are stripped by bash.exe, or at least that was my theory until I found that issue you posted in the winpty issues page.

You said there that there was a new console application build flag in Win10 that would allow conhost to process the escape sequences directly. If that is the case, the culprit is not bash.exe stripping out the escape sequences but actually conhost itself, because it is invoked by bash.exe in that special mode and just choosing to throw out all escape sequences it does not know how to support.

I am not sure, and I will have to get back to you when I find out.

@rprichard
Copy link
Owner

Thanks for the reference. It's interesting that LxssManager is apparently(?) OK with Win32 pipes being used for stdin/stdout/stderr. In that case, would the Linux process see pipes for stdio or would it see a tty/pty? I'm guessing it'd see pipes (assuming LxssManager actually does accept Win32 pipes). I guess wslbridge could use pipes instead of sockets, then? I imagine I'll keep it as-is to avoid undocumented APIs.

@Biswa96
Copy link

Biswa96 commented May 10, 2018

Which function first generates the port number with which the connection will be established? Backend or frontend?

@rprichard
Copy link
Owner

Frontend:

sockaddr_in addr = {};
addr.sin_family = AF_INET;
addr.sin_port = htons(0);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
const int bindRet = bind(s_, reinterpret_cast<const sockaddr*>(&addr), sizeof(addr));
assert(bindRet == 0);

@Biswa96
Copy link

Biswa96 commented Jan 10, 2019

Is it possible to replace socket with named pipe between backend and frontend?

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

No branches or pull requests

3 participants