← Back to context

Comment by dhx

3 years ago

Answer: https://git.tukaani.org/?p=xz.git;a=commitdiff;h=f9cf4c05edd...

Description of Linux's Landlock access control system if you are not familiar with it: https://docs.kernel.org/userspace-api/landlock.html

xz official (maybe...) incident response page: https://tukaani.org/xz-backdoor/

So that function checked if the following C code compiled, and only in that situation enabled the landlock?

Except that lone period, hard to recognize because of its small size and proximity to the left edge of the diff, caused the C code to become always invalid, hence keeping the landlock always disabled?

That's both vilely impressive and impressively vile. I didn't even spot it on my first read-through.

  • It also shows how brittle these sorts of checks are in general. I really think that this auto-disable of features based on compilation was a big mistake. It is not only very annoying when packaging things (Why does feature X not work? Because you forgot to include libY in the build environment of course) but they also fail silently even if intended. While this `.` was almost certainly malicious it is easy to imagine an accidental break. Maybe a minor typo or `-Werror`is enabled any one of these functions was marked as must use or something similar.

    It seems like it is infinitely better to have a default set of features and explicitly require the user to say `--enable-x --disable-y` as needed. Then error out if a required library isn't available. (Preferably saying which feature requires it.)

  • It's also iffy tbh. that the compilation check functionality:

    - doesn't force users to differentiate between syntax errors and other errors (e.g. symbols not found). Partially you can't even make it work properly if you want due to C macros.

    - it seems sensible, tbh. if "does compile" checks for compatibility seems sensible then there is so much wrong with the ecosystem in so many ways

  • Even more evil would have been to replace this line

        (void)SYS_landlock_create_ruleset;
    

    with this:

        (void)SYS_landloсk_create_ruleset;

    • Another point where I appreciate the Rust compiler:

          warning: the usage of Script Group `Cyrillic` in this crate consists solely of mixed script confusables
           --> src/lib.rs:1:4
            |
          1 | fn SYS_landloсk_create_ruleset() {
            |    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
            |
            = note: the usage includes 'с' (U+0441)
            = note: please recheck to make sure their usages are indeed what you want
            = note: `#[warn(mixed_script_confusables)]` on by default
      
      

      https://play.rust-lang.org/?version=stable&mode=debug&editio...

      1 reply →

    • With the . the author can claim it was unintentional. It's impossible (or at least very hard) to claim the Cyrillic c is unintentional.

      To me, that makes the . more evil.

      6 replies →

    • After the concept of such attacks had blow up idk. 1?2?3? years ago a lot of places now warn at least when mixing "languages"/ranges or sometimes on any usage of non us-ascii printable characters.

      So stuff like that is increasingly more reliable caught.

      Including by 3rd parties doing any ad-hoc scanning.

      Through adding `compiles check` fail with syntax errors definitely should be added tot he list of auto scan checks, at least in C/C++ (it's not something you would do in most languages tbh. even in C it seems to be an antipatters).

    • Nearly every modern IDE and diff viewer instantly highlights this though? I doubt this would get far.

  • I just got a little more respect for pythonic whitespace-sensitivity

    EDIT: come to think of it, even that might not have done much here, where well-formedness is the issue :(

    • Yeah, if anything, python worsens the situation. I had a friend DOS our server because he accidentally inserted a tab, causing the illusion that one statement was inside a block but was actually outside it. He swore off python at that point. I personally avoid the language, but I understand due to issues like that these days mixing tabs and spaces is an error (or is it just a warning?) by default. Regardless, still pretty silly to me to have whitespace play such a major significant role, besides the fact that I find it visually harder to read, like text without punctuation or capitalisation.

      34 replies →

    • In Python, you only need to indent the `def test_foo` by an additional whitespace, to make it a locally scoped function instead of a proper test function.

      4 replies →

    • AST diffs instead of textual diffs might have helped here (to spot the `.` making the code un-compilable).

      Edit: oof, though the stray character in question is inside a perfectly legitimate C string, so to catch this, any such diffs would need to Matroyshka down and that seems unsolvable / intractable.

      16 replies →

  • I agree. The way I read this, I missed it completely until I searched for it. I was looking too closely at the rest of the code around defines

This has plausible deniability on it.

There's better ways to hide by swapping in Unicode lookalike characters. Some of them even pixel match depending on the font.

Maybe I'm out of the loop but is intentionality settled here?

  • Unicode lookalikes would be detected by IDEs and other tools.

    There would be plausible deniability in a different situation, but this is the same author who implemented the backdoor and several similar changes that disable security features. I don't think the benefit of doubt is deserved here.

    • Ok there's a larger question here about the bazaar software development method.

      How can we ensure say, that Microsoft doesn't pay someone to throw a wrench in libre office development or Adobe to sabotage Gimp?

      There's lots of deception strategies for bad faith actors and given the paucity of people who actually do the work, it's really really hard to be picky.

      Especially with the complexity of library dependencies. Defect-at-a-distance may actually be a common strategy and this is the first that was caught

      10 replies →

  • > Maybe I'm out of the loop but is intentionality settled here?

    Yes. The exploit used a payload, that was stored in the tests directory as a binary compression test case, but which is very clearly a very intentional exploit payload.

    All the sneaky stuff was about deploying that payload without it being obvious.

  • the period right there on the left edge? if I saw that in a patch I'd be through the roof, that looks completely intentional

    • I'd never suspect this to be intentional if I'd spot it in a patch, even given the consequences in this particular case. I have written and committed things into code instead of writing it into some other window several times. Without a linter I probably wouldn't spot an extra dot when reviewing my own change before sending it out.

    • I love this type of hindsight to 20-10 comment. "If I saw...". That is a BIG if. Plenty of smart people on that mailing also missed it. I missed it myself when I opened the HN lead link. Very subtle.

      1 reply →

    • I distinctly remember having to remove such a superfluous . that I accidentally added into a file on multiple occasions.

      If you are using vi and your left shift key is dodgy, that can easily happen by accident.

    • Not me. Maybe someone is using an editor with a . key mapped to something. It's in a pretty convenient place.

      :wq!

This is so vile that even if caught red-handed during PR one could shrug off "oh, my IDE's auto formatting did this".

It seems like Lasse Collin is back on the scene and maybe pissed?

  • If he is innocent and a victim as much as everyone else in all this, I won't blame him for wanting blood.

    Most of us are humans after all, and being social creatures we tend to take violations of trust quite deeply.

  • I worry about his home/personal system, this guy seems to have befriended Lasse in order to get the position, is it possible Lasse himself has been compromised?

    I'd be nuking everything, possibly even disposing of hardware and setting up a new verifiable online identity on a clean system/hardware.

I feel like my version control system is better about highlighting the changed characters than these solid green or red strings.

  • It’s a giant block of new code, what is it supposed to do beyond tell you it’s a giant block of new code?

    Note that this is C code inside if a cmake string, even if your diff can do highlighting the odds it would highlight that are low, and if it did highlighting is generally just lexing so there wouldn’t be much to show.

  • I don't love unified diffs as a rule either. They're very noisy to read in general.

    A side by side in something like "meld" will highlight changes but also means you're reading the full context as it will exist in the code base.

    My number one complaint about "code review" is the number of people who simply run their eyes over the diff (in private orgs) because management says "code review" and that's as far as they ever take that in terms of defining outcomes.

    • I love unified diffs for many applications. You are right that side by side diffs have their uses, too.

  • It's git, so it can show a vastly better diff, just not from a URL with hardcoded diff settings.

    • Yeah, but I’m wondering where the code review was done. In a different context, would this be easier to spot?

What does the dot do?

  • The function is “check_c_source_compiles”. The comment indicates that the intention is to confirm that the Landlock functionality can be compiled on the system, in which case it will be enabled.

    The stray dot isn’t valid C, so it will never compile. By ensuring it can never compile, Landlock will never be enabled.

  • Fails the build, so that Landlock support is never enabled.

    • It feels like this is a poor way to determine if a feature should be enabled. There are just too many reasons it could fail, and default off on compilation failure just seems like a glaring security bug. If this is a common practice, it seems like the community should rethink this choice.

    • I don't think it fails the build. It's part of a test, trying to compile a bit of code. If it compiles the test is true and a certain feature is enabled. If the compilation fails the the feature is disabled.

      This is quite common in build systems. I had such a test produce incorrect results in the kernel build system recently. The problem is that the tests should really look carefully for an expected error message. If the compilation fails with the expected message the test result is false. If the compilation fails for some other reason the build should fail so the developer is forced to investigate.

      Disclaimer: I have not studied the xz build system in detail, just what I saw from the diff plus a bit of extrapolation.

      3 replies →