Slashdot Mirror


New Linux Kernel Flaw Allows Null Pointer Exploits

Trailrunner7 writes "A new flaw in the latest release of the Linux kernel gives attackers the ability to exploit NULL pointer dereferences and bypass the protections of SELinux, AppArmor and the Linux Security Module. Brad Spengler discovered the vulnerability and found a reliable way to exploit it, giving him complete control of the remote machine. This is somewhat similar to the magic that Mark Dowd performed last year to exploit Adobe Flash. Threatpost.com reports: 'The vulnerability is in the 2.6.30 release of the Linux kernel, and in a message to the Daily Dave mailing list Spengler said that he was able to exploit the flaw, which at first glance seemed unexploitable. He said that he was able to defeat the protection against exploiting NULL pointer dereferences on systems running SELinux and those running typical Linux implementations.'"

92 of 391 comments (clear)

  1. Just don't use that version by BPPG · · Score: 3, Insightful

    It's important to note that there is almost never any "preferred" or "special" release of Linux to use. And obviously this flaw doesn't affect people that don't use any security modules.

    This is not good news, but it's important news. The kernel's not likely to have a "fixed" re-release for this version, although there probably will be patches for it as well. And when in doubt, just don't upgrade. Not very many machines can take advantage of all of the cool bleeding-edge features that come with each release, anyways. Lots of older versions get "adopted" by someone who will continue to maintain that single kernel release.

    --
    What's the value of information that you don't know?
    1. Re:Just don't use that version by Kjella · · Score: 3, Insightful

      It's important to note that there is almost never any "preferred" or "special" release of Linux to use. (...) And when in doubt, just don't upgrade. Not very many machines can take advantage of all of the cool bleeding-edge features that come with each release, anyways. Lots of older versions get "adopted" by someone who will continue to maintain that single kernel release.

      As a guess pulled out of my nethers 99% use their distro's default shipping kernel, which means there's maybe a dozen kernels in widespread use with a long tail. Unless you're living on the bleeding edge that's what you want to do, otherwise you have to keep up with and patch stuff like this yourself. I'd much rather trust that than not upgrading or picking some random kernel version and hope it's adopted by someone.

      --
      Live today, because you never know what tomorrow brings
    2. Re:Just don't use that version by INT_QRK · · Score: 2, Funny

      don't know why but "uname -a" was replaced by ">" in my above post...something I did

    3. Re:Just don't use that version by PReDiToR · · Score: 2, Informative

      Your distro (lets say Fedora for this example) has to get the sources for a new kernel, apply their own patches, test that the kernel works, package it and then put it out to beta testers to see if it breaks any one of the many configurations of Fedora that are out there.

      Sound familiar?

      Then they have to upload it to their package management servers and put the fix out there for you to use.

      This might not sound like a lot of work, but who needs a new kernel when they are busy with a whole truck full of other packages that people would notice an upgrade in (OpenOffice.org, KDE, Gnome etc.)?

      If they keep to a kernel version for as long as possible they don't have to rewrite their own patches for a new version, they don't have to wonder if a new problem that comes through is due to the new kernel and they don't have to expend resources on a fairly back-of-the-store package that people (who use stock kernels) don't care about much.

      Contrast that with other users (like myself) who eschew the patches that a distro puts into their kernels and download the latest vanilla sources from kernel.org (usually the same day it comes out), go through the config to make sure nothing major needs tweaking and compile a kernel that will only run at full potential (if I configured everything right ... ) on a very small number of computers, not the whole gamut of x86 based machines (usually) that the Fedora stock kernel is designed for.
      Even on my Arch Linux system that is very good at using up to date sources I prefer to roll my own. If you (and others like you) would prefer to run a newer kernel, read up on it (Scroogle Is Your Friend) and don't be afraid to try. The worst that can happen (if you keep your original kernel in the boot menu, and the modules to support it) is that your new shiny kernel sits there and tells you that there is no way on earth it can boot the system and it is having a bit of a panic with itself. Fixed by booting into your stock kernel and trying again.

      Good luck with it if you choose to go that direction, and remember to read the changelogs for the newer kernels to see what has been improved and fixed. The latest stable kernel is 2.6.30.1, not 2.6.30. It isn't bleeding edge, it is the latest stable. Bleeding edge kernels have -xxn appended (where xxn is letters and numbers depending on what type of kernel or patches are added).

      --

      Do not meddle in the affairs of geeks for they are subtle and quick to anger
    4. Re:Just don't use that version by mvdwege · · Score: 4, Informative

      I'm very sorry, but you are wrong.

      There is no longer an unstable/stable kernel branch difference. Essentially all new kernels are development versions. It is specifically up to the distribution vendors to pick stable kernels out of this continuous release stream.

      Mart

      --
      "I know I will be modded down for this": where's the option '-1, Asking for it'?
  2. DRM is defective by design. by BPPG · · Score: 4, Informative

    I think that tag is mostly reserved for DRM related news...

    And I have seen news about linux DRM modules also tagged that.

    --
    What's the value of information that you don't know?
  3. Re:Double standards by Anonymous Coward · · Score: 4, Informative

    Thats because with Windows, no one would be able to marvel at how un-obvious the flaw is. According to The Register, the kernel actually has gaurds in place against just this type of valnerability, but the complier optimized them out during compiling. IMHO this makes this flaw a very good case study, even with security in place, you cannot really trust the compiler. (actually, this flaw apparently only occurs if security is in place... or if you use PulseAudio (in which case, you deserve it!)).

  4. Re:Double standards by Anonymous Coward · · Score: 2, Insightful

    If this had been Windows we'd find out 9 months later after the guy who discovered it informed Microsoft, they stick their fingers up their butt for 3 months. Microsoft would then spend 3 months finding that the code they used to fix the problem (which was copied from a dll they wrote in 2005) causes problems in newer versions of Excel because it uses null pointers to calculate file bloat or something. Then they threaten him with lawsuits for a few months if he releases the information. In a rush to release a fix MS uses a newer bit of code that breaks all versions of Excel because they really dont need another reason for people not to upgrade.

    The end result of which is that MS releases a fix mere days after the flaw is "announced".

    The Excel bug goes unfixed for 4 years because its a low priority and nobody has found a way to exploit it yet.

  5. I always disable those by brunes69 · · Score: 2, Interesting

    I always disable those security modules as they always end up to incompatibilities and other erratic behavior in software.

    Exactly what do they do anyway?

    1. Re:I always disable those by 140Mandak262Jamuna · · Score: 4, Funny

      They create vulnerabilities by allowing remote code to overload error handlers and thus pwn your system?

      --
      sed -e 's/Chuck Norris/Rajnikant/g' joke > fact
    2. Re:I always disable those by Antique+Geekmeister · · Score: 2, Interesting

      They ruin otherwise working code that was written in slightly different environments, and for which the very arcane behavior of SELinux has not been tuned. They're also often difficult to write test suites for, especially the unpredictability of SELinux changes, since they affect behavior due to factors entirely outside the control of the particular program author: they affect behavior based on where the package installs the code and what SELinux policies are in place.

      It's gotten better: Linux operating system authors have gotten more capable with it, and the software authors have learned not to stuff everything wherevery they feel like (with the exception of Dan Bernstein, but he's loosened his licenses, so we can fix that now).

    3. Re:I always disable those by Antique+Geekmeister · · Score: 2, Interesting

      SELinux does help prevent tools from executing in locations or in places that are inappropriate: it helps reduce the destructive capabilities of components that are mis-installed, installed without proper permissions, or that have certain classes of errors. It also helps force you to think before doing something foolish, such as running CGI tools that are not in /var/www/cgi-bin/: it's too easy for foolish people to use .htaccess or poorly handled HTTPD include directives to include some very foolish CGI tools, and I've had SELinux detect this and prevent a fool from running his very dangerous CGI utilities out of his NFS mounted home directory. So it has uses.

      Now, that "Jack will never learn to lock it down, so let's not help him so that he has to do it all from scratch himself" message you seem to have is, I'm afraid to say, both popular and insane. Jack _does not want_ to have to learn this material. Jack just wants to have his web site work. Jack doesn't have the time or the money to invest in a long-term career in server security programming: This is a modest tool that can be helpful against some classic errors. (Running CGI utilities out of home directories is my favorite that is blocked by SELinux by default.)

  6. Re:Double standards by Shinobi · · Score: 3, Insightful

    And yet comp sci trash wonder why some of us actually learn assembler, and don't blindly trust compilers and libraries.

  7. Wait, what? by TheRaven64 · · Score: 4, Interesting
    This code looks right?

    struct sock *sk = tun->sk; // initialize sk with tun->sk
    ...
    if (!tun)
    return POLLERR; // if tun is NULL return error

    So, he's dereferencing tun, and then checking if tun was NULL? Looks like the compiler is performing an incorrect optimisation if it's removing the test, but it's still horribly bad style. This ought to be crashing at the sk = tun->sk line, because the structure is smaller than a page, and page 0 is mapped no-access (I assume Linux does this; it's been standard practice in most operating systems for a couple of decades to protect against NULL-pointer dereferencing). Technically, however, the C standard allows tun->sk to be a valid address, so removing the test is a semantically-invalid optimisation. In practice, it's safe for any structure smaller than a page, because the code should crash before reaching the test.

    So, we have bad code in Linux and bad code in GCC, combining to make this a true GNU/Linux vulnerability.

    --
    I am TheRaven on Soylent News
    1. Re:Wait, what? by Anonymous Coward · · Score: 2, Interesting

      The patch.

    2. Re:Wait, what? by TheSunborn · · Score: 4, Insightful

      I think the compiler is correct. If tun is null, then tun->sk is undefined and the compiler can do what even optimization it want.

      So when the compiler see tun->sk it can assume that tun is not null, and do the optimization, because IF tun is null, then the program is invoked undefined behavier, which the compiler don't have to preserve/handle. (How do you keep the semantic of an undefined program??)

    3. Re:Wait, what? by pdh11 · · Score: 5, Interesting

      Technically, however, the C standard allows tun->sk to be a valid address, so removing the test is a semantically-invalid optimisation.

      No. Technically, if tun is null, dereferencing it in the expression tun->sk invokes undefined behaviour -- not implementation-defined behaviour. It is perfectly valid to remove the test, because no strictly conforming code could tell the difference -- the game is already over once you've dereferenced a null pointer. This is a kernel bug (and not even, as Brad Spengler appears to be claiming, a new class of kernel bug); it's not a GCC bug.

      But as other posters have said, it would indeed be a good security feature for GCC to warn when it does this.

      Peter

    4. Re:Wait, what? by TheRaven64 · · Score: 3, Informative

      No. Technically, if tun is null, dereferencing it in the expression tun->sk invokes undefined behaviour -- not implementation-defined behaviour

      I've seen a lot of people claiming that, however (as someone who hacks on a C compiler) there are a few things I take issue with in your assertion.

      First, NULL is a preprocessor construct, not a language construct; by the time it gets to the compiler the preprocessor has replaced it with a magic constant[1]. The standard requires that it be defined as some value that may not be dereferenced, which is typically 0 (but doesn't have to be, and isn't on some mainframes). Dereferencing NULL is invalid, however that is not what is happening here.

      The value &(tun->sk) is the address of tun, plus a fixed offset. The expression &(((struct foo*)0)->bar) is valid C and will give the value of the offset of the sk field in the foo struct. A typical definition of NULL is (void*)0, and &(((struct foo*)(void*)0)->bar) will also give the value of the offset of the bar field.

      In this case, it is tun->sk, not &(tun->sk) which is being loaded, however the pointer arithmetic which generates the address happens first. If tun is NULL then this is NULL + {the offset of sk}. While dereferencing NULL is explicitly not permitted, pointer arithmetic on NULL is permitted, and dereferencing any non-NULL memory address is permitted.

      This is obvious from an implementation perspective. If pointer arithmetic on the NULL address were not permitted then every single pointer arithmetic expression would require a check at every intermediate stage to make sure that it did not pass through NULL. For example (a - a + a + 1) would be an invalid pointer arithmetic expression on platforms where NULL is address 0 if address computations were not permitted on NULL.

      [1] GCC and C++1x both declare a new language keyword for an invalid pointer, but this is not part of standard C.

      --
      I am TheRaven on Soylent News
    5. Re:Wait, what? by Anonymous Coward · · Score: 2, Informative

      You are completely wrong and you should learn some C before posting crap like this.

      The NULL pointer has the value 0 and no other value. Period. Internally, it can be represented by other bit-patterns than all-0. But the C standard demands that
          void *x = 0;
      generates the NULL pointer.

      The last paragraph is also completely wrong because you fail to realize that the substraction of two pointers gives an integer and not another pointer.

      So: please, please don't post again until you've learnt the absolute basics of the C language to prevent further embarrassment!

    6. Re:Wait, what? by johnw · · Score: 4, Informative

      First, NULL is a preprocessor construct, not a language construct; by the time it gets to the compiler the preprocessor has replaced it with a magic constant[1].

      Which must be either "0" or "(void *) 0".

      The standard requires that it be defined as some value that may not be dereferenced, which is typically 0 (but doesn't have to be

      Not true - the standard requires NULL to be defined as one of the two values given above.

      and isn't on some mainframes

      There are indeed some platforms where a null pointer is not an all-bits-zero value, but this is achieved by compiler magic behind the scenes. It is still created by assigning the constant value 0 to a pointer, and can be checked for by comparing a pointer with a constant 0.

    7. Re:Wait, what? by vslashg · · Score: 3, Informative

      &(((struct foo*)(void*)0)->bar) will also give the value of the offset of the bar field.

      You're speaking with a voice of authority, which is dangerous because of how incorrect in general your post is.

      Others have already pointed out that you are wrong about NULL. Here's precisely what the spec says about the argument to &:

      The operand of the unary & operator shall be either a function designator, the result of a
      [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is
      not declared with the register storage-class specifier.

      (((struct foo*)(void*)0)->bar) in particular is none of those things, and your expression is not legal C.

      Some apparent dereferences of null pointers are allowed. For instance:

      void *a = 0;
      void *b = &(*a);

      The above is legal not because dereferencing a null pointer is legal, but rather because of an explicit exception to the rule carved out in section 6.5.3.2 of the spec, which says that in this case, the & and * cancel, and "the result is as if both were omitted".

      Your expression is neither safe nor portable. If you do need to check the offset of a field in a structure, use the standard library offsetof() macro -- that's what it's for.

    8. Re:Wait, what? by gnasher719 · · Score: 2, Informative

      The value &(tun->sk) is the address of tun, plus a fixed offset. The expression &(((struct foo*)0)->bar) is valid C and will give the value of the offset of the sk field in the foo struct. A typical definition of NULL is (void*)0, and &(((struct foo*)(void*)0)->bar) will also give the value of the offset of the bar field.

      Wrong. If tun is a null pointer, then the only valid operations are the following:

      1. Assign tun to a pointer variable of a matching type or of type void*, which will set that variable to a null pointer.
      2. Cast tun to another pointer type, which will produce a null pointer.
      3. Cast tun to an integral type, which will produce the value 0 (and this is true whatever bit pattern the compiler uses for null pointers)
      4. Comparing tun to a pointer of a matching type or type void* using the == or != operators.

      Dereferencing a pointer, even if it is just done to calculate an address, is undefined behaviour.

    9. Re:Wait, what? by Athanasius · · Score: 3, Interesting

      This ought to be crashing at the sk = tun->sk line, because the structure is smaller than a page, and page 0 is mapped no-access (I assume Linux does this; it's been standard practice in most operating systems for a couple of decades to protect against NULL-pointer dereferencing).

      If you actually read the exploit code (see: http://grsecurity.net/~spender/cheddar_bay.tgz) the thing that really enables this exploit is one of two ways to map page zero. One of these seems to be a flaw with SELinux (either with the default settings and/or how the default config commonly ships) or using personality(2) to select a personality that explicitly allows this.

      From the exploit for the personality case:

      int main(void)
      {
              int ret;
              struct stat fstat;
       
              ret = personality(PER_SVR4);
       
              if (ret == -1) {
                      fprintf(stderr, "Unable to set personality!\n");
                      return 0;
              }

      Note you do need some setuid root program even with this (from my reading of the exploit code).

      In the SELinux case "it just works" without needing the setuid program it seems.

    10. Re:Wait, what? by ext42fs · · Score: 2, Insightful

      I think the compiler is correct. If tun is null, then tun->sk is undefined and the compiler can do what even optimization it want.

      So when the compiler see tun->sk it can assume that tun is not null, and do the optimization, because IF tun is null, then the program is invoked undefined behavier, which the compiler don't have to preserve/handle. (How do you keep the semantic of an undefined program??)

      The compiler is a complete asshole for deliberately optimizing a too late NULL check away instead of screaming "possibly dereferencing NULL" or something.

    11. Re:Wait, what? by MSG · · Score: 3, Informative

      Which must be either "0" or "(void *) 0". ...
      There are indeed some platforms where a null pointer is not an all-bits-zero value, but this is achieved by compiler magic behind the scenes. It is still created by assigning the constant value 0 to a pointer, and can be checked for by comparing a pointer with a constant 0.

      What you've said is technically true, but doesn't contradict or clarify the post to which you replied in any way, so I'm not sure what your point is.

      As you point out, a NULL pointer is a pointer which is represented by "(void *) 0" in the C language. However, where you may be confused is that "(void *) 0 != (int) 0". At least, not always. The compiler is responsible for determining if any "0" is used in a pointer context and casting it to the appropriate value, which may not be the same as numeric "0". So, while it's always possible to check for a NULL pointer by comparing a pointer to 0 in code, the machine may use a different value for NULL pointers. When you check "if(p)", the binary code that is produced will be comparing the value of "p" to the NULL address which is appropriate for the machine on which it is running.

      The C FAQ has more information.

    12. Re:Wait, what? by sjames · · Score: 2, Insightful

      Arguably the compiler is wrong because it's (obviously) not actually impossible for address 0 to refer to valid memory however against convention and best practices that may be. The very existence of this problem proves that the compiler can NOT assume that tun is not null.

    13. Re:Wait, what? by Anonymous Coward · · Score: 5, Informative

      In this case, it is tun->sk, not &(tun->sk) which is being loaded, however the pointer arithmetic which generates the address happens first. If tun is NULL then this is NULL + {the offset of sk}. While dereferencing NULL is explicitly not permitted, pointer arithmetic on NULL is permitted, and dereferencing any non-NULL memory address is permitted.

      Raven, I've seen you make the same comment a few times in this story. Please stop pushing this nonsense.

      The language standard calls * and -> operations "dereferencing". The way it works is that tun->sk dereferences the whole struct, then hands you the sk field from it.

      When you implement this in your compiler you do an address computation first then load only the field because you don't want to load the whole struct when you don't need to, but that's an implementation detail. The compiler is required to act as if the pointer tun were being dereferenced.

      It would be a major missed optimization bug if the compiler didn't eliminate the later if (!tun) operation. This is a case where the input code is simply wrong.

  8. CFLAGS by Epsillon · · Score: 3, Informative

    CFLAGS+= -fno-delete-null-pointer-checks

    Job done (should work with Gentoo, buggered if I know how to do this in other distros, DYOR), even with -O2/-O3. This is an optimisation/code conflict. The code itself is perfectly valid, so if your CFLAGS are -O -pipe you have nothing to worry about. GCC's info pages show what is enabled at various optimisation levels. -fdelete-null-pointer-checks is enabled at -O2. Of course, this only applies when you compile your own kernel. If vendors are supplying kernels compiled with -O2 without checking what it does to the code then it is obvious who is to blame.

    --
    Resistance is futile. Reactance buggers it up.
    1. Re:CFLAGS by Tony+Hoyle · · Score: 3, Informative

      No. That doesn't fix the problem. All it does is stop the broken optimisation (why the *hell* did someone at gcc think such a thing should be default anyway?)

      You need an -ferror-on-bogus-null-pointer-checks parameter so that the code can be fixed.

      It's an easy error to make. It's the compilers job to warn you.. in this case not only did it fail to throw a warning it also made the problem worse by 'optimising' it.

    2. Re:CFLAGS by QuoteMstr · · Score: 2, Informative

      (why the *hell* did someone at gcc think such a thing should be default anyway?)

      Because it makes sense on every modern platform on earth except for strange embedded ones, that's why. This kernel bug is the result of incorrect kernel code, not a GCC bug.

  9. Re:Double standards by infolation · · Score: 5, Funny

    This language is called Pedantry. A pedant pedantically peddles english into pedanticism.

  10. Re:Serious bug in gcc? by Tony+Hoyle · · Score: 4, Informative

    gcc is definitely doing the wrong thing here.

    Given the code:
    a = foo->bar
    if(foo) something()

    gcc is doing precisely the wrong thing - optimising out the if on the theory that the app would have crashed if it was null.

    What it *should* do is throw a warning (even an error, given the clear intent of the code) pointing out that the variable is dereferensed before it is tested.

    This kind of error being missed by gcc is going to affect a *lot* of code - it's really not that uncommon a coding error, and is easy to do.

  11. Re:Serious bug in gcc? by dakkar · · Score: 2, Informative

    The description given by SANS is a bit misleading. What I believe is happening is:

    1. 1) tun is derefenced during the assignment to sk
    2. 2) if tun were NULL, the dereferencing would blow up the process
    3. 3) so the if (!tun) will always be false if we get there (says the compiler)

    Since point 2 is mostly true, the compiler is not completely wrong to assume point 3

    As Spengler says, a bigger problem is that loading SELinux (or, it looks like, most other security modules) causes the NULL dereference protection to be disabled.

    --
    dakkar - mobilis in mobile
  12. Actually, it's already been fixed by inode_buddha · · Score: 5, Informative

    Actually, it's already been fixed as of 2.6.31-rc3. Interestingly enough, the code by itself was fine until gcc tries to re-assign the pointer value upon compiling. Steven J. Vaughn-Nichols had a decent write-up about it in Computerworld.

    --
    C|N>K
    1. Re:Actually, it's already been fixed by inode_buddha · · Score: 4, Insightful

      Submissions and patches to the kernel are independently tested and verified at least twice before being signed off and committed, usually by upstream developers (more experienced). This is the normal process. The only thing different in this case is that a vulnerability was exposed, hence it is in the news.

      --
      C|N>K
    2. Re:Actually, it's already been fixed by harlows_monkeys · · Score: 2, Interesting

      Actually, it's already been fixed as of 2.6.31-rc3. Interestingly enough, the code by itself was fine until gcc tries to re-assign the pointer value upon compiling

      The code by itself is not fine. The underlying bug is that the kernel is allowing memory at virtual address 0 to be valid. The compiler was designed for an environment where there can never be a valid object at 0, and has chosen the bit pattern 000...000 to be the null pointer. If you want to use C in an environment where 0 can be a valid address, then you need to use a C compiler that uses some bit pattern other then 000...000 for the null pointer.

      And yes, compilers can do that. According to the C standard, assigning the constant 0 to a pointer type does NOT mean assigning the numerical representation of 0. It means assigning a machine dependent value that compares unequal when compared to any pointer to valid memory.

      Furthermore, the Linux version of gcc is designed for an environment where accessing invalid memory causes a fault. Thus, the compiler is doing nothing wrong optimizing out that test for null, since in the environment for which it was designed, null pointers follow the C standard and do not point to a legitimate object, and accesses of illegitimate objects fault, and in such an environment that test can never be executed.

      The kernel developers either need to make sure the kernel environment conforms to gcc's assumptions about its environment, or they should use a special version of gcc designed for the kernel environment.

  13. Re:Just like Linux by Tony+Hoyle · · Score: 3, Insightful

    Unless they're going to add a proper warning for the condition to gcc 'today' it won't, really.

    Sure there are enough developers to go over the kernel to make sure such errors haven't been missed elsewhere, but all it takes is one to miss it and it's still there. Then there's all the other software compiled by gcc..

    I'm not entirely sure how it can lead to an exploit (short of remapping page zero, which requires root privileges so doesn't really count) but since it has it's going to need a proper fix.

  14. Re:Serious bug in gcc? by Bananenrepublik · · Score: 5, Insightful

    They were writing nonsense. GCC makes use of the fact that in the C language any pointer that was dereferenced can't be NULL (this is made explicit in the standard). People use C as a high-level assembly where these assumptions don't hold. This is why code that doesn't assume this breaks. This issue came up a few months ago on the GCC lists, where an embedded developer pointed out that he regularly maps memory to the address 0x0, thereby running into issues with this assumption in the optimizers. The GCC developers introduced a command-line flag which tells the computer to not make that assumption, therefore allowing the compiler to be used even in environments where NULL pointers can be valid.

    Now, the exploit uses this feature of the compiler (or the C language, if you will) to get the kernel into an unspecified state (which is then exploited) -- the NULL pointer check will be "correctly" optimized away. But in order to do this it first has to make sure that the pointer dereference preceding the NULL pointer check doesn't trap. This needs some mucking around with SELinux, namely one has to map memory to 0x0.

    This is a beautiful exploit, which nicely demonstrates how complex interplay between parts can show unforeseen consequences. Linux fixes this by using the aforementioned new compiler option to not have the NULL pointer check optimized away.

  15. Re:Double standards by mortonda · · Score: 5, Informative

    This is arguably more of an issue in the compiler than in the kernel,

    Not completely... from the SANS Storm Center, the code was as follows:


    struct sock *sk = tun->sk; // initialize sk with tun->sk

    if (!tun)
            return POLLERR; // if tun is NULL return error

    The error was that the compiler optimized away the if statement, assuming that tun had already been initialized. The check should have been placed before the sock variable referenced it. Not entirely obvious maybe, but then again, it should have been checked before the assignment.

  16. Re:Double standards by gilgongo · · Score: 3, Insightful

    For such a piece of shit company, they sure do have a lot more marketshare than the computing godOS known as Linux.

    Microsoft's current market share has nothing to do with quality, and everything to do with monopoly. It doesn't matter whether their product is any good or not, because not only do the vast majority of computer users not even know what Windows is, they wouldn't have the first clue what an alternative to Windows or MS Office would be like.

    Time to learn about basic economic theory I think.

    --
    "And the meaning of words; when they cease to function; when will it start worrying you?"
  17. Re:Double standards by ivucica · · Score: 2, Funny

    gcc -pedantic $@

  18. Re:Serious bug in gcc? by Anonymous Coward · · Score: 2, Insightful

    The point is that GCC silently optimizes it away so the programmer has no idea that it's not even running the code they put in (however incorrect that code is). It's like saying "if there is an error in my code just remove that code and keep the rest without telling me".

  19. Re:Double standards by alnjmshntr · · Score: 4, Funny

    Right... Because Microsoft are really losing sleep over the negative comments posted on slashdot, so they have assembled a crack team of slashdotters to game the moderation system in their favour.

    You have to be kidding me.

    --
    If I had created the world I wouldn't have messed about with butterflies and daffodils. I would have started with lasers
  20. Re:Serious bug in gcc? by TheSunborn · · Score: 2, Informative

    This sound more like a gcc/embeded os bug. There is no requirement in c/c++ that the null pointer is (int)0. That is: It don't have to be all 0 bits.
    It just need to be distinct from any valid pointer, so if you run on a platform where you use memory address 0(Valid, but still wierd), you need
    to config gcc(If possible, I don't know if gcc supports this) to use an other bit pattern as null pointer(say 0xeffff), and then you need to configure your embeded os, to never
    return a memory address/buffer that contain the address you have used as null pointer.

  21. Re:Serious bug in gcc? by TheRaven64 · · Score: 5, Interesting
    Except that his explanation is wrong. Dereferencing NULL is illegal, but pointer arithmetic on NULL is legal (and, even if it were illegal, would be practically impossible for a compiler to check). This statement is not dereferencing NULL, it is (potentially) performing pointer arithmetic on NULL (adding the offset of the sk field to it) and then dereferencing the result. This may or may not be valid, depending on how NULL is defined (it doesn't have to be 0 in C, although it usually is), what the offset of sk is, and what the memory layout of the target platform is.

    On most modern platforms, NULL is defined as (void*)0 and the entire bottom page of memory is mapped as no-access. On some embedded systems, however, the bottom few hundred bytes are used for I/O and you get the addresses of these by adding a value to 0. On these systems it is perfectly valid (and correct) C to define a structure which has the layout of the attached devices and then cast 0 to a pointer to this structure and use that for I/O.

    --
    I am TheRaven on Soylent News
  22. Re:Serious bug in gcc? by Rockoon · · Score: 2, Insightful

    This issue is a bit more complicated than you people are making it out to be.

    For the most part, programmers DO WANT this kind of optimization, which is why they use an optimizing compiler. Things like dead-code elimination, constant propogation, and whole program optimizations are important to programmers.

    If you don't want this stuff done, you don't reach for an optimizing compiler and then enable those optimizations. Its their purpose. If (something we know at compile time) should *always* be eliminated in a decent optimizing compiler.

    Now, should GCC make assumptions in this specific case about the state of the pointer? Probably not. This isnt actualy a case of "something we know at compile time" so its a bug in the optimizer.

    --
    "His name was James Damore."
  23. Re:Double standards by Pvt_Ryan · · Score: 2, Insightful

    To be fair if it was windows we'd never know which bit of the code was exploitable or why just that there was an exploit after all we cant SEE their source.

    Good news is that this will be fixed in 2.30.2 in the next month instead of left to be fixed in windows 2012 if ever...

  24. Re:Double standards by Shinobi · · Score: 3, Insightful

    I never said anything about writing everything in it. But many of us with proficiency in it tend to check what the compiler actually outputs, because we know that the compiler is not smarter than the human who wrote it is. (A behaviour further reinforced by the two smelly piles of fecal matter that are MSVC and GCC). This is also why many of us don't blindly trust optimizations to the compiler either, and always double-check. A disassembler is also useful for tearing through critical pieces of code to see if the compiler has built it in the way you intended.

    I've removed quite a few obscure but potentially very nasty bugs in my software by doing that. Then again, I'm a freelancer, I live by my reputation for solid, fault-free code.

  25. Re:Double standards by Shinobi · · Score: 4, Interesting

    Sure. My last entire project has been specifically about that. Been working on a piece of software to go onto an embedded device with deterministic behaviour, with the hardware specs being 32kiBiByte RAM, no cache, 8MHz processor.

    Most people I am forced to work with who have a comp sci degree are unable to work under such conditions. On the other hand, EE's and comp.eng graduates tend to be very nice to work with on such projects.

  26. Re:Double standards by Shamenaught · · Score: 2, Insightful

    Well, Microsoft got that market share by providing cheap software, specifically DOS. It was arguably of low quality, but who cares that much about the quality if it's cheap, right?

    I don't know if it was originally the plan, but at some point along the way Microsoft realized they had a monopoly. They leveraged their share by putting up prices and using FUD tactics to discourage people from switching. The main issue I have is that although the prices went up, the comparative quality of software didn't. Sure, It looks a lot better than DOS, but that's because modern computers are practically supercomputers compared to what DOS ran on. So you see, having a large market share doesn't mean the company isn't a piece of shit, it just means they can be a piece of shit and get away with it.

    Sure, you can argue that a bug in the latest Linux kernel is a sign that there are bugs in lots of OSes. The difference is that with Linux it'll be fixed in a couple of days. Very few people will be using the latest kernel, AFAIK none of the big distros released with it yet, and although some users may have downloaded and compiled the source themselves (I did so myself, as it offered some driver compatibility for new hardware) the architecture is versatile enough that you can simply switch between different kernels, even without fully rebooting, although not completely without disruption.

    --
    mysql> SELECT * FROM `places` WHERE `place` LIKE 'home`; Empty set (0.00 sec)
  27. Re:Serious bug in gcc? by johnw · · Score: 3, Informative

    That is: It don't have to be all 0 bits. It just need to be distinct from any valid pointer,

    Correct - apart from the "just" bit.

    It doesn't need to be all 0 bits.
    It does need to be distinct from any valid pointer.

    *and*

    void *p = 0;

    must generate a null pointer, and:

    p == 0

    must come out true if p is a null pointer. The internal implementation need not be all zeroes, but it does need to look rather like it to source code.

  28. I really don't see how this is a compiler problem? by gbutler69 · · Score: 4, Insightful

    To me, the "if (!tun)" check should/must be before the de-reference; otherwise, it is meaningless! However, the compiler should print a warning in this case, not just optimize it away.

    --
    Over-the-top Response Guy! Giving "Over-the-Top Responses" since 1970.
  29. Re:Linus, you Rookie !! by luca · · Score: 4, Informative

    Ok, I know I shouldn't be feeding the troll, but read the article: the kernel source itself is perfectly fine, is the compiler that optimizes the check away.

  30. no exact code snippet found in Linux by pikine · · Score: 3, Informative

    I tried to google code search for "tun->sk" and Linux doesn't contain that snippet of code. Since SANS claimed that drivers/net/tun.c is at fault, I looked at that source file and didn't find any instances where "if (!...) return ...;" is performed after NULL dereference.

    I think the only fascinating bit of the story is that the SElinux extension allows you to map a page at memory address 0 (the NULL page), making NULL dereferencing valid. I also found out about that a while ago, but I didn't know it has anything to do with SElinux. By the way, mapping the NULL page also works on Mac OS X.

    However, mapping NULL page is typically NOT exploitable. A correct program will simply reject access to NULL pointer, giving it a special semantic regardless whether the memory page itself is valid or not.

    --
    I once had a signature.
  31. Re:Double standards by QuoteMstr · · Score: 4, Informative

    No. You are wrong.

    The code is grabbing the value of the sk field of the tun struct, not its address. Did you misread the code, or do you not actually know C? Or are you perhaps just on the sauce?

    You're claiming the code reads struct sock **sk = &tun->sk when in reality, it reads struct sock* sk = tun->sk, which is completely different.

  32. Re:Serious bug in gcc? by QuoteMstr · · Score: 4, Insightful

    Of course NULL is part of the C language, you blathering idiot, and it always has been. The level of ignorance here astounds me. Don't post about things you don't understand.

    Quoting from C89: (not C99, C89, the one that's older than dirt.)

    4.1.5 Common definitions The following types and macros are defined in the standard header . Some are also defined in other headers, as noted in their respective sections.... NULL which expands to an implementation-defined null pointer constant ... A.6.3.13 Library functions * The null pointer constant to which the macro NULL expands ($4.1.5).

    NULL wasn't even "added" in C89: NULL appears in the oldest, cruftiest UNIX code you can imagine. (That link is the original cat command from 1979.)

  33. "Assembler" by Merdalors · · Score: 2, Informative

    In my days (70's) of supporting a family by getting paid to squeeze code into a 32K "mainframe", everybody called it "Assembler" or "Assembler language".

    --
    Slashdot entertains. Windows pays the mortgage.
    1. Re:"Assembler" by Murple+the+Purple · · Score: 2, Informative

      I remember this as well. And here's evidence:

      http://www.amazon.com/Assembler-Language-Programming-Compatible-Computers/dp/0471886572/

  34. Interesting by improfane · · Score: 3, Funny

    Guys, I'm trying to decide what to post:

    [ ] Downplay how serious flaw is
    [ ] Compare to Window's track record
    [x] Make a meta-reference to Slashdot psychology
    [ ] Post work-around that doesn't fix problem
    [ ] Say that flaw is a feature
    [ ] bash Windows
      [ ] Claim that not all Windows software is bad
    [ ] Claim that the more popular gets, Linux will be targeted more
    [ ] Pretend I understand the problem ...or we could RFA

    --
    Slashdot needs Geekcode | Can anyone recommend any good SCIFI? My tastes: Foundation, Startide Rising, CITY, Ringworld,
  35. Re:Serious bug in gcc? by marcansoft · · Score: 5, Insightful

    Sure it does - GCC knows at compile time that if the if() condition were true, we're already in the "undefined behavior" realm and all bets are off. So it gets rid of it. The code is broken: it's not the compiler's job to compile for the maximum defensiveness of the resulting machine code, otherwise we'd all be using bounds-checking compilers. If the compiler realizes that a certain runtime value will lead to undefined results (because the programmer chose to do so), it is free to break the execution as much as it wants in that case for code that runs afterwards. Essentially, undefined behavior is a contract signed by the programmer that says "I certify that this will never happen", which is why the compiler chose to perform this optimization.

    Even though the real bug is clearly in the code, moving on to the realm of what's desirable from a compiler, I think it's clear that this behavior can make some problems worse (to the compiler, problems are binary - if there's a problem all bets are off - but not to us). This is fine in the name of optimization, but I think in this particular instance either a) kernel developers should opt to turn this optimization off, or b) (better) make GCC warn when this kind of optimization happens, because it's quite likely a bug.

    In effect, the code is a form of broken defensive programming (you check after the fact whether you've screwed up). It's wrong, but we still wouldn't want the compiler to silently remove the check. So I think the ideal solution (besides fixing the code) is to add a warning to the compiler. NULL pointer dereferences are a bug in the vast majority of cases, and checking for a NULL pointer after dereferencing it (in such a way that the compiler recognizes it and is about to remove the check) is at best redundant and more likely a bug.

    There's still the issue of the page 0 fuckery. If someone can make page 0 accesses not crash the kernel then that's also a bug - there are good reason why we want NULL and neal-NULL pointer accesses to always crash.

  36. Re:Double standards by dna_(c)(tm)(r) · · Score: 3, Informative

    Oh please, it's a response to

    If this had been Windows, the article would have been tagged defectivebydesign.

    You're not supposed to read the article, but at least the post you're criticizing.

  37. Re:Double standards by kestasjk · · Score: 4, Insightful

    So you can disassemble compiled code, way to go.. Have fun disassembling a huge binary that's far too large to economically analyze in assembly.

    What's that? You don't fully disassemble and analyze large binaries but only critical paths or small binaries? How unique and sought-after your services must be. I'm sure analysis of compiled kernels is the best way to tackle this bug..

    --
    // MD_Update(&m,buf,j);
  38. code found in Linux 2.6.30 by pikine · · Score: 4, Informative

    Oh, found the code on lxr. It looks like Linux kernels up to 2.6.29.6 are NOT affected, and this is a vulnerability introduced in 2.6.30 due to a fairly significant rewrite of tun.c. Linux 2.6.30 was released in Jun 9, 2009, just a month ago. Funny the tun.c rewrite was not mentioned in the set of changes for 2.6.30.

    I think this example actually shows a forte of Linux as open source. New vulnerability is found very quickly after "new" code is released.

    --
    I once had a signature.
  39. the set of changes for 2.6.30 by pikine · · Score: 4, Informative

    For some reason I didn't link this correctly. The set of changes for 2.6.30 is found http://kernelnewbies.org/Linux_2_6_30.

    --
    I once had a signature.
  40. Re:Linus, you Rookie !! by gnasher719 · · Score: 5, Informative

    Ok, I know I shouldn't be feeding the troll, but read the article: the kernel source itself is perfectly fine, is the compiler that optimizes the check away.

    Absolutely not. The code itself has a severe bug: If tun is a null pointer then it invokes undefined behaviour. Undefined behaviour means anything can happen. Anything can happen means a severe bug, especially in kernel code. The optimizing compiler just turned C source code that was buggy, but not obviously enough for the programmer, into assembler code that would have been obviously buggy to anyone. Most definitely not the fault of the compiler.

  41. Re:Double standards by QuoteMstr · · Score: 2, Insightful

    NO ONE has time to write all their code in assembly, not even for the kernel

    To be fair, the OP wasn't suggesting that programs actually be written in assembly, but rather that programmers learn assembly and know how to debug libraries. That's a sentiment I'll second: of course you don't write programs using machine code operations, but when something breaks, it's quite useful to be able to drop down to assembly in a debugger and see what's actually going on, especially when debugging optimized code.

    As for compiler bugs: once in a while, they really do happen. Of course, one's first, second, and even third reaction shouldn't be to blame the compiler, but when all other options are exhausted, the possibility is there.

  42. Re:Double standards by QuoteMstr · · Score: 2, Insightful

    For the sake of argument, let's suppose you're right. (I think it'll be a cold day in hell when the BSDs move away from GCC.) Increasing performance demands will lead to the inclusion of more optimizations in PCC, and these optimizations will lead people like you to make the same complaints about PCC that people make about GCC today.

    Really, what you're opposed to isn't GCC, but the notion of an optimizing compiler. Sorry, but history has spoken: the gain of optimization far outweighs the minor cost of forcing people like you to actually learn what's guaranteed by the language and what is not.

  43. Running a static checker on the Linux kernel? by Animats · · Score: 2, Interesting

    Isn't someone running a static checker on the Linux kernel? There are commercial tools which will find code that can dereference NULL. However, there aren't free tools that will do this.

  44. Re:Double standards by TheSunborn · · Score: 2, Interesting

    The compiler is allowed to assume that no other code(Including no other thread, running the same code) change the value of a variable behind its back(As long as the variable it not volatile(Volatile got it's own can of worms)), so the optimization is safe.

    so in the code

    int *data=myFunc();
    val=*data;
    printf("%d\n",val);
    val=*data; // The compiler is allowed to optimize this call out.
    printf("%d\n",val);

    And the compiler is allowed to turn this into nothing:

    int *val=myFunc(); // Returns a valid pointer to an int.
    *val=10;
    if(*val==11) {
        *val=42; // The compiler may remove anything in here.
    }

    If multi-threaded code were allowed to do what you describe, then it would be impossible to do most of the optimizations that good c compilers do.

  45. Re:Double standards by NormalVisual · · Score: 3, Informative

    And frankly, it's not particularly difficult to work under those constraints. There are a lot of us that were writing code 25-30 years ago, when that level of hardware represented a state-of-the-art microcomputer, except for the 8 MHz CPU - most CPUs then ran only a fraction of that speed. I still marvel at the fact that the tiny BlackBerry that I hold in my hand is *in every way* a faster and more capable computer than what I worked on back in the Dark Ages.

    Assembly of any sort isn't that difficult once you get some experience with it, and with the proper macros and defines set up, it can actually be fairly quick to code in. Some chips are easier than others (the 68K was *awesome* to code for), but it just requires some attention to detail and a good understanding of how the machine works.

    --
    Please stand clear of the doors, por favor mantenganse alejado de las puertas
  46. Re:Double standards by BitZtream · · Score: 2, Informative

    A bug exists with or without the optimization if the code you pasted is the actual code. tun being null makes the tun->sk reference invalid. You should end up with a panic at this point.

    If the compiler optimized away the tun check without there being a previous tun check, there is also a compiler bug. The compiler shouldn't have assumed that tun was initialized just because it was read from, which is all a dereference is, a read and an add.

    --
    Persistent Volume manager for Kubernetes - https://github.com/dwimsey/openshift-pvmanager
  47. Re:Double standards by BitZtream · · Score: 3, Informative

    Yes, but the rest of us have written about 1000 times more code than you because we didn't spend our time checking a ton of assembly because we presume the compiler is flawed.

    There are times when this sort of checking is acceptable if not required. The kernel is a good place to do it.

    You aren't going to do this for KDE or Gnome however.

    --
    Persistent Volume manager for Kubernetes - https://github.com/dwimsey/openshift-pvmanager
  48. Re:Serious bug in gcc? by Rockoon · · Score: 3, Interesting

    In effect, the code is a form of broken defensive programming (you check after the fact whether you've screwed up). It's wrong, but we still wouldn't want the compiler to silently remove the check. So I think the ideal solution (besides fixing the code) is to add a warning to the compiler. NULL pointer dereferences are a bug in the vast majority of cases, and checking for a NULL pointer after dereferencing it (in such a way that the compiler recognizes it and is about to remove the check) is at best redundant and more likely a bug.

    My problem with this sort of thinking is when you throw in macros and templates and whatnot, there can end up being hundreds, thousands, even millions of "redundant" tests againt NULL specified by the expanded source. Now, I suspect that simply adding this warning to GCC and then compiling some large project would generate so many such warnings that the only reasonable choice would be to then disable that warning. The warning would then have no value, and if so then that certainly doesnt address the "problem."

    As far as the other stuff.. my point was that the arguement that the compiler should never optimize away such if() statements is flawed. I was responding to someone who did in fact make such a claim. There are certainly cases where the pointer absolutely cannot be NULL (or absolutely must be) .. ex, the pointer was just assigned, or its nested within another test for null.

    --
    "His name was James Damore."
  49. Re:Serious bug in gcc? by LateArthurDent · · Score: 2, Interesting

    Given the code:
    a = foo->bar;
    if(foo) something()

    gcc is doing precisely the wrong thing - optimising out the if on the theory that the app would have crashed if it was null.

    No, that's not the theory. They weren't optimizing the if out because the app would have crashed, they were optimizing the if out because if the programmer is dereferencing foo beforehand without testing, one can assume that the programmer is sure that foo is not null by that point. I agree with you that a warning should be thrown (and I'm not sure if it is or isn't), but that if really should be optimized out.

  50. Re:Double standards by denominateur · · Score: 2, Informative

    The exploit maps 0x00000000 to userspace using pulseaudio, this prevents the segfault.

  51. Re:Double standards by Anonymous Coward · · Score: 2, Informative

    (I think it'll be a cold day in hell when the BSDs move away from GCC.)

    Oh, really! Time to buy me a new coat.

  52. Re:Just like Linux by Jimithing+DMB · · Score: 3, Interesting

    Funny enough a few months back I made a very similar error if not the exact same error while coding on the bootloader for Darwin/x86. Except in my case it wasn't exactly a true error because in the bootloader I know that a page zero dereference isn't going to fault the machine but will instead just read something out of the IVT.

    So as I recall it seemed perfectly reasonable to go ahead and initialize a local variable with the contents of something in the zero page and then check for null and end the function. But GCC had other ideas. It assumed that because I had dereferenced the pointer a few lines above that the pointer must not be NULL so it just stripped my NULL check out completely. Had it warned about this like "warning: pointer is dereferenced before checking for NULL, removing NULL check" then that would have been great. But there was no warning so I wound up sitting in GDB (via VMware debug stub) stepping through the code then looking at the disassembly until I realized that.. oops.. the compiler assumed that this code would never be reached because in user-land it would have segfaulted 4 lines ago if the pointer was indeed NULL.

    Obviously the fix is simple. Declare the variable but don't initialize it at that time. Do the null check and return if null. Then initialize the variable. If using C99 or C++ then you can actually defer the local variable declaration until after you've done the NULL check which IMO is preferable. It may be that the guy wrote it as C99 (where you can do this) then went oops, the compiler won't accept that in older C and simply moved the declaration and initialization statement up to the top of the function instead of splitting the declaration from the initialization. My recollection of how I managed to introduce this bug myself is shady but as I recall it was something like that.

  53. Re:Double standards by K.+S.+Kyosuke · · Score: 2, Insightful

    There *is* a sane way to develop for such environments, *without* C, with predictable results, with deterministic behaviour, in short time, interactively, iteratively, on a reasonably high level and without getting mad. It's called Forth. Why is that such a big deal suddenly, when it was no problem for decades?

    --
    Ezekiel 23:20
  54. Re:Double standards by ToasterMonkey · · Score: 2, Informative

    There aren't any important services that run setuid is there?

    Oh...

  55. Re:Double standards by jelle · · Score: 2, Funny

    but, erm...

    You're right...

    I should have had that coffee first...

    --
    --- Hindsight is 20/20, but walking backwards is not the answer.
  56. Re:Double standards by rtfa-troll · · Score: 2, Insightful

    The error was that the compiler optimized away the if statement,

    Being more specific, based on reading the code in the SANS report after getting the suggestion from a user comment in the Register, the error was that the compiler was in an optimising mode which told it to optimise away such checks where the Null pointer had already been dereferenced. -O2 was active and that clearly means that -fdelete-null-pointer-checks is turned on.

    Two groups are at fault here:

    The optimisation was sufficiently clearly documented (it's listed in gcc under -O2 and when you look at the documentation of that option it does say that some checks may be optimised away and that in some environments this may be dangerous). Thus the Linux Kernel team has some blame.

    In the GCC optimisation options under -O2 it does not explicitly mention that the optimisations may have security implications. There should be, in my opinion, a clear statement that below some optimisation level GCC will try not to change the meaning of code under any circumstances.

    From one point of view, I guess this shows the strength of the Linux model of development where release early/release often means such bugs can be found before the public starts to actually use the software.

    From another point of view, however, I wish that the Linux kernel developers could come up with a more mature attitude to security people, however immature. Yes, it's true that the "security bugs" are, in a sense, just more bugs that could cause loss of data. However, a) that's not an excuse and b) if those bugs did turn up on a real production system in an important application they could cause real problems; exploitable security bugs are much more dangerous than other data loss bugs precisely because they only trigger when someone wants them to trigger.

    Linux kernel people who want their kernel to be broadly userd have to make a clear security statement which says why bugs don't matter. It's not good enough to just say "don't use Linux for high security applications" but it should be enough to say "before you use Linux in a configuration where security might be important, ensure you have done a) a source code audit; b) the functional tests according to XYZ etc...".

    --
    =~ s,(.*),<sarcasm>$1</sarcasm>,g if any_point_you_wish();
  57. Re:Double standards by locofungus · · Score: 2, Interesting


    int *data=myFunc();
    val=*data;
    printf("%d\n",val);
    val=*data; // The compiler is allowed to optimize this call out.
    printf("%d\n",val);

    Actually, the compiler isn't allowed to optimize that second assignment to val out unless it can see the source for printf and can prove that there are not other aliases to the memory that data points to that might be changing it.

    Even if you assume the default printf(), myFunc might be returning a pointer to one of the buffers used for IO.

    This is one of the reasons that C99 introduced the __restrict keyword; to allow the compiler the make the sort of optimization you are suggesting here.

    Tim.

    --
    God said, "div D = rho, div B = 0, curl E = -@B/@t, curl H = J + @D/@t," and there was light.
  58. Re:Double standards by RightSaidFred99 · · Score: 2, Insightful

    C does not support threading. If this code breaks because of threading it is not the compiler's fault. This is not a compiler bug, and the correct behavior includes optimizing this away. It would be _nice_ if it warned.

  59. Re:Serious bug in gcc? by RightSaidFred99 · · Score: 2, Funny

    Because... so many people know the C language? And you clearly don't?

  60. Re:Linus, you Rookie !! by sjames · · Score: 2, Informative

    The code makes a potentially undefined assignment, but before doing anything significant with it, it checks for the undefined condition. It's not technically wrong but it is against best practices. Without the invalid optimization it wouldn't be a problem. In turn, the optimization is in the opposite condition. It is technically wrong, but where best practices are followed, it does no harm.

  61. Re:Double standards by Cyberax · · Score: 2, Informative

    Nope. PulseAudio is NOT necessary to trigger this flaw. Read the exploit source code.

    PS: I hate PulseAudio bashing.

  62. Re:Double standards by kdemetter · · Score: 3, Funny

    i compiled my kernel using that flag , and now it boots Windows instead.

  63. Re:Linus, you Rookie !! by lilo_booter · · Score: 4, Informative

    Umm - no - the *code* does the undefined behaviour and *then* checks if the undefined behaviour could happen. But, heck, mistakes happen - it was identified and fixed. Not much of a story really.

  64. Re:Linus, you Rookie !! by Anonymous Coward · · Score: 2, Informative

    The code *IS* technically wrong: It dereferences a NULL pointer. The fact that the pointer is checked against NULL *after* dereferencing it does not help one bit. Once you invoke undefined behavior, the code could do ANYTHING you can imagine and it wouldn't be the compiler's fault.

  65. Re:Linus, you Rookie !! by sjames · · Score: 2, Interesting

    The rest of us consider it a fundamental law of the universe.

    Clearly, your universe is too small! Technically, the code dereferenced NULL+offset where offset (and so NULL+offset) is non zero (which I presume you are hard wired to consider to be the NULL value).

    In an environment where a segv (or equivalent) won't be triggered, the code's not wrong until it makes use of an invalid dereference. The if would have prevented it. I don't think that makes it GOOD since in most environments it will fail.

    In some languages or with some C optimizers, the assignment would never be evaluated at all until after the if.

    Let's face it, the bug is a corner case in the complex interaction between the compiler and the kernel's vision of the environment.

  66. Re:Bullshit by gnasher719 · · Score: 2, Informative

    If, and only if "tun = 0; if (!tun) ..." be optimised, since NULL is not guarented to be 0.

    I left your comments about some C programmers out, because they just make you look like an idiot.

    A "null pointer constant" is by definition either an integer constant expression with a value of zero, or such an expression cast to (void *).
    NULL is guaranteed to be a macro that evaluates to a "null pointer constant", with parentheses around it if needed.
    In certain contexts (when assigned to a pointer lvalue, or when compared to a pointer expression), the compiler will replace a "null pointer constant" with a null pointer of the correct type.
    When used as the operand of &&, || or !, or used as the controlling expression in an if, while, do-while statement or ?: expression, a null pointer is converted to an int with value 0, any valid pointer that is not a null pointer is converted to an int with value 1.
    When a null pointer is cast to in integer type, the result is 0. When an integer with value 0 is cast to a pointer type, the result is a null pointer.

    The representation of a null pointer (that is what is stored in memory and what memcpy would copy) is not guaranteed to be all-bits zero, but the compiler guarantees that all of the above is still true.

    Dereferencing a null pointer invokes undefined behavior. Whether the instructions that a compiler generates to do this dereferencing cause a crash is irrelevant, the fact that a null pointer is dereferenced is enough. This also applies to pointer arithmetic, where the code will usually not crash, but nevertheless is undefined behaviour. And it is quite clear in the definition of the C language that a compiler is allowed to always assume that there is no undefined behavior. The dereferencing of tun invokes undefined behaviour when tun is a null pointer, therefore the compiler is allowed by the rules of the C language to _assume_ that tun is not a null pointer. Therefore it is absolutely legal for the compiler to remove the test.

  67. Re:Serious bug in gcc? by Your.Master · · Score: 2, Informative

    That's not true. It's not your fault, you just assumed the GP was right, and he's not.

    In your example, you thought b->two was (dereference of (0 + offset)) but actually it's ((dereference of 0) + an offset).

    To get the former you need b to be an actual struct and use (*b.two). Or with it still being a pointer you could do some fancy pointer arithmetic, like *(((int *) b) + 1).