Hacker Newsnew | past | comments | ask | show | jobs | submit | ryanprichard's commentslogin

Regarding a public API, this GitHub comment suggests that people at Microsoft are working on it.[1] Of course, Microsoft can't commit to anything. As the winpty maintainer, I hope some kind of public API emerges to reduce my maintenance burden and make winpty more robust and efficient.

Aside: About a year ago, I studied how the console handles worked (especially in relation to console attach/detach/alloc and CreateProcess), and I discovered a bunch of interesting things. For example, the "fake" handles were inherited regardless of the bInheritHandles parameter to CreateProcess, and an entire "ConsoleHandleSet" was inherited if a process attached to another process' console. Real handles in Win8 seemed to be either "bound" to a particular input/screen buffer or "unbound" so they worked with any attached console. It was possible to have a console open with no attached processes.

I tried to formalize the behavior I observed here: https://github.com/rprichard/win32-console-docs

In the course of testing, I found some neat bugs like:

- A small program that blue-screens Vista

- The inheritable flag on a console handle can be changed on any Windows version, except for Windows 7.

- CreateProcess has an undocumented(?) behavior where it duplicates stdio handles into the new process rather than inherit them. (The handle values will generally change.) Up until Windows 8.1, a stdio handle of INVALID_HANDLE_VALUE was duplicated into a true handle to the parent process. (Because INVALID_HANDLE_VALUE is actually the GetCurrentProcess() pseudo-handle, you see.)

- Assorted inconsistencies in Windows XP and WOW64 (probably fixed in newer OSs).

I'm not sure how much confidence I have in the spec. It is backed by a big test suite, but there are so many cases to consider.

[1] https://github.com/Microsoft/BashOnWindows/issues/111#issuec...


> winpty

Cool. There's a third option that you might want to consider for winpty. (I was experimenting with it before I left Microsoft.)

The basic idea is to use a DLL shim to provide your own console API implementation for a process and its children --- you can replace the system console API with your own by shimming DLL import and export tables. You'd use your own type of pseudohandle for your fake console handles; programs written to work with the old console pseudohandles should work correctly with your pseudohandles, provided you've hooked the relevant HANDLE-using APIs.


Yeah, I considered that route, but I was concerned that it'd be unreliable -- maybe with other programs doing clever tricks with import/export tables, or maybe with antivirus. I can't think of a specific reason it wouldn't work, though. I think it'd have to override CreateProcess to propagate the API hook. IIRC, ConEmu's CreateProcess starts a child in a suspended state so it can install its hook before resuming the child. Maybe it'd have to hook GetProcAddress, too.

I was assuming I'd use genuine console handles, but recognize that they're associated with the special console, so divert their API calls.

Maybe the technique would make programs slower. I know that's a complaint people have about ConEmu.

There's a similar (4th?) technique I've considered -- instead of hooking every process attached to the console, hook APIs in the conhost process and reimplement the internal protocol. It should avoid the performance problems and confine the hackiness to one address space. The trouble is that the protocol is undocumented. A small change could break everything without warning, but MS could also redesign the whole thing, making a fix impossible.


I also tried using the console accessibility APIs [1] to at least synchronize scraping and forwarding to the pty. The problem with this approach is that the console code issues EVENT_CONSOLE_UPDATE_REGION and such with its internal locks held, so attempting to read from the console from inside the accessibility handler deadlocks.

[1] https://msdn.microsoft.com/en-us/library/ms971319.aspx


To do that, you have to attach the conhost.exe process to its own console with AttachConsole, right? I tried that and also noticed the deadlock. An out-of-context handler avoids the deadlock, but then it's not synchronized.

The other interesting problems I found with that API were: (1) when editing an input line, EVENT_CONSOLE_CARET notifications were delayed, (2) if I hit ESC when editing an input line, the line would clear, but there'd be no update-region notification, and (3) it's impossible to distinguish between a call to ScrollConsoleScreenBuffer and the whole buffer scrolling because we've reached the end. ScrollConsoleScreenBuffer might scroll only part of the buffer.

winpty doesn't use the WinEvents API (yet), but it might be good enough to reduce polling when the console is idle.


> - A small program that blue-screens Vista

You mean like on current up-to-date versions of Vista and Server 2008? With a PoC on the github page? You realise that you have found a security vulnerability and are disclosing it publicly, right? Userspace must never crash the kernel, even if not further exploitable, especially so if it's possible for an unprivileged user. Be responsible, send a mail to secure@microsoft.com


Yes, it's a tiny program that (1) detaches the console, (2) attaches a new console, (3) closes all screen buffer handles, then (4) creates a new screen buffer. The fourth step caused a BSOD on Vista and Server 2008. AFAIK, they were up-to-date.

I did report it to Microsoft before making it public. The reply was:

> Thank you for contacting the Microsoft Security Response Center (MSRC). I would suggest trying on a local VM to confirm BSOD. However, this currently is just a local DOS, which would would not be something we would investigate further. If you have any additional information on how this could be further used to exploit another user or a remote DOS, please let us know and we will look into it.

> For an in-depth discussion of what constitutes a product vulnerability please see the following:

> "Definition of a Security Vulnerability" <https://technet.microsoft.com/library/cc751383.aspx>

>Again, we appreciate your report.


I might be suffering from reverse nostalgia, but it was never hard to bluescreen Vista, and I never considered those issues worth reporting.


Just debugged it and it looks like a NULL pointer read in CSRSS, in winsrv!SrvCreateConsoleScreenBuffer.


In fact, the same bug exists in XP, but the NULL page is mapped in XP which is why it does not BSoD. So far I have not seen writes, only reads.

Update: it looks like the NULL pointer is accessed several times in the code. They mostly are 16-bit accesses, so it is probably not addresses. They seems to be in font-related code.


Yes. Please report these bugs!


FWIW, the tis-interpreter doesn't flag that code (aside from the missing semicolon). I think you're right, though, that it has UB.


If you haven't seen it, I'd also recommend looking at the excel1040[1] spreadsheet. It's been developed for about 20 years by a single author, AFAICT. It has numerous forms, schedules, and worksheets, and it makes aggressive use of formulas and locked cells to ensure that calculations are correct. The spreadsheets closely resemble the actual forms, though I don't think people are actually mailing them in as-is.

[1] https://sites.google.com/site/excel1040/


PSA: i tried this out and its very basic. so basic that it doesnt even cover dcap deductions.


I tried it on this bit of code, but it didn't detect a type mismatch. Is it supposed to?

  def foo(n: int):
      pass
  def bar():
      foo("123")
It does detect this mismatch:

  def foo(n: int):
      pass
  foo("123")


This is intended behavior, actually! By default, mypy doesn't type check the interior of functions that don't have any type annotations. This lets you slowly introduce types to a large codebase without having to convert everything at once (or even file by file). Adding a type annotation to "bar" will cause mypy to check it:

  def foo(n: int):
      pass
  def bar() -> None:
      foo("123")

  >> main: note: In function "bar":
  >> main:4: error: Argument 1 to "foo" has incompatible type "str"; expected "int"


_Generic might not work so well to handle int vs double vs pointer-to-T. Apparently, even unselected associations must type-check.

e.g.: Here's a simple implementation:

  enum AnyKind { AnyInt, AnyDouble, AnyStr };
  
  struct Any {
      enum AnyKind kind;
      union {
          int i;
          double d;
          const char *s;
      } u;
  };
  
  #define ANY(x) \
      _Generic((x),                                               \
          int:          (struct Any){ .kind = AnyInt, .u.i = (x) },      \
          double:       (struct Any){ .kind = AnyDouble, .u.d = (x) },   \
          const char *: (struct Any){ .kind = AnyStr, .u.s = (x) })
  
  int main() {
      ANY(1);
      ANY(1.0);
      ANY("abc");
  }
Clang gives errors like:

  error: initializing 'const char *' with an expression of incompatible type 'double'
This issue was discussed a bit on the GCC bugtracker: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64509

Qualifiers might also be an issue. My impression so far is that every combination of differently qualified type is supposed to require a different _Generic association. (GCC 5.2 and Clang 3.7 differ here.) That would require a huge number of _Generic associations, but it might be possible to strip the qualifiers using a comma operator, _Generic( (0,(x)), ... ). A comma expression is not an lvalue, so perhaps it cannot be qualified. DR423[1] askes that question.

[1] http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_423.htm


What a fantastically informative reply, thanks for this! Having not used _Generic myself, it's good to know what kind of limitations to expect.


The example does not actually use compound literals. (i.e. _arg's initializer would work in C89.) It does use two other C99 features, though -- variadic macros and a for-loop-scoped variable declaration. The biggest compatibility issue, though, are its use of GCC extensions:

- Statement expressions: e.g.: int x = ({ int y = 0; y; });

- If zero-args are allowed (e.g. bar()), then _args is 0-sized, which is also non-standard.

These GCC extensions are somewhat common. Clang has them, and (I think) EDG's frontend does too. MSVC does not have either of them, even in MSVC 2015.

That said, a compound literal might be a good way to remove the extension use, but as long as bar() returns void, the do-while(0) trick is also sufficient for replacing the statement expression.

I think this compound literal usage works:

  #define bar(...) (bar( \
      sizeof((const char*[]) { NULL, __VA_ARGS__ }) / sizeof(const char*) - 1, \
      (const char*[]) { NULL, __VA_ARGS__ } + 1))
bar() results in trailing commas. My impression is that C99 allows them in array initializers. (I saw an example in the n1256 C draft.) I don't recall whether C89 also had them. __VA_ARGS__ is expanded twice, but I think that's OK, because sizeof() only evaluates its operand when it has VLA type, and it never will. This code will work in MSVC 2013 (if not earlier).


I'm not familiar with MSVC, but when I tried this example:

  #include <stdio.h>

  void bar(int n, const char *p[]) {
    for (int i = 0; i < n; i++) {
      printf("%s\t", p[i]);
    }
    putchar('\n');
  }

  #define bar(...) (bar( \
  sizeof((const char*[]) { NULL, __VA_ARGS__ }) / sizeof(const char*) - 1, \
  (const char*[]) { NULL, __VA_ARGS__ } + 1))

  int main(/* int argc, char **argv */) {
    bar();
    bar("a");
    bar("a", "b");
    bar("a", "b", "c");
    return 0;
  }
Using the online MSVC compiler at http://webcompiler.cloudapp.net/ (which runs Visual C++ 19.00.23720.0), it failed with these error message:

  Compiled with  /EHsc /nologo /W4 /c
  main.cpp
  main.cpp(20): error C4576: a parenthesized type followed by    an 
  initializer list is a non-standard explicit type conversion syntax
  main.cpp(21): error C4576: a parenthesized type followed by an initializer
  list is a non-standard explicit type conversion syntax
  main.cpp(22): error C4576: a parenthesized type followed by an initializer list
  is a non-standard explicit type conversion syntax
  main.cpp(23): error C4576: a parenthesized type followed by an initializer list
  is a non-standard explicit type conversion syntax


If you don't need the return value, the do-while approach works as you suggested:

  #define bar(...) do {		                   	 \
	const char *_args[] = {NULL, __VA_ARGS__};       \
	bar(sizeof(_args)/sizeof(*_args) - 1, _args + 1);\
  } while (0)
If for some absurd reason you really do need to emulate a "compound statement expression" in MSVC (because you need to declare some temp variables in a macro that can be used for assignment), it turns out that it can be done with a "lambda expression":

  #include <stdio.h>

  int bar(int n, const char *p[])
  {
    int total = 0; 
    for (int i = 0; i < n; i++) {
      total += printf("%s\t", p[i]);
    }
    putchar('\n');
    return total;
  }

  #define bar(...) [](){                                       \
    const char *_args[] = {NULL, __VA_ARGS__};                 \
    return bar(sizeof(_args)/sizeof(*_args) - 1, _args + 1);   \
  }()

  int main(/* int argc, char **argv */) {
    int total = 0;
    total += bar();
    total += bar("a");
    total += bar("a", "b");
    total += bar("a", "b", "c");
    printf("total: %d\n", total);
    return 0;
  }


Compound literals were never formally added to C++.

Still, that hasn't stopped various front-ends (including GCC and Clang) from adding them to their C++ dialects. My code compiles with Clang, but not GCC. GCC complains that it's not OK to take the address of the array compound literal.

FWIW, C99 makes it clear that the object has automatic storage duration lasting until the end of the enclosing block. i.e. There shouldn't be an issue with dangling pointers.


No, _arg's initializer would not work in C89 if any of the arguments was not a constant.

  void f()
  {
    // line below is bad C90, but good C99
    int array[2] = {g(), h()};
  }
from http://www.drdobbs.com/the-new-c-declarations-initialization...


I didn't realize statement expressions were a GCC extension.

How do you do the safe min/max in MSVC? e.g.

    #define min(a,b) ({ \
      __typeof__(a) _a = (a); \
      __typeof__(b) _b = (b); \
      _a > _b ? _b : _a; \
    })
works well in GCC/Clang. MSVC has decltype(a) _a instead of__typeof__, but I didn't know it doesn't have blocks-as-expressions.


My impression is that it's impossible in MSVC's C dialect today. (Obviously there's std::min in C++.)

AFAICT, it could be done using _Generic and inline functions, if/when MSVC adds _Generic. I'd expect to see _Generic before seeing any of the GCC extensions, but I'm not aware of any commitment from MS to add it. There are some issues with _Generic and qualifiers that might slow its adoption. e.g. There's an open defect report regarding qualified rvalues (DR423), but even lvalues seem to behave differently between GCC 5.2.0 and Clang 3.7.1. GCC ignores an lvalue's qualifiers but still allows a "const int" branch. AFAICT, a const-qualified branch is never selected with GCC?

I'm wondering whether it's possible to use _Generic to require that the left and right operands have the same type (either before or after integral promotions). Qualifiers are an obvious nuisance, but the bigger problem is that even the unselected branches must still compile, and C does not have tuples.


MSVC is a c++ compiler so you should probably just use a templated inline function.


Someone just sent a patch this morning upgrading it to Clang 3.7, which is available in the Ubuntu 15.10 repository, but not earlier. There are also official x64 llvm.org binaries for 14.04 that work.

I don't actually use the program on a daily basis, but I do pull it out on special occasions. Most recently I used it while tracking down https://github.com/atom/electron/issues/3380. It's helpful because Electron/Chromium is big and I'm unfamiliar with the code.


Just built it on 15.10 and it will segfault when I do "sourceweb index" but will run fine "sourceweb ./index", seems like a path is mandatory.

All in all this is not as feature complete as source navigator, which is old but works for me better still.


SourceWeb needs a list of C++ invocations (compile_commands.json), but it ignores compiler errors, so I'm not sure how precise the invocations need to be. If all the C++ source files in a directory were naively listed, the index might still be useful. I've never actually done that, though -- I normally use the sw-btrace tool to build the JSON file.

The indexer comes up with a globally-unique name for each "symbol" it indexes. This turned out to be a hard problem for things like templates and macros. The indexer names static functions by prepending a filename, e.g. "bio_ssl.c/ssl_write". For local variables, it also appends a file offset. With templates/macros, it can determine that a single identifier corresponds to arbitrarily many different symbols, and when you right-click that identifier in the GUI, it attempts to show them all in a popup menu, which fills the entire screen.


Will this OpenSSH server be able to run interactive console programs (like cmd.exe or python.exe), or will it be limited to (say) PowerShell?

Windows doesn't have a good API for hosting a console--it's not like Unix, where a pty has a master end and a slave end. Trying to run a console program in mintty.exe (https://github.com/mintty/mintty/issues/56) or Cygwin SSHD fails for this reason. I wrote a tool, winpty, that makes a best-effort attempt to emulate a Unix pty master by scraping the console buffer, but it has some limitations, so I'm not sure Microsoft would want to use it. Maybe they would expand the console API?


I too was very skeptical. Something about posts from "The Powershell Team" about porting sshd makes me deeply cynical that they would get the integration right from a layering perspective, i.e. as if they would make it support powershell and nothing else.

Fortunately this example shows it going straight into cmd and then they invoke powershell as a next step:

    C:\Master>ssh.exe -l user@127.0.0.1
    user@127.0.0.1's password: **********
    Microsoft Windows [Version 10.0.10566]
    (c) 2016 Microsoft Corporation. All rights reserved.
    user@DEV-10566-829 C:\Users\user>powershell -File -
- https://github.com/PowerShell/Win32-OpenSSH/wiki/ssh.exe-exa...

That gives me some hope that it's being done right.


There are these two interesting commits, "Add pty mode support code":

https://github.com/PowerShell/Win32-OpenSSH/commit/55f2ec682...

and "Add ANSI parsing engine and console draw support to SSH client":

https://github.com/PowerShell/Win32-OpenSSH/commit/7aac59e52...

Something about this reminds me of ANSI.SYS.


you could run ANSI.sys in modern cmd.exe, sadly there's no ANSI.sys in Win7 anymore.

https://groups.google.com/forum/#!topic/alt.msdos.batch.nt/Y...


Cool. Looks like that is essentially listing DEVICE=ANSI.SYS in config.nt? Google results imply some things about 16-bit emulation here -- was that post about running actual DOS ANSI.SYS in a VDM running actual DOS COMMAND.COM, within a native Windows terminal?


IIRC, the command.com only bootstrap the ANSI coloring, after that you can run anything in cmd.exe


> Will this OpenSSH server be able to run interactive console programs

I would think so. Anything less would not be a real SSH server.


At least there seems to be a supported method for updating the 14.04 kernel: https://wiki.ubuntu.com/TrustyTahr/ReleaseNotes#LTS_Hardware...

Apparently, Ubuntu 14.04.2 installs a 3.16 kernel by default, and previous 14.04 installs can be updated by installing a bunch of "*-utopic" packages.


This seems like a colossal mess waiting to happen. I'm glad that I read their plan, so that I can completely avoid it.

The allure of Ubuntu LTS releases (currently 12.04 and 14.04) is the extended support cycle -- practically speaking the kernel is the biggest component of this for a lot of people.

If you use the 3.16 kernel (from Ubuntu 14.10) on 14.04, you are now on a 6 month support cycle [1]. One which doesn't even have defined dates (they're all still TBD). Now you have to keep running on the kernel upgrade treadmill to maintain support, moving to backported kernels from progressively newer Ubuntu releases every 6 months.

[1] https://wiki.ubuntu.com/Kernel/LTSEnablementStack#Kernel.2BA...


> practically speaking the kernel is the biggest component of this for a lot of people.

Really? I mean, step back from your initial gut reaction and ask yourself how many software developers could even name which version of the kernel their code runs on without checking. Most developers never make a syscall directly and, increasingly, aren't even calling something like libc directly because they use higher-level libraries.

Sure, some people really care cause they recently hit an issue with specific drivers and a few people are using a really new feature, but that's a much smaller group than the number of people running code which doesn't even depend on Linux, much less a specific point release.

Looking at the release notes, I'd say there are a LOT more people affected by real bugs which are fixed in 14.04.2 than will be affected by hypothetical bugs nobody seems to have noticed yet:

https://wiki.ubuntu.com/TrustyTahr/ReleaseNotes/ChangeSummar...


Overreacting much? The shortened support is limited to the packages you upgrade. It's a 9 month cycle with a new version available every in 6 months. Most importantly, these are just packages, they can be uninstalled of they don't work and you fall back to LTS versions. And this is all the same for 12.04.


For some reason, Chrome seems to work fine with extensions on my Ubuntu 14.04, kernel 3.13.

I agree with those saying this is completely stupid. In corporate environments, there are a lot of Ubuntu LTS, RHEL, and CentOS desktops. They won't be upgraded to >= 3.16 for years.

Edit: oh, wait, this starts in the next version.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: