Hacker News new | past | comments | ask | show | jobs | submit login
Results of recent PostScript CharString security research (vexillium.org)
63 points by acdha on June 24, 2015 | hide | past | favorite | 18 comments



Does anybody know the precise (more precise than given in the slides) reason Windows had to put a font renderer in the kernel? That's absolutely insane.

EDIT: holy jeez, this isn't even the whole thing. MS has their own first-party ttf renderer in the kernel too, what the heck?


"In the kernel" is a bit of a misnomer in Windows. The graphics subsystem is not in the NT kernel (which is a pretty-minimal microkernel), though it is within the same Win32 process as the one containing NT kernel services.

In other words: "within the kernel" from a userland perspective; in a separate security domain from NT's own perspective.


Does it execute in ring 0? I don't really understand how Windows works.


Yes, as do the rest of win32k.


Performance: NT 3 had a reputation for being sluggish so NT 4 broke that nice design by shoving anything sensitive into ring 0. Some of that was to catch up with more mature Unixes like SGI in the important technical workstation market – this was an era where things like Autodesk benchmarks drove $10+K purchases – and I'm sure Windows 95 was a big motivation.

At the time the argument was stronger since not only were processors slower but they also lacked the later optimizations for things like syscalls.


If syscalls are slow, it seems weird to put your GUI code in the kernel, requiring a syscall to access it.


It depends on how much work you're doing in that syscall: if you can collapse all of the work for font discovery, loading, rendering, determining the output parameters, communicating with the video driver, etc. into a single syscall that can be a big win relative to a classic microkernel system where each of those operations involves the overhead of crossing a process and security boundary.


Here's a better answer, straight from Microsoft - the entire document is interesting because it shows how sensitive they were both to adoption for NT vs. 95 but also how worried they were about other operating systems, particularly IBM's OS/2:

https://msdn.microsoft.com/en-us/library/cc750820.aspx

“Still, because Windows NT is a Windows-based operating system, in which all other environmental subsystems utilize the basic functions provided by Win32, and because the graphics and windowing subsystems have a very high rate of interaction with hardware (video drivers, mouse and keyboard drivers, and so forth), the Windows NT 4.0 design team decided to move that common functionality from user mode into kernel mode. In this way, the functions can be performed without shared memory buffers or paired threads, and with fewer thread and process context switches. This change as implemented in Windows NT 4.0 results in faster operation and reduced memory requirements, both visible benefits to the end user.”

“By making the Window Manager and GDI subsystems into Executive services, both operations decrease in size and improve in performance. This is largely due to the elimination of the shared memory buffers, as well as a substantial reduction in the code size and thread/process switching from the more complex client/server design. Consider, for example, the client/server transition time on a Pentium 100 which is in the order of 60-70 m seconds, whereas a kernel-mode transition is on the order of 4 to 5 m seconds. For screen graphics calls, this difference can become significant enough to be visible to the end user.”

“Moving Window Manager and GDI to kernel mode completely eliminates the buffer and related code complexities because all of the data in the client's address space is fully accessible from kernel mode. The total amount of working set memory saved with this change in the release of Windows NT 4.0 is estimated to be between 256K for machines that require few simultaneously open applications and 1 MB for users who consistently have many applications open at the same time.”

Don't miss this bit of optimism:

“Due to the modular design of Windows NT moving Window Manager and GDI to kernel mode will make no difference to the security subsystem or to the overall security of the operating system this will also have no effect on the C2 or E3 security certification evaluation, other than making it easier to document the internal architecture of Windows NT.”


Same reason they moved IO drivers to the kernel for NT 4.0, I'd guess. It was another time. Look at the WMF format, which is essentially just calls to GDI.


Great work. From looking at the PDF [1], it seems that this was done with something like IDA Pro rather than from sources. I imagine work like this would be a good candidate for the Microsoft Shared Source Initiative [2].

[1] http://j00ru.vexillium.org/dump/recon2015.pdf

[2] https://www.microsoft.com/en-us/sharedsource/


Not even the PDB symbols are available for ATMFD, probably because it is third party code originally included into Win2000.


The biggest attack vector I see here is embedded fonts; perhaps allowing browsers to download and use embedded fonts should be restricted to trusted sites too, since some font formats do contain an embedded Turing-complete language. It gives a whole new meaning to the term "web-safe fonts"...


Chrome and Firefox require all web fonts to pass the OpenType Sanitiser https://github.com/khaledhosny/ots


Turing-completeness isn't a problem per se (lots of people get this wrong) because no attacker is trying to compute something: they want to run some shellcode, or redirect an HTTP request, or display something on screen, or something like that, none of which a Turing machine can do.

The worst a Turing machine can do is run forever, which is easily prevented by limiting the number of steps it can ran.


this really misses the point/problem entirely, the problem with parsing a turing complete format is that verifying data encoded with it in the general case (as valid/non malicious/useful) is equivilent to the halting problem.

They are dangerous to parse not because they can potentially run forever, but because due to their expressiveness, it is very easy to arbitraily trigger bugs, aided by the massive nessisary complexity of most parsers.

Those two things together make avoiding logic errors invoked by malicious data, leading to exploitability essentially impossible to prevent.

Another factor is it is impossible to formally verify something that executes turing complete code.


Would a primitive recursive language be less dangerous? Well, it depends on the language.

> They are dangerous to parse not because they can potentially run forever, but because due to their expressiveness, it is very easy to arbitraily trigger bugs, aided by the massive nessisary complexity of most parsers. > Those two things together make avoiding logic errors invoked by malicious data, leading to exploitability essentially impossible to prevent.

Actually, the parsers for these languages are not too complex -- the problem is that they're written in a language ill-suited to writing parsers. The interpreters are complex, but all the exploitability is very easily avoided: by writing the interpreter in a memory-safe language.

This problem might be bug-prone, but a bug in a font interpreter should lead to whacky looking fonts, and never to remote code execution. The fact that it routinely does just shows we're using the wrong tools for the job.


there are more classes of exploits than simply memory management errors. For instance look at the laundry list of issues surrounding verification of x.509 certificates. Deciding a forged certificate is valid is catastrophic, and invokes no sort of memory related exploit at all.


X.509 certificates don't contain any Turing-complete languages, so the fact that X.509 interpreters have the same class of bugs as font interpreters, that supports my point that Turing-completeness itself is not the problem.




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

Search: