
Being Sneaky in C - alexggordon
http://www.codersnotes.com/notes/being-sneaky-in-c
======
patrickmay
I like the original Ken Thompson sneakiness in C
([http://electronicdesign.com/dev-tools/thompson-ritchie-
and-k...](http://electronicdesign.com/dev-tools/thompson-ritchie-and-
kernighan-fathers-c)):

"Also in his Turing Award lecture, he described how he had incorporated a
backdoor security hole in the original UNIX C compiler. To do this, the C
compiler recognized when it was recompiling itself and the UNIX login program.
When it recompiled itself, it modified the compiler so the compiler backdoor
was included. When it recompiled the UNIX login program, the login program
would allow Thompson to always be able to log in using a fixed set of
credentials."

~~~
kenko
That really isn't the same thing, though. That's language-agnostic conceptual
sneakiness that happened to be implemented in C.

------
thaumaturgy
OpenBSD specifically modified malloc() a few years ago to prevent this sort of
sneakiness ([http://www.tw.openbsd.org/papers/eurobsdcon2009/otto-
malloc....](http://www.tw.openbsd.org/papers/eurobsdcon2009/otto-malloc.pdf)
[pdf]). So they route their malloc() calls through mmap() which returns
randomized pages, and free() immediately returns memory to the kernel rather
than leaving it mapped in the current process.

I'd be surprised if these changes haven't made it into FreeBSD, but afaik
Linux doesn't work this way (by default, anyway).

~~~
kazinator
If your claim is that OpenBSD routes every call to malloc/free through
mmap/munmap, it is simply not believable.

Do you have a URL to a git ... hahaha, pardon me, CVS repo?

~~~
marios
[http://bxr.su/OpenBSD/lib/libc/stdlib/malloc.c#omalloc](http://bxr.su/OpenBSD/lib/libc/stdlib/malloc.c#omalloc)
^Not the CVS repo, but close enough for those who want to check OpenBSD's
malloc implementation. The malloc.conf manpage is also an interesting read :
[http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-
current/man5/...](http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-
current/man5/malloc.conf.5)

And some context around malloc and the various techniques OpenBSD implements
to make exploitation of bugs more difficult:
[http://www.openbsd.org/papers/dev-sw-hostile-
env.html](http://www.openbsd.org/papers/dev-sw-hostile-env.html)

The tl;dr is : if your code compiles and runs on OpenBSD, chances are it will
fine on other Unices. The opposite is not necessarily true though.

~~~
comex
I don't think that source refutes the parent's point: only large allocations
go directly to mmap/munmap as opposed to being cached. Of course, there are
other anti-exploitation measures too...

------
ojn
It also makes the assumption that it's a little-endian system. On a big-endian
system, the high order byte of the timestamp would be modified, which would
probably be too obvious.

------
esmi
"In C/C++, you can use bugs in one part of a program to cause trouble in
another. That’s pretty darn underhanded."

I would argue every language has that property. But with C/C++ being so
closely tied to the ABI of the machine perhaps they are more underhanded than
others. But to me, this branding does feel a bit unfair.

Still, a fun contest and an interesting read.

~~~
spdionis
You can always cause that kind of bug, but I would argue that C/C++ is
massively more underhanded than other languages.

------
codezero
The description of the bug in surveil.txt in the source archive was a bit
easier for me to understand, really nifty :)

------
jonahx
Would setting the malloc'd memory back to the original message before freeing
it solve the problem?

~~~
kayamon
Yes. You could also memset any memory to zero once you're done with it, which
isn't a bad idea for applications with high security requirements.

~~~
TheLoneWolfling
...Except, of course, the the compiler can and will optimize away any such
memset.

Do _not_ attempt to write secure software with C / C++. It is a Bad Idea(TM).
Because what you wrote is not what gets run.

For instance: there is _no_ way to write a portable secure memset in portable
C / C++. (You can write a "secure" memset that works in all current compilers,
but that is _not_ the same thing. What doesn't get optimized now can and will
be optimized tomorrow.)

~~~
kosmic_k
So what is someone working with embedded devices for IoT supposed to do? Much
of that work is based on ARM C/C++ Compilers.

~~~
pjc50
In practice, of course, memset actually works, because it's a function and the
compiler's usage tracing is nowhere near able to spot that you don't reference
those zeros that you write.

(IoT security is doom for other reasons though, mostly UI, updatability and
cloud services)

~~~
TheLoneWolfling
For now.

And then that code you wrote now silently becomes deadly a few years down the
line.

~~~
pjc50
I would be very interested to see the compiler that can optimise away memset
across a shared library boundary.

~~~
pcwalton
LLVM can and will do it. It will assume it knows what a function named
"memcpy" (for example) does and optimizes accordingly. (Look at
TargetLibraryInfo.cpp and grep for LibFunc::memset in, for example,
SimplifyLibCalls.cpp.)

(That said, I think TheLoneWolfling is being too strong with his/her claims.
You _can_ get modern compilers to avoid dangerous optimizations; it's just not
for the faint of heart.)

~~~
TheLoneWolfling
Also: isn't that a bug? Is there something in a C / C++ standard that states
that a function named "memcpy" (for example) is necessarily the normal
function?

~~~
pcwalton
Compilers have been doing this for a long time. The optimizations that this
enables are essential for performance. They shouldn't stop; if the spec
prohibits it, the spec should change (and if it doesn't, the compilers should
ignore the spec).

~~~
TheLoneWolfling
Good to know about the first and last part.

And as for the second part... Meh. I don't see any optimizations that hard-
coding calling something named "memcpy" (or whatever) does that cannot be
enabled by looking at the actual code that gets linked. Albeit with more
difficulty.

------
amelius
Would there be a way to do this automatically? Like a "sneaky pre-compiler"?

------
itistoday2
Looking at the source, this is where the alarm bells should go off in a
reviewer's head:

    
    
        memcpy(filter->buffer, output->piu_text_utf8, sizeof(output->piu_text_utf8));
    

1\. memcpy is less safe than memmove and strncpy. strncpy should be used.

2\. The two character arrays should use the same constant in defining their
length, and that constant should be used both in the struct definitions and
here in the copy operation.

3\. The code is written in C in spite of it being 2014 at the time.

~~~
rdc12
The code is from an entry in the Underhanded C Contest, it is pretty much a
given that the entries will be written in C.

~~~
itistoday2
I am aware of that.

