Live data from Hacker News

The Linux Backdoor Attempt of 2003 (2013)

freedom-to-tinker.com

131–140 of 144 posts

Re: The Linux Backdoor Attempt of 2003 (2013)

#131
post #29

Earlier quoted context omitted.

I would put parentheses here, I never like mixing logical operators with other types (or even different types of logical operators). While it's of course entirely redundant here, it also makes the code easier to read IMO. I think the parent's point is more convincing: why make this check only for root in the first place?

The parentheses are required if == is changed to =. == has a higher precedence than &&, but = has a lower precedence. a = b && c && d means a = (b && c && d)

Sure, my point was that even with the proper == comparison I'd still write the (now redundant) parens because I find it more readable that way.

Actually in languages like Rust with type inference that make it cheap and non-verbose to declare intermediate values I tend to avoid complicated conditions altogether, I could rewrite the provided expression like:

    let invalid_options = (options == (__WCLONE|__WALL));
    let is_root = (current->uid == 0);

    if invalid_options && is_root {
        // ...
    }
One might argue that it's overkill but I find that it's more "self-documenting" that way. I find that the more experienced I get, the most verbose my code becomes. Maybe it's early onset dementia, or maybe it's realizing that it's easier to write the code than to read it.

Of course you can do that in C as well but you have to declare the boolean variables, and in general it's frowned upon to intermingle code and variable declarations so you'd have to add them at the beginning of the function so it adds boilerplate etc...

Re: The Linux Backdoor Attempt of 2003 (2013)

#132
post #86

Earlier quoted context omitted.

If memory serves me right the CVS bug was originally discovered and exploited by a member of an infamous file sharing site. After descriptions(?) of that bug were leaked in underground circles, an east European hacker wrote up his own exploit for it. This second exploit was eventually traded for hatorihanzo.c, a kernel exploit, which was also a 0-day at the time. The recipient of the hatorihanzo.c then tried to backd…

This sounds like a very interesting tale. Are there more details written somewhere? How close to first-person is your source of information?

Not that I'm aware of, but I wish. Memory is getting hazy these days. AFAIK the kernel.org breaches were made by the kind of hackers doing it for fun and games (if you get that thing) and not the kind working for nation states. I'm sure you can (or at least, at some point could) find others who know more details at your favorite compsec conf.

Re: The Linux Backdoor Attempt of 2003 (2013)

#133
post #105

Earlier quoted context omitted.

It would break these kinds of constructs, which are common. if ((fd = open(...)) != -1) { /* do something with fd */ } else { perror("open"); } The compiler outputs a warning when you have something like "if (a = b)". If that's what you mean (it sometimes is), you have to write it "if ((a = b))" to silence the warning.

TBF, that doesn't actually work - you have to write: int fd; /* fd must be declared in order to be assigned */ if ((fd = open(...)) != -1) { /* do something with fd */ } else { perror("open"); } which would be better written as: int fd = open(...); if (fd != -1) /* etc */ It would be nice for scoping reasons to be able to write something like: if ((int fd = open(...)) != -1) /* etc */ but if ((int fd == open(...)) !=…

Exactly my thoughts, I was about to comment on that but I was too lazy so I omitted the declaration. Obviously, this is HN, so someone had to point it out ;)

Anyways, I am a bit torn about the second option. I like the idea of putting the call inside the if clause as it makes for a very explicit error handling but the uninitialized declaration is ugly. What I do in practice tends to depend on the situation but it is rarely satisfying.

Your last suggestion would be ideal, but as you said, it is invalid code unfortunately.

Maybe this

  for (int fd = open(...); fd != -1; fd = -1) {
      /* do stuff */
  }
Just kidding, don't do that.

Re: The Linux Backdoor Attempt of 2003 (2013)

#134
post #118

Earlier quoted context omitted.

It has been a long time since I make sure my codebases have `-Wall -Werror`. This bug is from 2003 both when that wasn't as common & when compiler diagnostics weren't as good/reliable.

This code would not trigger under -Wall -Werror. Try it.

I was referring to what the parent wrote:

> ITT: everyone pretending they've never burned hours troubleshooting only to find a stupid `=` instead of a `==`.

In the general case that OP was talking about, not for underhanded code, my comment holds.

Re: The Linux Backdoor Attempt of 2003 (2013)

#135
post #123
post #115

Earlier quoted context omitted.

Why would it require that much data? I always thought you wouldn't need to add or change more bytes than are in the output. Also, git hashes aren't just based on source code. You can add that data anywhere that git uses to generate the hash.

That's true of a CRC code, but hashes are a lot harder to break. Git hashes each file, and puts those hashes into a tree object, like a directory listing. Then it hashes the trees, recursively back up to the root of the repository. Finally the hash of the root tree is put in the commit object, and the commit object is hashed. Thus the two places you can put additional data to be hashed are the file contents (either i…

I'm still not following why it'd require so much data? I thought the goal was to have the commit hash collide with an existing commit hash, is that not enough?

I looked around, and it seems like the right place to hide the added data is in the "trailer" section of the commit. It's where signed-off-by lives and is used to generate the commit hash.

You might want to come up with a plausible reason for random data to go in there though. (likely using a header that wouldn't normally get printed out)

Re: The Linux Backdoor Attempt of 2003 (2013)

#136
post #105

Earlier quoted context omitted.

It would break these kinds of constructs, which are common. if ((fd = open(...)) != -1) { /* do something with fd */ } else { perror("open"); } The compiler outputs a warning when you have something like "if (a = b)". If that's what you mean (it sometimes is), you have to write it "if ((a = b))" to silence the warning.

TBF, that doesn't actually work - you have to write: int fd; /* fd must be declared in order to be assigned */ if ((fd = open(...)) != -1) { /* do something with fd */ } else { perror("open"); } which would be better written as: int fd = open(...); if (fd != -1) /* etc */ It would be nice for scoping reasons to be able to write something like: if ((int fd = open(...)) != -1) /* etc */ but if ((int fd == open(...)) !=…

C++17 has this! See https://en.cppreference.com/w/cpp/language/if.

Re: The Linux Backdoor Attempt of 2003 (2013)

#137
post #105
post #103

Earlier quoted context omitted.

It should really be forbidden by the compiler these days, or at least a very loud warning.

It would break these kinds of constructs, which are common. if ((fd = open(...)) != -1) { /* do something with fd */ } else { perror("open"); } The compiler outputs a warning when you have something like "if (a = b)". If that's what you mean (it sometimes is), you have to write it "if ((a = b))" to silence the warning.

Here's a classic:

  char *strcpy(char *d, char *s) {
      char *r = d;
      while (*d++ = *s++);
      return r;
  }
(If you don't need the return value, this becomes even nicer.)

Re: The Linux Backdoor Attempt of 2003 (2013)

#138
How would git have handled the same issue?

I imagine if Linus pushed to the remote repo, it would have said “your repo isn’t up to date”.

But AFAIK, it doesn’t have the same sort of built in checksum checkers.

If an attacker signed the commit insecurely, would git complain? Can you set git to require PGP signatures?

Probably.

Re: The Linux Backdoor Attempt of 2003 (2013)

#139
post #133

Earlier quoted context omitted.

TBF, that doesn't actually work - you have to write: int fd; /* fd must be declared in order to be assigned */ if ((fd = open(...)) != -1) { /* do something with fd */ } else { perror("open"); } which would be better written as: int fd = open(...); if (fd != -1) /* etc */ It would be nice for scoping reasons to be able to write something like: if ((int fd = open(...)) != -1) /* etc */ but if ((int fd == open(...)) !=…

Exactly my thoughts, I was about to comment on that but I was too lazy so I omitted the declaration. Obviously, this is HN, so someone had to point it out ;) Anyways, I am a bit torn about the second option. I like the idea of putting the call inside the if clause as it makes for a very explicit error handling but the uninitialized declaration is ugly. What I do in practice tends to depend on the situation but it is…

  > for (int fd = open(...); fd != -1; fd = -1) {
that doesn't correctly (or rather at all) handle the failure case. You should do (IIRC):

  #define LET(...) for(__VA_ARGS__,_tmp[0],*_once=_tmp; _once ;_once=0)
  /* ^^^ goes in a header file */
  LET(int fd = open())
    {
    if(fd == -1) { /* handle error, return or break */ }
    /* do stuff */
    }

Re: The Linux Backdoor Attempt of 2003 (2013)

#140
post #12

There should be safe guards against such errors. Even with approval, the reviewer may not notice it. Which brings up the question: how many more root-based backdoors are there now in the source code?

Unfortunately in C and its derivatives, the safeguards would have to be external tools (static analysis, linters); it's a perfectly valid statement in code. I wouldn't mind if languages simply mark assignments in conditions as errors. It's clever code, but clever code should be avoided in critical systems. And in general, I guess.

Not all c-syntax languages let you implicitly convert from integer or pointer to boolean though. Java and C# don't. I have heard MISRA C doesn't allow it.

I actually don't mind this feature of C personally, just playing devil's advocate. Some people feel really strongly about not implicitly allowing conversion to bool. This is why.

Post reply on HN