|
Not sure I'll look for the other "easteregg", though I noticed that you set the new thread's impersonation token, which is presumably how you implement setuid() and friends [yes, that is how you implement them] -- is that the other easteregg? I also see that you use the last RID of SIDs as the UID/GID, and that you have hardcoded passwd(4)/group(4) entries, so you only support local users (which is fine). Oh, ah, _task_copy(). You swap stacks... I think because of course. Your execve() is real though, since you use CreateProcessAsUser(), which is good. The compromise you made is pretty neat, though obviously some things might not work well. Though I'm guessing this is working quite well for you. Your file names are weird; they often tell me nothing about what to expect to find in them. I looked for fork() because that's the difficult one to implement on WIN32. What Cygwin does is some crazy gymnastics that sometimes fails. You might know that I think fork() is "evil" [0], or if you hadn't, you do now, and I guess you're likely to agree with that take, but I'd love to hear your thoughts on that, because clearly you've thought about fork(). I've to say that you've clearly thought a lot about this, and though I've not tried it (and probably won't) you seem to have done an excellent job. [0] https://gist.github.com/nicowilliams/a8a07b0fc75df05f684c23c... |
Thank you. I needed that. I started the project in 2016 and have been obsessed with it since then. The weird thing is that I never had to use workarounds or hacks that are mentioned by the Cygwin team [0]. For instance, the select() call does map cleanly on top of the Win32 API. I just needed to use WSAWaitForMultipleEvents() instead of WaitForMultipleEvents() (the other "easteregg"). Why the Cygwin people didn't figure this out baffles me. I guess their current code base doesn't allow the rewrite. My big breakthrough was when I realized that the "inconsistent interfaces" [1] in Win32 file handles can be implemented as virtual file systems. One for each handle type (char, disk, pipe, etc). That was my "throwing away 1000 lines of code" [2] moment.
As to the weird file names, I use the file names OpenBSD uses. My rule is to always use the file name of the header (.h) file where the system call is declared in OpenBSD. I also use their struct and constant names, prefixed with "WIN_".
The "fork is evil" thing is discussed a lot in the programmers community. I myself find it quite clever. Threads are highly volatile and are very hard to program without running into race conditions. The solution is to make a copy of everything the child will be using: duplicate file descriptors, the stack, globals (rss). The kernel does all this for you in one system call. I often wonder how the people who complain about the absence of real concurrency in their programming languages [3] actually would use this feature. In my opinion the best way to use concurrency is to string individual programs into a pipeline. This will never go "evil" on you.
[0] https://cygwin.com/cygwin-ug-net/highlights.html
[1] https://www.usenix.org/legacy/publications/library/proceedin...
[2] https://skeptics.stackexchange.com/questions/43800/did-the-c...
[3] https://news.ycombinator.com/item?id=32408577