Announcement

Collapse
No announcement yet.

X.Org Server Hit By New Local Privilege Escalation Vulnerability

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Originally posted by ryao View Post
    We can agree to disagree until you realize that the propaganda that rewrites in Rust are guaranteed to be better than mature code is false.
    I've never said any software rewrite in Rust is absolutely better than original, never made that claim.
    What I have been questioning from the start, is that rewrite doesn't necessary introduce more bugs.

    Originally posted by ryao View Post
    Most people will realize that within 10 years. I am just sick of seeing it and 10 years is a long time to wait, so I felt obligated to say something. I have already been through this once with Java and I will be through it again with Rust. What really bothers me is that after people learn that, I will have to go through this again with the language that comes after Rust. Just thinking about it makes me want to speak out to try to end this frustrating cycle, since it is painful to watch. :/
    Rewriting softwares in new PL isn't entirely a bad idea, as it can reveal pros and cons of writing new projects in that PL and potentially improve it.

    In terms of Rust, there is indeed advantages of rewriting code in Rust since many codebase in real world get new code added, old code refactored/rewritten all the time.
    It's not like that once the code is mature/stable, it never gets changed or only minor changes.

    In reality, they might see refactor due to new requirements and adding significant amount of new code, and some existing projects are already very complex enough to reason that they don't have memory related bugs/CVEs, that's why I think it will be beneficial for some projects to be incrementally rewritten in Rust, like the web browser, linux kernel, systemd, etc.

    What I am proposing is to INCREMENTAL REWRITE, not abandon the existing codebase, freeze dev and everything else just to rewrite, that absolutely makes no sense.

    Comment


    • Originally posted by NobodyXu View Post

      I've never said any software rewrite in Rust is absolutely better than original, never made that claim.
      What I have been questioning from the start, is that rewrite doesn't necessary introduce more bugs.

      Do it from scratch and not having more bugs will be like winning the lottery. It just does not really happen in software development when the original is non-trivial in size and mature.

      If you are literally transcribing the existing source files, then you might have a chance to avoid making new mistakes, but few do that. It is also not always possible due to differences in how different programming languages work.

      Originally posted by NobodyXu View Post
      Rewriting softwares in new PL isn't entirely a bad idea, as it can reveal pros and cons of writing new projects in that PL and potentially improve it.

      In terms of Rust, there is indeed advantages of rewriting code in Rust since many codebase in real world get new code added, old code refactored/rewritten all the time.
      It's not like that once the code is mature/stable, it never gets changed or only minor changes.

      In reality, they might see refactor due to new requirements and adding significant amount of new code, and some existing projects are already very complex enough to reason that they don't have memory related bugs/CVEs, that's why I think it will be beneficial for some projects to be incrementally rewritten in Rust, like the web browser, linux kernel, systemd, etc.

      What I am proposing is to INCREMENTAL REWRITE, not abandon the existing codebase, freeze dev and everything else just to rewrite, that absolutely makes no sense.
      Incrementally adding features to an existing code base is easier than doing a complete rewrite.

      An “incremental rewrite” in a new language does not seem feasible to me. You would be spending substantial time writing bindings. Those bindings would be a source of bugs since you will need to keep things in sync at all times. It is so easy to make mistakes that mistakes are a near certainty unless you find some way to perfectly automate it especially since things like type systems are not going to work across foreign function interfaces. All of the time you could have spent improving the code base will be spent trying to get the same thing you currently have. Maybe you might find some bugs while doing it, but you can find bugs just by reviewing the existing code.

      You will not find many developers working on critical systems advocating this. I took a non-scientific survey of 5 other OSS developers that do kernel development the other day and all of them agreed that rewrites were not worthwhile. That is not a surprise considering that whenever I ask anyone I know who does serious work in this area, I hear that opinions that mirror mine. I imagine you would have difficulty finding many people who think otherwise even if you emailed the LKML. You might find a few outliers, but the overwhelming majority should think otherwise.
      Last edited by ryao; 18 February 2023, 10:09 PM.

      Comment


      • Originally posted by ryao View Post
        Do it from scratch and not having more bugs will be like winning the lottery. It just does not really happen in software development when the original is non-trivial in size and mature.

        If you are literally transcribing the existing source files, then you might have a chance to avoid making new mistakes, but few do that.
        I think you can reuse the previous tests during the rewrite when porting incrementally, so it can avoid re-introducing existing bugs while better architecture/tooling can help in avoiding new mistakes, but again, I am saying what could happen.

        Originally posted by ryao View Post
        An “incremental rewrite” in a new language does not seem feasible to me. You would be spending substantial time writing bindings. Those bindings would be a source of bugs since you will need to keep things in sync at all times. It is so easy to make mistakes that mistakes are a near certainty unless you find some way to perfectly automate it since things like type systems are not going to work across foreign function interfaces. :/

        You will not find many developers working on critical systems advocating this. I took a non-scientific survey of 5 other OSS developers that do kernel development the other day and all of them agreed that rewrites were not worthwhile. Nobody I know who does serious work in this areas thinks this is a good idea. I imagine you would have difficulty finding many people who think otherwise even if you emailed the LKML.
        That could be a problem, but I do think doing this on projects like web browser, Linux kernel and systemd is still beneficial, as it would enable new modules/functionalities to be written in a better PL.

        For rust, it has bindgen for automatically generating bindings for C, though you still need to abstract over it to create a safe interface and macros in C doesn't work in Rust.
        That could be buggy but I am still quite confident as Asahi Linux already uses Rust to write its GPU driver and it turns out to be quite helpful to the developer.

        Comment


        • Originally posted by NobodyXu View Post
          I think you can reuse the previous tests during the rewrite when porting incrementally, so it can avoid re-introducing existing bugs while better architecture/tooling can help in avoiding new mistakes, but again, I am saying what could happen.


          That would require writing a drop-in replacement, but not all attempts to do things over again are drop in replacements since people tend to decide to redesign everything, including external interfaces on which test cases rely. Also, test cases do help, but they tend to suffer from limited test coverage and flaky tests, so it is less useful than you think. If you can reuse them, then they are useful, but only to a point.

          Originally posted by NobodyXu View Post
          That could be a problem, but I do think doing this on projects like web browser, Linux kernel and systemd is still beneficial, as it would enable new modules/functionalities to be written in a better PL.


          Writing new modules in another language is generally fine.

          Originally posted by NobodyXu View Post
          For rust, it has bindgen for automatically generating bindings for C, though you still need to abstract over it to create a safe interface and macros in C doesn't work in Rust.
          That could be buggy but I am still quite confident as Asahi Linux already uses Rust to write its GPU driver and it turns out to be quite helpful to the developer.
          Writing a new GPU driver in Rust is not doing a rewrite.

          Comment


          • Originally posted by ryao View Post

            That would require writing a drop-in replacement, but not all attempts to do things over again are drop in replacements since people tend to decide to redesign everything, including external interfaces on which test cases rely. Also, test cases do help, but they tend to suffer from limited test coverage and flaky tests, so it is less useful than you think. If you can reuse them, then they are useful, but only to a point.

            Yeah, that's certainly true that not all rewrite are drop-in and test cases have limited coverage.
            But the regression tests would definitely help them avoid many errors of the past.

            Originally posted by ryao View Post

            Writing a new GPU driver in Rust is not doing a rewrite.
            Sorry it is a bit off-topic.
            Just saying that for cross language, there can be binding generators that can help.

            Comment


            • Originally posted by NobodyXu View Post
              But the regression tests would definitely help them avoid many errors of the past.
              It depends on how rigorous the project was in making test cases to catch recurrences of past bugs. Most projects write new tests to detect old bugs only occasionally, so there are many past bugs that not only passed the test suite once, but will go undetected by the test suite if they happen again. :/

              Comment


              • Originally posted by ryao View Post

                It depends on how rigorous the project was in making test cases to catch recurrences of past bugs. Most projects write new tests to detect old bugs only occasionally, so there are many past bugs that not only passed the test suite once, but will go undetected by the test suite if they happen again. :/
                Yeah that could happen and I suppose it is not uncommon even for projects with relatively high test coverage.

                Comment


                • Originally posted by NobodyXu View Post

                  Yeah that could happen and I suppose it is not uncommon even for projects with relatively high test coverage.
                  It would be weird to find a project with test coverage that can catch all historical bugs, especially given that some bugs are not easy to reliably test.

                  By the way, as I read and learn more, I find that Rust is not as memory safe as its proponents claim it to be. This paper in particular is somewhat eye opening since the authors not only discuss the types of memory bugs that are still present in Rust, but they also give examples of memory safety bugs in Rust code that have CVE numbers and those examples directly contradict what Rust's promoters say about Rust code not having such bugs:



                  Rust introduces a new type of dangling pointer bug that the authors of that paper call a "lifetime corruption" bug due to the interactions between "safe" and "unsafe" Rust. "Safe" rust also still can have memory safety issues in a number of areas where it relies on runtime checks. The runtime checks turn those into denial of service attack vectors, assuming that the compiler did not miscompile the code. These days, I am interested in finding ways to detect execution paths that can trip assertions in code that I develop, since such things are bugs. A runtime check is no different than an assertion in my eyes, so if code I developed were in Rust, I would still be trying to find memory safety bugs in the code, even if somehow the code entirely used "safe" Rust.

                  Thinking about it some more, if a runtime check that crashes the program when a memory safety issue occurs really is enough to solve the problem, then we could just recompile all C code with various sanitizers to catch all memory issues and put that into production. One reason that we do not do that is that it is somewhat slow. The other reason is that simply crashing a program to prevent execution through a memory safety issue is not a real solution to the problem and is really just a mitigation at best.

                  Rust is able to rely on fewer runtime checks, which helps its performance versus the combination of C/C++ and every imaginable runtime memory safety check via sanitizers. The fact that Rust avoids some of that via compiler checks means that it does not take the route of doing a runtime crash as often as C plus various sanitizers would, but crashing as a mitigation is not always acceptable. If for example, a program crashing due to a memory safety issue means that someone dies, then Rust's runtime mitigations did not improve matters at all. In that case, Rust is a worse solution than C since with C, you can at least use sound static analyzers to prove the absence of memory safety issues, which is currently not possible with Rust due to a lack of tool availability.

                  If you can prove the absence of memory safety issues with C, then that eliminates the argument for using Rust in the first place. The main reason tools that can prove the absence of memory safety issues are not widely deployed is that they are expensive since only industries where failures are known to cause people to die are using them. Industries where failures are not typically considered to cause fatalities instead pursue the latest half baked idea for solving the same problems. If those other industries had adopted sound static analysis tools like the aviation and nuclear power industries did, memory safety would be a solved problem and no one would find Rust interesting any more than they find ALGOL interesting.
                  Last edited by ryao; 08 April 2023, 07:41 PM.

                  Comment


                  • Originally posted by ryao View Post
                    By the way, as I read and learn more, I find that Rust is not as memory safe as its proponents claim it to be. This paper in particular is somewhat eye opening since the authors not only discuss the types of memory bugs that are still present in Rust, but they also give examples of memory safety bugs in Rust code that have CVE numbers and those examples directly contradict what Rust's promoters say about Rust code not having such bugs:
                    I have to disagree on this, since Rust only advertises for safe code being memory safe.
                    In fact, "unsafe" is what separates the concern, leaving potential memory bugs in unsafe code only and unsafe code makes up a significantly less portion of the program than safe code.

                    Also, I don't think "out of bound bug" in Rust is a memory bug since it does not trigger any UB but just terminates the program.

                    It's true that it still aborts the program and causing deny-of-service, but it is 100% better than let it rip and letting attackers take over your system, even if it means that the kernel would panic.

                    Recently, iOS/iPadOS/MacOS is found to have a out-of-bound memory bug in its code and might give app the ability to execute arbitrary code in kernel space.
                    In this case, it will always be better to terminate.

                    Thanks for the links, it will be great if there is a way to check for this in compiler.
                    I haven't read this yet but the easiest way to eliminate this bug is to add a new lint that disables `Index`/`IndexMut` and instead only give programmer access to:

                    Code:
                    fn get(index: usize) -> Option<T>;
                    With that, you can recover from the error.

                    Even if the programmer choose to continue to use "unwrap" or "expect", it can be easily spot in a code review.
                    Or using something like https://github.com/dtolnay/no-panic

                    While that's a bit inconvenient, it might actually make sense to do this.

                    I heard that Ada checks this at compile time by declaring a integer range for the type read in, that is also doable in Rust by creating a newtype though more verbose.

                    Originally posted by ryao View Post
                    Rust is able to rely on fewer runtime checks, which helps its performance versus the combination of C/C++ and every imaginable runtime memory safety check via sanitizers. The fact that Rust avoids some of that via compiler checks means that it does not take the route of doing a runtime crash as often as C plus various sanitizers would, but crashing as a mitigation is not always acceptable. If for example, a program crashing due to a memory safety issue means that someone dies, then Rust's runtime mitigations did not improve matters at all.
                    Kind of disagree, let's consider what will happen if the memory bug is not caught and program not crashed.
                    Indeed it will still continue to run as if everything is ok, until something went terribly wrong and it could also kill people's life.

                    I think deny-of-service causing death in these systems is rare, such system with that high stakes should always have another backup system or something that is significantly less complex, like using a physical system that has no electronics in it.

                    Originally posted by ryao View Post
                    In that case, Rust is a worse solution than C since with C, you can at least use sound static analyzers to prove the absence of memory safety issues, which is currently not possible with Rust due to a lack of tool availability.
                    I'm not that familiar with this as borrow checker proved to be more than enough for most of my projects in Rust.
                    For some projects using unsafe, I would usually use miri plus sanitizer and multiple runs to find bugs and increase confidence.

                    I remembered that ada is also working with Rust, so maybe Rust will have that in the future.

                    Originally posted by ryao View Post
                    If you can prove the absence of memory safety issues with C, then that eliminates the argument for using Rust in the first place. The main reason tools that can prove the absence of memory safety issues are not widely deployed is that they are expensive since only industries where failures are known to cause people to die are using them. Industries where failures are not typically considered to cause fatalities instead pursue the latest half baked idea for solving the same problems. If those other industries had adopted sound static analysis tools like the aviation and nuclear power industries did, memory safety would be a solved problem and no one would find Rust interesting any more than they find ALGOL interesting.
                    I would literally still use Rust in that case.
                    If Rust does not exist, then I would just use C++ or cppfront etc.

                    C lacks generics and instead use macros, a poor man solution.
                    C macro isn't even sanitized and you could easily do weird and very confusing things with it.

                    It doesn't even have a easy to use HashMap/BTreeMap in the stdlib, just one cumbersome function in libc.
                    C++ at least has it, although its complex constructor overloading plus initializer_list stuff makes it a bit harder to use, plus lack of borrow checker in C++ is a really deal breaker since you could easily do something stupid yet not realizing it, like causing a reallocation in HashMap while holding a reference/pointer.

                    It also doesn't support async, so most network bounds program manually implement it or by having a callback based one.
                    That is something really hard to use.

                    I also wish C/C++ would have something like cargo for dependency management instead of using apt/homebrew or whatever.

                    Installing rust toolchain and cross compilation for rust itself is also easy in rust, using rustup would install everything needed.

                    Cross compiling C/C++ is hard and TBH any rust crate using C/C++ crate would also have to deal with this.

                    Thankfully we have zig, which provides zig-cc for easy cross compilation and it even supports cross compiling to different glibc version to keep bardwards compatibility.

                    Not to mention that borrow checker in Rust indeed catches a lot of memory bugs, including thread-related race condition and miri is also very useful.

                    Comment


                    • Originally posted by NobodyXu View Post
                      It's true that it still aborts the program and causing deny-of-service, but it is 100% better than let it rip and letting attackers take over your system, even if it means that the kernel would panic.

                      Originally posted by NobodyXu View Post

                      I have to disagree on this, since Rust only advertises for safe code being memory safe.
                      In fact, "unsafe" is what separates the concern, leaving potential memory bugs in unsafe code only and unsafe code makes up a significantly less portion of the program than safe code.

                      Also, I don't think "out of bound bug" in Rust is a memory bug since it does not trigger any UB but just terminates the program.

                      It's true that it still aborts the program and causing deny-of-service, but it is 100% better than let it rip and letting attackers take over your system, even if it means that the kernel would panic..

                      I was comparing Rust against C + various sanitizers such that the C program will be aborted if there is a memory safety issue. Even without the sanitizers, many memory safety issues also result in aborting a program. Aborting a program is a mitigation, but it is not a silver bullet and is rarely an acceptable solution since the program aborting is still a bug. gpsd for example is written in C and is designed to never abort since aborting can result in people dying since they need gpsd to work to be able to avoid being lost in the wilderness.

                      I suggest going back and rereading what I wrote, since you seem to have missed that I was comparing C augmented with techniques for either eliminating all memory safety issues or turning memory safety issues into aborts to Rust. Rust performs better than C with sanitizers that turn memory safety issues into aborts since it does not need to do as many runtime checks, but it does not perform better than C that has been proven to have no memory safety issues via sound static analysis.

                      The advertising that Rust is more safe than C could not be more wrong when it is compared to C code that has been validated by sound static analysis such as what is used in aviation and nuclear power industries. Those tools are sadly not popular outside of those industries, but their existence makes Rust inferior to C for reliability at the high end of development tool availability. A plane crashing or a nuclear power plant having a meltdown because aborts occurred in every redundant safety system is just not acceptable, but that is the Rust way of making code “memory safe” for a number of memory safety issues that it claims to avoid. Giving Rust partial credit in such situations makes no sense.

                      That said, with the right tools, the two should become equivalent for reliability. Sadly, sound tool development is a low priority for the industry and adoption is an even lower priority. The larger industry is content with half steps that they advertise to be full steps, only for the truth that they were half steps to become widely acknowledged years later. The real solution is not yet another language, but to develop open source sound static analyzers according to the theory of abstract interpretation that have full support for concurrency, recursion and dynamic memory; and can prove the absence of all memory safety issues, undefined behavior and runtime conditions that can trip assertions. Some open source options exist, but they are not as fully featured as the commercial options (e.g. no concurrency support) and almost nobody uses them. I guess even that could be considered a half step, since it does not prove that the program does what it is expected to do, but that is the best that we can expect automated tools to achieve. Beyond that, we need formal verification, but that is infeasible in practice.
                      Last edited by ryao; 10 April 2023, 09:23 AM.

                      Comment

                      Working...
                      X